Browse Source

增加新聊天接口,支持虚拟人ID

boweniac 2 months ago
parent
commit
440fd4bd77

+ 13 - 0
desc/wechat/xiaoice.api

@@ -14,6 +14,15 @@ type (
 
         Text *string `json:"text"`
     }
+
+    ChatReq {
+        // 大模型生成内容
+        AvatarId *string `json:"avatar_id"`
+
+        UserId *uint64 `json:"user_id"`
+
+        Text *string `json:"text"`
+    }
 )
 
 @server(
@@ -28,4 +37,8 @@ service Wechat {
     // gen gptbots | 调用gptbots
     @handler gptbotsMessage
     post /api/xiaoice/message (MessageReq) returns (BaseDataInfo)
+
+    // gen gptbots | message 接口的升级版,支持 avatar_id 参数
+    @handler gptbotsChat
+    post /api/xiaoice/chat (ChatReq) returns (BaseDataInfo)
 }

+ 5 - 0
internal/handler/routes.go

@@ -1485,6 +1485,11 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
 				Path:    "/api/xiaoice/message",
 				Handler: xiaoice.GptbotsMessageHandler(serverCtx),
 			},
+			{
+				Method:  http.MethodPost,
+				Path:    "/api/xiaoice/chat",
+				Handler: xiaoice.GptbotsChatHandler(serverCtx),
+			},
 		},
 	)
 }

+ 44 - 0
internal/handler/xiaoice/gptbots_chat_handler.go

@@ -0,0 +1,44 @@
+package xiaoice
+
+import (
+	"net/http"
+
+	"github.com/zeromicro/go-zero/rest/httpx"
+
+	"wechat-api/internal/logic/xiaoice"
+	"wechat-api/internal/svc"
+	"wechat-api/internal/types"
+)
+
+// swagger:route post /api/xiaoice/chat xiaoice GptbotsChat
+//
+// gen gptbots | message 接口的升级版,支持 avatar_id 参数
+//
+// gen gptbots | message 接口的升级版,支持 avatar_id 参数
+//
+// Parameters:
+//  + name: body
+//    require: true
+//    in: body
+//    type: ChatReq
+//
+// Responses:
+//  200: BaseDataInfo
+
+func GptbotsChatHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
+	return func(w http.ResponseWriter, r *http.Request) {
+		var req types.ChatReq
+		if err := httpx.Parse(r, &req, true); err != nil {
+			httpx.ErrorCtx(r.Context(), w, err)
+			return
+		}
+
+		l := xiaoice.NewGptbotsChatLogic(r.Context(), svcCtx)
+		resp, err := l.GptbotsChat(&req)
+		if err != nil {
+			httpx.ErrorCtx(r.Context(), w, err)
+		} else {
+			httpx.OkJsonCtx(r.Context(), w, resp)
+		}
+	}
+}

+ 175 - 0
internal/logic/xiaoice/gptbots_chat_logic.go

@@ -0,0 +1,175 @@
+package xiaoice
+
+import (
+	"bytes"
+	"context"
+	"encoding/json"
+	"fmt"
+	"github.com/suyuan32/simple-admin-common/msg/errormsg"
+	"github.com/zeromicro/go-zero/core/errorx"
+	"io"
+	"net/http"
+	"net/url"
+	"strconv"
+
+	"wechat-api/internal/svc"
+	"wechat-api/internal/types"
+
+	"github.com/zeromicro/go-zero/core/logx"
+)
+
+type GptbotsChatLogic struct {
+	logx.Logger
+	ctx    context.Context
+	svcCtx *svc.ServiceContext
+}
+
+func NewGptbotsChatLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GptbotsChatLogic {
+	return &GptbotsChatLogic{
+		Logger: logx.WithContext(ctx),
+		ctx:    ctx,
+		svcCtx: svcCtx}
+}
+
+func (l *GptbotsChatLogic) GptbotsChat(req *types.ChatReq) (resp *types.BaseDataInfo, err error) {
+	apikeyMap := map[string]string{
+		"VHPF0W063": "app-hQL7oVq57McK5VBHlsMfhtUD",
+		"VHPTL3UAP": "app-JbKgUsjs6fs13JDcTcE8d9f1",
+	}
+	apikey := apikeyMap[*req.AvatarId]
+	if apikey == "" {
+		return nil, fmt.Errorf("未知虚拟人id")
+	}
+
+	conversationId, err := l.GetConversation(apikey, strconv.FormatUint(*req.UserId, 10))
+	if conversationId == nil || err != nil {
+		return nil, err
+	}
+
+	baseURL, err := url.Parse("https://api.gptbots.ai/v1/conversation/message")
+	if err != nil {
+		return nil, errorx.NewDefaultError(fmt.Sprintf("生成内容失败: %+v", err))
+	}
+
+	// 构建请求体
+	requestBody := map[string]string{
+		"text":            *req.Text,
+		"conversation_id": *conversationId,
+		"response_mode":   "blocking",
+	}
+	jsonBody, err := json.Marshal(requestBody)
+	if err != nil {
+		return nil, errorx.NewDefaultError(fmt.Sprintf("生成内容失败: %+v", err))
+	}
+
+	// 创建HTTP请求
+	httpReq, err := http.NewRequest("POST", baseURL.String(), bytes.NewBuffer(jsonBody))
+	if err != nil {
+		return nil, errorx.NewDefaultError(fmt.Sprintf("生成内容失败: %+v", err))
+	}
+
+	// 添加必要的Header信息
+	httpReq.Header.Set("Authorization", fmt.Sprintf("Bearer %s", apikey))
+	httpReq.Header.Set("Content-Type", "application/json")
+
+	// 创建HTTP客户端并执行请求
+	client := &http.Client{}
+	response, err := client.Do(httpReq)
+	if err != nil {
+		return nil, errorx.NewDefaultError(fmt.Sprintf("生成内容失败: %+v", err))
+	}
+	defer func(Body io.ReadCloser) {
+		err := Body.Close()
+		if err != nil {
+			l.Error("生成内容失败: %v", err)
+		}
+	}(response.Body)
+
+	// 读取和输出响应
+	body, err := io.ReadAll(response.Body)
+	if err != nil {
+		return nil, errorx.NewDefaultError(fmt.Sprintf("生成内容失败: %+v", err))
+	}
+
+	// 检查响应状态
+	if response.StatusCode != http.StatusOK {
+		//log.Fatalf("请求失败,状态码:%d,响应: %s", response.StatusCode, string(body))
+		return nil, errorx.NewDefaultError(fmt.Sprintf("生成内容失败:%d,响应: %s", response.StatusCode, string(body)))
+	}
+
+	// 解析 JSON 响应
+	var responseMap types.GptbotsMessageResp
+	if err := json.Unmarshal(body, &responseMap); err != nil {
+		return nil, errorx.NewDefaultError(fmt.Sprintf("生成内容失败: %+v", err))
+	}
+
+	data := ""
+	if responseMap.FlowOutput != nil && len(responseMap.FlowOutput) > 0 {
+		data = TrimHtml(Markdown2Html(responseMap.FlowOutput[0].Content))
+	}
+
+	return &types.BaseDataInfo{Msg: errormsg.Success, Data: data}, nil
+}
+
+func (l *GptbotsChatLogic) GetConversation(apikey string, userId string) (conversationId *string, err error) {
+	val, _ := l.svcCtx.Rds.HGet(l.ctx, "xiaoice_conversation", userId).Result()
+	if val == "" {
+		baseURL, err := url.Parse("https://api.gptbots.ai/v1/conversation")
+		if err != nil {
+			return nil, err
+		}
+
+		// 构建请求体
+		requestBody := map[string]string{
+			"user_id": userId,
+		}
+		jsonBody, err := json.Marshal(requestBody)
+		if err != nil {
+			return nil, err
+		}
+
+		// 创建HTTP请求
+		req, err := http.NewRequest("POST", baseURL.String(), bytes.NewBuffer(jsonBody))
+		if err != nil {
+			return nil, err
+		}
+
+		// 添加必要的Header信息
+		req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", apikey))
+		req.Header.Set("Content-Type", "application/json")
+
+		// 创建HTTP客户端并执行请求
+		client := &http.Client{}
+		response, err := client.Do(req)
+		if err != nil {
+			return nil, err
+		}
+		defer func(Body io.ReadCloser) {
+			err := Body.Close()
+			if err != nil {
+				l.Error("创建会话失败败: %v", err)
+			}
+		}(response.Body)
+
+		// 读取和输出响应
+		body, err := io.ReadAll(response.Body)
+		if err != nil {
+			return nil, err
+		}
+
+		// 检查响应状态
+		if response.StatusCode != http.StatusOK {
+			//log.Fatalf("请求失败,状态码:%d,响应: %s", response.StatusCode, string(body))
+			return nil, errorx.NewDefaultError(fmt.Sprintf("创建会话失败:%d,响应: %s", response.StatusCode, string(body)))
+		}
+
+		// 解析 JSON 响应
+		var responseMap types.ConversationResp
+		if err := json.Unmarshal(body, &responseMap); err != nil {
+			return nil, err
+		}
+		l.svcCtx.Rds.HSet(l.ctx, "xiaoice_conversation", userId, *responseMap.ConversationId)
+		return responseMap.ConversationId, nil
+	}
+	return &val, nil
+}

+ 8 - 0
internal/types/types.go

@@ -2904,3 +2904,11 @@ type MessageReq struct {
 	UserId *uint64 `json:"user_id"`
 	Text   *string `json:"text"`
 }
+
+// swagger:model ChatReq
+type ChatReq struct {
+	// 大模型生成内容
+	AvatarId *string `json:"avatar_id"`
+	UserId   *uint64 `json:"user_id"`
+	Text     *string `json:"text"`
+}