question.go 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  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. //P393 stream接口不再使用
  146. //if sRes.Result.Answer == "" {
  147. // poolErr := ChatGptPool.Get()
  148. // if poolErr != nil {
  149. // return "", nil, 0, poolErr
  150. // }
  151. // cRes, err := ChatGpt.GPTDo(ctx, qRes)
  152. // if err != nil {
  153. // ChatGptPool.Add()
  154. // return "", nil, 0, err
  155. // }
  156. // return "", cRes, Answer_ChatGPT, nil
  157. //}
  158. // 校验是否有业务逻辑
  159. matchArr := regExpSmart.FindStringSubmatch(sRes.Result.Answer)
  160. if len(matchArr) == 0 {
  161. return sRes.Result.Answer, nil, Answer_UsuallyProblem, nil
  162. }
  163. // 查询业务逻辑
  164. var bRes = &BusinessRes{}
  165. bRes, err = q.getIsbusinessData(ctx, matchArr[0])
  166. _, infoId := GetScenarioAndInfoId(qRes.Href)
  167. if bRes.Source == scenarioName[DetailPage] && infoId == "" {
  168. return bRes.AutoUrl, nil, Answer_Isbusiness, nil
  169. }
  170. // 权限校验
  171. jSession := SessionCtx.Get(ctx).JSession
  172. powerPass := func() bool {
  173. if bRes.CheckMember == 0 && bRes.CheckNewvip == 0 && bRes.CheckNewentniche == 0 {
  174. return true
  175. }
  176. power := utility.Middleground.PowerCheckCenter.Check(g.Config().MustGet(ctx, "chat.appId").String(), jSession.UserId, jSession.NewUid, jSession.AccountId, jSession.EntId, jSession.PositionType, jSession.PositionId)
  177. // 大会员权益校验
  178. if bRes.CheckMember == 1 && power.Member.Status > 0 && bRes.ServiceId != "" {
  179. for _, v := range strings.Split(bRes.ServiceId, ",") {
  180. for _, vv := range power.Member.MemberPowerList {
  181. if gconv.Int64(v) == vv {
  182. return true
  183. }
  184. }
  185. }
  186. }
  187. // 校验新版超级订阅
  188. if bRes.CheckNewvip == 1 && power.Vip.Upgrade > 0 && power.Vip.Status > 0 {
  189. return true
  190. }
  191. // 校验商机管理
  192. if bRes.CheckNewentniche == 1 && power.Entniche.Status > 0 && power.Entniche.IsNew > 0 {
  193. return true
  194. }
  195. return false
  196. }()
  197. if !powerPass {
  198. return bRes.Noperm, nil, Answer_Isbusiness, nil
  199. }
  200. businessRes, err := utility.DoBusiness(ctx, bRes.Joggle, &utility.RpcParams{
  201. UserId: jSession.UserId,
  202. Answer: bRes.Answer,
  203. BiddingId: infoId,
  204. BaseUserId: jSession.NewUid,
  205. })
  206. if err != nil {
  207. return "", nil, Answer_Isbusiness, nil
  208. }
  209. if businessRes.ErrMsg != "" {
  210. return "", nil, Answer_Isbusiness, fmt.Errorf(businessRes.ErrMsg)
  211. }
  212. return businessRes.ReplyMsg, nil, Answer_Isbusiness, nil
  213. }