question.go 6.2 KB

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