diff --git a/config/config.yaml b/config/config.yaml index 6166634..cc45e36 100644 --- a/config/config.yaml +++ b/config/config.yaml @@ -146,7 +146,7 @@ eino_tools: # == 通用工具 == # 表格转图片 excel2pic: - base_url: "http://excel2pic:8000/api/v1/convert" + base_url: "http://192.168.6.109:8010/api/v1/convert" dingtalk: api_key: "dingsbbntrkeiyazcfdg" diff --git a/go.mod b/go.mod index 095f736..ac6aa2a 100644 --- a/go.mod +++ b/go.mod @@ -33,6 +33,8 @@ require ( github.com/spf13/viper v1.17.0 github.com/stretchr/testify v1.11.1 github.com/tmc/langchaingo v0.1.13 + github.com/unidoc/unioffice v1.39.0 + github.com/volcengine/volcengine-go-sdk v1.2.9 github.com/xuri/excelize/v2 v2.10.0 golang.org/x/sync v0.17.0 google.golang.org/grpc v1.64.0 @@ -75,6 +77,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/jmespath/go-jmespath v0.4.0 // 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 @@ -112,6 +115,7 @@ require ( github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/fasthttp v1.51.0 // indirect github.com/valyala/tcplisten v1.0.0 // indirect + github.com/volcengine/volc-sdk-golang v1.0.23 // indirect github.com/wk8/go-ordered-map/v2 v2.1.8 // indirect github.com/xuri/efp v0.0.1 // indirect github.com/xuri/nfp v0.0.2-0.20250530014748-2ddeb826f9a9 // indirect @@ -128,5 +132,6 @@ require ( google.golang.org/genproto/googleapis/rpc v0.0.0-20240604185151-ef581f913117 // indirect google.golang.org/protobuf v1.34.1 // indirect gopkg.in/ini.v1 v1.67.0 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 7d1f8b1..1c08769 100644 --- a/go.sum +++ b/go.sum @@ -101,6 +101,7 @@ github.com/aliyun/credentials-go v1.4.6 h1:CG8rc/nxCNKfXbZWpWDzI9GjF4Tuu3Es14qT8 github.com/aliyun/credentials-go v1.4.6/go.mod h1:Jm6d+xIgwJVLVWT561vy67ZRP4lPTQxMbEYRuT2Ti1U= github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M= github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY= +github.com/avast/retry-go v3.0.0+incompatible/go.mod h1:XtSnn+n/sHqQIpZ10K1qAevBhOOCWBLXXy3hyiqqBrY= github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk= github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg= github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA= @@ -237,6 +238,7 @@ github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvq github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= @@ -248,6 +250,7 @@ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= @@ -266,6 +269,7 @@ github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/wire v0.7.0 h1:JxUKI6+CVBgCO2WToKy/nQk0sS+amI9z9EjVmdaocj4= @@ -293,6 +297,10 @@ github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= +github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= +github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= +github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= @@ -310,6 +318,7 @@ github.com/klauspost/cpuid/v2 v2.2.9/go.mod h1:rqkxqrZ1EhYM9G+hXH7YdowN5R5RGN6NK github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= @@ -443,12 +452,18 @@ github.com/tmc/langchaingo v0.1.13 h1:rcpMWBIi2y3B90XxfE4Ao8dhCQPVDMaNPnN5cGB1Ca github.com/tmc/langchaingo v0.1.13/go.mod h1:vpQ5NOIhpzxDfTZK9B6tf2GM/MoaHewPWM5KXXGh7hg= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= +github.com/unidoc/unioffice v1.39.0 h1:Wo5zvrzCqhyK/1Zi5dg8a5F5+NRftIMZPnFPYwruLto= +github.com/unidoc/unioffice v1.39.0/go.mod h1:Axz6ltIZZTUUyHoEnPe4Mb3VmsN4TRHT5iZCGZ1rgnU= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fasthttp v1.51.0 h1:8b30A5JlZ6C7AS81RsWjYMQmrZG6feChmgAolCl1SqA= github.com/valyala/fasthttp v1.51.0/go.mod h1:oI2XroL+lI7vdXyYoQk03bXBThfFl2cVdIA3Xl7cH8g= github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8= github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= +github.com/volcengine/volc-sdk-golang v1.0.23 h1:anOslb2Qp6ywnsbyq9jqR0ljuO63kg9PY+4OehIk5R8= +github.com/volcengine/volc-sdk-golang v1.0.23/go.mod h1:AfG/PZRUkHJ9inETvbjNifTDgut25Wbkm2QoYBTbvyU= +github.com/volcengine/volcengine-go-sdk v1.2.9 h1:du2gnImtyWXKkQFnJW/GXCs+UBibGGOXIbP1Ams2pB8= +github.com/volcengine/volcengine-go-sdk v1.2.9/go.mod h1:oxoVo+A17kvkwPkIeIHPVLjSw7EQAm+l/Vau1YGHN+A= github.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/fJgbpc= github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw= github.com/x-cray/logrus-prefixed-formatter v0.5.2 h1:00txxvfBM9muc0jiLIEAkAcIMJzfthRT6usrui8uGmg= @@ -839,11 +854,14 @@ google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2 google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg= google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/bsm/ratelimit.v1 v1.0.0-20160220154919-db14e161995a/go.mod h1:KF9sEfUPAXdG8Oev9e99iLGnl2uJMjc5B+4y3O7x610= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= diff --git a/internal/biz/advice.go b/internal/biz/advice.go new file mode 100644 index 0000000..5c2a93a --- /dev/null +++ b/internal/biz/advice.go @@ -0,0 +1,153 @@ +package biz + +import ( + "ai_scheduler/internal/biz/llm_service/third_party" + "ai_scheduler/internal/entitys" + "context" + "encoding/json" + "fmt" + "os" + + "strings" + + "github.com/volcengine/volcengine-go-sdk/service/arkruntime/model" + "github.com/volcengine/volcengine-go-sdk/volcengine" +) + +type AdviceBiz struct { + hsyq *third_party.Hsyq +} + +func NewAdviceBiz(hsyq *third_party.Hsyq) *AdviceBiz { + return &AdviceBiz{ + hsyq: hsyq, + } +} + +const ( + key = "236ba4b6-9daa-4755-b22f-2fd274cd223a" + modelName = "doubao-seed-1-8-251228" +) + +var dataMap = map[string]string{ + "DialectFeatures": (&entitys.DialectFeatures{}).Example(), + "SentencePatterns": (&entitys.SentencePatterns{}).Example(), + "PersonalityTags": (&entitys.PersonalityTags{}).Example(), + "ToneTags": (&entitys.ToneTags{}).Example(), + "SignatureDialogues": (&entitys.SignatureDialogues{}).Example(), + "RegionValue": (&entitys.RegionValue{}).Example(), + "CompetitionComparison": (&entitys.CompetitionComparison{}).Example(), + "CoreSellingPoints": (&entitys.CoreSellingPoints{}).Example(), + "SupportingFacilities": (&entitys.SupportingFacilities{}).Example(), + "DeveloperBacking": (&entitys.DeveloperBacking{}).Example(), + "NeedsMining": (&entitys.NeedsMining{}).Example(), + "PainPointResponse": (&entitys.PainPointResponse{}).Example(), + "ValueBuilding": (&entitys.ValueBuilding{}).Example(), + "ClosingTechniques": (&entitys.ClosingTechniques{}).Example(), + "CommunicationRhythm": (&entitys.CommunicationRhythm{}).Example(), +} + +func (a *AdviceBiz) WordAna(ctx context.Context, wordContent string) error { + examples := a.getAllExamples() + prompt := a.buildSimplePrompt(wordContent, examples) + anaContent, err := a.callLlm(ctx, prompt) + if err != nil { + return err + } + data := a.parseResponse(anaContent) + jsonData, _ := json.MarshalIndent(data, "", " ") + os.WriteFile("extracted.json", jsonData, 0644) + fmt.Println("✅ 数据已保存到 extracted.json") + return nil +} + +func (a *AdviceBiz) callLlm(ctx context.Context, prompt string) (string, error) { + var message = make([]*model.ChatCompletionMessage, 1) + message[0] = &model.ChatCompletionMessage{ + Role: model.ChatMessageRoleSystem, + Content: &model.ChatCompletionMessageContent{ + StringValue: volcengine.String(prompt), + }, + } + + res, err := a.hsyq.RequestHsyq(ctx, key, modelName, message) + if err != nil { + return "", err + } + return *res.Choices[0].Message.Content.StringValue, nil +} + +func (a *AdviceBiz) getAllExamples() map[string]string { + return dataMap +} + +func (a *AdviceBiz) buildSimplePrompt(wordContent string, examples map[string]string) string { + // 最简单的提示词模板 + template := `分析以下房地产销售对话,按指定格式提取信息: + +对话内容: +%s + +请按照以下` + fmt.Sprintf("%d", len(examples)) + `个格式生成JSON数据,每个格式用===分隔: + +%s + +输出要求: +1. 每个结构体一个JSON对象 +2. 严格按照示例格式 +3. 用空行分隔不同结构体` + + // 构建格式部分 + var formats strings.Builder + for name, example := range examples { + formats.WriteString(fmt.Sprintf("=== %s ===\n示例:%s\n\n", name, example)) + } + + return fmt.Sprintf(template, wordContent, formats.String()) +} + +func (a *AdviceBiz) parseResponse(response string) map[string]interface{} { + result := make(map[string]interface{}) + + // 按空行分割 + parts := strings.Split(response, "\n\n") + + for _, part := range parts { + part = strings.TrimSpace(part) + if part == "" || !strings.Contains(part, "{") { + continue + } + + // 找到第一个 { 和最后一个 } + start := strings.Index(part, "{") + end := strings.LastIndex(part, "}") + + if start == -1 || end == -1 || end <= start { + continue + } + + jsonStr := part[start : end+1] + + // 尝试解析 + var data interface{} + if err := json.Unmarshal([]byte(jsonStr), &data); err == nil { + // 判断是什么结构体 + for _, name := range getStructNames() { + if strings.Contains(jsonStr, `"`+name+`"`) || strings.Contains(part, name) { + result[name] = data + break + } + } + } + } + + return result +} + +func getStructNames() []string { + var res = make([]string, 0, len(dataMap)) + for k, _ := range dataMap { + res = append(res, k) + } + return res +} diff --git a/internal/biz/provider_set.go b/internal/biz/provider_set.go index 6f95898..12eb9c3 100644 --- a/internal/biz/provider_set.go +++ b/internal/biz/provider_set.go @@ -3,6 +3,7 @@ package biz import ( "ai_scheduler/internal/biz/do" "ai_scheduler/internal/biz/llm_service" + "ai_scheduler/internal/biz/llm_service/third_party" "github.com/google/wire" ) @@ -21,4 +22,6 @@ var ProviderSetBiz = wire.NewSet( NewQywxAppBiz, NewGroupConfigBiz, do.NewMacro, + NewAdviceBiz, + third_party.NewHsyq, ) diff --git a/internal/data/impl/provider_set.go b/internal/data/impl/provider_set.go index c200234..9c34713 100644 --- a/internal/data/impl/provider_set.go +++ b/internal/data/impl/provider_set.go @@ -18,4 +18,7 @@ var ProviderImpl = wire.NewSet( NewBotGroupConfigImpl, NewBotGroupQywxImpl, NewReportDailyCacheImpl, + NewAdviceAdvicerImplImpl, + NewAdviceProjectImpl, + NewAdviceTalkImpl, ) diff --git a/internal/server/router/router.go b/internal/server/router/router.go index 17fff12..843a8a7 100644 --- a/internal/server/router/router.go +++ b/internal/server/router/router.go @@ -26,7 +26,7 @@ type RouterServer struct { // SetupRoutes 设置路由 func SetupRoutes(app *fiber.App, ChatService *services.ChatService, sessionService *services.SessionService, task *services.TaskService, gateway *gateway.Gateway, callbackService *services.CallbackService, chatHist *services.HistoryService, - capabilityService *services.CapabilityService, + capabilityService *services.CapabilityService, advice *services.AdviceService, ) { app.Use(func(c *fiber.Ctx) error { // 设置 CORS 头 @@ -98,6 +98,9 @@ func SetupRoutes(app *fiber.App, ChatService *services.ChatService, sessionServi // 能力 r.Post("/capability/product/ingest", capabilityService.ProductIngest) // 商品数据提取 r.Post("/capability/product/ingest/:thread_id/confirm", capabilityService.ProductIngestConfirm) // 商品数据提取确认 + + advicer := r.Group("advice/") + advicer.Post("file/word", advice.WordAna) } func routerSocket(app *fiber.App, chatService *services.ChatService) { diff --git a/internal/services/advice.go b/internal/services/advice.go new file mode 100644 index 0000000..9ac7352 --- /dev/null +++ b/internal/services/advice.go @@ -0,0 +1,62 @@ +package services + +import ( + "ai_scheduler/internal/biz" + "ai_scheduler/internal/config" + "ai_scheduler/internal/entitys" + "ai_scheduler/internal/pkg/file_download" + "context" + "errors" + + "net/url" + + "github.com/gofiber/fiber/v2" +) + +// ChatHandler 聊天处理器 +type AdviceService struct { + adviceBiz *biz.AdviceBiz + cfg *config.Config +} + +// NewChatHandler 创建聊天处理器 +func NewAdviceService( + adviceBiz *biz.AdviceBiz, + cfg *config.Config, +) *AdviceService { + return &AdviceService{ + adviceBiz: adviceBiz, + cfg: cfg, + } +} + +func (a *AdviceService) WordAna(c *fiber.Ctx) error { + req := &entitys.WordAnaReq{} + if err := c.BodyParser(req); err != nil { + return err + } + // URL 解码 + fileURL, err := url.PathUnescape(req.WordFileUrl) + if err != nil { + return errors.New("URL 解码失败") + } + result, _, err := file_download.GetWordTextFromURL(fileURL, file_download.IsWordFile) + if err != nil { + return err + } + return a.adviceBiz.WordAna(c.UserContext(), result) +} + +func (a *AdviceService) WordAnat(path string) error { + + // URL 解码 + fileURL, err := url.PathUnescape(path) + if err != nil { + return errors.New("URL 解码失败") + } + result, _, err := file_download.GetWordTextFromURL(fileURL, file_download.IsWordFile) + if err != nil { + return err + } + return a.adviceBiz.WordAna(context.Background(), result) +} diff --git a/internal/services/dtalk_bot_test.go b/internal/services/dtalk_bot_test.go index 37c206e..8df3265 100644 --- a/internal/services/dtalk_bot_test.go +++ b/internal/services/dtalk_bot_test.go @@ -6,6 +6,7 @@ import ( dingtalk2 "ai_scheduler/internal/biz/handle/dingtalk" "ai_scheduler/internal/biz/handle/qywx" "ai_scheduler/internal/biz/llm_service" + "ai_scheduler/internal/biz/llm_service/third_party" "ai_scheduler/internal/biz/tools_regis" "ai_scheduler/internal/config" "ai_scheduler/internal/data/impl" @@ -29,13 +30,13 @@ import ( ) func Test_Report(t *testing.T) { - run() + Run() a := cronService.CronReportSendDingTalk(context.Background()) t.Log(a) } func Test_Report_QYWX(t *testing.T) { - run() + Run() a := cronService.CronReportSendQywx(context.Background()) t.Log(a) } @@ -48,7 +49,7 @@ var ( ) // run 函数是程序的入口函数,负责初始化和配置各个组件 -func run() { +func Run() { // 加载测试配置 // configConfig, err = config.LoadConfigWithTest() configConfig, err = config.LoadConfigWithEnv() @@ -62,6 +63,7 @@ func run() { botConfigImpl := impl.NewBotConfigImpl(db) botGroupImpl := impl.NewBotGroupImpl(db) botUserImpl := impl.NewBotUserImpl(db) + reportDailyCacheImpl := impl.NewReportDailyCacheImpl(db) // 初始化Do业务对象 doDo := do.NewDo(sessionImpl, sysImpl, taskImpl, chatHisImpl, configConfig) // 初始化Ollama客户端 @@ -92,7 +94,7 @@ func run() { // 初始化Ollama服务 ollamaService := llm_service.NewOllamaGenerate(client, utils_vllmClient, configConfig, chatHisImpl) // 初始化工具管理器 - manager := tools.NewManager(configConfig, client) + manager := tools.NewManager(configConfig, client, rdb) // 初始化钉钉联系人客户端 contactClient, _ := dingtalk.NewContactClient(configConfig) // 初始化钉钉记事本客户端 @@ -117,11 +119,15 @@ func run() { botGroupConfigImpl := impl.NewBotGroupConfigImpl(db) botGroupQywxImpl := impl.NewBotGroupQywxImpl(db) qywxAuth := qywx.NewAuth(configConfig, rdb) + macro := do.NewMacro(botGroupImpl, reportDailyCacheImpl, configConfig, rdb) group := qywx.NewGroup(botGroupQywxImpl, qywxAuth) other := qywx.NewOther(qywxAuth) qywxAppBiz := biz.NewQywxAppBiz(configConfig, botGroupQywxImpl, group, other) - groupConfigBiz := biz.NewGroupConfigBiz(toolRegis, utils_ossClient, botGroupConfigImpl, registry, configConfig, impl.NewReportDailyCacheImpl(db), rdb) - dingTalkBotBiz := biz.NewDingTalkBotBiz(doDo, handle, botConfigImpl, botGroupImpl, user, botChatHisImpl, impl.NewReportDailyCacheImpl(db), manager, configConfig, sendCardClient, groupConfigBiz) + groupConfigBiz := biz.NewGroupConfigBiz(toolRegis, utils_ossClient, botGroupConfigImpl, registry, configConfig, reportDailyCacheImpl, rdb, macro, manager, handle) + dingTalkBotBiz := biz.NewDingTalkBotBiz(doDo, handle, botConfigImpl, botGroupImpl, user, botChatHisImpl, reportDailyCacheImpl, manager, configConfig, sendCardClient, groupConfigBiz, macro) // 初始化钉钉机器人服务 cronService = NewCronService(configConfig, dingTalkBotBiz, qywxAppBiz, groupConfigBiz) + hsyq := third_party.NewHsyq() + advicerbiz := biz.NewAdviceBiz(hsyq) + advicer = NewAdviceService(advicerbiz, configConfig) } diff --git a/internal/services/provider_set.go b/internal/services/provider_set.go index 55eed7a..83a9373 100644 --- a/internal/services/provider_set.go +++ b/internal/services/provider_set.go @@ -15,4 +15,5 @@ var ProviderSetServices = wire.NewSet( NewHistoryService, NewCapabilityService, NewCronService, + NewAdviceService, ) diff --git a/internal/test/bench_test.go b/internal/test/bench_test.go new file mode 100644 index 0000000..cbcbad5 --- /dev/null +++ b/internal/test/bench_test.go @@ -0,0 +1,108 @@ +package test + +import ( + "runtime" + "testing" +) + +// 测试用的结构体 +type Person struct { + Name string + Age int + Address string + Email string + Phone string + Balance float64 + Active bool +} + +// 返回指针 +func NewPersonPtr(name string, age int) *Person { + return &Person{ + Name: name, + Age: age, + Address: "Some Address", + Email: "test@example.com", + Phone: "1234567890", + Balance: 1000.0, + Active: true, + } +} + +// 返回值 +func NewPersonValue(name string, age int) Person { + return Person{ + Name: name, + Age: age, + Address: "Some Address", + Email: "test@example.com", + Phone: "1234567890", + Balance: 1000.0, + Active: true, + } +} + +var globalPtr *Person +var globalValue Person + +func BenchmarkSmallStruct(b *testing.B) { + runtime.GC() + b.Run("ValueWithSmallStruct", func(b *testing.B) { + for i := 0; i < b.N; i++ { + p := NewPersonValue("John", 30) + globalValue = p + } + }) + + runtime.Gosched() + runtime.GC() + b.Run("PointerWithSmallStruct", func(b *testing.B) { + for i := 0; i < b.N; i++ { + p := NewPersonPtr("John", 30) + globalPtr = p + } + }) +} + +var globalLargePtr *LargeStruct +var globalLargeValue LargeStruct + +func BenchmarkLargeStruct(b *testing.B) { + runtime.GC() + b.Run("ValueWithLargeStruct", func(b *testing.B) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + s := NewLargeValue(1) + globalLargeValue = s + } + }) + + runtime.Gosched() + runtime.GC() + b.Run("PointerWithLargeStruct", func(b *testing.B) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + p := NewLargePtr(1) + globalLargePtr = p + } + }) +} + +func NewLargePtr(id int) *LargeStruct { + return &LargeStruct{ + ID: id, + } +} + +// 返回值 +func NewLargeValue(id int) LargeStruct { + return LargeStruct{ + ID: id, + } +} + +// Benchmark 大结构体指针 +type LargeStruct struct { + Data [1024]byte + ID int +}