wangchuanjin 5 mesi fa
parent
commit
7b30a6de82
3 ha cambiato i file con 154 aggiunte e 31 eliminazioni
  1. 8 6
      api/aiSearch/v1/aiSearchApi.go
  2. 1 3
      go.mod
  3. 145 22
      internal/controller/aiSearch/aiSearch_v1_chat.go

+ 8 - 6
api/aiSearch/v1/aiSearchApi.go

@@ -56,15 +56,17 @@ type ProblemConfigurationRes struct {
 }
 
 type ChatReq struct {
-	g.Meta  `path:"/chat" tags:"AiSearch" method:"post" summary:"聊天"`
-	SId     int    `json:"sId" v:"required" dc:"当前会话id"`
-	Content string `json:"content" v:"required" dc:"用户发送内容"`
+	g.Meta   `path:"/chat" tags:"AiSearch" method:"post" summary:"聊天"`
+	SId      string `json:"sId" v:"required" dc:"当前会话id"`
+	Question string `json:"question" v:"required" dc:"用户发送内容"`
+	Item     int    `json:"item" v:"required" dc:"分类"`
 }
 
 type ChatRes struct {
-	ErrorCode int         `dc:"状态码"`
-	ErrorMsg  string      `dc:"错误信息"`
-	Data      interface{} `dc:"返回数据"`
+	ErrorCode int                      `dc:"状态码"`
+	Answer    string                   `dc:"答案"`
+	Count     int                      `dc:"列表长度"`
+	List      []map[string]interface{} `dc:"列表"`
 }
 
 type BiddingListReq struct {

+ 1 - 3
go.mod

@@ -1,8 +1,6 @@
 module aiChat
 
-go 1.21
-
-toolchain go1.23.6
+go 1.20
 
 require (
 	app.yhyue.com/moapp/jybase v0.0.0-20250220061341-81c668b6c7ea

+ 145 - 22
internal/controller/aiSearch/aiSearch_v1_chat.go

@@ -2,39 +2,140 @@ package aiSearch
 
 import (
 	"aiChat/api/aiSearch/v1"
+	"aiChat/internal/model"
+	"aiChat/internal/model/bidSearch"
 	"context"
-	"errors"
 	"fmt"
 	"io/ioutil"
-	"log"
 	"strings"
 	"time"
 
+	"github.com/gogf/gf/v2/util/gconv"
+
+	. "app.yhyue.com/moapp/jybase/encrypt"
+	"github.com/gogf/gf/v2/database/gdb"
 	"github.com/gogf/gf/v2/encoding/gjson"
 	"github.com/gogf/gf/v2/frame/g"
 	"github.com/gogf/gf/v2/os/gtime"
 )
 
 func (c *ControllerV1) Chat(ctx context.Context, req *v1.ChatReq) (res *v1.ChatRes, err error) {
-	content := fmt.Sprintf(g.Cfg("ai_search.yaml").MustGet(ctx, "doubaoPrompt").String(), gtime.Now().Format("Ymd"), req.Content)
-	query, largeModelReply, err := c.doubao(ctx, content)
-	if err != nil {
-		content = fmt.Sprintf(g.Cfg("ai_search.yaml").MustGet(ctx, "zhipuPrompt").String(), gtime.Now().Format("Ymd"), req.Content)
-		query, largeModelReply, err = c.zhipu(ctx, content)
+	res = &v1.ChatRes{ErrorCode: 0}
+	sid := gconv.Int64(SE.Decode4HexByCheck(req.SId))
+	if sid == 0 {
+		g.Log().Error(ctx, "无效的sid参数", req.SId)
+		return
+	}
+	startTime := gtime.Now().Format("Y-m-d h:m:s.u")
+	success := 0
+	prompt := fmt.Sprintf(g.Cfg("ai_search.yaml").MustGet(ctx, "doubaoPrompt").String(), gtime.Now().Format("Ymd"), req.Question)
+	large_model := "doubao"
+	callLogs := g.List{}
+	content, largeModelReply, err, isLimit := c.doubao(ctx, prompt)
+	if !isLimit {
+		large_model_success := 1
+		error_msg := ""
+		if err != nil {
+			error_msg = err.Error()
+			large_model_success = 0
+		}
+		callLogs = append(callLogs, g.Map{
+			"large_model":           large_model,
+			"large_model_reply":     largeModelReply,
+			"large_model_starttime": startTime,
+			"large_model_endtime":   gtime.Now().Format("Y-m-d h:m:s.u"),
+			"large_model_success":   large_model_success,
+			"error_msg":             error_msg,
+		})
+	}
+	if isLimit || err != nil {
+		prompt = fmt.Sprintf(g.Cfg("ai_search.yaml").MustGet(ctx, "zhipuPrompt").String(), gtime.Now().Format("Ymd"), req.Question)
+		content, largeModelReply, err, _ = c.zhipu(ctx, prompt)
+		large_model = "zhipu"
+		large_model_success := 1
+		error_msg := ""
+		if err != nil {
+			error_msg = err.Error()
+			large_model_success = 0
+		}
+		callLogs = append(callLogs, g.Map{
+			"large_model":           large_model,
+			"large_model_reply":     largeModelReply,
+			"large_model_starttime": startTime,
+			"large_model_endtime":   gtime.Now().Format("Y-m-d h:m:s.u"),
+			"large_model_success":   large_model_success,
+			"error_msg":             error_msg,
+		})
+	}
+	large_model_endtime := gtime.Now().Format("Y-m-d h:m:s.u")
+	if err == nil {
+		success = 1
+	} else {
+		large_model = ""
+	}
+	sess, sessErr := model.GetSession(g.RequestFromCtx(ctx))
+	if sessErr != nil {
+		return
+	}
+	bs, bsErr := bidSearch.NewBidSearch(ctx, sess.PersonId, content)
+	if bsErr != nil {
+		return
+	}
+	query, list := bs.Search()
+	answer := ""
+	if err := g.DB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
+		chatId, chatErr := tx.InsertAndGetId("ai_search_chat", g.Map{
+			"position_id":         sess.PositionId,
+			"item":                req.Item,
+			"question":            req.Question,
+			"answer":              answer,
+			"starttime":           startTime,
+			"large_model_endtime": large_model_endtime,
+			"endtime":             gtime.Now().Format("Y-m-d h:m:s.u"),
+			"success":             success,
+			"es_query":            query,
+			"list_count":          len(list),
+			"session_id":          sid,
+			"status":              1,
+			"large_model":         large_model,
+			"create_time":         gtime.Datetime(),
+		})
+		if chatErr != nil {
+			g.Log().Error(ctx, "ai_search_chat保存出错", chatErr)
+			return chatErr
+		}
+		//
+		// bids := g.List{}
+		// for _, v := range list {
+		// 	bids = append(bids, g.Map{
+		// 		"position_id": sess.PositionId,
+		// 		"chat_id":     chatId,
+		// 	})
+		// }
+		//
+		for _, v := range callLogs {
+			v["chat_id"] = chatId
+			v["create_time"] = gtime.Datetime()
+		}
+		return nil
+	}); err == nil {
+		res.ErrorCode = 1
+		res.List = list
+	} else {
+		g.Log().Error(ctx, sess.PositionId, "保存数据库出错", err)
 	}
-	log.Println(query, largeModelReply, err)
-	return nil, nil
+	return
 }
 
 //调用豆包大模型
-func (c *ControllerV1) doubao(ctx context.Context, content string) (string, string, error) {
+func (c *ControllerV1) doubao(ctx context.Context, content string) (string, string, error, bool) {
 	count, err := g.Redis("main").Incr(ctx, fmt.Sprintf("aiSearch_doubaoCall_%s", gtime.Now().Format("Ymd")))
 	if err != nil {
 		g.Log().Error(ctx, "从redis获取doubao调用次数出错", err)
-		return "", "", err
+		return "", "", err, true
 	} else if doubaoCallMax := g.Cfg("ai_search.yaml").MustGet(ctx, "doubaoCallMax").Int64(); count > doubaoCallMax {
 		g.Log().Info(ctx, "doubao调用次数达到上限", doubaoCallMax, count)
-		return "", "", errors.New("doubao调用次数达到上限")
+		return "", "", nil, true
 	}
 	// 构造请求数据
 	messages := []map[string]interface{}{}
@@ -53,14 +154,14 @@ func (c *ControllerV1) doubao(ctx context.Context, content string) (string, stri
 }
 
 //调用智普大模型
-func (c *ControllerV1) zhipu(ctx context.Context, content string) (string, string, error) {
+func (c *ControllerV1) zhipu(ctx context.Context, content string) (string, string, error, bool) {
 	count, err := g.Redis("main").Incr(ctx, fmt.Sprintf("aiSearch_zhipuCall_%s", gtime.Now().Format("YYYYmmdd")))
 	if err != nil {
 		g.Log().Error(ctx, "从redis获取zhipu调用次数出错", err)
-		return "", "", err
+		return "", "", err, true
 	} else if doubaoCallMax := g.Cfg("ai_search.yaml").MustGet(ctx, "zhipuCallMax").Int64(); count > doubaoCallMax {
 		g.Log().Info(ctx, "zhipu调用次数达到上限", doubaoCallMax, count)
-		return "", "", errors.New("zhipu调用次数达到上限")
+		return "", "", nil, true
 	}
 	// 构造请求数据
 	messages := []map[string]interface{}{}
@@ -78,39 +179,61 @@ func (c *ControllerV1) zhipu(ctx context.Context, content string) (string, strin
 	return c.post(ctx, "zhipu", "https://open.bigmodel.cn/api/paas/v4/chat/completions", "3d84d30b7ab4c94dbf71853cb7e44719.hLLS4CA2MqVQs6kR", requestData)
 }
 
-func (c *ControllerV1) post(ctx context.Context, t, apiURL, pass string, requestData map[string]interface{}) (string, string, error) {
+func (c *ControllerV1) post(ctx context.Context, t, apiURL, pass string, requestData map[string]interface{}) (string, string, error, bool) {
+	ddd := `{
+"关键词": {
+"选择": ["软件"],
+"排除": []
+},
+"发布时间范围": "20210126-20250226",
+"搜索范围": ["标题", "正文"],
+"匹配模式": "精准匹配",
+"信息类型": "招标公告",
+"地区": {
+"选择": ["广东", "广西", "海南","北京"],
+"排除": []
+},
+"金额": "0-2000万",
+"采购单位联系方式": "不限",
+"中标单位联系方式": "不限",
+"附件": "不限",
+"采购单位": "不限",
+"中标单位": "不限",
+"招标代理": "不限"
+}`
+	return ddd, "", nil, false
 	resp, err := g.Client().Timeout(time.Duration(g.Cfg("ai_search.yaml").MustGet(ctx, "timeout").Int())*time.Second).
 		SetHeader("Authorization", fmt.Sprintf("Bearer %s", pass)).
 		ContentType("application/json").
 		Post(ctx, apiURL, requestData)
 	if err != nil {
 		g.Log().Error(ctx, t, "请求出错", err)
-		return "", "", err
+		return "", "", err, false
 	}
 	defer resp.Body.Close()
 	b, be := ioutil.ReadAll(resp.Body)
 	if be != nil {
 		g.Log().Error(ctx, t, "gjson.LoadJson出错", be)
-		return "", "", err
+		return "", "", err, false
 	}
 	largeModelReply := string(b)
 	g.Log().Info(ctx, t, "请求回复", largeModelReply)
 	r, re := gjson.LoadJson(b)
 	if re != nil {
 		g.Log().Error(ctx, t, largeModelReply, "gjson.LoadJson出错", re)
-		return "", largeModelReply, err
+		return "", largeModelReply, err, false
 	}
 	content := ""
 	choices := r.GetJsons("choices")
 	if len(choices) == 0 {
-		return "", largeModelReply, err
+		return "", largeModelReply, err, false
 	}
 	message := choices[0].GetJson("message")
 	if message == nil {
-		return "", largeModelReply, err
+		return "", largeModelReply, err, false
 	}
 	content = message.Get("content").String()
 	content = strings.ReplaceAll(content, "```json", "")
 	content = strings.ReplaceAll(content, "```", "")
-	return content, largeModelReply, nil
+	return content, largeModelReply, nil, false
 }