299 lines
8.5 KiB
Go
299 lines
8.5 KiB
Go
package user
|
||
|
||
import (
|
||
"io"
|
||
"strconv"
|
||
"time"
|
||
|
||
"github.com/flipped-aurora/gin-vue-admin/server/global"
|
||
"github.com/flipped-aurora/gin-vue-admin/server/model/common/response"
|
||
petRequest "github.com/flipped-aurora/gin-vue-admin/server/model/pet/request"
|
||
petResponse "github.com/flipped-aurora/gin-vue-admin/server/model/pet/response"
|
||
"github.com/flipped-aurora/gin-vue-admin/server/service"
|
||
"github.com/flipped-aurora/gin-vue-admin/server/utils"
|
||
"github.com/gin-gonic/gin"
|
||
"go.uber.org/zap"
|
||
)
|
||
|
||
type PetAssistantApi struct{}
|
||
|
||
var petChatService = service.ServiceGroupApp.PetServiceGroup.PetChatService
|
||
|
||
// AskPetAssistant 向宠物助手提问(非流式)
|
||
// @Tags PetAssistant
|
||
// @Summary 向宠物助手提问
|
||
// @Security ApiKeyAuth
|
||
// @Accept application/json
|
||
// @Produce application/json
|
||
// @Param data body petRequest.ChatRequest true "宠物助手提问请求"
|
||
// @Success 200 {object} response.Response{data=petResponse.ChatResponse,msg=string} "提问成功"
|
||
// @Router /api/v1/pet/user/assistant/ask [post]
|
||
func (p *PetAssistantApi) AskPetAssistant(ctx *gin.Context) {
|
||
// 创建业务用Context
|
||
businessCtx := ctx.Request.Context()
|
||
|
||
// 获取用户ID
|
||
userId := utils.GetAppUserID(ctx)
|
||
if userId == 0 {
|
||
global.GVA_LOG.Error("获取用户ID失败")
|
||
response.FailWithMessage("用户认证失败", ctx)
|
||
return
|
||
}
|
||
|
||
// 绑定请求参数
|
||
var req petRequest.ChatRequest
|
||
if err := ctx.ShouldBindJSON(&req); err != nil {
|
||
global.GVA_LOG.Error("参数绑定失败", zap.Error(err))
|
||
response.FailWithMessage("参数错误: "+err.Error(), ctx)
|
||
return
|
||
}
|
||
|
||
// 参数验证
|
||
if req.Message == "" {
|
||
response.FailWithMessage("消息内容不能为空", ctx)
|
||
return
|
||
}
|
||
|
||
// 设置默认参数
|
||
if req.Temperature <= 0 {
|
||
req.Temperature = 0.7
|
||
}
|
||
if req.MaxTokens <= 0 {
|
||
req.MaxTokens = 1000
|
||
}
|
||
|
||
// 调用服务层
|
||
resp, err := petChatService.SendMessage(businessCtx, userId, req)
|
||
if err != nil {
|
||
global.GVA_LOG.Error("发送消息失败", zap.Error(err), zap.Uint("userId", userId))
|
||
response.FailWithMessage("发送消息失败: "+err.Error(), ctx)
|
||
return
|
||
}
|
||
|
||
response.OkWithDetailed(resp, "发送成功", ctx)
|
||
}
|
||
|
||
// StreamAskPetAssistant 向宠物助手流式提问
|
||
// @Tags PetAssistant
|
||
// @Summary 向宠物助手流式提问接口
|
||
// @Security ApiKeyAuth
|
||
// @Accept application/json
|
||
// @Produce text/event-stream
|
||
// @Param data body petRequest.ChatRequest true "宠物助手流式提问请求"
|
||
// @Success 200 {string} string "流式响应"
|
||
// @Router /api/v1/pet/user/assistant/stream-ask [post]
|
||
func (p *PetAssistantApi) StreamAskPetAssistant(ctx *gin.Context) {
|
||
// 创建业务用Context
|
||
businessCtx := ctx.Request.Context()
|
||
|
||
// 获取用户ID
|
||
userId := utils.GetAppUserID(ctx)
|
||
if userId == 0 {
|
||
global.GVA_LOG.Error("获取用户ID失败")
|
||
response.FailWithMessage("用户认证失败", ctx)
|
||
return
|
||
}
|
||
|
||
// 绑定请求参数
|
||
var req petRequest.ChatRequest
|
||
if err := ctx.ShouldBindJSON(&req); err != nil {
|
||
global.GVA_LOG.Error("参数绑定失败", zap.Error(err))
|
||
response.FailWithMessage("参数错误: "+err.Error(), ctx)
|
||
return
|
||
}
|
||
|
||
// 参数验证
|
||
if req.Message == "" {
|
||
response.FailWithMessage("消息内容不能为空", ctx)
|
||
return
|
||
}
|
||
|
||
// 强制设置为流式响应
|
||
req.Stream = true
|
||
|
||
// 设置默认参数
|
||
if req.Temperature <= 0 {
|
||
req.Temperature = 0.7
|
||
}
|
||
if req.MaxTokens <= 0 {
|
||
req.MaxTokens = 1000
|
||
}
|
||
|
||
// 设置SSE响应头
|
||
ctx.Header("Content-Type", "text/event-stream")
|
||
ctx.Header("Cache-Control", "no-cache")
|
||
ctx.Header("Connection", "keep-alive")
|
||
ctx.Header("Access-Control-Allow-Origin", "*")
|
||
ctx.Header("Access-Control-Allow-Headers", "Cache-Control")
|
||
|
||
// 创建事件通道
|
||
eventChan := make(chan petResponse.StreamEvent, 100)
|
||
defer close(eventChan)
|
||
|
||
// 启动流式聊天
|
||
go func() {
|
||
if err := petChatService.StreamChat(businessCtx, userId, req, eventChan); err != nil {
|
||
global.GVA_LOG.Error("流式聊天失败", zap.Error(err), zap.Uint("userId", userId))
|
||
eventChan <- petResponse.StreamEvent{
|
||
Event: "error",
|
||
Data: map[string]interface{}{
|
||
"error": "流式聊天失败: " + err.Error(),
|
||
},
|
||
}
|
||
}
|
||
}()
|
||
|
||
// 发送流式数据
|
||
ctx.Stream(func(w io.Writer) bool {
|
||
select {
|
||
case event, ok := <-eventChan:
|
||
if !ok {
|
||
return false
|
||
}
|
||
|
||
switch event.Event {
|
||
case "message":
|
||
// 发送消息事件
|
||
ctx.SSEvent("message", event.Data)
|
||
case "error":
|
||
// 发送错误事件
|
||
ctx.SSEvent("error", event.Data)
|
||
return false
|
||
case "done":
|
||
// 发送完成事件
|
||
ctx.SSEvent("done", event.Data)
|
||
return false
|
||
}
|
||
return true
|
||
case <-time.After(30 * time.Second):
|
||
// 超时处理
|
||
ctx.SSEvent("error", map[string]interface{}{
|
||
"error": "流式响应超时",
|
||
})
|
||
return false
|
||
}
|
||
})
|
||
}
|
||
|
||
// GetAssistantHistory 获取宠物助手对话历史
|
||
// @Tags PetAssistant
|
||
// @Summary 获取宠物助手对话历史记录
|
||
// @Security ApiKeyAuth
|
||
// @Accept application/json
|
||
// @Produce application/json
|
||
// @Param sessionId query string false "会话ID"
|
||
// @Param page query int false "页码" default(1)
|
||
// @Param pageSize query int false "每页数量" default(20)
|
||
// @Success 200 {object} response.Response{data=[]pet.PetAiAssistantConversations,msg=string} "获取成功"
|
||
// @Router /api/v1/pet/user/assistant/history [get]
|
||
func (p *PetAssistantApi) GetAssistantHistory(ctx *gin.Context) {
|
||
// 创建业务用Context
|
||
businessCtx := ctx.Request.Context()
|
||
|
||
// 获取用户ID
|
||
userId := utils.GetAppUserID(ctx)
|
||
if userId == 0 {
|
||
global.GVA_LOG.Error("获取用户ID失败")
|
||
response.FailWithMessage("用户认证失败", ctx)
|
||
return
|
||
}
|
||
|
||
// 获取查询参数
|
||
sessionId := ctx.Query("sessionId")
|
||
pageStr := ctx.DefaultQuery("page", "1")
|
||
pageSizeStr := ctx.DefaultQuery("pageSize", "20")
|
||
|
||
page, err := strconv.Atoi(pageStr)
|
||
if err != nil || page < 1 {
|
||
page = 1
|
||
}
|
||
|
||
pageSize, err := strconv.Atoi(pageSizeStr)
|
||
if err != nil || pageSize < 1 || pageSize > 100 {
|
||
pageSize = 20
|
||
}
|
||
|
||
// 计算limit
|
||
limit := pageSize
|
||
|
||
// 调用服务层
|
||
conversations, err := petChatService.GetChatHistory(businessCtx, userId, sessionId, limit)
|
||
if err != nil {
|
||
global.GVA_LOG.Error("获取聊天历史失败", zap.Error(err), zap.Uint("userId", userId))
|
||
response.FailWithMessage("获取聊天历史失败: "+err.Error(), ctx)
|
||
return
|
||
}
|
||
|
||
response.OkWithDetailed(conversations, "获取成功", ctx)
|
||
}
|
||
|
||
// ClearAssistantHistory 清空宠物助手对话历史
|
||
// @Tags PetAssistant
|
||
// @Summary 清空宠物助手对话历史记录
|
||
// @Security ApiKeyAuth
|
||
// @Accept application/json
|
||
// @Produce application/json
|
||
// @Param sessionId query string false "会话ID,不传则清空所有会话"
|
||
// @Success 200 {object} response.Response{msg=string} "清空成功"
|
||
// @Router /api/v1/pet/user/assistant/clear-history [delete]
|
||
func (p *PetAssistantApi) ClearAssistantHistory(ctx *gin.Context) {
|
||
// 创建业务用Context
|
||
businessCtx := ctx.Request.Context()
|
||
|
||
// 获取用户ID
|
||
userId := utils.GetAppUserID(ctx)
|
||
if userId == 0 {
|
||
global.GVA_LOG.Error("获取用户ID失败")
|
||
response.FailWithMessage("用户认证失败", ctx)
|
||
return
|
||
}
|
||
|
||
// 获取会话ID(可选)
|
||
sessionId := ctx.Query("sessionId")
|
||
|
||
// 调用服务层
|
||
err := petChatService.ClearChatHistory(businessCtx, userId, sessionId)
|
||
if err != nil {
|
||
global.GVA_LOG.Error("清空聊天历史失败", zap.Error(err), zap.Uint("userId", userId))
|
||
response.FailWithMessage("清空聊天历史失败: "+err.Error(), ctx)
|
||
return
|
||
}
|
||
|
||
if sessionId != "" {
|
||
response.OkWithMessage("指定会话历史清空成功", ctx)
|
||
} else {
|
||
response.OkWithMessage("所有聊天历史清空成功", ctx)
|
||
}
|
||
}
|
||
|
||
// GetAssistantSessions 获取宠物助手会话列表
|
||
// @Tags PetAssistant
|
||
// @Summary 获取用户的宠物助手会话列表
|
||
// @Security ApiKeyAuth
|
||
// @Accept application/json
|
||
// @Produce application/json
|
||
// @Success 200 {object} response.Response{data=[]map[string]interface{},msg=string} "获取成功"
|
||
// @Router /api/v1/pet/user/assistant/sessions [get]
|
||
func (p *PetAssistantApi) GetAssistantSessions(ctx *gin.Context) {
|
||
// 创建业务用Context
|
||
businessCtx := ctx.Request.Context()
|
||
|
||
// 获取用户ID
|
||
userId := utils.GetAppUserID(ctx)
|
||
if userId == 0 {
|
||
global.GVA_LOG.Error("获取用户ID失败")
|
||
response.FailWithMessage("用户认证失败", ctx)
|
||
return
|
||
}
|
||
|
||
// 调用服务层
|
||
sessions, err := petChatService.GetChatSessions(businessCtx, userId)
|
||
if err != nil {
|
||
global.GVA_LOG.Error("获取会话列表失败", zap.Error(err), zap.Uint("userId", userId))
|
||
response.FailWithMessage("获取会话列表失败: "+err.Error(), ctx)
|
||
return
|
||
}
|
||
|
||
response.OkWithDetailed(sessions, "获取成功", ctx)
|
||
}
|