aiSearch_v1_chat.go 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  1. package aiSearch
  2. import (
  3. "aiChat/api/aiSearch/v1"
  4. "aiChat/internal/model"
  5. "aiChat/internal/model/bidSearch"
  6. "aiChat/utility"
  7. "context"
  8. "fmt"
  9. "io/ioutil"
  10. "strings"
  11. "time"
  12. . "app.yhyue.com/moapp/jybase/encrypt"
  13. "github.com/gogf/gf/v2/database/gdb"
  14. "github.com/gogf/gf/v2/encoding/gjson"
  15. "github.com/gogf/gf/v2/frame/g"
  16. "github.com/gogf/gf/v2/os/gtime"
  17. "github.com/gogf/gf/v2/util/gconv"
  18. )
  19. func (c *ControllerV1) Chat(ctx context.Context, req *v1.ChatReq) (res *v1.ChatRes, err error) {
  20. res = &v1.ChatRes{Status: 0}
  21. sid := gconv.Int64(SE.Decode4HexByCheck(req.SId))
  22. if sid == 0 {
  23. g.Log().Error(ctx, "无效的sid参数", req.SId)
  24. return
  25. }
  26. sess, sessErr := model.GetSession(g.RequestFromCtx(ctx))
  27. if sessErr != nil {
  28. g.Log().Error(ctx, "获取session出错", sessErr)
  29. return
  30. }
  31. startTime := gtime.Now().Format("Y-m-d h:m:s.u")
  32. answerStatus := 0
  33. prompt := fmt.Sprintf(g.Cfg("ai_search.yaml").MustGet(ctx, "doubaoPrompt").String(), gtime.Now().Format("Ymd"), req.Question)
  34. largeModel := "doubao"
  35. callLogs := g.List{}
  36. content, largeModelReply, err, isLimit := c.doubao(ctx, prompt)
  37. if !isLimit {
  38. large_model_success := 1
  39. error_msg := ""
  40. if err != nil {
  41. error_msg = err.Error()
  42. large_model_success = 0
  43. }
  44. callLogs = append(callLogs, g.Map{
  45. "position_id": sess.PositionId,
  46. "large_model": largeModel,
  47. "large_model_reply": largeModelReply,
  48. "large_model_starttime": startTime,
  49. "large_model_endtime": gtime.Now().Format("Y-m-d h:m:s.u"),
  50. "large_model_success": large_model_success,
  51. "error_msg": error_msg,
  52. })
  53. }
  54. if isLimit || err != nil {
  55. prompt = fmt.Sprintf(g.Cfg("ai_search.yaml").MustGet(ctx, "zhipuPrompt").String(), gtime.Now().Format("Ymd"), req.Question)
  56. content, largeModelReply, err, _ = c.zhipu(ctx, prompt)
  57. largeModel = "zhipu"
  58. large_model_success := 1
  59. error_msg := ""
  60. if err != nil {
  61. error_msg = err.Error()
  62. large_model_success = 0
  63. }
  64. callLogs = append(callLogs, g.Map{
  65. "position_id": sess.PositionId,
  66. "large_model": largeModel,
  67. "large_model_reply": largeModelReply,
  68. "large_model_starttime": startTime,
  69. "large_model_endtime": gtime.Now().Format("Y-m-d h:m:s.u"),
  70. "large_model_success": large_model_success,
  71. "error_msg": error_msg,
  72. })
  73. }
  74. large_model_endtime := gtime.Now().Format("Y-m-d h:m:s.u")
  75. if err == nil {
  76. answerStatus = 1
  77. } else {
  78. largeModel = ""
  79. }
  80. bs, bsErr := bidSearch.NewBidSearch(ctx, sess.PersonId, content)
  81. if bsErr != nil {
  82. return
  83. }
  84. query, list := bs.Search()
  85. answer := ""
  86. var bestBids []*v1.ResBidding
  87. if len(list) > 0 {
  88. if bestBidListMaxLen := g.Cfg("ai_search.yaml").MustGet(ctx, "bestBidListMaxLen").Int(); len(list) > bestBidListMaxLen {
  89. bestBids = make([]*v1.ResBidding, bestBidListMaxLen)
  90. copy(bestBids, list[:bestBidListMaxLen])
  91. } else {
  92. bestBids = make([]*v1.ResBidding, len(list))
  93. copy(bestBids, list[:])
  94. }
  95. answer = gconv.String(bestBids)
  96. collection := utility.GetMyBidCollect(ctx, sess.PositionId)
  97. for _, v := range bestBids {
  98. if collection[v.InfoId] {
  99. v.Collect = 1
  100. }
  101. v.InfoId = EncodeArticleId2ByCheck(v.InfoId)
  102. }
  103. }
  104. if err := g.DB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
  105. chatId, chatErr := tx.InsertAndGetId("ai_search_chat", g.Map{
  106. "position_id": sess.PositionId,
  107. "item": req.Item,
  108. "question": req.Question,
  109. "answer": answer,
  110. "starttime": startTime,
  111. "large_model_endtime": large_model_endtime,
  112. "endtime": gtime.Now().Format("Y-m-d h:m:s.u"),
  113. "es_query": query,
  114. "list_count": len(list),
  115. "session_id": sid,
  116. "status": 1,
  117. "large_model": largeModel,
  118. "answer_status": answerStatus,
  119. "create_time": gtime.Datetime(),
  120. })
  121. if chatErr != nil {
  122. g.Log().Error(ctx, "ai_search_chat保存出错", chatErr)
  123. return chatErr
  124. }
  125. //
  126. bids := g.List{}
  127. for _, v := range list {
  128. bids = append(bids, g.Map{
  129. "position_id": sess.PositionId,
  130. "chat_id": chatId,
  131. "infoid": v.InfoId,
  132. "title": v.Title,
  133. "area": v.Area,
  134. "city": v.City,
  135. "district": v.District,
  136. "subtype": v.Subtype,
  137. "industry": v.Industry,
  138. "annex": v.Annex,
  139. "buyerclass": v.Buyerclass,
  140. "budget": v.Budget,
  141. "bidamount": v.Bidamount,
  142. "publishtime": v.Publishtime,
  143. "create_time": gtime.Datetime(),
  144. })
  145. }
  146. if len(bids) > 0 {
  147. if _, bidsErr := tx.Insert("ai_search_bidding", bids, 200); bidsErr != nil {
  148. g.Log().Error(ctx, "ai_search_bidding保存出错", bidsErr)
  149. return bidsErr
  150. }
  151. }
  152. //
  153. for _, v := range callLogs {
  154. v["chat_id"] = chatId
  155. v["create_time"] = gtime.Datetime()
  156. }
  157. if len(callLogs) > 0 {
  158. if _, callLogsErr := tx.Insert("ai_search_log", callLogs); callLogsErr != nil {
  159. g.Log().Error(ctx, "ai_search_log保存出错", callLogsErr)
  160. return callLogsErr
  161. }
  162. }
  163. return nil
  164. }); err == nil {
  165. res.Status = 1
  166. res.List = bestBids
  167. } else {
  168. g.Log().Error(ctx, sess.PositionId, "保存数据库出错", err)
  169. }
  170. return
  171. }
  172. //调用豆包大模型
  173. func (c *ControllerV1) doubao(ctx context.Context, content string) (string, string, error, bool) {
  174. count, err := g.Redis("main").Incr(ctx, fmt.Sprintf("aiSearch_doubaoCall_%s", gtime.Now().Format("Ymd")))
  175. if err != nil {
  176. g.Log().Error(ctx, "从redis获取doubao调用次数出错", err)
  177. return "", "", err, true
  178. } else if doubaoCallMax := g.Cfg("ai_search.yaml").MustGet(ctx, "doubaoCallMax").Int64(); count > doubaoCallMax {
  179. g.Log().Info(ctx, "doubao调用次数达到上限", doubaoCallMax, count)
  180. return "", "", nil, true
  181. }
  182. // 构造请求数据
  183. messages := []map[string]interface{}{}
  184. messages = append(messages, map[string]interface{}{
  185. "role": "user",
  186. "content": content,
  187. })
  188. //glm-4-air glm-4-0520 glm-4-flash
  189. requestData := map[string]interface{}{
  190. "model": "ep-20250207170552-g8dsx",
  191. "temperature": 0.1,
  192. "top_p": 0.7,
  193. "messages": messages,
  194. }
  195. return c.post(ctx, "doubao", "https://ark.cn-beijing.volces.com/api/v3/chat/completions", "3dd861bf-b8a7-41d4-bb0b-5076362c572d", requestData)
  196. }
  197. //调用智普大模型
  198. func (c *ControllerV1) zhipu(ctx context.Context, content string) (string, string, error, bool) {
  199. count, err := g.Redis("main").Incr(ctx, fmt.Sprintf("aiSearch_zhipuCall_%s", gtime.Now().Format("YYYYmmdd")))
  200. if err != nil {
  201. g.Log().Error(ctx, "从redis获取zhipu调用次数出错", err)
  202. return "", "", err, true
  203. } else if doubaoCallMax := g.Cfg("ai_search.yaml").MustGet(ctx, "zhipuCallMax").Int64(); count > doubaoCallMax {
  204. g.Log().Info(ctx, "zhipu调用次数达到上限", doubaoCallMax, count)
  205. return "", "", nil, true
  206. }
  207. // 构造请求数据
  208. messages := []map[string]interface{}{}
  209. messages = append(messages, map[string]interface{}{
  210. "role": "user",
  211. "content": content,
  212. })
  213. //glm-4-air glm-4-0520 glm-4-flash
  214. requestData := map[string]interface{}{
  215. "model": "glm-4-flash",
  216. "messages": messages,
  217. "temperature": 0.1,
  218. "max_tokens": 4096,
  219. }
  220. return c.post(ctx, "zhipu", "https://open.bigmodel.cn/api/paas/v4/chat/completions", "3d84d30b7ab4c94dbf71853cb7e44719.hLLS4CA2MqVQs6kR", requestData)
  221. }
  222. func (c *ControllerV1) post(ctx context.Context, t, apiURL, pass string, requestData map[string]interface{}) (string, string, error, bool) {
  223. ddd := `{
  224. "关键词": {
  225. "选择": ["软件"],
  226. "排除": []
  227. },
  228. "发布时间范围": "20210126-20250226",
  229. "搜索范围": ["标题", "正文"],
  230. "匹配模式": "精准匹配",
  231. "信息类型": "招标公告",
  232. "地区": {
  233. "选择": ["广东", "广西", "海南","北京"],
  234. "排除": []
  235. },
  236. "金额": "0-2000万",
  237. "采购单位联系方式": "不限",
  238. "中标单位联系方式": "不限",
  239. "附件": "不限",
  240. "采购单位": "不限",
  241. "中标单位": "不限",
  242. "招标代理": "不限"
  243. }`
  244. return ddd, "", nil, false
  245. resp, err := g.Client().Timeout(time.Duration(g.Cfg("ai_search.yaml").MustGet(ctx, "timeout").Int())*time.Second).
  246. SetHeader("Authorization", fmt.Sprintf("Bearer %s", pass)).
  247. ContentType("application/json").
  248. Post(ctx, apiURL, requestData)
  249. if err != nil {
  250. g.Log().Error(ctx, t, "请求出错", err)
  251. return "", "", err, false
  252. }
  253. defer resp.Body.Close()
  254. b, be := ioutil.ReadAll(resp.Body)
  255. if be != nil {
  256. g.Log().Error(ctx, t, "gjson.LoadJson出错", be)
  257. return "", "", err, false
  258. }
  259. largeModelReply := string(b)
  260. g.Log().Info(ctx, t, "请求回复", largeModelReply)
  261. r, re := gjson.LoadJson(b)
  262. if re != nil {
  263. g.Log().Error(ctx, t, largeModelReply, "gjson.LoadJson出错", re)
  264. return "", largeModelReply, err, false
  265. }
  266. content := ""
  267. choices := r.GetJsons("choices")
  268. if len(choices) == 0 {
  269. return "", largeModelReply, err, false
  270. }
  271. message := choices[0].GetJson("message")
  272. if message == nil {
  273. return "", largeModelReply, err, false
  274. }
  275. content = message.Get("content").String()
  276. content = strings.ReplaceAll(content, "```json", "")
  277. content = strings.ReplaceAll(content, "```", "")
  278. return content, largeModelReply, nil, false
  279. }