feat: 添加执行费用统计及token信息记录
在流程执行和节点执行中新增 TotalFee 和 TokenInfo 字段,用于记录每次模型调用的详细计费数据;流程执行完成时汇总所有节点的 token 消耗和费用;重构 token 更新逻辑,从响应字段提取改为使用回调返回的 billingData;优化 URL 后缀提取方法以正确处理带查询参数的链接。
This commit is contained in:
@@ -14,6 +14,7 @@ import (
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strconv"
|
||||
@@ -97,7 +98,7 @@ func GetModelInfo(ctx context.Context, req *flowDto.GetModelInfoReq) (res *flowD
|
||||
return
|
||||
}
|
||||
|
||||
func GetComposeResult(ctx context.Context, buildType int, modelName, promptContent, skillName string, form []map[string]any, userForm []map[string]any, fileUrl []string, sessionId, nodeId string, cause string) (res *flowDto.ComposeCallbackReq, err error) {
|
||||
func GetComposeResult(ctx context.Context, nodeExecutionId int64, buildType int, modelName, promptContent, skillName string, form []map[string]any, userForm []map[string]any, fileUrl []string, sessionId, nodeId string, cause string) (res *flowDto.ComposeCallbackReq, err error) {
|
||||
var callbackUrl = utils.GetCallbackURL(ctx, "/flow/execution/composeCallBack")
|
||||
var consult = make([]flowDto.Consult, 0)
|
||||
var collectFileUrls func(val any) (fullyConsumed bool)
|
||||
@@ -206,18 +207,19 @@ func GetComposeResult(ctx context.Context, buildType int, modelName, promptConte
|
||||
if err = gconv.Struct(waitRes, msg); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
updateTokenCount(ctx, nodeExecutionId, msg.BillingData)
|
||||
if !g.IsEmpty(msg.ErrorMsg) {
|
||||
return nil, fmt.Errorf(msg.ErrorMsg)
|
||||
}
|
||||
return msg, nil
|
||||
}
|
||||
|
||||
func CreateGatewayTask(ctx context.Context, epicycleId int64, model string, content map[string]any) (map[string]any, error) {
|
||||
func CreateGatewayTask(ctx context.Context, nodeExecutionId int64, epicycleId int64, model string, content map[string]any) (map[string]any, error) {
|
||||
taskId, err := createGatewayTaskOnly(ctx, epicycleId, model, content)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return waitGatewayResult(ctx, taskId)
|
||||
return waitGatewayResult(ctx, nodeExecutionId, taskId)
|
||||
}
|
||||
|
||||
// createGatewayTaskOnly creates a gateway task and returns the taskId only
|
||||
@@ -249,12 +251,11 @@ func createGatewayTaskOnly(ctx context.Context, epicycleId int64, model string,
|
||||
if g.IsEmpty(res.TaskId) {
|
||||
return "", fmt.Errorf("创建模型任务失败,taskId为空")
|
||||
}
|
||||
|
||||
return res.TaskId, nil
|
||||
}
|
||||
|
||||
// waitGatewayResult waits for a created gateway task to complete and returns the result
|
||||
func waitGatewayResult(ctx context.Context, taskId string) (map[string]any, error) {
|
||||
func waitGatewayResult(ctx context.Context, nodeExecutionId int64, taskId string) (map[string]any, error) {
|
||||
waitRes, err := Wait(ctx, taskId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -264,6 +265,7 @@ func waitGatewayResult(ctx context.Context, taskId string) (map[string]any, erro
|
||||
if err = gconv.Struct(waitRes, task); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
updateTokenCount(ctx, nodeExecutionId, task.BillingData)
|
||||
if task.State == 3 || !g.IsEmpty(task.ErrorMsg) {
|
||||
return nil, fmt.Errorf("模型执行失败:%s", task.ErrorMsg)
|
||||
}
|
||||
@@ -279,14 +281,23 @@ func waitGatewayResult(ctx context.Context, taskId string) (map[string]any, erro
|
||||
}
|
||||
|
||||
// updateTokenCount updates the token count in node execution
|
||||
func updateTokenCount(ctx context.Context, nodeExecutionId int64, responseField string, result map[string]any) {
|
||||
if responseField == "" {
|
||||
func updateTokenCount(ctx context.Context, nodeExecutionId int64, tokenInfo []map[string]any) {
|
||||
res, err := nodeDao.NodeExecutionDao.Get(ctx, &nodeDto.GetNodeExecutionReq{
|
||||
Id: nodeExecutionId,
|
||||
}, entity.NodeExecutionCol.TokenInfo)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
var t []map[string]any
|
||||
for _, item := range res.TokenInfo {
|
||||
t = append(t, item)
|
||||
}
|
||||
for _, item := range tokenInfo {
|
||||
t = append(t, item)
|
||||
}
|
||||
_, _ = nodeDao.NodeExecutionDao.Update(ctx, &nodeDto.UpdateNodeExecutionReq{
|
||||
Id: nodeExecutionId,
|
||||
CompletionTokens: gconv.Int(result[responseField]),
|
||||
TotalTokens: gconv.Int(result[responseField]),
|
||||
Id: nodeExecutionId,
|
||||
TokenInfo: t,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -315,7 +326,7 @@ func GetModelResult(ctx context.Context, sessionId string, nodeInput *flowDto.No
|
||||
}
|
||||
}
|
||||
}
|
||||
composeResult, err := GetComposeResult(ctx, buildType, nodeInput.Config.ModelConfig.ModelName, nodeInput.Config.PromptContent, skillName, form, userForm, nodeInput.Global.FileUrl, sessionId, nodeInput.Config.Id, nodeInput.Config.Name)
|
||||
composeResult, err := GetComposeResult(ctx, nodeInput.NodeExecutionId, buildType, nodeInput.Config.ModelConfig.ModelName, nodeInput.Config.PromptContent, skillName, form, userForm, nodeInput.Global.FileUrl, sessionId, nodeInput.Config.Id, nodeInput.Config.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -344,7 +355,7 @@ func GetModelResult(ctx context.Context, sessionId string, nodeInput *flowDto.No
|
||||
}
|
||||
|
||||
var taskResult map[string]any
|
||||
taskResult, err = CreateGatewayTask(ctx, composeResult.EpicycleId, nodeInput.Config.ModelConfig.ModelName, item)
|
||||
taskResult, err = CreateGatewayTask(ctx, nodeInput.NodeExecutionId, composeResult.EpicycleId, nodeInput.Config.ModelConfig.ModelName, item)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -364,7 +375,7 @@ func GetModelResult(ctx context.Context, sessionId string, nodeInput *flowDto.No
|
||||
}
|
||||
|
||||
mapTaskResult[idx] = taskResult
|
||||
updateTokenCount(ctx, nodeInput.NodeExecutionId, modelInfo.Model.ResponseTokenField, taskResult)
|
||||
//updateTokenCount(ctx, nodeInput.NodeExecutionId, modelInfo.Model.ResponseTokenField, taskResult)
|
||||
}
|
||||
} else {
|
||||
taskIdList := make([]string, len(composeResult.Messages.Rounds))
|
||||
@@ -393,7 +404,7 @@ func GetModelResult(ctx context.Context, sessionId string, nodeInput *flowDto.No
|
||||
go func(idx int, taskId string) {
|
||||
defer wg.Done()
|
||||
|
||||
taskResult, err := waitGatewayResult(subCtx, taskId)
|
||||
taskResult, err := waitGatewayResult(subCtx, nodeInput.NodeExecutionId, taskId)
|
||||
if err != nil {
|
||||
errChan <- err
|
||||
globalCancel() // 全局取消,所有协程收到ctx取消信号快速退出
|
||||
@@ -405,7 +416,7 @@ func GetModelResult(ctx context.Context, sessionId string, nodeInput *flowDto.No
|
||||
mapTaskResult[idx] = taskResult
|
||||
mu.Unlock()
|
||||
|
||||
updateTokenCount(ctx, nodeInput.NodeExecutionId, modelInfo.Model.ResponseTokenField, taskResult)
|
||||
//updateTokenCount(ctx, nodeInput.NodeExecutionId, modelInfo.Model.ResponseTokenField, taskResult)
|
||||
}(idx, taskId)
|
||||
}
|
||||
|
||||
@@ -426,7 +437,7 @@ func GetModelResult(ctx context.Context, sessionId string, nodeInput *flowDto.No
|
||||
} else {
|
||||
for idx, item := range composeResult.Messages.Rounds {
|
||||
mapTaskResult[idx] = item
|
||||
updateTokenCount(ctx, nodeInput.NodeExecutionId, modelInfo.Model.ResponseTokenField, item)
|
||||
//updateTokenCount(ctx, nodeInput.NodeExecutionId, modelInfo.Model.ResponseTokenField, item)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -622,6 +633,32 @@ func GetFileTypeByPath(filePath string) string {
|
||||
}
|
||||
}
|
||||
|
||||
// GetUrlSuffix 获取URL文件后缀
|
||||
// rawUrl: 原始链接
|
||||
// withDot: true 返回 .mp4 false 返回 mp4
|
||||
func GetUrlSuffix(rawUrl string, withDot bool) string {
|
||||
// 解析URL,剥离查询参数
|
||||
u, err := url.Parse(rawUrl)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
// 提取路径部分
|
||||
filePath := u.Path
|
||||
// 获取文件名
|
||||
fileName := path.Base(filePath)
|
||||
if fileName == "" || !strings.Contains(fileName, ".") {
|
||||
return ""
|
||||
}
|
||||
|
||||
// 截取后缀
|
||||
suffix := path.Ext(fileName)
|
||||
if !withDot {
|
||||
suffix = strings.TrimPrefix(suffix, ".")
|
||||
}
|
||||
return suffix
|
||||
}
|
||||
|
||||
func BuildText(text string) string {
|
||||
// 生成单条HTML
|
||||
var htmlBuilder strings.Builder
|
||||
|
||||
Reference in New Issue
Block a user