diff --git a/go.mod b/go.mod index 374a7f3..095f736 100644 --- a/go.mod +++ b/go.mod @@ -9,6 +9,7 @@ require ( github.com/alibabacloud-go/dingtalk v1.6.96 github.com/alibabacloud-go/tea v1.2.2 github.com/alibabacloud-go/tea-utils/v2 v2.0.6 + github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible github.com/cloudwego/eino v0.7.7 github.com/cloudwego/eino-ext/components/model/ollama v0.1.6 github.com/cloudwego/eino-ext/components/model/openai v0.1.5 @@ -25,10 +26,12 @@ require ( github.com/gofiber/websocket/v2 v2.2.1 github.com/google/uuid v1.6.0 github.com/google/wire v0.7.0 - github.com/json-iterator/go v1.1.12 github.com/ollama/ollama v0.12.7 github.com/redis/go-redis/v9 v9.16.0 + github.com/robfig/cron/v3 v3.0.1 + github.com/shopspring/decimal v1.4.0 github.com/spf13/viper v1.17.0 + github.com/stretchr/testify v1.11.1 github.com/tmc/langchaingo v0.1.13 github.com/xuri/excelize/v2 v2.10.0 golang.org/x/sync v0.17.0 @@ -39,14 +42,12 @@ require ( ) require ( - dario.cat/mergo v1.0.0 // indirect filippo.io/edwards25519 v1.1.0 // indirect github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.5 // indirect github.com/alibabacloud-go/debug v1.0.1 // indirect github.com/alibabacloud-go/gateway-dingtalk v1.0.2 // indirect github.com/alibabacloud-go/openapi-util v0.1.1 // indirect github.com/alibabacloud-go/tea-xml v1.1.3 // indirect - github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible // indirect github.com/aliyun/credentials-go v1.4.6 // indirect github.com/andybalholm/brotli v1.1.0 // indirect github.com/bahlo/generic-list-go v0.2.0 // indirect @@ -58,6 +59,7 @@ require ( github.com/clbanning/mxj/v2 v2.5.5 // indirect github.com/cloudwego/base64x v0.1.6 // indirect github.com/cloudwego/eino-ext/libs/acl/openai v0.1.2 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/dlclark/regexp2 v1.11.4 // indirect github.com/dustin/go-humanize v1.0.1 // indirect @@ -73,6 +75,7 @@ require ( github.com/hashicorp/hcl v1.0.0 // indirect github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/now v1.1.5 // indirect + github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/compress v1.17.9 // indirect github.com/klauspost/cpuid/v2 v2.2.9 // indirect github.com/leodido/go-urn v1.4.0 // indirect @@ -89,14 +92,13 @@ require ( github.com/pelletier/go-toml/v2 v2.2.2 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pkoukk/tiktoken-go v0.1.6 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/richardlehane/mscfb v1.0.4 // indirect github.com/richardlehane/msoleps v1.0.4 // indirect github.com/rivo/uniseg v0.2.0 // indirect - github.com/robfig/cron/v3 v3.0.1 // indirect github.com/sagikazarmark/locafero v0.3.0 // indirect github.com/sagikazarmark/slog-shim v0.1.0 // indirect github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee // indirect - github.com/shopspring/decimal v1.4.0 // indirect github.com/sirupsen/logrus v1.9.3 // indirect github.com/slongfield/pyfmt v0.0.0-20220222012616-ea85ff4c361f // indirect github.com/sourcegraph/conc v0.3.0 // indirect diff --git a/go.sum b/go.sum index f101537..7d1f8b1 100644 --- a/go.sum +++ b/go.sum @@ -35,8 +35,6 @@ cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohl cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= -dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= -dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= @@ -195,8 +193,6 @@ github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclK github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-kratos/kratos/v2 v2.9.1 h1:EGif6/S/aK/RCR5clIbyhioTNyoSrii3FC118jG40Z0= -github.com/go-kratos/kratos/v2 v2.9.1/go.mod h1:a1MQLjMhIh7R0kcJS9SzJYR43BRI7EPzzN0J1Ksu2bA= github.com/go-kratos/kratos/v2 v2.9.2 h1:px8GJQBeLpquDKQWQ9zohEWiLA8n4D/pv7aH3asvUvo= github.com/go-kratos/kratos/v2 v2.9.2/go.mod h1:Jc7jaeYd4RAPjetun2C+oFAOO7HNMHTT/Z4LxpuEDJM= github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= diff --git a/internal/biz/do/ctx.go b/internal/biz/do/ctx.go index 48813b1..6058b38 100644 --- a/internal/biz/do/ctx.go +++ b/internal/biz/do/ctx.go @@ -253,7 +253,7 @@ func (d *Do) startMessageHandler( requireData *entitys.RequireData, ) <-chan struct{} { done := make(chan struct{}) - var chat []string + var chat []entitys.Response go func() { defer func() { @@ -263,10 +263,13 @@ func (d *Do) startMessageHandler( hisLog = &entitys.ChatHisLog{} ) if len(chat) > 0 { + // 合并所有回答-转json字符串 + ans, _ := json.Marshal(chat) + AiRes := &model.AiChatHi{ SessionID: requireData.Session, Ques: requireData.Req.Text, - Ans: strings.Join(chat, ""), + Ans: string(ans), Files: requireData.Req.Img, TaskID: requireData.Task.TaskID, } @@ -281,14 +284,42 @@ func (d *Do) startMessageHandler( }() + streamText := "" + streamIndex := "" for v := range requireData.Ch { // 自动检测通道关闭 if err := sendWithTimeout(client, v, 10*time.Second); err != nil { log.Errorf("Send error: %v", err) return } - if v.Type == entitys.ResponseText || v.Type == entitys.ResponseStream || v.Type == entitys.ResponseJson { - chat = append(chat, v.Content) + // 文本+卡片 + if v.Type == entitys.ResponseText || v.Type == entitys.ResponseJson { + chat = append(chat, v) } + // 流式-追加 + if v.Type == entitys.ResponseStream { + streamText += v.Content + streamIndex = v.Index + } + // 流式-阶段结束|对话结束 + if streamText != "" && v.Type != entitys.ResponseStream { + chat = append(chat, entitys.Response{ + Content: streamText, + Type: entitys.ResponseText, + Index: streamIndex, + }) + streamText = "" + streamIndex = "" + } + } + // 流式结束 + if streamText != "" { + chat = append(chat, entitys.Response{ + Content: streamText, + Type: entitys.ResponseText, + Index: streamIndex, + }) + streamText = "" + streamIndex = "" } }() diff --git a/internal/biz/do/prompt.go b/internal/biz/do/prompt.go index a27d698..3e4e965 100644 --- a/internal/biz/do/prompt.go +++ b/internal/biz/do/prompt.go @@ -36,9 +36,12 @@ func (f *WithSys) CreatePrompt(ctx context.Context, rec *entitys.Recognize) (mes mes = append(prompt, api.Message{ Role: "system", // 系统角色 Content: rec.SystemPrompt, // 系统提示内容 + // }, api.Message{ // 助手回复无需 + // Role: "assistant", // 助手角色 + // Content: "### 聊天记录:" + pkg.JsonStringIgonErr(rec.ChatHis), // 助手回复内容 }, api.Message{ - Role: "assistant", // 助手角色 - Content: "### 聊天记录:" + pkg.JsonStringIgonErr(rec.ChatHis), // 助手回复内容 + Role: "assistant", // 助手角色 + Content: "用户历史输入:" + pkg.JsonStringIgonErr(rec.ChatHis), // 用户历史输入 }, api.Message{ Role: "user", // 用户角色 Content: content.String(), // 用户输入内容 @@ -63,10 +66,10 @@ func (f *WithSys) getUserContent(ctx context.Context, rec *entitys.Recognize) (c content.WriteString(rec.UserContent.Tag) } - if len(rec.ChatHis.Messages) > 0 { - content.WriteString("### 引用历史聊天记录:\n") - content.WriteString(pkg.JsonStringIgonErr(rec.ChatHis)) - } + // if len(rec.ChatHis.Messages) > 0 { + // content.WriteString("### 引用历史聊天记录:\n") + // content.WriteString(pkg.JsonStringIgonErr(rec.ChatHis)) + // } if hasFile { content.WriteString("\n") diff --git a/internal/biz/router.go b/internal/biz/router.go index 7d045f8..3069ab0 100644 --- a/internal/biz/router.go +++ b/internal/biz/router.go @@ -174,16 +174,17 @@ func (r *AiRouterBiz) buildChatHistory(requireData *entitys.RequireData) entitys // 用户消息 messages = append(messages, entitys.HisMessage{ Role: constants.RoleUser, // 用户角色 - Content: h.Ans, // 用户输入内容 + Content: h.Ques, // 用户输入内容 Timestamp: h.CreateAt.Format(time.DateTime), }) - // 助手消息 - messages = append(messages, entitys.HisMessage{ - Role: constants.RoleAssistant, // 助手角色 - Content: h.Ques, // 助手回复内容 - Timestamp: h.CreateAt.Format(time.DateTime), - }) + // 助手消息 - 助手回复噪音太大且无需,pass + // ansStr := r.ansNoiseReduction(h.Ans) // 助手回复降噪 + // messages = append(messages, entitys.HisMessage{ + // Role: constants.RoleAssistant, // 助手角色 + // Content: ansStr, // 助手回复内容 + // Timestamp: h.CreateAt.Format(time.DateTime), + // }) } // 构建聊天历史上下文 @@ -196,3 +197,20 @@ func (r *AiRouterBiz) buildChatHistory(requireData *entitys.RequireData) entitys }, } } + +// ansNoiseReduction 助手回复降噪 +// func (r *AiRouterBiz) ansNoiseReduction(ansJson string) string { +// // 使用anw统一类型解析 +// ansStruct := make([]*entitys.Response, 0) +// err := json.Unmarshal([]byte(ansJson), &ansStruct) +// if err != nil { +// log.Errorf("解析助手回复失败: %s", err.Error()) +// return ansJson +// } +// var ansStr string +// for _, item := range ansStruct { +// ansStr += item.Content +// } + +// return ansStr +// } diff --git a/internal/data/model/ai_chat_his.gen.go b/internal/data/model/ai_chat_his.gen.go index 595b4c4..f4108ae 100644 --- a/internal/data/model/ai_chat_his.gen.go +++ b/internal/data/model/ai_chat_his.gen.go @@ -20,8 +20,8 @@ type AiChatHi struct { Useful int32 `gorm:"column:useful;not null;comment:0不评价,1有用,其他为无用" json:"useful"` // 0不评价,1有用,其他为无用 CreateAt time.Time `gorm:"column:create_at;default:CURRENT_TIMESTAMP" json:"create_at"` UpdatedAt time.Time `gorm:"column:updated_at;default:CURRENT_TIMESTAMP" json:"updated_at"` - TaskID int32 `gorm:"column:task_id;not null" json:"task_id"` // 任务ID - Content string `gorm:"column:content" json:"content"` // 前端回传数据 + TaskID int32 `gorm:"column:task_id;comment:任务id" json:"task_id"` // 任务id + Content string `gorm:"column:content;comment:前端回传数据" json:"content"` // 前端回传数据 } // TableName AiChatHi's table name diff --git a/internal/pkg/utils_ollama/client.go b/internal/pkg/utils_ollama/client.go index fa88afa..febd8cd 100644 --- a/internal/pkg/utils_ollama/client.go +++ b/internal/pkg/utils_ollama/client.go @@ -53,6 +53,7 @@ func (c *Client) ToolSelect(ctx context.Context, messages []api.Message, tools [ res = resp return nil }) + if err != nil { return }