|
@@ -1,45 +1,70 @@
|
|
|
package model
|
|
|
|
|
|
import (
|
|
|
- elastic "app.yhyue.com/moapp/jybase/esv1"
|
|
|
+ "aiChat/internal/consts"
|
|
|
+ "aiChat/utility"
|
|
|
"context"
|
|
|
"fmt"
|
|
|
"github.com/gogf/gf/v2/frame/g"
|
|
|
"github.com/gogf/gf/v2/util/gconv"
|
|
|
+ "regexp"
|
|
|
+ "strings"
|
|
|
)
|
|
|
|
|
|
var (
|
|
|
- Question = &cQuestion{}
|
|
|
+ Question = &cQuestion{}
|
|
|
+ regExpSmart = regexp.MustCompile("smart_\\S+_smart")
|
|
|
)
|
|
|
|
|
|
const (
|
|
|
- answerFrom = iota
|
|
|
- Answer_UsuallyProblem
|
|
|
+ Answer_UsuallyProblem = iota + 1
|
|
|
Answer_Isbusiness
|
|
|
Answer_ChatGPT
|
|
|
-
|
|
|
- index, itype = "aiquestion", "aiquestion"
|
|
|
- GetQuestionListSql = `{"query":{"bool":{"must":[{"term":{"status":1}},{"term":{"isbusiness":%d}},{"term":{"source":"%s"}}]}},"from":0,"size":%d,"sort":[{"id":"desc"}],"_source": ["question"]}`
|
|
|
- GetAnswerFromQuestion = `{"query":{"bool":{"must":[{"term":{"status":1}},{"multi_match":{"query":"%s","minimum_should_match":"%s","fields":["question"]}}]}},"from":0,"size":1,"_source":["check_member","isbusiness","question","answer","auto_url","joggle","service_id","noperm","source"]}`
|
|
|
)
|
|
|
|
|
|
type cQuestion struct {
|
|
|
}
|
|
|
|
|
|
-// QuestionReq 用户发送过来的问题详情
|
|
|
+type BaseQuestion struct {
|
|
|
+ Prompt string `json:"prompt"`
|
|
|
+ History [][]string `json:"history"`
|
|
|
+}
|
|
|
+
|
|
|
type QuestionReq struct {
|
|
|
- Context string `json:"context"` //内容
|
|
|
- History []struct {
|
|
|
- Q string `json:"q"` //问题
|
|
|
- A string `json:"a"` //答案
|
|
|
- } `json:"history,omitempty"` //会话上下文,会话历史
|
|
|
- Href string `json:"href,omitempty"` //咨询页面
|
|
|
+ *BaseQuestion
|
|
|
+ Href string `json:"href"` //咨询页面
|
|
|
+}
|
|
|
+
|
|
|
+// GetGuessQuestion 猜你想问
|
|
|
+func (q *cQuestion) GetGuessQuestion(ctx context.Context, limit int) (list []string, err error) {
|
|
|
+ list = make([]string, 0, limit)
|
|
|
+ res, err := g.Model("ai_question_list").Ctx(ctx).Fields("question").
|
|
|
+ Where("status = 1 and question_type = ?", consts.QUESTION_TYPE_GUESS).OrderDesc("id").Limit(limit).All()
|
|
|
+ if err != nil {
|
|
|
+ return nil, err
|
|
|
+ }
|
|
|
+ for _, m := range res.List() {
|
|
|
+ list = append(list, gconv.String(m["question"]))
|
|
|
+ }
|
|
|
+ return
|
|
|
+}
|
|
|
+
|
|
|
+// GetUsuallyProblem 获取常见问题
|
|
|
+func (q *cQuestion) GetUsuallyProblem(ctx context.Context, scenario, limit int) (list []string, err error) {
|
|
|
+ list = make([]string, 0, limit)
|
|
|
+ res, err := g.Model("ai_question_list").Ctx(ctx).Fields("question").
|
|
|
+ Where("status = 1 and question_type = ? and source = ?", consts.QUESTION_TYPE_USUALLY, scenario).OrderDesc("id").Limit(limit).All()
|
|
|
+ if err != nil {
|
|
|
+ return nil, err
|
|
|
+ }
|
|
|
+ for _, m := range res.List() {
|
|
|
+ list = append(list, gconv.String(m["question"]))
|
|
|
+ }
|
|
|
+ return
|
|
|
}
|
|
|
|
|
|
-// QuestionEsRes 问题检索库查询结果
|
|
|
-type QuestionEsRes struct {
|
|
|
+type BusinessRes struct {
|
|
|
CheckMember int `json:"check_member" dc:"是否校验大会员权限"`
|
|
|
- Isbusiness int `json:"isbusiness" dc:"业务意图 0:否 1:是"`
|
|
|
Answer string `json:"answer" dc:"答案"`
|
|
|
AutoUrl string `json:"auto_url" dc:"默认url"`
|
|
|
Joggle string `json:"joggle" dc:"业务接口"`
|
|
@@ -48,39 +73,81 @@ type QuestionEsRes struct {
|
|
|
ServiceId string `json:"service_id" dc:"大会员功能服务id"`
|
|
|
}
|
|
|
|
|
|
-// GetProblem 获取常见问题及猜你想问
|
|
|
-func (q *cQuestion) GetProblem(scenario, isbusiness, limit int) (list []string) {
|
|
|
- list = make([]string, 0, limit)
|
|
|
- res := elastic.Get(index, itype, fmt.Sprintf(GetQuestionListSql, isbusiness, scenarioName[scenario], limit))
|
|
|
- if res != nil && len(*res) > 0 {
|
|
|
- for _, m := range *res {
|
|
|
- list = append(list, gconv.MapStrStr(m)["question"])
|
|
|
- }
|
|
|
+// getIsbusinessData 获取业务规则
|
|
|
+func (q *cQuestion) getIsbusinessData(ctx context.Context, code string) (bRes *BusinessRes, err error) {
|
|
|
+ res, err := g.Model("ai_question").Ctx(ctx).Fields("check_member", "answer", "auto_url", "joggle", "noperm", "source", "service_id").Where("ai_code = ?", code).One()
|
|
|
+ if err != nil {
|
|
|
+ return nil, err
|
|
|
}
|
|
|
- return
|
|
|
+ if res.IsEmpty() {
|
|
|
+ return nil, fmt.Errorf("未知业务指令")
|
|
|
+ }
|
|
|
+ bRes = &BusinessRes{}
|
|
|
+ if err = res.Struct(bRes); err != nil {
|
|
|
+ return nil, err
|
|
|
+ }
|
|
|
+ return bRes, nil
|
|
|
}
|
|
|
|
|
|
-// GetAnswer 获取答案
|
|
|
-func (q *cQuestion) GetAnswer(ctx context.Context, question *QuestionReq) (itemFrom int, detail string, err error) {
|
|
|
- res := elastic.Get(index, itype, fmt.Sprintf(GetAnswerFromQuestion, question.Context, g.Config().MustGet(ctx, "chat.match", "70%").String()))
|
|
|
- if res == nil || len(*res) == 0 {
|
|
|
- return getAnswerFromChatGPT()
|
|
|
+// DetailQuestion 问题处理
|
|
|
+func (q *cQuestion) DetailQuestion(ctx context.Context, qRes *QuestionReq) (reply string, from int, err error) {
|
|
|
+ cRes, err := ChatGpt.Do(ctx, qRes)
|
|
|
+ if err != nil {
|
|
|
+ return "", 0, err
|
|
|
}
|
|
|
- qResObj := &QuestionEsRes{}
|
|
|
- gconv.Struct((*res)[0], qResObj)
|
|
|
-
|
|
|
- // 非业务问题直接返回
|
|
|
- if qResObj.Isbusiness == 0 {
|
|
|
- return Answer_UsuallyProblem, qResObj.Answer, nil
|
|
|
+ // 校验是否有业务逻辑
|
|
|
+ matchArr := regExpSmart.FindStringSubmatch(cRes.Response)
|
|
|
+ if len(matchArr) == 0 {
|
|
|
+ return cRes.Response, Answer_ChatGPT, nil
|
|
|
}
|
|
|
+ // 查询业务逻辑
|
|
|
+ var bRes = &BusinessRes{}
|
|
|
+ bRes, err = q.getIsbusinessData(ctx, matchArr[0])
|
|
|
|
|
|
- // 业务问题
|
|
|
- //qResObj.CheckMember
|
|
|
-
|
|
|
- return Answer_Isbusiness, "", nil
|
|
|
-}
|
|
|
-
|
|
|
-// getChatGPT 获取ChatGPT答案
|
|
|
-func getAnswerFromChatGPT() (int, string, error) {
|
|
|
- return Answer_ChatGPT, "", nil
|
|
|
+ // 权限校验
|
|
|
+ jSession := SessionCtx.Get(ctx).JSession
|
|
|
+ powerPass := func() bool {
|
|
|
+ power := utility.Middleground.PowerCheckCenter.Check(g.Config().MustGet(ctx, "chat.appId").String(), jSession.UserId, jSession.NewUid, jSession.AccountId, jSession.EntId, jSession.PositionType, jSession.PositionId)
|
|
|
+ // 大会员权益校验
|
|
|
+ if bRes.CheckMember == 1 && power.Member.Status <= 0 {
|
|
|
+ return false
|
|
|
+ }
|
|
|
+ // 大会员权益ServiceId校验
|
|
|
+ if bRes.ServiceId != "" {
|
|
|
+ for _, v := range strings.Split(bRes.ServiceId, ",") {
|
|
|
+ var ok bool = false
|
|
|
+ for _, vv := range power.Member.MemberPowerList {
|
|
|
+ if gconv.Int64(v) == vv {
|
|
|
+ ok = true
|
|
|
+ break
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if !ok {
|
|
|
+ return false
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return true
|
|
|
+ }()
|
|
|
+ if !powerPass {
|
|
|
+ return bRes.Noperm, Answer_Isbusiness, nil
|
|
|
+ }
|
|
|
+ _, infoId := GetScenarioAndInfoId(qRes.Href)
|
|
|
+ if bRes.Source == scenarioName[DetailPage] && infoId == "" {
|
|
|
+ return bRes.AutoUrl, Answer_Isbusiness, nil
|
|
|
+ }
|
|
|
+ businessRes, err := DoBusiness(ctx, bRes.Joggle, &RpcParams{
|
|
|
+ UserId: jSession.UserId,
|
|
|
+ Answer: bRes.Answer,
|
|
|
+ BiddingId: infoId,
|
|
|
+ IsEnt: false,
|
|
|
+ BaseUserId: jSession.NewUid,
|
|
|
+ })
|
|
|
+ if err != nil {
|
|
|
+ return "", Answer_Isbusiness, nil
|
|
|
+ }
|
|
|
+ if businessRes.ErrMsg != "" {
|
|
|
+ return "", Answer_Isbusiness, fmt.Errorf(businessRes.ErrMsg)
|
|
|
+ }
|
|
|
+ return businessRes.ReplyMsg, Answer_Isbusiness, nil
|
|
|
}
|