question.go 5.7 KB

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