feat: support for wanxiang image/video generation in ai-proxy & ai-statistics (#2378)

This commit is contained in:
mirror
2025-06-16 09:39:37 +08:00
committed by GitHub
parent de8a4d0b03
commit 7040e4bd34
5 changed files with 47 additions and 19 deletions

View File

@@ -61,6 +61,8 @@ const (
// TODO: 以下是一些非标准的API名称需要进一步确认是否支持 // TODO: 以下是一些非标准的API名称需要进一步确认是否支持
ApiNameCohereV1Rerank ApiName = "cohere/v1/rerank" ApiNameCohereV1Rerank ApiName = "cohere/v1/rerank"
ApiNameQwenAsyncAIGC ApiName = "api/v1/services/aigc"
ApiNameQwenAsyncTask ApiName = "api/v1/tasks/"
providerTypeMoonshot = "moonshot" providerTypeMoonshot = "moonshot"
providerTypeAzure = "azure" providerTypeAzure = "azure"

View File

@@ -37,6 +37,9 @@ const (
qwenBailianPath = "/api/v1/apps" qwenBailianPath = "/api/v1/apps"
qwenMultimodalGenerationPath = "/api/v1/services/aigc/multimodal-generation/generation" qwenMultimodalGenerationPath = "/api/v1/services/aigc/multimodal-generation/generation"
qwenAsyncAIGCPath = "/api/v1/services/aigc/"
qwenAsyncTaskPath = "/api/v1/tasks/"
qwenTopPMin = 0.000001 qwenTopPMin = 0.000001
qwenTopPMax = 0.999999 qwenTopPMax = 0.999999
@@ -74,6 +77,8 @@ func (m *qwenProviderInitializer) DefaultCapabilities(qwenEnableCompatible bool)
return map[string]string{ return map[string]string{
string(ApiNameChatCompletion): qwenChatCompletionPath, string(ApiNameChatCompletion): qwenChatCompletionPath,
string(ApiNameEmbeddings): qwenTextEmbeddingPath, string(ApiNameEmbeddings): qwenTextEmbeddingPath,
string(ApiNameQwenAsyncAIGC): qwenAsyncAIGCPath,
string(ApiNameQwenAsyncTask): qwenAsyncTaskPath,
} }
} }
} }
@@ -689,6 +694,10 @@ func (m *qwenProvider) GetApiName(path string) ApiName {
case strings.Contains(path, qwenTextEmbeddingPath), case strings.Contains(path, qwenTextEmbeddingPath),
strings.Contains(path, qwenCompatibleTextEmbeddingPath): strings.Contains(path, qwenCompatibleTextEmbeddingPath):
return ApiNameEmbeddings return ApiNameEmbeddings
case strings.Contains(path, qwenAsyncAIGCPath):
return ApiNameQwenAsyncAIGC
case strings.Contains(path, qwenAsyncTaskPath):
return ApiNameQwenAsyncTask
default: default:
return "" return ""
} }

View File

@@ -23,6 +23,7 @@ description: AI可观测配置参考
| 名称 | 数据类型 | 填写要求 | 默认值 | 描述 | | 名称 | 数据类型 | 填写要求 | 默认值 | 描述 |
|----------------|-------|------|-----|------------------------| |----------------|-------|------|-----|------------------------|
| `attributes` | []Attribute | 非必填 | - | 用户希望记录在log/span中的信息 | | `attributes` | []Attribute | 非必填 | - | 用户希望记录在log/span中的信息 |
| `disable_openai_usage` | bool | 非必填 | false | 非openai兼容协议时model、token的支持非标配置为true时可以避免报错 |
Attribute 配置说明: Attribute 配置说明:

View File

@@ -22,7 +22,8 @@ Users can also expand observable values through configuration:
| Name | Type | Required | Default | Description | | Name | Type | Required | Default | Description |
|----------------|-------|------|-----|------------------------| |----------------|-------|------|-----|------------------------|
| `attributes` | []Attribute | required | - | Information that the user wants to record in log/span | | `attributes` | []Attribute | optional | - | Information that the user wants to record in log/span |
| `disable_openai_usage` | bool | optional | false | When using a non-OpenAI-compatible protocol, the support for model and token is non-standard. Setting the configuration to true can prevent errors. |
Attribute Configuration instructions: Attribute Configuration instructions:

View File

@@ -92,6 +92,8 @@ type AIStatisticsConfig struct {
attributes []Attribute attributes []Attribute
// If there exist attributes extracted from streaming body, chunks should be buffered // If there exist attributes extracted from streaming body, chunks should be buffered
shouldBufferStreamingBody bool shouldBufferStreamingBody bool
// If disableOpenaiUsage is true, model/input_token/output_token logs will be skipped
disableOpenaiUsage bool
} }
func generateMetricName(route, cluster, model, consumer, metricName string) string { func generateMetricName(route, cluster, model, consumer, metricName string) string {
@@ -160,6 +162,10 @@ func parseConfig(configJson gjson.Result, config *AIStatisticsConfig, log wrappe
} }
// Metric settings // Metric settings
config.counterMetrics = make(map[string]proxywasm.MetricCounter) config.counterMetrics = make(map[string]proxywasm.MetricCounter)
// Parse openai usage config setting.
config.disableOpenaiUsage = configJson.Get("disable_openai_usage").Bool()
return nil return nil
} }
@@ -264,15 +270,17 @@ func onHttpStreamingBody(ctx wrapper.HttpContext, config AIStatisticsConfig, dat
} }
// Set information about this request // Set information about this request
if model, inputToken, outputToken, ok := getUsage(data); ok { if !config.disableOpenaiUsage {
ctx.SetUserAttribute(Model, model) if model, inputToken, outputToken, ok := getUsage(data); ok {
ctx.SetUserAttribute(InputToken, inputToken) ctx.SetUserAttribute(Model, model)
ctx.SetUserAttribute(OutputToken, outputToken) ctx.SetUserAttribute(InputToken, inputToken)
// Set span attributes for ARMS. ctx.SetUserAttribute(OutputToken, outputToken)
setSpanAttribute(ArmsModelName, model, log) // Set span attributes for ARMS.
setSpanAttribute(ArmsInputToken, inputToken, log) setSpanAttribute(ArmsModelName, model, log)
setSpanAttribute(ArmsOutputToken, outputToken, log) setSpanAttribute(ArmsInputToken, inputToken, log)
setSpanAttribute(ArmsTotalToken, inputToken+outputToken, log) setSpanAttribute(ArmsOutputToken, outputToken, log)
setSpanAttribute(ArmsTotalToken, inputToken+outputToken, log)
}
} }
// If the end of the stream is reached, record metrics/logs/spans. // If the end of the stream is reached, record metrics/logs/spans.
if endOfStream { if endOfStream {
@@ -311,15 +319,17 @@ func onHttpResponseBody(ctx wrapper.HttpContext, config AIStatisticsConfig, body
} }
// Set information about this request // Set information about this request
if model, inputToken, outputToken, ok := getUsage(body); ok { if !config.disableOpenaiUsage {
ctx.SetUserAttribute(Model, model) if model, inputToken, outputToken, ok := getUsage(body); ok {
ctx.SetUserAttribute(InputToken, inputToken) ctx.SetUserAttribute(Model, model)
ctx.SetUserAttribute(OutputToken, outputToken) ctx.SetUserAttribute(InputToken, inputToken)
// Set span attributes for ARMS. ctx.SetUserAttribute(OutputToken, outputToken)
setSpanAttribute(ArmsModelName, model, log) // Set span attributes for ARMS.
setSpanAttribute(ArmsInputToken, inputToken, log) setSpanAttribute(ArmsModelName, model, log)
setSpanAttribute(ArmsOutputToken, outputToken, log) setSpanAttribute(ArmsInputToken, inputToken, log)
setSpanAttribute(ArmsTotalToken, inputToken+outputToken, log) setSpanAttribute(ArmsOutputToken, outputToken, log)
setSpanAttribute(ArmsTotalToken, inputToken+outputToken, log)
}
} }
// Set user defined log & span attributes. // Set user defined log & span attributes.
@@ -471,6 +481,11 @@ func writeMetric(ctx wrapper.HttpContext, config AIStatisticsConfig, log wrapper
log.Warnf("ClusterName typd assert failed, skip metric record") log.Warnf("ClusterName typd assert failed, skip metric record")
return return
} }
if config.disableOpenaiUsage {
return
}
if ctx.GetUserAttribute(Model) == nil || ctx.GetUserAttribute(InputToken) == nil || ctx.GetUserAttribute(OutputToken) == nil { if ctx.GetUserAttribute(Model) == nil || ctx.GetUserAttribute(InputToken) == nil || ctx.GetUserAttribute(OutputToken) == nil {
log.Warnf("get usage information failed, skip metric record") log.Warnf("get usage information failed, skip metric record")
return return