feat: 新增业务字段路径读写工具

新增 TakeBusinessFields、WriteBusinessFields、SetByPath 与 GetByPath 等工具,支持按映射路径写入请求体与解析响应,并更新相关依赖。
This commit is contained in:
2026-08-18 10:11:09 +08:00
parent 55c797dd96
commit 76c55fbb73
41 changed files with 6011 additions and 56 deletions
+164
View File
@@ -0,0 +1,164 @@
package entity
import (
"model-gateway/consts/model"
"gitea.redpowerfuture.com/red-future/common/beans"
)
type modelManageCol struct {
beans.SQLBaseCol
ModelSupplier string
ModelName string
ModelType string
BaseURL string
SystemModel string
HttpMethod string
ChatModel string
ResponseType string
ApiKey string
Enabled string
RequestHeadMapping string
RequestBodyMapping string
RequestBusinessFieldMapping string
ResponseMapping string
ResponseBodyMapping string
ResponseBusinessFieldMapping string
MaxConcurrency string
TokenPredictPrice string
TokenPredictPriceUnit string
PriceConfig string
MaxTokens string
MinDuration string
MaxDuration string
LastFrame string
}
var ModelManageCol = modelManageCol{
SQLBaseCol: beans.DefSQLBaseCol,
ModelSupplier: "model_supplier",
ModelName: "model_name",
ModelType: "model_type",
BaseURL: "base_url",
SystemModel: "system_model",
HttpMethod: "http_method",
ChatModel: "chat_model",
ResponseType: "response_type",
ApiKey: "api_key",
Enabled: "enabled",
RequestHeadMapping: "request_head_mapping",
RequestBodyMapping: "request_body_mapping",
RequestBusinessFieldMapping: "request_business_field_mapping",
ResponseMapping: "response_mapping",
ResponseBodyMapping: "response_body_mapping",
ResponseBusinessFieldMapping: "response_business_field_mapping",
MaxConcurrency: "max_concurrency",
TokenPredictPrice: "token_predict_price",
TokenPredictPriceUnit: "token_predict_price_unit",
PriceConfig: "price_config",
MaxTokens: "max_tokens",
MinDuration: "min_duration",
MaxDuration: "max_duration",
LastFrame: "last_frame",
}
type ModelManage struct {
beans.SQLBaseDO `orm:",inline"`
ModelSupplier model.SupplierType `orm:"model_supplier" json:"modelSupplier" description:"模型供应商"`
ModelName string `orm:"model_name" json:"modelName" description:"模型名称"`
ModelType model.ModelType `orm:"model_type" json:"modelType" description:"模型类型"`
BaseURL string `orm:"base_url" json:"baseUrl" description:"模型地址"`
SystemModel *bool `orm:"system_model" json:"systemModel" description:"系统模型"`
HttpMethod string `orm:"http_method" json:"httpMethod" description:"http方法"`
ChatModel *bool `orm:"chat_model" json:"chatModel" description:"是否聊天模型"`
ResponseType model.ResponseType `orm:"response_type" json:"responseType" description:"返回类型:1同步,2异步,3流"`
ApiKey string `orm:"api_key" json:"apiKey" description:"api key"`
Enabled *bool `orm:"enabled" json:"enabled" description:"是否启用"`
RequestHeadMapping map[string]string `orm:"request_head_mapping" json:"requestHeadMapping" description:"请求头映射"`
RequestBodyMapping map[string]any `orm:"request_body_mapping" json:"requestBodyMapping" description:"请求体映射"`
RequestBusinessFieldMapping map[string]string `orm:"request_business_field_mapping" json:"requestBusinessFieldMapping" description:"请求业务字段映射"`
ResponseMapping map[string]any `orm:"response_mapping" json:"responseMapping" description:"响应映射"`
ResponseBodyMapping map[string]string `orm:"response_body_mapping" json:"responseBodyMapping" description:"响应主体映射"`
ResponseBusinessFieldMapping map[string]string `orm:"response_business_field_mapping" json:"responseBusinessFieldMapping" description:"响应业务字段映射"`
MaxConcurrency int `orm:"max_concurrency" json:"maxConcurrency" description:"最大并发数"`
TokenMapping *TokenMapping `orm:"token_mapping" json:"tokenMapping" description:"token映射"`
AsyncTaskMapping *AsyncTaskMapping `orm:"async_task_mapping" json:"asyncTaskMapping" description:"异步任务映射"`
TokenPredictPrice float64 `orm:"token_predict_price" json:"tokenPredictPrice" description:"模型Token预估价格"`
TokenPredictPriceUnit string `orm:"token_predict_price_unit" json:"tokenPredictPriceUnit" description:"模型token预估价格单位(秒,百万Token,千Token,字数)"`
PriceConfig *PriceConfig `orm:"price_config" json:"priceConfig" description:"计费规则"`
MaxTokens int `orm:"max_tokens" json:"maxTokens" description:"最大token数"`
MinDuration int `orm:"min_duration" json:"minDuration" description:"最小时长(秒)"`
MaxDuration int `orm:"max_duration" json:"maxDuration" description:"最大时长(秒)"`
LastFrame string `orm:"last_frame" json:"lastFrame" description:"视频的尾帧图像"`
}
type TokenMapping struct {
PromptTokens string `json:"promptTokens" dc:"输入token"`
CompletionTokens string `json:"completionTokens" dc:"输出token"`
TotalTokens string `json:"totalTokens" dc:"总token"`
}
type AsyncTaskMapping struct {
Url string `json:"url" dc:"url"`
HttpMethod string `json:"httpMethod" dc:"http方法" d:"POST"`
RequestHeadMapping map[string]string `json:"requestHeadMapping" description:"请求头映射"`
ResponseMapping map[string]any `json:"responseMapping" description:"响应映射"`
TaskId string `json:"taskId" dc:"任务id"`
TaskStatus string `json:"taskStatus" dc:"任务状态"`
TaskStatusPending string `json:"taskStatusPending" dc:"任务状态-待处理"`
TaskStatusRunning string `json:"taskStatusRunning" dc:"任务状态-运行中"`
TaskStatusSuccess string `json:"taskStatusSuccess" dc:"任务状态-成功"`
TaskStatusFailed string `json:"taskStatusFailed" dc:"任务状态-失败"`
TaskStatusCancel string `json:"taskStatusCancel" dc:"任务状态-取消"`
TaskStatusUnknown string `json:"taskStatusUnknown" dc:"任务状态-未知"`
}
// PriceConfig 模型计费规则(price_config 列,JSONB)。
// 命中条件为固定字段结构(PriceMatch):token 档位从调用用量读取,媒体类型由请求体参考媒体字段推导,
// 全部字段缺省表示无条件命中。
type PriceConfig struct {
Currency string `json:"currency" dc:"币种,默认CNY"`
Unit string `json:"unit" dc:"单价基准:per_1K-千token/per_1M-百万token/per_1-单个"`
Rules []PriceRule `json:"rules" dc:"定价规则数组,按序首条命中生效"`
Discount *PriceDiscount `json:"discount" dc:"模型级限时折扣,规则级可覆盖"`
// 单规则便捷字段:Rules 为空时的兜底价(等价于一条空 match 规则),全部为 0 时不参与计费
InputPrice float64 `json:"inputPrice,omitempty" dc:"输入单价"`
OutputPrice float64 `json:"outputPrice,omitempty" dc:"输出单价"`
CacheHitPrice float64 `json:"cacheHitPrice,omitempty" dc:"缓存命中单价"`
CacheStorageHourPrice float64 `json:"cacheStorageHourPrice,omitempty" dc:"缓存存储单价(元/小时)"`
}
// PriceRule 定价规则:match 条件命中后按价格项计价,缺省项视为 0
type PriceRule struct {
Name string `json:"name"`
Match *PriceMatch `json:"match,omitempty" dc:"命中条件(固定字段,见 PriceMatch);空表示任意调用"`
Input float64 `json:"input" dc:"输入单价(非音频)"`
InputAudio float64 `json:"inputAudio,omitempty" dc:"输入单价(音频),请求体 reference_audio 参考媒体字段命中时生效(见 DetectMediaType"`
Output float64 `json:"output" dc:"输出单价"`
CacheHit float64 `json:"cacheHit" dc:"缓存命中单价(非音频)"`
CacheHitAudio float64 `json:"cacheHitAudio,omitempty" dc:"缓存命中单价(音频),请求体 reference_audio 参考媒体字段命中时生效(见 DetectMediaType"`
CacheStorageHour float64 `json:"cacheStorageHour" dc:"缓存存储单价(元/小时)"`
Discount *PriceDiscount `json:"discount" dc:"规则级折扣,覆盖模型级折扣"`
}
// PriceMatch 命中条件:字段对应调用上下文固定路径,全部缺省(空值)表示无条件命中任意调用。
// token 档位(InputLength/OutputLength/TotalLength/CachedTokens)从调用用量读取,
// MediaType 由请求体参考媒体字段推导(见 DetectMediaType)。
type PriceMatch struct {
MediaType string `json:"mediaType,omitempty" dc:"输入媒体类型精确值(audio/no_video/has_video,由请求体参考媒体字段推导)"`
InputLengthMax int64 `json:"inputLengthMax,omitempty" dc:"输入token上限(<=usage.prompt_tokens"`
InputLengthMin int64 `json:"inputLengthMin,omitempty" dc:"输入token下限(>=usage.prompt_tokens"`
OutputLengthMax int64 `json:"outputLengthMax,omitempty" dc:"输出token上限(<=usage.completion_tokens"`
OutputLengthMin int64 `json:"outputLengthMin,omitempty" dc:"输出token下限(>=usage.completion_tokens"`
TotalLengthMax int64 `json:"totalLengthMax,omitempty" dc:"总token上限(<=usage.total_tokens"`
TotalLengthMin int64 `json:"totalLengthMin,omitempty" dc:"总token下限(>=usage.total_tokens"`
CachedTokensMax int64 `json:"cachedTokensMax,omitempty" dc:"缓存命中token上限(<=usage.cached_tokens"`
CachedTokensMin int64 `json:"cachedTokensMin,omitempty" dc:"缓存命中token下限(>=usage.cached_tokens"`
}
// PriceDiscount 限时折扣:rate 为折扣率(0.4=4折),effective 为空数组表示长期有效
type PriceDiscount struct {
Rate float64 `json:"rate" dc:"折扣率"`
Effective [2]string `json:"effective" dc:"有效期[起始,截止],格式YYYY-MM-DD,缺省长期有效"`
}
+60
View File
@@ -0,0 +1,60 @@
package entity
import (
"gitea.redpowerfuture.com/red-future/common/beans"
)
type modelSessionCol struct {
beans.SQLBaseCol
ModelId string
BizName string
SessionId string
RetryCount string
RequestPath string
ResponsePath string
OriginalRequestPath string
OriginalResponsePath string
DurationSeconds string
PromptTokens string
CompletionTokens string
TotalTokens string
TotalCost string
ErrorMsg string
}
var ModelSessionCol = modelSessionCol{
SQLBaseCol: beans.DefSQLBaseCol,
ModelId: "model_id",
BizName: "biz_name",
SessionId: "session_id",
RetryCount: "retry_count",
RequestPath: "request_path",
ResponsePath: "response_path",
OriginalRequestPath: "original_request_path",
OriginalResponsePath: "original_response_path",
DurationSeconds: "duration_seconds",
PromptTokens: "prompt_tokens",
CompletionTokens: "completion_tokens",
TotalTokens: "total_tokens",
TotalCost: "total_cost",
ErrorMsg: "error_msg",
}
// ModelSession 模型网关任务
type ModelSession struct {
beans.SQLBaseDO `orm:",inline"`
ModelId int64 `orm:"model_id" json:"modelId" dc:"模型ID"`
BizName string `orm:"biz_name" json:"bizName" dc:"业务名称"`
SessionId string `orm:"session_id" json:"sessionId" dc:"会话ID"`
RetryCount int `orm:"retry_count" json:"retryCount" dc:"重试"`
RequestPath string `orm:"request_path" json:"requestPath" dc:"请求参数保存路径"`
ResponsePath string `orm:"response_path" json:"responsePath" dc:"响应结果保存路径"`
OriginalRequestPath string `orm:"original_request_path" json:"originalRequestPath" dc:"原始请求参数保存路径"`
OriginalResponsePath string `orm:"original_response_path" json:"originalResponsePath" dc:"原始响应结果保存路径"`
DurationSeconds int64 `orm:"duration_seconds" json:"durationSeconds" dc:"耗时(秒)"`
PromptTokens int64 `orm:"prompt_tokens" json:"promptTokens" dc:"输入token"`
CompletionTokens int64 `orm:"completion_tokens" json:"completionTokens" dc:"输出token"`
TotalTokens int64 `orm:"total_tokens" json:"totalTokens" dc:"总token"`
TotalCost float64 `orm:"total_cost" json:"totalCost" dc:"总费用(元)"`
ErrorMsg string `orm:"error_msg" json:"errorMsg" dc:"错误消息"`
}
+57
View File
@@ -0,0 +1,57 @@
package entity
import (
"gitea.redpowerfuture.com/red-future/common/beans"
)
type modelTaskEndCol struct {
beans.SQLBaseCol
ModelId string
BizName string
MsgTopic string
RetryCount string
ResponseParams string
OriginalResponseParams string
DurationSeconds string
TaskId string
PromptTokens string
CompletionTokens string
TotalTokens string
TotalCost string
ErrorMsg string
}
var ModelTaskEndCol = modelTaskEndCol{
SQLBaseCol: beans.DefSQLBaseCol,
ModelId: "model_id",
BizName: "biz_name",
MsgTopic: "msg_topic",
RetryCount: "retry_count",
ResponseParams: "response_params",
OriginalResponseParams: "original_response_params",
DurationSeconds: "duration_seconds",
TaskId: "task_id",
PromptTokens: "prompt_tokens",
CompletionTokens: "completion_tokens",
TotalTokens: "total_tokens",
TotalCost: "total_cost",
ErrorMsg: "error_msg",
}
// ModelTaskEnd 模型网关任务
type ModelTaskEnd struct {
beans.SQLBaseDO `orm:",inline"`
ModelId int64 `orm:"model_id" json:"modelId" dc:"模型ID"`
BizName string `orm:"biz_name" json:"bizName" dc:"业务名称"`
MsgTopic string `orm:"msg_topic" json:"msgTopic" dc:"消息主题"`
RetryCount int `orm:"retry_count" json:"retryCount" dc:"重试"`
ResponseParams string `orm:"response_params" json:"responseParams" dc:"响应结果"`
OriginalResponseParams string `orm:"original_response_params" json:"originalResponseParams" dc:"原始响应结果"`
DurationSeconds int64 `orm:"duration_seconds" json:"durationSeconds" dc:"耗时(秒)"`
TaskId string `orm:"task_id" json:"taskId" dc:"任务ID"`
PromptTokens int64 `orm:"prompt_tokens" json:"promptTokens" dc:"输入token"`
CompletionTokens int64 `orm:"completion_tokens" json:"completionTokens" dc:"输出token"`
TotalTokens int64 `orm:"total_tokens" json:"totalTokens" dc:"总token"`
TotalCost float64 `orm:"total_cost" json:"totalCost" dc:"本次调用总费用(元),未配置计费规则为0"`
ErrorMsg string `orm:"error_msg" json:"errorMsg" dc:"错误消息"`
}
+54
View File
@@ -0,0 +1,54 @@
package entity
import (
"gitea.redpowerfuture.com/red-future/common/beans"
)
type modelTaskStartCol struct {
beans.SQLBaseCol
ModelId string
BizName string
MsgTopic string
RetryCount string
RequestPath string
OriginalRequestPath string
ResponseParams string
OriginalResponseParams string
DurationSeconds string
TaskId string
MediaType string
ErrorMsg string
}
var ModelTaskStartCol = modelTaskStartCol{
SQLBaseCol: beans.DefSQLBaseCol,
ModelId: "model_id",
BizName: "biz_name",
MsgTopic: "msg_topic",
RetryCount: "retry_count",
RequestPath: "request_path",
OriginalRequestPath: "original_request_path",
ResponseParams: "response_params",
OriginalResponseParams: "original_response_params",
DurationSeconds: "duration_seconds",
TaskId: "task_id",
MediaType: "media_type",
ErrorMsg: "error_msg",
}
// ModelTaskStart 模型网关任务
type ModelTaskStart struct {
beans.SQLBaseDO `orm:",inline"`
ModelId int64 `orm:"model_id" json:"modelId" dc:"模型ID"`
BizName string `orm:"biz_name" json:"bizName" dc:"业务名称"`
MsgTopic string `orm:"msg_topic" json:"msgTopic" dc:"消息主题"`
RetryCount int `orm:"retry_count" json:"retryCount" dc:"重试"`
RequestPath string `orm:"request_path" json:"requestPath" dc:"请求参数保存路径"`
OriginalRequestPath string `orm:"original_request_path" json:"originalRequestPath" dc:"原始请求参数保存路径"`
ResponseParams map[string]any `orm:"response_params" json:"responseParams" dc:"响应结果"`
OriginalResponseParams map[string]any `orm:"original_response_params" json:"originalResponseParams" dc:"原始响应结果"`
DurationSeconds int64 `orm:"duration_seconds" json:"durationSeconds" dc:"耗时(秒)"`
TaskId string `orm:"task_id" json:"taskId" dc:"任务ID"`
MediaType string `orm:"media_type" json:"mediaType" dc:"输入媒体类型快照(audio/no_video/has_video,创建任务时按请求体推导)"`
ErrorMsg string `orm:"error_msg" json:"errorMsg" dc:"错误消息"`
}