Merge remote-tracking branch 'yvan/main'
# Conflicts: # server/go.mod # server/go.sum
This commit is contained in:
@@ -1,6 +1,9 @@
|
||||
package pet
|
||||
|
||||
import "github.com/flipped-aurora/gin-vue-admin/server/service"
|
||||
import (
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/api/v1/pet/user"
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/service"
|
||||
)
|
||||
|
||||
type ApiGroup struct {
|
||||
PetAdoptionApplicationsApi
|
||||
@@ -13,6 +16,7 @@ type ApiGroup struct {
|
||||
PetFamilyPetsApi
|
||||
PetPetsApi
|
||||
PetRecordsApi
|
||||
PetUserApiGroup user.ApiGroup
|
||||
}
|
||||
|
||||
var (
|
||||
|
||||
@@ -3,6 +3,7 @@ package user
|
||||
import "github.com/flipped-aurora/gin-vue-admin/server/service"
|
||||
|
||||
type ApiGroup struct {
|
||||
PetAssistantApi
|
||||
}
|
||||
|
||||
var (
|
||||
|
||||
@@ -0,0 +1,298 @@
|
||||
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)
|
||||
}
|
||||
Reference in New Issue
Block a user