question.go 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. package model
  2. import (
  3. "aiChat/utility"
  4. "aiChat/utility/fsw"
  5. "context"
  6. "encoding/json"
  7. "fmt"
  8. "github.com/gogf/gf/v2/frame/g"
  9. "github.com/gogf/gf/v2/util/gconv"
  10. "io"
  11. "regexp"
  12. "strings"
  13. )
  14. var (
  15. Question = &cQuestion{}
  16. regExpSmart = regexp.MustCompile("smart_\\S+_smart")
  17. )
  18. const (
  19. Answer_UsuallyProblem = iota + 1
  20. Answer_Isbusiness
  21. Answer_ChatGPT
  22. )
  23. type cQuestion struct {
  24. }
  25. type BaseQuestion struct {
  26. Prompt string `json:"prompt"`
  27. History [][]string `json:"history"`
  28. }
  29. type QuestionReq struct {
  30. *BaseQuestion
  31. Href string `json:"href"` //咨询页面
  32. }
  33. // ParseHistoryFsw 过滤历史记录敏感词
  34. func (r *BaseQuestion) ParseHistoryFsw() {
  35. if len(r.History) == 0 {
  36. return
  37. }
  38. var newHistory [][]string
  39. for i := len(r.History) - 1; i >= 0; i-- {
  40. var pass bool = true
  41. for _, v := range r.History[i] {
  42. if fsw.Match(v) {
  43. pass = false
  44. }
  45. }
  46. if pass {
  47. newHistory = append(newHistory, r.History[i])
  48. if len(newHistory) > 3 {
  49. break
  50. }
  51. }
  52. }
  53. r.History = newHistory
  54. }
  55. type questionFilter struct {
  56. HasBuyer bool `json:"hasBuyer" dc:"有采购单位"`
  57. HasWinner bool `json:"hasWinner" dc:"有中标单位"`
  58. TopType InfoType `json:"topType" dc:"信息类型"`
  59. }
  60. type InfoType map[string]bool
  61. func (t InfoType) Check(infoType string) bool {
  62. if len(t) == 0 {
  63. return false
  64. }
  65. if _, ok := t[infoType]; ok {
  66. return true
  67. }
  68. return false
  69. }
  70. // GetUsuallyProblem 获取常见问题
  71. func (q *cQuestion) GetUsuallyProblem(ctx context.Context, href string, limit int) (list []string, err error) {
  72. scenario, infoId := GetScenarioAndInfoId(href)
  73. list = make([]string, 0, limit)
  74. res, err := g.Model("ai_question_list").Ctx(ctx).Fields("question", "filter").
  75. Where("status = 1 and source = ?", scenario).OrderDesc("create_time").OrderAsc("id").Limit(limit).All()
  76. if err != nil {
  77. return nil, err
  78. }
  79. hasWinner, hasBuyer, infoTypes := getInfo(infoId)
  80. for _, m := range res.List() {
  81. if m["filter"] != nil {
  82. tFilter := questionFilter{}
  83. if json.Unmarshal(gconv.Bytes(m["filter"]), &tFilter) != nil {
  84. continue
  85. }
  86. if !((hasBuyer && tFilter.HasBuyer) ||
  87. (hasWinner && tFilter.HasWinner) ||
  88. len(infoTypes) > 0 && tFilter.TopType.Check(infoTypes)) {
  89. continue
  90. }
  91. }
  92. list = append(list, gconv.String(m["question"]))
  93. }
  94. return
  95. }
  96. func getInfo(infoId string) (hasWinner, hasBuyer bool, infoTypes string) {
  97. if infoId == "" {
  98. return
  99. }
  100. res, ok := utility.MgoBidding.FindById(utility.BiddingConf.Collection, infoId, `{"buyer":1,"winner":1,"toptype":1}`)
  101. if ok && res == nil || len(*res) == 0 {
  102. res, _ = utility.MgoBidding.FindById(utility.BiddingConf.Collection, infoId, `{"buyer":1,"winner":1,"toptype":1}`)
  103. }
  104. if res != nil && len(*res) > 0 {
  105. hasWinner = (*res)["winner"] != nil
  106. hasBuyer = (*res)["buyer"] != nil
  107. infoTypes = gconv.String((*res)["toptype"])
  108. }
  109. return
  110. }
  111. type BusinessRes struct {
  112. Answer string `json:"answer" dc:"答案"`
  113. AutoUrl string `json:"auto_url" dc:"默认url"`
  114. Joggle string `json:"joggle" dc:"业务接口"`
  115. Noperm string `json:"noperm" dc:"无权限回复"`
  116. Source string `json:"source" dc:"问题所属"`
  117. CheckMember int `json:"check_member" dc:"是否校验大会员权限"`
  118. ServiceId string `json:"service_id" dc:"大会员功能服务id"`
  119. CheckNewentniche int `json:"check_newentniche" dc:"校验新版商机管理"`
  120. CheckNewvip int `json:"check_newvip" dc:"校验是否是新版超级订阅"`
  121. }
  122. // getIsbusinessData 获取业务规则
  123. func (q *cQuestion) getIsbusinessData(ctx context.Context, code string) (bRes *BusinessRes, err error) {
  124. res, err := g.Model("ai_question").Ctx(ctx).Fields("check_member", "answer", "auto_url", "joggle", "noperm", "source", "service_id", "check_newvip", "check_newentniche").Where("ai_code = ?", code).One()
  125. if err != nil {
  126. return nil, err
  127. }
  128. if res.IsEmpty() {
  129. return nil, fmt.Errorf("未知业务指令")
  130. }
  131. bRes = &BusinessRes{}
  132. if err = res.Struct(bRes); err != nil {
  133. return nil, err
  134. }
  135. return bRes, nil
  136. }
  137. // DetailQuestion 问题处理
  138. func (q *cQuestion) DetailQuestion(ctx context.Context, qRes *QuestionReq) (reply string, res io.ReadCloser, from int, err error) {
  139. qRes.ParseHistoryFsw()
  140. // 语义服务
  141. sRes, err := ChatGpt.SimpleDo(ctx, qRes)
  142. if err != nil {
  143. return "", nil, 0, err
  144. }
  145. if sRes.Result.Answer == "" {
  146. poolErr := ChatGptPool.Get()
  147. if poolErr != nil {
  148. return "", nil, 0, poolErr
  149. }
  150. cRes, err := ChatGpt.GPTDo(ctx, qRes)
  151. if err != nil {
  152. ChatGptPool.Add()
  153. return "", nil, 0, err
  154. }
  155. return "", cRes, Answer_ChatGPT, nil
  156. }
  157. // 校验是否有业务逻辑
  158. matchArr := regExpSmart.FindStringSubmatch(sRes.Result.Answer)
  159. if len(matchArr) == 0 {
  160. return sRes.Result.Answer, nil, Answer_UsuallyProblem, nil
  161. }
  162. // 查询业务逻辑
  163. var bRes = &BusinessRes{}
  164. bRes, err = q.getIsbusinessData(ctx, matchArr[0])
  165. _, infoId := GetScenarioAndInfoId(qRes.Href)
  166. if bRes.Source == scenarioName[DetailPage] && infoId == "" {
  167. return bRes.AutoUrl, nil, Answer_Isbusiness, nil
  168. }
  169. // 权限校验
  170. jSession := SessionCtx.Get(ctx).JSession
  171. powerPass := func() bool {
  172. if bRes.CheckMember == 0 && bRes.CheckNewvip == 0 && bRes.CheckNewentniche == 0 {
  173. return true
  174. }
  175. power := utility.Middleground.PowerCheckCenter.Check(g.Config().MustGet(ctx, "chat.appId").String(), jSession.UserId, jSession.NewUid, jSession.AccountId, jSession.EntId, jSession.PositionType, jSession.PositionId)
  176. // 大会员权益校验
  177. if bRes.CheckMember == 1 && power.Member.Status > 0 && bRes.ServiceId != "" {
  178. for _, v := range strings.Split(bRes.ServiceId, ",") {
  179. for _, vv := range power.Member.MemberPowerList {
  180. if gconv.Int64(v) == vv {
  181. return true
  182. }
  183. }
  184. }
  185. }
  186. // 校验新版超级订阅
  187. if bRes.CheckNewvip == 1 && power.Vip.Upgrade > 0 && power.Vip.Status > 0 {
  188. return true
  189. }
  190. // 校验商机管理
  191. if bRes.CheckNewentniche == 1 && power.Entniche.Status > 0 && power.Entniche.IsNew > 0 {
  192. return true
  193. }
  194. return false
  195. }()
  196. if !powerPass {
  197. return bRes.Noperm, nil, Answer_Isbusiness, nil
  198. }
  199. businessRes, err := utility.DoBusiness(ctx, bRes.Joggle, &utility.RpcParams{
  200. UserId: jSession.UserId,
  201. Answer: bRes.Answer,
  202. BiddingId: infoId,
  203. BaseUserId: jSession.NewUid,
  204. })
  205. if err != nil {
  206. return "", nil, Answer_Isbusiness, nil
  207. }
  208. if businessRes.ErrMsg != "" {
  209. return "", nil, Answer_Isbusiness, fmt.Errorf(businessRes.ErrMsg)
  210. }
  211. return businessRes.ReplyMsg, nil, Answer_Isbusiness, nil
  212. }