From 9590721d30050450b3c83026b53f160a607c2f86 Mon Sep 17 00:00:00 2001 From: renzhiyuan <465386466@qq.com> Date: Sun, 8 Feb 2026 16:34:41 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E9=87=8D=E6=9E=84advice=E6=A8=A1?= =?UTF-8?q?=E5=9D=97=E5=B9=B6=E4=BC=98=E5=8C=96=E5=AF=B9=E8=AF=9D=E5=8A=9F?= =?UTF-8?q?=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README-test.md | 51 ++- internal/biz/advice_advicer.go | 24 +- internal/biz/advice_chat.go | 304 +++++++++++++++--- internal/biz/advice_client.go | 10 +- internal/biz/advice_file.go | 2 +- internal/biz/advice_project.go | 116 ++++++- internal/biz/advice_skill.go | 10 +- internal/biz/llm_service/third_party/hsyq.go | 65 +++- internal/data/constants/hsyq.go | 25 ++ internal/data/impl/advice_model_sup_impl.go | 17 + internal/data/impl/advice_session_impl.go | 17 + internal/data/impl/provider_set.go | 2 + .../data/model/ai_advice_model_sup.gen.go | 29 ++ internal/data/model/ai_advice_project.gen.go | 12 +- internal/data/model/ai_advice_session.gen.go | 32 ++ internal/data/mongo_model/advicer_chat_his.go | 46 +++ internal/data/mongo_model/provider_set.go | 1 + internal/entitys/advicer_data.go | 35 +- internal/pkg/response.go | 2 +- internal/server/router/router.go | 13 +- internal/services/advice/advicer.go | 6 +- internal/services/advice/chat.go | 42 ++- internal/services/advice/client.go | 3 +- internal/services/advice/project.go | 24 +- internal/services/advice/talk_skill.go | 3 +- tmpl/dataTemp/queryTempl.go | 13 +- 26 files changed, 794 insertions(+), 110 deletions(-) create mode 100644 internal/data/constants/hsyq.go create mode 100644 internal/data/impl/advice_model_sup_impl.go create mode 100644 internal/data/impl/advice_session_impl.go create mode 100644 internal/data/model/ai_advice_model_sup.gen.go create mode 100644 internal/data/model/ai_advice_session.gen.go create mode 100644 internal/data/mongo_model/advicer_chat_his.go diff --git a/README-test.md b/README-test.md index 459e555..4a43562 100644 --- a/README-test.md +++ b/README-test.md @@ -1,3 +1,48 @@ -```json -{"advicer":{"dialectFeatures":{"region":"四川成都话","intensity":0.6,"KeyWords":null},"personalityTags":["耐心细致","专业严谨","善于对比","共情能力强"],"sentencePatterns":{"openingMode":["我给你介绍一下","我们先来看一下","我跟你说一下"],"explanationMode":["是这样的","我跟你讲","你发现没得","我跟你说"],"confirmationMode":["对吧?","是不是嘛?","你晓得不?","明白了噻?"],"summaryMode":["所以说","简单说就是","总而言之"],"transitionMode":["然后的话","再其次","还有一点","除此之外"]},"signatureDialogues":[{"context":"客户质疑地块太小","dialogue":"哥,14亩确实不大,但你要在成都是2.5环内城买房,这种是个普遍存在的一个现象。你看万景和绿城都是13亩,中铁建只有8.8亩,339那个邦泰只有11亩。我们虽然地小,但楼间距开阔啊,看过去都是200多米!"},{"context":"客户担心物业费高","dialogue":"姐,我懂你意思,我们也觉得物业费是有点贵。但招商物业是铂金服务,有管家送外卖、免费宠物喂养这些增值服务。你算一下,就算贵一块钱,十年也就多14000,但好物业让房子增值不止这点!"},{"context":"客户犹豫价格","dialogue":"说实话,这个地段的地价都比28板块贵5000多,但我们单价只贵3000。你看龙湖滨江云河颂套内单价都36000了,我们才33000,真的性价比高!现在不买,以后这个板块可能就买不起了。"}],"toneTags":{"enthusiasm":0.8,"patience":0.9,"confidence":0.85,"friendliness":0.8,"persuasion":0.75}},"client":{"customer":[{"personalInfo":{"name":"唐先生","gender":"男","location":"成都北门","isFirstHome":false,"familyOrganize":"夫妻+1孩+父母同住"},"purchasePurpose":{"primaryPurpose":"改善居住条件","secondaryPurpose":"资产保值","decisionMakers":"夫妻双方"},"coreDemands":{"totalBudgetMin":350,"preferredLayout":"118㎡四房三卫双套房","coreAppeal":"在预算内满足家庭居住功能,确保房产保值"},"concerns":["总价超预算风险","板块保值能力","开发商资金实力","社区小,绿化空间有限"],"decisionProfile":["预算导向,严格控制总价","重点关注户型功能性和实用性","需要对比板块发展潜力","对开发商交付能力有顾虑"]},{"personalInfo":{"name":"冯女士","gender":"女","location":"成都","isFirstHome":false,"familyOrganize":"夫妻+1孩"},"purchasePurpose":{"primaryPurpose":"改善居住条件","secondaryPurpose":"资产保值","decisionMakers":"夫妻双方"},"coreDemands":{"totalBudgetMin":380,"preferredLayout":"118㎡四房三卫(非临路)","coreAppeal":"安静舒适、品质高端的改善型住房"},"concerns":["临路噪音影响","社区小,活动空间不足","未来周边施工影响","装修标准细节"],"decisionProfile":["对噪音敏感,需要安静环境","重视社区品质和舒适度","关注装修细节和硬件配置","需要详细对比不同户型差异"]}]},"project":{"competitionComparison":{"招商景成序":{"产品对比":"我们118平做四房三卫双套房,功能性更强","价格对比":"招商卖3万左右,我们卖33000,但我们地价比他们贵6000,其实利润更低","地段对比":"招商在28板块,我们在槐树店板块,是成华区number one板块,配套更成熟"},"邦泰云锦":{"价格参考":"他们当时12800拿地,现在卖34000","品质对比":"我们外立面全玻璃幕墙+铝单板,比他们成本高30%,装修标准也更高","定位相似":"邦泰也是首个项目,要打造口碑"},"龙湖滨江云河颂":{"价格对比":"他们单价32000-35000,但得房率只有95%,套内算下来36000+","优势突出":"我们得房率118平实得132平,套内单价才33000,而且楼间距比他们开阔","优点承认":"龙湖位置确实好,看沙河公园,是龙湖最高端的滨江系列"}},"coreSellingPoints":{"产品配置高端":"全玻璃幕墙+铝单板外立面,三层中空氩气玻璃,3.2米层高,方太Y9烟机灶具、20套洗碗机、安吉尔净水器、高仪卫浴","地段稀缺性":"成华区2.5环内侧核心地段,槐树店板块是成华区number one板块,被三板桥、万象城、火车东站包围","得房率高":"118平实得132平,套内单价33000,比龙湖滨江云河颂套内单价低3000","户型功能性强":"118平做四房三卫双套房,满足三代人居住需求,南向采光好","物业高端":"招商铂金物业,前三年5块物业费,提供酒店式增值服务"},"developerBacking":{"company实力":"中兴资产,多元化民营企业","合作方":"招商铂金物业,招商首次与外部民营企业合作的高端物业","开发经验":"宜宾有5个项目,贵州有2个项目,成都是首个项目","资金安全":"在河南渑池有铝土一矿和二矿,每年稳定注入10亿资金"},"regionValue":{"区位层级":["成华区2.5环内侧,槐树店板块是成华区number one板块","北接三板桥商圈,西靠万象城,东临火车东站","被成都东门第一梯队板块包围,锦江区、高新的客户都首选"],"发展规划":["槐树店板块是攀成钢之后第二个富人区","整个板块都是300万到900万的总价段","未来全是改善型住宅,没有刚需盘"],"地价论证":["我们地价19500,华晨府20400,棕榈也是2万+","2.5环内现在地价没有低于19000的","面粉贵了,面包不可能便宜"],"板块热度":["从21年新希望锦麟一品开始,这边全是高端盘","龙湖最高端的滨江系列在这里,新希望的锦麟系列也在这里","各大品牌开发商争相恐后都在这边拿地"]},"supportingFacilities":{"交通配套":{"地铁":"双店路站300-350米(7号线),槐树店站550米(4号线),未来12号线","通达性":"到华西锦江院区30分钟车程,到万象城1.6公里,到三板桥1.8公里","道路":"中环路、成洛大道,到春熙路5个站,到火车东站2个站"},"医疗配套":{"三甲医院":"成都市第六人民医院、市二医院3公里内","便利性":"社区医院就在附近,日常就医方便","顶尖医疗":"华西医院锦江院区30分钟车程"},"商业配套":{"大型商圈":"万象城1.6公里,三板桥商圈1.8公里","未来商业":"槐树店上东里商业,明年年底开业,有永辉超市","社区商业":"成华奥园广场商业、十里风荷商业,满足日常消费"},"教育配套":{"小学":"城市附小锦汇东城小学,成华区生源最好的学校,周边新盘都读这个学校","幼儿园":"楼下公立幼儿园,明年9月招生","私立学校":"金苹果幼儿园,成华区英华英才学校"},"生态配套":{"公园":"楼下40亩槐树店公园,400米沙河公园,100亩多宝寺公园,700米内3个公园","绿化":"小区内有风雨连廊,口袋公园,周边是高端住宅绿化"}}},"skill":{"closingTechniques":{"优惠策略":{"价格优惠":["今天定的话,我可以跟领导申请额外折扣","买车位的话,总价多给两个点优惠","一次性付款再优惠一个点"],"附加价值":["优先选车位","享受招商物业的增值服务"]},"决策推动":{"小步推进":["要不先交个小定保留房源?","可以先排个号,有优惠优先通知你","今天不定的话,我帮你留意好楼层"]},"紧迫感营造":{"房源稀缺":["118只剩20多套了,好楼层不多","这栋楼就60户,卖一套少一套","特价房只有这几套,今天不定可能就没了"],"时间紧迫":["今天是月底最后一天,领导有压力价格可谈","我们刚刚开盘,还有额外优惠,月底冲业绩价格最有弹性"]}},"communicationRhythm":{"开场阶段":{"关键动作":"亲切称呼,简单寒暄,确认看房重点","时间占比":"5%","目标":"建立关系,了解需求"},"样板间带看":{"关键动作":"户型讲解→装修标准介绍→居住场景模拟","时间占比":"40%","目标":"体验产品细节"},"沙盘讲解":{"关键动作":"板块价值→周边配套→项目亮点→开发商介绍","时间占比":"30%","目标":"建立价值认知"},"洽谈阶段":{"关键动作":"算价→痛点应对→优惠讲解→促单","时间占比":"25%","目标":"解决顾虑,推动成交"}},"needsMining":{"居住需求":["几个人住?有老人小孩吗?","主要是自住还是考虑投资?","现在住哪里?想改善哪些方面?"],"通勤需求":["在哪个位置上班?","主要开车还是坐地铁?","对地铁距离有要求吗?"],"预算需求":["你们总价想控制在多少以内?","是考虑按揭还是一次性?","月供能接受多少范围?"]},"painPointResponse":{"临路噪音":{"户型优势":"双主卧和客厅朝中庭,只有书房和儿童房临路,影响小","硬件保障":"用的是三层中空氩气玻璃,隔音隔热效果比双层玻璃好一倍","距离说明":"我们楼盘离路有25米以上,还有23米的绿化隔离带"},"地块太小":{"对比竞品":"其他楼盘楼间距大多30米左右,我们的居住私密性和舒适度更好","承认事实":"14亩确实不大","普遍现象":"2.5环内都是小地块,万景13亩,中铁建8.8亩,339的邦泰才11亩","转化优势":"但人少安静,楼间距反而更开阔,我们楼间距最高有300米"},"物业费高":{"价值分析":"但6块里3块是增值服务,包括每年一次深度保洁、6次免费宠物喂养、夜间外卖送上门、生日宴布置等酒店式服务","价格补贴":"前三年补贴到5块,跟其他高端盘差不多,而且物业是招商铂金物业,服务过清华大学、最高人民法院","理解感受":"我懂你,我们也觉得物业费是有点贵"}},"valueBuilding":{"产品价值塑造":["我们是用改善的价格,买豪宅的标准,很多细节都是3000万豪宅才有的配置","外立面成本比竞品高30%,装修标准也是同面积段最高的","118平做四房三卫双套房,功能性在成都独一无二"],"地段价值塑造":["买房最重要的是地段、地段、还是地段","核心地段的核心资产才保值增值,2.5环内的地卖一块少一块","槐树店板块是攀成钢之后的第二个富人区,未来全是高端住宅"],"物业价值塑造":["招商铂金物业是央企物业,服务过清华大学、最高人民法院","增值服务每年能省几千块,而且好物业能让房子增值更多","前三年补贴后物业费5块,跟其他高端盘差不多,但服务更好"]}}} -``` \ No newline at end of file +**[输出格式]** +- **格式类型**:严格输出json格式字符串,不需要其他任何格式和内容 +- **数据结构**: + { + "result": "{{chat_content}}", + "mission_status": "{{mission_status}}", + "mission_complete_desc": "{{mission_complete_desc}}" + } + +**[字段说明]** +1. **result** (字符串) + - 对应变量:`{{chat_content}}` + - 内容:顾问的实际对话内容 + - 要求:自然语言回复,面向用户 + +2. **mission_status** (字符串) + - 对应变量:`{{mission_status}}` + - 取值:`"completed"` 或 `"in_progress"` 或 `"fail"` + - 说明:标识当前任务完成状态 + - `"completed"`:任务已全部完成 + - `"in_progress"`:任务仍在进行中 + - `"fail"`:任务失败,客户已经明确拒绝或者对任务内容表达反对 + +3. **mission_complete_desc** (字符串) + - 对应变量:`{{mission_complete_desc}}` + - 内容:根据mission_status提供相应描述 + - 当`mission_status: "completed"`时:简要总结任务完成情况 + - 当`mission_status: "in_progress"`时:说明下一步需要做什么 + +**[示例]** +{ +"result": "需要我给您安排时间吗", +"mission_status": "in_progress", +"mission_complete_desc": "需要用户确认什么时候到售楼部" +} + +{ +"result": "好的,那就周日下午两点,我到时候在售楼部等您,来了记得给我打电话", +"mission_status": "completed", +"mission_complete_desc": "客户确认周日下午两点到售楼部" +} + +**[强制要求]** +1. 必须输出完整、有效的JSON对象 +2. 所有字段均为必需字段,不可省略 +3. JSON格式必须严格正确,无语法错误 +4. `mission_status`只能使用指定的两个值 +5. `result`字段内容需符合对话语境 \ No newline at end of file diff --git a/internal/biz/advice_advicer.go b/internal/biz/advice_advicer.go index 935d58f..a5ddcf8 100644 --- a/internal/biz/advice_advicer.go +++ b/internal/biz/advice_advicer.go @@ -35,10 +35,10 @@ func NewAdviceAdvicerBiz( } } -func (a *AdviceAdvicerBiz) Update(ctx context.Context, data *entitys.AdvicerInitReq) error { +func (a *AdviceAdvicerBiz) Update(ctx context.Context, data *entitys.AdvicerInitReq) (int32, error) { birth, err := time.Parse("2006-01-02", data.Birth) if err != nil { - return err + return 0, err } param := &model.AiAdviceAdvicer{ AdvicerID: data.AdvicerID, @@ -49,13 +49,13 @@ func (a *AdviceAdvicerBiz) Update(ctx context.Context, data *entitys.AdvicerInit WorkingYears: data.WorkingYears, } if param.AdvicerID == 0 { - _, err = a.advicerImpl.Add(param) + err = a.advicerImpl.AddWithData(param) } else { cond := builder.NewCond() cond = cond.And(builder.Eq{"advicer_id": param.AdvicerID}) err = a.advicerImpl.UpdateByCond(&cond, param) } - return err + return param.AdvicerID, err } func (a *AdviceAdvicerBiz) List(ctx context.Context, data *entitys.AdvicerListReq) ([]map[string]interface{}, error) { @@ -66,14 +66,14 @@ func (a *AdviceAdvicerBiz) List(ctx context.Context, data *entitys.AdvicerListRe return list, err } -func (a *AdviceAdvicerBiz) VersionAdd(ctx context.Context, param *entitys.AdvicerVersionAddReq) (err error) { +func (a *AdviceAdvicerBiz) VersionAdd(ctx context.Context, param *entitys.AdvicerVersionAddReq) (id interface{}, err error) { cond := builder.NewCond() cond = cond.And(builder.Eq{"advicer_id": param.AdvicerID}) _, err = a.advicerImpl.GetOneBySearch(&cond) if err != nil { - return errors.New("顾问不存在") + return 0, errors.New("顾问不存在") } - _, err = a.mongo.Co(a.advicerVersionMongo).InsertOne(ctx, &mongo_model.AdvicerVersionMongo{ + res, err := a.mongo.Co(a.advicerVersionMongo).InsertOne(ctx, &mongo_model.AdvicerVersionMongo{ AdvicerId: param.AdvicerID, VersionDesc: param.VersionDesc, DialectFeatures: param.DialectFeatures, @@ -83,8 +83,10 @@ func (a *AdviceAdvicerBiz) VersionAdd(ctx context.Context, param *entitys.Advice SignatureDialogues: param.SignatureDialogues, LastUpdateTime: time.Now(), }) - - return err + if err != nil { + return nil, err + } + return res.InsertedID, err } func (a *AdviceAdvicerBiz) VersionUpdate(ctx context.Context, param *entitys.AdvicerVersionUpdateReq) (err error) { @@ -118,7 +120,7 @@ func (a *AdviceAdvicerBiz) VersionList(ctx context.Context, param *entitys.Advic filter := bson.M{} // 1. advicer_id 条件 if param.AdvicerId != 0 { - filter["AdvicerId"] = param.AdvicerId + filter["advicerId"] = param.AdvicerId } // 2. _id 条件 @@ -133,7 +135,7 @@ func (a *AdviceAdvicerBiz) VersionList(ctx context.Context, param *entitys.Advic // 3. version_desc 模糊查询 if len(param.VersionDesc) != 0 { // 正确的方式:指定字段名 - filter["VersionDesc"] = bson.M{ + filter["versionDesc"] = bson.M{ "$regex": primitive.Regex{ Pattern: param.VersionDesc, Options: "i", diff --git a/internal/biz/advice_chat.go b/internal/biz/advice_chat.go index 58c14fb..1ac2057 100644 --- a/internal/biz/advice_chat.go +++ b/internal/biz/advice_chat.go @@ -2,83 +2,278 @@ package biz import ( "ai_scheduler/internal/biz/llm_service/third_party" + "ai_scheduler/internal/data/constants" + "ai_scheduler/internal/data/mongo_model" + + "ai_scheduler/internal/data/impl" + dbmodel "ai_scheduler/internal/data/model" "ai_scheduler/internal/entitys" "ai_scheduler/internal/pkg" "ai_scheduler/utils" "context" "encoding/json" - "strings" - "time" + "errors" + "fmt" "github.com/google/uuid" "github.com/volcengine/volcengine-go-sdk/service/arkruntime/model" + "github.com/volcengine/volcengine-go-sdk/service/arkruntime/model/responses" "github.com/volcengine/volcengine-go-sdk/volcengine" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/mongo/options" + "xorm.io/builder" + + "strings" + "time" ) type AdviceChatBiz struct { - hsyq *third_party.Hsyq - rdb *utils.Rdb + hsyq *third_party.Hsyq + rdb *utils.Rdb + aiAdviceSessionImpl *impl.AiAdviceSessionImpl + aiAdviceModelSupImpl *impl.AiAdviceModelSupImpl + advicerChatHisMongo *mongo_model.AdvicerChatHisMongo + mongo *pkg.Mongo } func NewAdviceChatBiz( hsyq *third_party.Hsyq, rdb *utils.Rdb, + aiAdviceSessionImpl *impl.AiAdviceSessionImpl, + aiAdviceModelSupImpl *impl.AiAdviceModelSupImpl, + advicerChatHisMongo *mongo_model.AdvicerChatHisMongo, + mongo *pkg.Mongo, ) *AdviceChatBiz { return &AdviceChatBiz{ - hsyq: hsyq, - rdb: rdb, + hsyq: hsyq, + rdb: rdb, + aiAdviceSessionImpl: aiAdviceSessionImpl, + aiAdviceModelSupImpl: aiAdviceModelSupImpl, + advicerChatHisMongo: advicerChatHisMongo, + mongo: mongo, } } -func (a *AdviceChatBiz) Regis(ctx context.Context, chatData *entitys.ChatData) (string, error) { - sessionId := uuid.New().String() - prompt, err := a.buildBasePrompt(ctx, chatData) +func (a *AdviceChatBiz) contextCache(ctx context.Context, chatData *entitys.ChatData, req *entitys.AdvicerChatRegistReq, projectInfo *entitys.AdvicerProjectInfoRes) (promptJson string, contextCache string, err error) { + switch constants.Mode(projectInfo.ModelInfo.Mode) { + case constants.ModeResponse: + prompt, err := a.buildBasePromptResponse(ctx, chatData, req) + if err != nil { + return "", "", err + } + cache, err := a.hsyq.CreateResponse(ctx, projectInfo.ModelInfo.Key, projectInfo.ModelInfo.ChatModel, prompt, "", true) + if err != nil { + return "", "", err + } + contextCache = cache.Id + promptJson = pkg.JsonStringIgonErr(prompt) + case constants.ModeContext: + prompt, err := a.buildBasePromptContext(ctx, chatData, req) + if err != nil { + return "", "", err + } + contextCache, err = a.hsyq.CreateContextCache(ctx, projectInfo.ModelInfo.Key, projectInfo.ModelInfo.ChatModel, prompt) + if err != nil { + return "", "", err + } + promptJson = pkg.JsonStringIgonErr(prompt) + default: + return "", "", fmt.Errorf("未知的mode类型:%d", projectInfo.ModelInfo.Mode) + } + return +} + +func (a *AdviceChatBiz) Regis(ctx context.Context, chatData *entitys.ChatData, req *entitys.AdvicerChatRegistReq, projectInfo *entitys.AdvicerProjectInfoRes) (string, error) { + promptJson, contextCache, err := a.contextCache(ctx, chatData, req, projectInfo) if err != nil { return "", err } - err = a.rdb.Rdb.SetEx(ctx, sessionId, pkg.JsonStringIgonErr(prompt), 3600*time.Second).Err() + sessionId := uuid.New().String() + //创建会话 + _, err = a.aiAdviceSessionImpl.Add(&dbmodel.AiAdviceSession{ + SessionID: sessionId, + ProjectID: projectInfo.Base.ProjectID, + SupID: projectInfo.Base.ModelSupID, + AdvicerVersionID: req.AdvicerVersionId, + ClientID: req.ClientId, + TalkSkillID: req.TalkSkillId, + Mission: req.Mission, + ContextCache: contextCache, + CreateAt: time.Now(), + }) + if err != nil { + return "", err + } + err = a.rdb.Rdb.SetEx(ctx, sessionId, promptJson, 3600*time.Second).Err() return sessionId, err } -func (a *AdviceChatBiz) Chat(ctx context.Context, chat *entitys.AdvicerChatReq) ([]string, error) { +func (a *AdviceChatBiz) Chat(ctx context.Context, chat *entitys.AdvicerChatReq) (assistant mongo_model.Assistant, err error) { + var session dbmodel.AiAdviceSession + cond := builder.NewCond() + cond = cond.And(builder.Eq{"session_id": chat.SessionId}) + err = a.aiAdviceSessionImpl.GetOneBySearchToStrut(&cond, &session) + if err != nil { + return assistant, err + } + if session.SessionID == "" { + return assistant, errors.New("未找到会话信息") + } if len(chat.Content) == 0 { - return nil, nil + return assistant, nil } - basePromptJson, err := a.getChatDataFromStringSessionId(ctx, chat.SessionId) + var modelInfo dbmodel.AiAdviceModelSup + cond = builder.NewCond() + cond = cond.And(builder.Eq{"sup_id": session.SupID}) + err = a.aiAdviceModelSupImpl.GetOneBySearchToStrut(&cond, &modelInfo) if err != nil { - return nil, err + return assistant, err } - prompt, err := a.setContent(ctx, basePromptJson, chat.Content) + if modelInfo.SupID == 0 { + return assistant, errors.New("未找到模型信息") + } + //basePromptJson, err := a.getChatDataFromStringSessionId(ctx, chat.SessionId) + //if err != nil { + // return nil, err + //} + chatHis, err := a.getChatHis(ctx, session.SessionID, 6) + prompt, err := a.buildChatPromptResponse(ctx, chat, &session, chatHis) if err != nil { - return nil, err + return assistant, err } - resContent, err := a.callLlm(ctx, prompt, fileModel) + resContent, err := a.callLlmResponse(ctx, prompt, modelInfo.Key, modelInfo.ChatModel, session.ContextCache) if err != nil { - return nil, err + return assistant, err } - resSlice := strings.Split(resContent, "\n") - return resSlice, nil + + result := resContent.Output[0].GetOutputMessage().Content[0].GetText().GetText() + if err = json.Unmarshal([]byte(result), &assistant); err != nil { + return assistant, err + } + chatCtx, cancel := context.WithCancel(context.Background()) + go func(session dbmodel.AiAdviceSession) { + defer cancel() + _, _ = a.mongo.Co(a.advicerChatHisMongo).InsertOne(chatCtx, &mongo_model.AdvicerChatHisMongo{ + SessionId: chat.SessionId, + User: chat.Content, + Assistant: assistant, + InToken: resContent.Usage.InputTokens, + OutToken: resContent.Usage.OutputTokens, + CreatAt: time.Now(), + }) + if assistant.MissionStatus == "fail" || assistant.MissionStatus == "complete" { + cond = builder.NewCond() + cond = cond.And(builder.Eq{"session_id": chat.SessionId}) + session.MissionStatus = assistant.MissionStatus + session.MissionCompleteDesc = assistant.MissionCompleteDesc + _ = a.aiAdviceSessionImpl.UpdateByCond(&cond, session) + } + }(session) + return } -func (a *AdviceChatBiz) buildBasePrompt(ctx context.Context, chatData *entitys.ChatData) ([]*model.ChatCompletionMessage, error) { - var message = make([]*model.ChatCompletionMessage, 3) +func (a *AdviceChatBiz) buildChatPromptResponse(ctx context.Context, chat *entitys.AdvicerChatReq, session *dbmodel.AiAdviceSession, chatList []mongo_model.AdvicerChatHisMongoEntity) ([]*responses.InputItem, error) { + + var message = make([]*responses.InputItem, 3) + message[0] = &responses.InputItem{ + Union: &responses.InputItem_EasyMessage{ + EasyMessage: &responses.ItemEasyMessage{ + Role: responses.MessageRole_system, + Content: &responses.MessageContent{Union: &responses.MessageContent_StringValue{StringValue: a.taskPrompt(session)}}, + }, + }, + } + message[1] = &responses.InputItem{ + Union: &responses.InputItem_EasyMessage{ + EasyMessage: &responses.ItemEasyMessage{ + Role: responses.MessageRole_system, + Content: &responses.MessageContent{Union: &responses.MessageContent_StringValue{StringValue: "历史聊天记录:\n" + pkg.JsonStringIgonErr(chatList)}}, + }, + }, + } + message[2] = &responses.InputItem{ + Union: &responses.InputItem_EasyMessage{ + EasyMessage: &responses.ItemEasyMessage{ + Role: responses.MessageRole_user, + Content: &responses.MessageContent{Union: &responses.MessageContent_StringValue{StringValue: chat.Content}}, + }, + }, + } + + return message, nil +} +func (a *AdviceChatBiz) getChatHis(ctx context.Context, sessionId string, limit int64) (chatList []mongo_model.AdvicerChatHisMongoEntity, err error) { + chatList = make([]mongo_model.AdvicerChatHisMongoEntity, 0) + filter := bson.M{} + filter["sessionId"] = sessionId + cursor, err := a.mongo.Co(a.advicerChatHisMongo).Find(ctx, filter, options.Find().SetLimit(limit)) + if err != nil { + return chatList, err + } + for cursor.Next(ctx) { + var chatHIS mongo_model.AdvicerChatHisMongo + if err := cursor.Decode(&chatHIS); err != nil { + return nil, err + } + chatList = append(chatList, chatHIS.Entity()) + } + + if err := cursor.Err(); err != nil { + return nil, err + } + return +} + +func (a *AdviceChatBiz) buildChatPrompt(ctx context.Context, chat *entitys.AdvicerChatReq, session *dbmodel.AiAdviceSession, modelInfo *dbmodel.AiAdviceModelSup) (model.ContextChatCompletionRequest, error) { + var message = make([]*model.ChatCompletionMessage, 2) + message[0] = &model.ChatCompletionMessage{ + Role: model.ChatMessageRoleUser, + Content: &model.ChatCompletionMessageContent{ + StringValue: volcengine.String(chat.Content), + }, + } + message[1] = &model.ChatCompletionMessage{ + Role: model.ChatMessageRoleAssistant, + Content: &model.ChatCompletionMessageContent{ + StringValue: volcengine.String(a.taskPrompt(session)), + }, + } + + req := model.ContextChatCompletionRequest{ + ContextID: session.ContextCache, + Model: modelInfo.ChatModel, + Messages: message, + Stream: false, + } + return req, nil +} + +func (a *AdviceChatBiz) taskPrompt(session *dbmodel.AiAdviceSession) string { + //type mission struct { + // missionName string + // status string + // missionCompleteDesc string + //} + //var m = &mission{ + // missionName: session.Mission, + // status: pkg.Ter(session.MissionStatus == 1, "进行中", "已完成"), + // missionCompleteDesc: session.MissionCompleteDesc, + //} + //missionJon, _ := json.Marshal(m) + return "[当前时间]" + time.Now().Format("2006-01-02 15:04:05") +} + +func (a *AdviceChatBiz) buildBasePromptContext(ctx context.Context, chatData *entitys.ChatData, req *entitys.AdvicerChatRegistReq) ([]*model.ChatCompletionMessage, error) { + var message = make([]*model.ChatCompletionMessage, 2) message[0] = &model.ChatCompletionMessage{ Role: model.ChatMessageRoleSystem, Content: &model.ChatCompletionMessageContent{ - StringValue: volcengine.String(a.sysPrompt(chatData)), + StringValue: volcengine.String(a.sysPrompt(chatData, req)), }, } - message[1] = &model.ChatCompletionMessage{ - Role: model.ChatMessageRoleUser, - Content: &model.ChatCompletionMessageContent{ - StringValue: volcengine.String("{{chat_content}}"), - }, - } - - message[2] = &model.ChatCompletionMessage{ - Role: model.ChatMessageRoleAssistant, + Role: model.ChatMessageRoleSystem, Content: &model.ChatCompletionMessageContent{ StringValue: volcengine.String(a.assistantPrompt(chatData)), }, @@ -86,7 +281,28 @@ func (a *AdviceChatBiz) buildBasePrompt(ctx context.Context, chatData *entitys.C return message, nil } -func (a *AdviceChatBiz) setContent(ctx context.Context, basePromptJson string, content string) ([]*model.ChatCompletionMessage, error) { +func (a *AdviceChatBiz) buildBasePromptResponse(ctx context.Context, chatData *entitys.ChatData, req *entitys.AdvicerChatRegistReq) ([]*responses.InputItem, error) { + var message = make([]*responses.InputItem, 2) + message[0] = &responses.InputItem{ + Union: &responses.InputItem_EasyMessage{ + EasyMessage: &responses.ItemEasyMessage{ + Role: responses.MessageRole_system, + Content: &responses.MessageContent{Union: &responses.MessageContent_StringValue{StringValue: a.sysPrompt(chatData, req)}}, + }, + }, + } + message[1] = &responses.InputItem{ + Union: &responses.InputItem_EasyMessage{ + EasyMessage: &responses.ItemEasyMessage{ + Role: responses.MessageRole_system, + Content: &responses.MessageContent{Union: &responses.MessageContent_StringValue{StringValue: a.assistantPrompt(chatData)}}, + }, + }, + } + return message, nil +} + +func (a *AdviceChatBiz) setContent(ctx context.Context, basePromptJson string, content string, session *dbmodel.AiAdviceSession) ([]*model.ChatCompletionMessage, error) { promptJson := strings.ReplaceAll(basePromptJson, "{{chat_content}}", content) var basePrompt []*model.ChatCompletionMessage err := json.Unmarshal([]byte(promptJson), &basePrompt) @@ -97,8 +313,14 @@ func (a *AdviceChatBiz) setContent(ctx context.Context, basePromptJson string, c return basePrompt, nil } -func (a *AdviceChatBiz) sysPrompt(chatData *entitys.ChatData) string { - return "【场景】现在你是专业的顾问,我们在聊天软件里面聊天,当前时间是2026/01/30 16:13:30\n【要求】提供的json内容包含顾问,项目,对话技巧,客户信息,请根据json内容进行模仿真人进行对话,** 绝对不能让对方看出来你是ai!**\n【规则】\n1.必须模仿顾问的聊天方式,不能有markdown格式,聊天内容必须贴近聊天软件的正常聊天,非客户要求不要自顾自的介绍项目!开场白不要太长!\n2.不要有任何特殊格式,有比较长的对话内容注意提行\n3.尽量邀约对方来项目上来\n4.不能有任何画外音的文字格式出现!比如(等待对方回复)" +func (a *AdviceChatBiz) sysPrompt(chatData *entitys.ChatData, req *entitys.AdvicerChatRegistReq) string { + var prompt strings.Builder + prompt.WriteString(constants.BasePrompt) + prompt.WriteString(req.Mission) + prompt.WriteString(constants.BasePrompt2) + + return prompt.String() + } func (a *AdviceChatBiz) assistantPrompt(chatData *entitys.ChatData) string { @@ -115,10 +337,18 @@ func (a *AdviceChatBiz) getChatDataFromStringSessionId(ctx context.Context, sess return cache.Val(), cache.Err() } -func (a *AdviceChatBiz) callLlm(ctx context.Context, prompt []*model.ChatCompletionMessage, modelName string) (string, error) { - res, err := a.hsyq.RequestHsyq(ctx, key, modelName, prompt) +func (a *AdviceChatBiz) callLlm(ctx context.Context, request model.ContextChatCompletionRequest, key string) (string, error) { + res, err := a.hsyq.ChatWithRequest(ctx, key, request) if err != nil { return "", err } return *res.Choices[0].Message.Content.StringValue, nil } + +func (a *AdviceChatBiz) callLlmResponse(ctx context.Context, request []*responses.InputItem, key string, modelName string, id string) (*responses.ResponseObject, error) { + res, err := a.hsyq.CreateResponse(ctx, key, modelName, request, id, false) + if err != nil { + return nil, err + } + return res, nil +} diff --git a/internal/biz/advice_client.go b/internal/biz/advice_client.go index 77fd54a..391f585 100644 --- a/internal/biz/advice_client.go +++ b/internal/biz/advice_client.go @@ -29,9 +29,9 @@ func NewAdviceClientBiz( } } -func (a *AdviceClientBiz) Add(ctx context.Context, param *entitys.AdvicerClientAddReq) (err error) { +func (a *AdviceClientBiz) Add(ctx context.Context, param *entitys.AdvicerClientAddReq) (id interface{}, err error) { - _, err = a.mongo.Co(a.AdvicerClientMongo).InsertOne(ctx, &mongo_model.AdvicerClientMongo{ + res, err := a.mongo.Co(a.AdvicerClientMongo).InsertOne(ctx, &mongo_model.AdvicerClientMongo{ ProjectId: param.ProjectId, AdvicerId: param.AdvicerId, PersonalInfo: param.PersonalInfo, @@ -41,8 +41,10 @@ func (a *AdviceClientBiz) Add(ctx context.Context, param *entitys.AdvicerClientA DecisionProfile: param.DecisionProfile, LastUpdateTime: time.Now(), }) - - return err + if err != nil { + return nil, err + } + return res.InsertedID, err } func (a *AdviceClientBiz) Update(ctx context.Context, param *entitys.AdvicerrClientUpdateReq) (err error) { diff --git a/internal/biz/advice_file.go b/internal/biz/advice_file.go index 65c8431..e437bf8 100644 --- a/internal/biz/advice_file.go +++ b/internal/biz/advice_file.go @@ -149,7 +149,7 @@ func (a *AdviceFileBiz) callLlm(ctx context.Context, prompt string, modelName st StringValue: volcengine.String(prompt), }, } - res, err := a.hsyq.RequestHsyq(ctx, key, modelName, message) + res, err := a.hsyq.Chat(ctx, key, modelName, message) if err != nil { return "", err } diff --git a/internal/biz/advice_project.go b/internal/biz/advice_project.go index bd48d77..9b1a433 100644 --- a/internal/biz/advice_project.go +++ b/internal/biz/advice_project.go @@ -1,10 +1,11 @@ package biz import ( + "ai_scheduler/internal/data/impl" + "ai_scheduler/internal/data/model" "ai_scheduler/internal/data/mongo_model" "ai_scheduler/internal/entitys" "ai_scheduler/internal/pkg" - "errors" "fmt" "time" @@ -12,26 +13,60 @@ import ( "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" + "xorm.io/builder" ) type AdviceProjectBiz struct { - AdvicerProjectMongo *mongo_model.AdvicerProjectMongo - mongo *pkg.Mongo + AdvicerProjectMongo *mongo_model.AdvicerProjectMongo + adviceProjectImpl *impl.AdviceProjectImpl + aiAdviceModelSupImpl *impl.AiAdviceModelSupImpl + mongo *pkg.Mongo } func NewAdviceProjectBiz( advicerProjectMongo *mongo_model.AdvicerProjectMongo, + adviceProjectImpl *impl.AdviceProjectImpl, + aiAdviceModelSupImpl *impl.AiAdviceModelSupImpl, mongo *pkg.Mongo, ) *AdviceProjectBiz { return &AdviceProjectBiz{ - AdvicerProjectMongo: advicerProjectMongo, - mongo: mongo, + AdvicerProjectMongo: advicerProjectMongo, + mongo: mongo, + adviceProjectImpl: adviceProjectImpl, + aiAdviceModelSupImpl: aiAdviceModelSupImpl, } } -func (a *AdviceProjectBiz) Add(ctx context.Context, param *entitys.AdvicerProjectAddReq) (err error) { +func (a *AdviceProjectBiz) BaseAdd(ctx context.Context, param *entitys.AdvicerProjectBaseAddReq) (res *entitys.AdvicerProjectBaseAddRes, err error) { + add := &model.AiAdviceProject{ + Name: param.Name, + ModelSupID: param.ModelSupId, + } + err = a.adviceProjectImpl.AddWithData(add) + if err != nil { + return nil, err + } + return &entitys.AdvicerProjectBaseAddRes{ + ProjectId: add.ProjectID, + }, err +} - _, err = a.mongo.Co(a.AdvicerProjectMongo).InsertOne(ctx, &mongo_model.AdvicerProjectMongo{ +func (a *AdviceProjectBiz) BaseUpdate(ctx context.Context, param *entitys.AdvicerProjectBaseUpdateReq) (err error) { + if param.ProjectId == 0 { + return + } + cond := builder.NewCond() + cond = cond.And(builder.Eq{"project_id": param.ProjectId}) + err = a.adviceProjectImpl.UpdateByCond(&cond, &model.AiAdviceProject{ + Name: param.Name, + ModelSupID: param.ModelSupId, + }) + return err +} + +func (a *AdviceProjectBiz) Add(ctx context.Context, param *entitys.AdvicerProjectAddReq) (id interface{}, err error) { + + res, err := a.mongo.Co(a.AdvicerProjectMongo).InsertOne(ctx, &mongo_model.AdvicerProjectMongo{ ProjectId: param.ProjectId, ProjectInfo: param.ProjectInfo, RegionValue: param.RegionValue, @@ -42,22 +77,27 @@ func (a *AdviceProjectBiz) Add(ctx context.Context, param *entitys.AdvicerProjec LastUpdateTime: time.Now(), }) - return err + return res.InsertedID, err } func (a *AdviceProjectBiz) Update(ctx context.Context, param *entitys.AdvicerrProjectUpdateReq) (err error) { filter := bson.M{} - if len(param.Id) == 0 { - return errors.New("ID不能为空") + if len(param.Id) != 0 { + objectID, err := primitive.ObjectIDFromHex(param.Id) + if err != nil { + return fmt.Errorf("ID转换失败: %w", err) + } + filter["_id"] = objectID } - objectID, err := primitive.ObjectIDFromHex(param.Id) - if err != nil { - return fmt.Errorf("ID转换失败: %w", err) + if param.ProjectId != 0 { + + filter["projectId"] = param.ProjectId } - filter["_id"] = objectID + update := bson.M{ "$set": &mongo_model.AdvicerProjectMongo{ ProjectId: param.ProjectId, + ProjectInfo: param.ProjectInfo, RegionValue: param.RegionValue, CompetitionComparison: param.CompetitionComparison, CoreSellingPoints: param.CoreSellingPoints, @@ -70,7 +110,53 @@ func (a *AdviceProjectBiz) Update(ctx context.Context, param *entitys.AdvicerrPr return res.Err() } -func (a *AdviceProjectBiz) Info(ctx context.Context, param *entitys.AdvicerProjectInfoReq) (info mongo_model.AdvicerProjectMongo, err error) { +func (a *AdviceProjectBiz) Info(ctx context.Context, param *entitys.AdvicerProjectInfoReq) (info *entitys.AdvicerProjectInfoRes, err error) { + configInfo, err := a.ConfigInfo(ctx, param) + if err != nil { + return nil, err + } + baseInfo, err := a.BaseInfo(configInfo.ProjectId) + if err != nil { + return nil, err + } + supInfo, err := a.ModelInfo(baseInfo.ModelSupID) + if err != nil { + return nil, err + } + return &entitys.AdvicerProjectInfoRes{ + ConfigInfo: configInfo, + Base: baseInfo, + ModelInfo: supInfo, + }, nil +} + +func (a *AdviceProjectBiz) BaseInfo(projectId int32) (baseInfo model.AiAdviceProject, err error) { + if projectId == 0 { + return + } + cond := builder.NewCond() + cond = cond.And(builder.Eq{"project_id": projectId}) + err = a.adviceProjectImpl.GetOneBySearchToStrut(&cond, &baseInfo) + if err != nil { + return baseInfo, err + } + return baseInfo, nil +} + +func (a *AdviceProjectBiz) ModelInfo(supId int32) (supInfo model.AiAdviceModelSup, err error) { + if supId == 0 { + return + } + cond := builder.NewCond() + cond = cond.And(builder.Eq{"sup_id": supId}) + err = a.aiAdviceModelSupImpl.GetOneBySearchToStrut(&cond, &supInfo) + if err != nil { + return supInfo, err + } + return supInfo, nil +} + +func (a *AdviceProjectBiz) ConfigInfo(ctx context.Context, param *entitys.AdvicerProjectInfoReq) (info mongo_model.AdvicerProjectMongo, err error) { filter := bson.M{} if param.ProjectId != 0 { diff --git a/internal/biz/advice_skill.go b/internal/biz/advice_skill.go index 38e64c7..eeb682f 100644 --- a/internal/biz/advice_skill.go +++ b/internal/biz/advice_skill.go @@ -29,9 +29,9 @@ func NewAdviceSkillBiz( } } -func (a *AdviceSkillBiz) VersionAdd(ctx context.Context, param *entitys.AdvicerTalkSkillAddReq) (err error) { +func (a *AdviceSkillBiz) VersionAdd(ctx context.Context, param *entitys.AdvicerTalkSkillAddReq) (id interface{}, err error) { - _, err = a.mongo.Co(a.AdvicerTalkSkillMongo).InsertOne(ctx, &mongo_model.AdvicerTalkSkillMongo{ + res, err := a.mongo.Co(a.AdvicerTalkSkillMongo).InsertOne(ctx, &mongo_model.AdvicerTalkSkillMongo{ ProjectId: param.ProjectId, AdvicerId: param.AdvicerId, Desc: param.Desc, @@ -42,8 +42,10 @@ func (a *AdviceSkillBiz) VersionAdd(ctx context.Context, param *entitys.AdvicerT CommunicationRhythm: param.CommunicationRhythm, LastUpdateTime: time.Now(), }) - - return err + if err != nil { + return nil, err + } + return res.InsertedID, err } func (a *AdviceSkillBiz) VersionUpdate(ctx context.Context, param *entitys.AdvicerTalkSkillUpdateReq) (err error) { diff --git a/internal/biz/llm_service/third_party/hsyq.go b/internal/biz/llm_service/third_party/hsyq.go index 6b74e0c..2a9eb9d 100644 --- a/internal/biz/llm_service/third_party/hsyq.go +++ b/internal/biz/llm_service/third_party/hsyq.go @@ -9,6 +9,7 @@ import ( "github.com/volcengine/volcengine-go-sdk/service/arkruntime" "github.com/volcengine/volcengine-go-sdk/service/arkruntime/model" "github.com/volcengine/volcengine-go-sdk/service/arkruntime/model/responses" + "github.com/volcengine/volcengine-go-sdk/volcengine" ) type Hsyq struct { @@ -38,7 +39,7 @@ func (h *Hsyq) getClient(key string) *arkruntime.Client { } // 火山引擎 -func (h *Hsyq) RequestHsyq(ctx context.Context, key string, modelName string, prompt []*model.ChatCompletionMessage) (model.ChatCompletionResponse, error) { +func (h *Hsyq) Chat(ctx context.Context, key string, modelName string, prompt []*model.ChatCompletionMessage) (model.ChatCompletionResponse, error) { req := model.CreateChatCompletionRequest{ Model: modelName, Messages: prompt, @@ -54,6 +55,68 @@ func (h *Hsyq) RequestHsyq(ctx context.Context, key string, modelName string, pr return resp, err } +// 火山引擎 +func (h *Hsyq) ChatWithRequest(ctx context.Context, key string, request model.ContextChatCompletionRequest) (model.ChatCompletionResponse, error) { + + resp, err := h.getClient(key).CreateContextChatCompletion(ctx, request) + if err != nil { + return model.ChatCompletionResponse{ID: ""}, err + } + log.Info("token用量:", resp.Usage.TotalTokens, "输入:", resp.Usage.PromptTokens, "输出:", resp.Usage.CompletionTokens) + return resp, err +} + +func (h *Hsyq) CreateContextCache(ctx context.Context, key string, modelName string, prompt []*model.ChatCompletionMessage) (string, error) { + req := model.CreateContextRequest{ + Model: modelName, + Messages: prompt, + TTL: volcengine.Int(3600), + Mode: model.ContextModeSession, + TruncationStrategy: &model.TruncationStrategy{Type: model.TruncationStrategyTypeRollingTokens}, + } + + resp, err := h.getClient(key).CreateContext(ctx, req) + if err != nil { + return "", err + } + log.Info("token用量:", resp.Usage.TotalTokens, "输入:", resp.Usage.PromptTokens, "输出:", resp.Usage.CompletionTokens) + return resp.ID, err +} + +func (h *Hsyq) CreateResponse(ctx context.Context, key string, modelName string, prompt []*responses.InputItem, id string, isRegis bool) (*responses.ResponseObject, error) { + + req := &responses.ResponsesRequest{ + Model: modelName, + Input: &responses.ResponsesInput{ + Union: &responses.ResponsesInput_ListValue{ + ListValue: &responses.InputItemList{ListValue: prompt}, + }, + }, + Stream: new(bool), + Thinking: &responses.ResponsesThinking{Type: responses.ThinkingType_disabled.Enum()}, + } + if isRegis { + prefix := true + req.Caching = &responses.ResponsesCaching{Type: responses.CacheType_enabled.Enum(), Prefix: &prefix} + req.ExpireAt = volcengine.Int64(time.Now().Unix() + 3600) + } + if len(id) != 0 { + req.PreviousResponseId = &id + //req.Text = &responses.ResponsesText{ + // Format: &responses.TextFormat{ + // Type: responses.TextType_json_object, + // Schema: + // } + //} + } + resp, err := h.getClient(key).CreateResponses(ctx, req) + if err != nil { + return nil, err + } + log.Info("token用量:", resp.Usage.TotalTokens, "输入:", resp.Usage.InputTokens, "输出:", resp.Usage.OutputTokens) + return resp, err +} + func (h *Hsyq) RequestHsyqJson(ctx context.Context, key string, modelName string, prompt []*responses.InputItem) (*responses.ResponseObject, error) { req := responses.ResponsesRequest{ Model: modelName, diff --git a/internal/data/constants/hsyq.go b/internal/data/constants/hsyq.go new file mode 100644 index 0000000..6bea684 --- /dev/null +++ b/internal/data/constants/hsyq.go @@ -0,0 +1,25 @@ +package constants + +type SupWay int32 + +const ( + SupWayHsyq SupWay = iota + 1 +) + +type Mode int32 + +const ( + ModeResponse Mode = 1 + ModeContext Mode = 2 +) + +const BasePrompt = `**[场景]**现在你是专业的顾问,我们在聊天软件里面聊天 +**[要求]**提供的json内容包含顾问,项目,对话技巧,客户信息,请根据json内容进行模仿真人进行对话,** 绝对不能让对方看出来你是ai!** +**[规则]** +1.必须模仿顾问的聊天方式,不能有markdown格式,聊天内容必须贴近聊天软件的正常聊天,非客户要求不要自顾自的介绍项目!开场白不要太长! +2.不要有任何特殊格式,有比较长的对话内容注意提行 +3.结合[任务内容]信息,若任务状态为"in_progress",则在对话中尽量完成任务;如果任务状态为"completed"或"fail",则主动结束对话,且该轮对话中不再更新任务状态,mission_complete_desc记录最终结果且不再更改。不要每一句对话都包含任务内容,不要目的性太强! +4.不能有任何画外音的文字格式出现!比如(等待对方回复) +**[任务内容]**` + +const BasePrompt2 = "**[输出格式]**\n- **格式类型**:严格输出json格式字符串,不需要其他任何格式和内容\n- **数据结构**:\n {\n \"result\": \"{{chat_content}}\",\n \"mission\": \"{{mission}}\"\n \"mission_status\": \"{{mission_status}}\",\n \"mission_complete_desc\": \"{{mission_complete_desc}}\"\n }\n\n**[字段说明]**\n1. **result** (字符串)\n - 对应变量:`{{chat_content}}`\n - 内容:顾问的实际对话内容\n - 要求:自然语言回复,面向用户\n\n2. **mission** (字符串)\n - 对应变量:`{{mission}}`\n - 取值:任务内容\n - 说明:需要完成的任务内容\n\n3. **mission_status** (字符串)\n - 对应变量:`{{mission_status}}`\n - 取值:`\"completed\"` 或 `\"in_progress\"` 或 `\"fail\"`\n - 说明:标识当前任务完成状态\n - `\"completed\"`:任务已全部完成\n - `\"in_progress\"`:任务仍在进行中\n - `\"fail\"`:任务失败,客户已经明确拒绝或者对任务内容表达反对\n\n4. **mission_complete_desc** (字符串)\n - 对应变量:`{{mission_complete_desc}}`\n - 内容:根据mission_status提供相应描述\n - 当`mission_status: \"completed\"`时:简要总结任务完成情况\n - 当`mission_status: \"in_progress\"`时:说明下一步需要做什么\n\n**[示例]**\n{\n\"result\": \"需要我给您安排时间吗\",\n\"mission\": \"邀请客户到售楼部\",\n\"mission_status\": \"in_progress\",\n\"mission_complete_desc\": \"需要用户确认什么时候到售楼部\"\n}\n\n{\n\"result\": \"好的,那就周日下午两点,我到时候在售楼部等您,来了记得给我打电话\",\n\"mission_status\": \"completed\",\n\"mission_complete_desc\": \"客户确认周日下午两点到售楼部\"\n}\n\n**[强制要求]**\n1. 必须输出完整、有效的JSON对象\n2. 所有字段均为必需字段,不可省略\n3. JSON格式必须严格正确,无语法错误\n4. `mission_status`只能使用指定的两个值\n5. `result`字段内容需符合对话语境" diff --git a/internal/data/impl/advice_model_sup_impl.go b/internal/data/impl/advice_model_sup_impl.go new file mode 100644 index 0000000..ba92799 --- /dev/null +++ b/internal/data/impl/advice_model_sup_impl.go @@ -0,0 +1,17 @@ +package impl + +import ( + "ai_scheduler/internal/data/model" + "ai_scheduler/tmpl/dataTemp" + "ai_scheduler/utils" +) + +type AiAdviceModelSupImpl struct { + dataTemp.DataTemp +} + +func NewAiAdviceModelSupImpl(db *utils.Db) *AiAdviceModelSupImpl { + return &AiAdviceModelSupImpl{ + DataTemp: *dataTemp.NewDataTemp(db, new(model.AiAdviceModelSup)), + } +} diff --git a/internal/data/impl/advice_session_impl.go b/internal/data/impl/advice_session_impl.go new file mode 100644 index 0000000..4e9371b --- /dev/null +++ b/internal/data/impl/advice_session_impl.go @@ -0,0 +1,17 @@ +package impl + +import ( + "ai_scheduler/internal/data/model" + "ai_scheduler/tmpl/dataTemp" + "ai_scheduler/utils" +) + +type AiAdviceSessionImpl struct { + dataTemp.DataTemp +} + +func NewAiAdviceSessionImpl(db *utils.Db) *AiAdviceSessionImpl { + return &AiAdviceSessionImpl{ + DataTemp: *dataTemp.NewDataTemp(db, new(model.AiAdviceSession)), + } +} diff --git a/internal/data/impl/provider_set.go b/internal/data/impl/provider_set.go index 610821a..3670a3c 100644 --- a/internal/data/impl/provider_set.go +++ b/internal/data/impl/provider_set.go @@ -24,4 +24,6 @@ var ProviderImpl = wire.NewSet( NewAdviceTalkImpl, NewAdviceAdvicerVersionImpl, NewAdviceClientImpl, + NewAiAdviceSessionImpl, + NewAiAdviceModelSupImpl, ) diff --git a/internal/data/model/ai_advice_model_sup.gen.go b/internal/data/model/ai_advice_model_sup.gen.go new file mode 100644 index 0000000..68feb37 --- /dev/null +++ b/internal/data/model/ai_advice_model_sup.gen.go @@ -0,0 +1,29 @@ +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. + +package model + +import ( + "time" +) + +const TableNameAiAdviceModelSup = "ai_advice_model_sup" + +// AiAdviceModelSup mapped from table +type AiAdviceModelSup struct { + SupID int32 `gorm:"column:sup_id;primaryKey;autoIncrement:true" json:"sup_id"` + SupName string `gorm:"column:sup_name;not null;comment:备注" json:"sup_name"` // 备注 + SupWay int32 `gorm:"column:sup_way;not null;comment:供应方,1:火山引擎" json:"sup_way"` // 供应方,1:火山引擎 + Key string `gorm:"column:key;not null" json:"key"` + FileModel string `gorm:"column:file_model;not null;comment:文件读取model" json:"file_model"` // 文件读取model + JSONModel string `gorm:"column:json_model;not null;comment:json格式处理model" json:"json_model"` // json格式处理model + ChatModel string `gorm:"column:chat_model;not null;comment:对话模型" json:"chat_model"` // 对话模型 + Mode int32 `gorm:"column:mode;not null;comment:模式" json:"mode"` // 模式 + CreateAt time.Time `gorm:"column:create_at;default:CURRENT_TIMESTAMP" json:"create_at"` +} + +// TableName AiAdviceModelSup's table name +func (*AiAdviceModelSup) TableName() string { + return TableNameAiAdviceModelSup +} diff --git a/internal/data/model/ai_advice_project.gen.go b/internal/data/model/ai_advice_project.gen.go index 5829e36..15573c6 100644 --- a/internal/data/model/ai_advice_project.gen.go +++ b/internal/data/model/ai_advice_project.gen.go @@ -12,14 +12,10 @@ const TableNameAiAdviceProject = "ai_advice_project" // AiAdviceProject mapped from table type AiAdviceProject struct { - ProjectID int32 `gorm:"column:project_id;primaryKey;autoIncrement:true" json:"project_id"` - Name string `gorm:"column:name;not null;comment:姓名" json:"name"` // 姓名 - RegionValue string `gorm:"column:region_value;comment:区域价值话术库" json:"region_value"` // 区域价值话术库 - CompetitionComparison string `gorm:"column:competition_comparison;comment:竞品对比话术" json:"competition_comparison"` // 竞品对比话术 - CoreSellingPoints string `gorm:"column:core_selling_points;comment:项目核心卖点" json:"core_selling_points"` // 项目核心卖点 - SupportingFacilities string `gorm:"column:supporting_facilities;comment:配套体系" json:"supporting_facilities"` // 配套体系 - DeveloperBacking string `gorm:"column:developer_backing;comment:开发商背书" json:"developer_backing"` // 开发商背书 - CreateAt time.Time `gorm:"column:create_at;default:CURRENT_TIMESTAMP" json:"create_at"` + ProjectID int32 `gorm:"column:project_id;primaryKey;autoIncrement:true" json:"project_id"` + Name string `gorm:"column:name;not null;comment:姓名" json:"name"` // 姓名 + ModelSupID int32 `gorm:"column:model_sup_id;not null;comment:模型提供方配置,关联advicer_model_sup" json:"model_sup_id"` // 模型提供方配置,关联advicer_model_sup + CreateAt time.Time `gorm:"column:create_at;default:CURRENT_TIMESTAMP" json:"create_at"` } // TableName AiAdviceProject's table name diff --git a/internal/data/model/ai_advice_session.gen.go b/internal/data/model/ai_advice_session.gen.go new file mode 100644 index 0000000..4ee8688 --- /dev/null +++ b/internal/data/model/ai_advice_session.gen.go @@ -0,0 +1,32 @@ +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. + +package model + +import ( + "time" +) + +const TableNameAiAdviceSession = "ai_advice_session" + +// AiAdviceSession mapped from table +type AiAdviceSession struct { + ID int32 `gorm:"column:id;primaryKey;autoIncrement:true" json:"id"` + SessionID string `gorm:"column:session_id;not null" json:"session_id"` + ProjectID int32 `gorm:"column:project_id;not null" json:"project_id"` + SupID int32 `gorm:"column:sup_id;not null" json:"sup_id"` + AdvicerVersionID string `gorm:"column:advicer_version_id;not null;comment:顾问版本" json:"advicer_version_id"` // 顾问版本 + ClientID string `gorm:"column:client_id;not null;comment:客户信息id" json:"client_id"` // 客户信息id + TalkSkillID string `gorm:"column:talk_skill_id;not null;comment:聊天话术id" json:"talk_skill_id"` // 聊天话术id + ContextCache string `gorm:"column:context_cache;not null;comment:上下文缓存信息(火山引擎)" json:"context_cache"` // 上下文缓存信息(火山引擎) + Mission string `gorm:"column:mission;not null;comment:任务" json:"mission"` // 任务 + MissionStatus string `gorm:"column:mission_status;not null;default:1;comment:任务状态" json:"mission_status"` // 任务状态 + MissionCompleteDesc string `gorm:"column:mission_complete_desc;not null;comment:任务完成描述" json:"mission_complete_desc"` // 任务完成描述 + CreateAt time.Time `gorm:"column:create_at;default:CURRENT_TIMESTAMP" json:"create_at"` +} + +// TableName AiAdviceSession's table name +func (*AiAdviceSession) TableName() string { + return TableNameAiAdviceSession +} diff --git a/internal/data/mongo_model/advicer_chat_his.go b/internal/data/mongo_model/advicer_chat_his.go new file mode 100644 index 0000000..79a4560 --- /dev/null +++ b/internal/data/mongo_model/advicer_chat_his.go @@ -0,0 +1,46 @@ +package mongo_model + +import ( + "time" +) + +type AdvicerChatHisMongo struct { + SessionId string `json:"sessionId" bson:"sessionId"` + User string `json:"User" bson:"User"` + Assistant Assistant `json:"assistant" bson:"assistant"` + InToken int64 `json:"inToken" bson:"inToken"` + OutToken int64 `json:"outToken" bson:"outToken"` + CreatAt time.Time `json:"creatAt" bson:"creatAt"` +} + +func NewAdvicerChatHisMongo() *AdvicerChatHisMongo { + return &AdvicerChatHisMongo{} +} + +func (a *AdvicerChatHisMongo) MongoTableName() string { + return "advicer_chat_his" +} + +type AdvicerChatHisMongoEntity struct { + User string `json:"user"` + Assistant string `json:"assistant"` + MissionStatus string `json:"missionStatus"` + MissionNext string `json:"missionNext"` + CreateAt string `json:"createAt"` +} + +func (a *AdvicerChatHisMongo) Entity() AdvicerChatHisMongoEntity { + return AdvicerChatHisMongoEntity{ + User: a.User, + Assistant: a.Assistant.Result, + MissionStatus: a.Assistant.MissionStatus, + MissionNext: a.Assistant.MissionCompleteDesc, + CreateAt: a.CreatAt.Format(time.DateTime), + } +} + +type Assistant struct { + Result string `json:"result"` + MissionStatus string `json:"mission_status"` + MissionCompleteDesc string `json:"mission_complete_desc"` +} diff --git a/internal/data/mongo_model/provider_set.go b/internal/data/mongo_model/provider_set.go index 7520345..916b5dd 100644 --- a/internal/data/mongo_model/provider_set.go +++ b/internal/data/mongo_model/provider_set.go @@ -7,4 +7,5 @@ var ProviderSetMongo = wire.NewSet( NewAdvicerTalkSkillMongo, NewAdvicerProjectMongo, NewAdvicerClientMongo, + NewAdvicerChatHisMongo, ) diff --git a/internal/entitys/advicer_data.go b/internal/entitys/advicer_data.go index 4a22a67..2c28b48 100644 --- a/internal/entitys/advicer_data.go +++ b/internal/entitys/advicer_data.go @@ -1,14 +1,17 @@ package entitys -import "ai_scheduler/internal/data/mongo_model" +import ( + "ai_scheduler/internal/data/model" + "ai_scheduler/internal/data/mongo_model" +) type AdvicerInitReq struct { - AdvicerID int32 `json:"AdvicerId"` - ProjectID int32 `json:"ProjectId"` + AdvicerID int32 `json:"advicerId"` + ProjectID int32 `json:"projectId"` Name string `json:"name"` // 姓名 Birth string `json:"birth"` // 用户名称 Gender int32 `json:"gender"` // 1:男,2:女 - WorkingYears int32 `json:"WorkingYears"` // 工作年限 + WorkingYears int32 `json:"workingYears"` // 工作年限 } type AdvicerInfoReq struct { @@ -16,7 +19,7 @@ type AdvicerInfoReq struct { } type AdvicerListReq struct { - ProjectId int32 `json:"ProjectId"` + ProjectId int32 `json:"projectId"` } type AdvicerVersionAddReq struct { @@ -92,6 +95,21 @@ type AdvicerTalkSkillInfoReq struct { Id string `json:"id"` } +type AdvicerProjectBaseAddReq struct { + Name string `json:"name"` + ModelSupId int32 `json:"modelSupId"` +} + +type AdvicerProjectBaseAddRes struct { + ProjectId int32 `json:"projectId"` +} + +type AdvicerProjectBaseUpdateReq struct { + ProjectId int32 `json:"projectId"` + Name string `json:"name"` + ModelSupId int32 `json:"modelSupId"` +} + type AdvicerProjectAddReq struct { ProjectId int32 `json:"projectId" bson:"projectId"` ProjectInfo mongo_model.ProjectInfo `json:"projectInfo" bson:"projectInfo"` @@ -118,6 +136,12 @@ type AdvicerProjectInfoReq struct { ProjectId int32 `json:"projectId" bson:"projectId"` } +type AdvicerProjectInfoRes struct { + Base model.AiAdviceProject + ConfigInfo mongo_model.AdvicerProjectMongo + ModelInfo model.AiAdviceModelSup +} + type AdvicerClientAddReq struct { ProjectId int32 `json:"projectId" bson:"projectId"` AdvicerId int32 `json:"advicerId" bson:"advicerId"` @@ -157,6 +181,7 @@ type AdvicerChatRegistReq struct { AdvicerVersionId string `json:"advicerVersionId"` ClientId string `json:"clientId"` TalkSkillId string `json:"talkSkillId"` + Mission string `json:"mission"` } type AdvicerChatRegistRes struct { diff --git a/internal/pkg/response.go b/internal/pkg/response.go index b65b780..037aeb9 100644 --- a/internal/pkg/response.go +++ b/internal/pkg/response.go @@ -15,7 +15,7 @@ func HandleResponse(c *fiber.Ctx, data interface{}, e error) (err error) { case error: err = data.(error) case int, int32, int64, float32, float64, string, bool: - c.Response().SetBody([]byte(fmt.Sprintf("%s", data))) + c.Response().SetBody([]byte(fmt.Sprintf("%v", data))) case []byte: c.Response().SetBody(data.([]byte)) default: diff --git a/internal/server/router/router.go b/internal/server/router/router.go index 2954faa..19593f1 100644 --- a/internal/server/router/router.go +++ b/internal/server/router/router.go @@ -111,11 +111,13 @@ func SetupRoutes(app *fiber.App, ChatService *services.ChatService, sessionServi advicer.Post("skill/list", adviceTalkSkill.TalkSkillList) advicer.Post("skill/add", adviceTalkSkill.TalkSkillAdd) advicer.Post("skill/update", adviceTalkSkill.TalkSkillUpdate) - advicer.Post("skill/del", adviceTalkSkill.TalkSkillUpdate) + advicer.Post("skill/del", adviceTalkSkill.TalkSkillDel) //项目 - advicer.Post("project/add", adviceProject.Add) - advicer.Post("project/update", adviceProject.Update) + advicer.Post("project/base/init", adviceProject.BaseInit) + advicer.Post("project/base/update", adviceProject.BaseUpdate) + advicer.Post("project/info/add", adviceProject.Add) + advicer.Post("project/info/update", adviceProject.Update) advicer.Post("project/info", adviceProject.Info) //客户 @@ -124,7 +126,7 @@ func SetupRoutes(app *fiber.App, ChatService *services.ChatService, sessionServi advicer.Post("client/list", adviceClient.List) advicer.Post("client/del", adviceClient.Del) - //客户 + //会话 advicer.Post("chat/regis", adviceChat.Regis) advicer.Post("chat/chat", adviceChat.Chat) @@ -185,6 +187,9 @@ func registerCommon(c *fiber.Ctx, err error) error { } body := c.Response().Body() + if c.Locals("skip_response_wrap") == true { + return c.JSON(string(body)) + } var rawData json.RawMessage if len(body) > 0 { if err := json.Unmarshal(body, &rawData); err != nil { diff --git a/internal/services/advice/advicer.go b/internal/services/advice/advicer.go index 51d1d86..f2f9035 100644 --- a/internal/services/advice/advicer.go +++ b/internal/services/advice/advicer.go @@ -31,7 +31,8 @@ func (d *AdvicerService) AdvicerUpdate(c *fiber.Ctx) error { if err := c.BodyParser(req); err != nil { return err } - return d.adviceBiz.Update(c.UserContext(), req) + id, err := d.adviceBiz.Update(c.UserContext(), req) + return pkg.HandleResponse(c, int(id), err) } func (d *AdvicerService) AdvicerList(c *fiber.Ctx) error { @@ -48,7 +49,8 @@ func (d *AdvicerService) AdvicerVersionAdd(c *fiber.Ctx) error { if err := c.BodyParser(req); err != nil { return err } - return d.adviceBiz.VersionAdd(c.UserContext(), req) + id, err := d.adviceBiz.VersionAdd(c.UserContext(), req) + return pkg.HandleResponse(c, id, err) } func (d *AdvicerService) AdvicerVersionUpdate(c *fiber.Ctx) error { diff --git a/internal/services/advice/chat.go b/internal/services/advice/chat.go index 4759b7b..d8baf09 100644 --- a/internal/services/advice/chat.go +++ b/internal/services/advice/chat.go @@ -53,6 +53,10 @@ func (a *ChatService) Regis(c *fiber.Ctx) error { if len(req.TalkSkillId) == 0 { return errorcode.ParamErr("talkSkillId is empty") } + if len(req.Mission) == 0 { + return errorcode.ParamErr("misiion is empty") + } + //顾问版本信息 versionInfo, err := a.adviceAdvicerBiz.VersionInfo(c.UserContext(), &entitys.AdvicerVersionInfoReq{ Id: req.AdvicerVersionId, @@ -68,6 +72,7 @@ func (a *ChatService) Regis(c *fiber.Ctx) error { if err != nil { return err } + //项目信息 projectInfo, err := a.adviceProjectBiz.Info(c.UserContext(), &entitys.AdvicerProjectInfoReq{ ProjectId: advicerInfo.ProjectID, @@ -75,6 +80,15 @@ func (a *ChatService) Regis(c *fiber.Ctx) error { if err != nil { return err } + + if len(projectInfo.ModelInfo.Key) == 0 { + return errorcode.ParamErr("项目未设置模型key") + } + + if len(projectInfo.ModelInfo.ChatModel) == 0 { + return errorcode.ParamErr("项目未设置模型对话模型") + } + //销售技巧 talkSkill, err := a.adviceSkillBiz.Info(c.UserContext(), &entitys.AdvicerTalkSkillInfoReq{ Id: req.TalkSkillId, @@ -96,11 +110,12 @@ func (a *ChatService) Regis(c *fiber.Ctx) error { chat := entitys.ChatData{ ClientInfo: clientInfo.Entity(), TalkSkill: talkSkill.Entity(), - ProjectInfo: projectInfo.Entity(), + ProjectInfo: projectInfo.ConfigInfo.Entity(), AdvicerInfo: advicerInfo.Entity(), AdvicerVersion: versionInfo.Entity(), } - sessionId, err := a.adviceChatBiz.Regis(c.UserContext(), &chat) + sessionId, err := a.adviceChatBiz.Regis(c.UserContext(), &chat, req, projectInfo) + log.Info(sessionId) return pkg.HandleResponse(c, sessionId, err) } @@ -110,7 +125,28 @@ func (a *ChatService) Chat(c *fiber.Ctx) error { if err := c.BodyParser(req); err != nil { return err } - + if len(req.SessionId) == 0 { + return errorcode.ParamErr("SessionId is empty") + } + if len(req.Content) == 0 { + return errorcode.ParamErr("Content is empty") + } + res, err := a.adviceChatBiz.Chat(c.UserContext(), req) + log.Info(res) + return pkg.HandleResponse(c, res, err) +} + +func (a *ChatService) ChatContext(c *fiber.Ctx) error { + req := &entitys.AdvicerChatReq{} + if err := c.BodyParser(req); err != nil { + return err + } + if len(req.SessionId) == 0 { + return errorcode.ParamErr("SessionId is empty") + } + if len(req.Content) == 0 { + return errorcode.ParamErr("Content is empty") + } res, err := a.adviceChatBiz.Chat(c.UserContext(), req) log.Info(res) return pkg.HandleResponse(c, res, err) diff --git a/internal/services/advice/client.go b/internal/services/advice/client.go index d884414..d8377b4 100644 --- a/internal/services/advice/client.go +++ b/internal/services/advice/client.go @@ -31,7 +31,8 @@ func (d *ClientService) Add(c *fiber.Ctx) error { if err := c.BodyParser(req); err != nil { return err } - return d.AdviceClientBiz.Add(c.UserContext(), req) + id, err := d.AdviceClientBiz.Add(c.UserContext(), req) + return pkg.HandleResponse(c, id, err) } func (d *ClientService) Update(c *fiber.Ctx) error { diff --git a/internal/services/advice/project.go b/internal/services/advice/project.go index 22cd036..9c28c49 100644 --- a/internal/services/advice/project.go +++ b/internal/services/advice/project.go @@ -3,6 +3,7 @@ package advice import ( "ai_scheduler/internal/biz" "ai_scheduler/internal/config" + errorcode "ai_scheduler/internal/data/error" "ai_scheduler/internal/entitys" "ai_scheduler/internal/pkg" @@ -26,12 +27,33 @@ func NewProjectService( } } +func (d *ProjectService) BaseInit(c *fiber.Ctx) error { + req := &entitys.AdvicerProjectBaseAddReq{} + if err := c.BodyParser(req); err != nil { + return err + } + add, err := d.adviceProjectBiz.BaseAdd(c.UserContext(), req) + return pkg.HandleResponse(c, add, err) +} + +func (d *ProjectService) BaseUpdate(c *fiber.Ctx) error { + req := &entitys.AdvicerProjectBaseUpdateReq{} + if err := c.BodyParser(req); err != nil { + return err + } + if req.ProjectId == 0 { + return errorcode.ParamErr("projectId is empty") + } + return d.adviceProjectBiz.BaseUpdate(c.UserContext(), req) +} + func (d *ProjectService) Add(c *fiber.Ctx) error { req := &entitys.AdvicerProjectAddReq{} if err := c.BodyParser(req); err != nil { return err } - return d.adviceProjectBiz.Add(c.UserContext(), req) + id, err := d.adviceProjectBiz.Add(c.UserContext(), req) + return pkg.HandleResponse(c, id, err) } func (d *ProjectService) Update(c *fiber.Ctx) error { diff --git a/internal/services/advice/talk_skill.go b/internal/services/advice/talk_skill.go index d47ccec..3746893 100644 --- a/internal/services/advice/talk_skill.go +++ b/internal/services/advice/talk_skill.go @@ -31,7 +31,8 @@ func (d *TalkSkillService) TalkSkillAdd(c *fiber.Ctx) error { if err := c.BodyParser(req); err != nil { return err } - return d.adviceSkillBiz.VersionAdd(c.UserContext(), req) + id, err := d.adviceSkillBiz.VersionAdd(c.UserContext(), req) + return pkg.HandleResponse(c, id, err) } func (d *TalkSkillService) TalkSkillUpdate(c *fiber.Ctx) error { diff --git a/tmpl/dataTemp/queryTempl.go b/tmpl/dataTemp/queryTempl.go index 2c97141..8f322ba 100644 --- a/tmpl/dataTemp/queryTempl.go +++ b/tmpl/dataTemp/queryTempl.go @@ -1,7 +1,6 @@ package dataTemp import ( - "ai_scheduler/internal/pkg/mapstructure" "ai_scheduler/utils" "context" "database/sql" @@ -10,7 +9,6 @@ import ( "github.com/go-kratos/kratos/v2/log" "gorm.io/gorm" - "xorm.io/builder" ) @@ -62,18 +60,17 @@ func (k DataTemp) GetById(id int32) (data map[string]interface{}, err error) { } func (k DataTemp) Add(data interface{}) (id int, err error) { - var primary *PrimaryKey + add := k.Db.Model(k.Model).Create(data) - _ = mapstructure.Decode(data, &primary) - return primary.Id, add.Error + return 0, add.Error } -func (k DataTemp) AddWithData(data interface{}) (interface{}, error) { +func (k DataTemp) AddWithData(data interface{}) error { result := k.Db.Model(k.Model).Create(data) if result.Error != nil { - return data, result.Error + return result.Error } - return data, nil + return nil } func (k DataTemp) GetList(cond *builder.Cond, pageBoIn *ReqPageBo) (list []map[string]interface{}, pageBoOut *RespPageBo, err error) {