From a416353c291f684fe91343e834f174734ac0123e Mon Sep 17 00:00:00 2001 From: yvan <8574526@qq.com> Date: Tue, 9 Sep 2025 16:05:39 +0800 Subject: [PATCH] 1 --- server/api/v1/pet/enter.go | 6 +- server/api/v1/pet/user/enter.go | 1 + server/api/v1/pet/user/pet_assistant_api.go | 298 ++++++++++++++++++++ server/initialize/router.go | 2 +- server/initialize/router_biz.go | 6 + server/model/pet/request/chat_request.go | 60 ++++ server/model/pet/response/chat_response.go | 128 +++++++++ server/router/pet/enter.go | 2 + server/router/pet/pet_assistant_router.go | 25 ++ server/service/pet/pet_chat_service.go | 31 +- 10 files changed, 532 insertions(+), 27 deletions(-) create mode 100644 server/api/v1/pet/user/pet_assistant_api.go create mode 100644 server/model/pet/request/chat_request.go create mode 100644 server/model/pet/response/chat_response.go create mode 100644 server/router/pet/pet_assistant_router.go diff --git a/server/api/v1/pet/enter.go b/server/api/v1/pet/enter.go index 583b4f7d..afcfc71b 100644 --- a/server/api/v1/pet/enter.go +++ b/server/api/v1/pet/enter.go @@ -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 ( diff --git a/server/api/v1/pet/user/enter.go b/server/api/v1/pet/user/enter.go index b801d9c4..ff72ab6e 100644 --- a/server/api/v1/pet/user/enter.go +++ b/server/api/v1/pet/user/enter.go @@ -3,6 +3,7 @@ package user import "github.com/flipped-aurora/gin-vue-admin/server/service" type ApiGroup struct { + PetAssistantApi } var ( diff --git a/server/api/v1/pet/user/pet_assistant_api.go b/server/api/v1/pet/user/pet_assistant_api.go new file mode 100644 index 00000000..e11bd951 --- /dev/null +++ b/server/api/v1/pet/user/pet_assistant_api.go @@ -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) +} diff --git a/server/initialize/router.go b/server/initialize/router.go index 4f447e5a..3d299d5f 100644 --- a/server/initialize/router.go +++ b/server/initialize/router.go @@ -116,7 +116,7 @@ func Routers() *gin.Engine { InstallPlugin(PrivateGroup, PublicGroup, Router) // 注册业务路由 - initBizRouter(PrivateGroup, PublicGroup) + initBizRouter(PrivateGroup, PublicGroup, UserGroup) global.GVA_ROUTERS = Router.Routes() diff --git a/server/initialize/router_biz.go b/server/initialize/router_biz.go index e78840a3..b10d4201 100644 --- a/server/initialize/router_biz.go +++ b/server/initialize/router_biz.go @@ -12,6 +12,7 @@ func holder(routers ...*gin.RouterGroup) { func initBizRouter(routers ...*gin.RouterGroup) { privateGroup := routers[0] publicGroup := routers[1] + userGroup := routers[2] holder(publicGroup, privateGroup) { petRouter := router.RouterGroupApp.Pet @@ -25,5 +26,10 @@ func initBizRouter(routers ...*gin.RouterGroup) { petRouter.InitPetFamilyPetsRouter(privateGroup, publicGroup) petRouter.InitPetPetsRouter(privateGroup, publicGroup) // 占位方法,保证文件可以正确加载,避免go空变量检测报错,请勿删除。 petRouter.InitPetRecordsRouter(privateGroup, publicGroup) + + // 用户相关路由(需要UserJWTAuth认证) + if userGroup != nil { + petRouter.InitPetAssistantRouter(userGroup, publicGroup) + } } } diff --git a/server/model/pet/request/chat_request.go b/server/model/pet/request/chat_request.go new file mode 100644 index 00000000..fae75ae2 --- /dev/null +++ b/server/model/pet/request/chat_request.go @@ -0,0 +1,60 @@ +package request + +import ( + "github.com/flipped-aurora/gin-vue-admin/server/model/common/request" +) + +// ChatRequest 宠物助手聊天请求结构体 +type ChatRequest struct { + Message string `json:"message" binding:"required" validate:"required,min=1,max=2000"` // 用户消息内容,必填,1-2000字符 + SessionId string `json:"sessionId" validate:"omitempty,uuid4"` // 会话ID,可选,UUID格式 + Stream bool `json:"stream"` // 是否流式响应,默认false + Temperature float64 `json:"temperature" validate:"omitempty,min=0,max=2"` // 温度参数,控制随机性,范围0-2 + MaxTokens int `json:"maxTokens" validate:"omitempty,min=1,max=4000"` // 最大生成token数,范围1-4000 + Model string `json:"model" validate:"omitempty,min=1,max=100"` // 模型名称,可选 + TopP float64 `json:"topP" validate:"omitempty,min=0,max=1"` // 核采样参数,范围0-1 +} + +// ChatHistoryRequest 获取聊天历史请求结构体 +type ChatHistoryRequest struct { + SessionId string `json:"sessionId" form:"sessionId" validate:"omitempty,uuid4"` // 会话ID,可选,UUID格式 + request.PageInfo // 分页信息 +} + +// ClearHistoryRequest 清空聊天历史请求结构体 +type ClearHistoryRequest struct { + SessionId string `json:"sessionId" form:"sessionId" validate:"omitempty,uuid4"` // 会话ID,可选,不传则清空所有会话 +} + +// SessionsRequest 获取会话列表请求结构体 +type SessionsRequest struct { + request.PageInfo // 分页信息 +} + +// StopGenerationRequest 停止生成请求结构体 +type StopGenerationRequest struct { + RequestId string `json:"requestId" binding:"required" validate:"required,uuid4"` // 请求ID,必填,UUID格式 +} + +// RegenerateRequest 重新生成回复请求结构体 +type RegenerateRequest struct { + SessionId string `json:"sessionId" binding:"required" validate:"required,uuid4"` // 会话ID,必填 + MessageId uint `json:"messageId" binding:"required" validate:"required,min=1"` // 要重新生成的消息ID + Temperature float64 `json:"temperature" validate:"omitempty,min=0,max=2"` // 温度参数 + MaxTokens int `json:"maxTokens" validate:"omitempty,min=1,max=4000"` // 最大token数 +} + +// FeedbackRequest 用户反馈请求结构体 +type FeedbackRequest struct { + MessageId uint `json:"messageId" binding:"required" validate:"required,min=1"` // 消息ID,必填 + FeedbackType string `json:"feedbackType" binding:"required" validate:"required,oneof=like dislike"` // 反馈类型:like/dislike + Comment string `json:"comment" validate:"omitempty,max=500"` // 反馈评论,可选,最多500字符 +} + +// ExportHistoryRequest 导出聊天历史请求结构体 +type ExportHistoryRequest struct { + SessionId string `json:"sessionId" form:"sessionId" validate:"omitempty,uuid4"` // 会话ID,可选 + Format string `json:"format" form:"format" validate:"omitempty,oneof=json txt markdown"` // 导出格式:json/txt/markdown + StartTime string `json:"startTime" form:"startTime" validate:"omitempty,datetime=2006-01-02"` // 开始时间,可选 + EndTime string `json:"endTime" form:"endTime" validate:"omitempty,datetime=2006-01-02"` // 结束时间,可选 +} diff --git a/server/model/pet/response/chat_response.go b/server/model/pet/response/chat_response.go new file mode 100644 index 00000000..c4e0dd9b --- /dev/null +++ b/server/model/pet/response/chat_response.go @@ -0,0 +1,128 @@ +package response + +import ( + "time" + + "github.com/flipped-aurora/gin-vue-admin/server/model/pet" +) + +// ChatResponse 宠物助手聊天响应结构体 +type ChatResponse struct { + ID uint `json:"id"` // 消息ID + Message string `json:"message"` // AI回复消息内容 + SessionId string `json:"sessionId"` // 会话ID + IsSensitive bool `json:"isSensitive"` // 是否包含敏感词 + TokenCount int `json:"tokenCount"` // Token消耗数量 + ResponseTime int64 `json:"responseTime"` // 响应时间(毫秒) + RequestId string `json:"requestId,omitempty"` // 请求ID,用于流式响应管理 + Model string `json:"model,omitempty"` // 使用的模型名称 + CreatedAt time.Time `json:"createdAt"` // 创建时间 + FinishReason string `json:"finishReason,omitempty"` // 完成原因:stop/length/content_filter +} + +// StreamEvent 流式事件结构体 +type StreamEvent struct { + Event string `json:"event"` // 事件类型: message, error, done, start + Data interface{} `json:"data"` // 事件数据 +} + +// StreamMessageData 流式消息数据结构体 +type StreamMessageData struct { + Delta string `json:"delta"` // 增量消息内容 + SessionId string `json:"sessionId"` // 会话ID + RequestId string `json:"requestId"` // 请求ID +} + +// StreamErrorData 流式错误数据结构体 +type StreamErrorData struct { + Error string `json:"error"` // 错误信息 + Code string `json:"code"` // 错误代码 + RequestId string `json:"requestId"` // 请求ID +} + +// StreamDoneData 流式完成数据结构体 +type StreamDoneData struct { + Message string `json:"message"` // 完整消息内容 + SessionId string `json:"sessionId"` // 会话ID + RequestId string `json:"requestId"` // 请求ID + TokenCount int `json:"tokenCount"` // Token消耗数量 + ResponseTime int64 `json:"responseTime"` // 响应时间(毫秒) + IsSensitive bool `json:"isSensitive"` // 是否包含敏感词 + FinishReason string `json:"finishReason"` // 完成原因 +} + +// ChatHistoryResponse 聊天历史响应结构体 +type ChatHistoryResponse struct { + List []pet.PetAiAssistantConversations `json:"list"` // 对话记录列表 + Total int64 `json:"total"` // 总记录数 + Page int `json:"page"` // 当前页码 + PageSize int `json:"pageSize"` // 每页大小 +} + +// SessionInfo 会话信息结构体 +type SessionInfo struct { + SessionId string `json:"sessionId"` // 会话ID + LastUpdated time.Time `json:"lastUpdated"` // 最后更新时间 + MessageCount int `json:"messageCount"` // 消息数量 + FirstMessage string `json:"firstMessage"` // 第一条消息内容(用作会话标题) + CreatedAt time.Time `json:"createdAt"` // 创建时间 +} + +// SessionsResponse 会话列表响应结构体 +type SessionsResponse struct { + List []SessionInfo `json:"list"` // 会话列表 + Total int64 `json:"total"` // 总会话数 + Page int `json:"page"` // 当前页码 + PageSize int `json:"pageSize"` // 每页大小 +} + +// TokenUsage Token使用情况结构体 +type TokenUsage struct { + PromptTokens int `json:"promptTokens"` // 输入token数 + CompletionTokens int `json:"completionTokens"` // 输出token数 + TotalTokens int `json:"totalTokens"` // 总token数 +} + +// ModelInfo 模型信息结构体 +type ModelInfo struct { + Name string `json:"name"` // 模型名称 + Description string `json:"description"` // 模型描述 + MaxTokens int `json:"maxTokens"` // 最大token数 + Available bool `json:"available"` // 是否可用 +} + +// ModelsResponse 可用模型列表响应结构体 +type ModelsResponse struct { + Models []ModelInfo `json:"models"` // 模型列表 +} + +// StatsResponse 统计信息响应结构体 +type StatsResponse struct { + TotalSessions int64 `json:"totalSessions"` // 总会话数 + TotalMessages int64 `json:"totalMessages"` // 总消息数 + TotalTokens int64 `json:"totalTokens"` // 总token消耗 + LastChatTime *time.Time `json:"lastChatTime"` // 最后聊天时间 + AverageResponse float64 `json:"averageResponse"` // 平均响应时间(毫秒) + SensitiveCount int64 `json:"sensitiveCount"` // 敏感词触发次数 + PopularQuestions []string `json:"popularQuestions"` // 热门问题 +} + +// ExportResponse 导出响应结构体 +type ExportResponse struct { + FileName string `json:"fileName"` // 文件名 + FileSize int64 `json:"fileSize"` // 文件大小(字节) + DownloadUrl string `json:"downloadUrl"` // 下载链接 + ExpiresAt int64 `json:"expiresAt"` // 过期时间戳 +} + +// HealthResponse 健康检查响应结构体 +type HealthResponse struct { + Status string `json:"status"` // 服务状态:healthy/unhealthy + LLMService string `json:"llmService"` // LLM服务状态 + SensitiveFilter string `json:"sensitiveFilter"` // 敏感词过滤状态 + Database string `json:"database"` // 数据库状态 + LastChecked time.Time `json:"lastChecked"` // 最后检查时间 + ResponseTime int64 `json:"responseTime"` // 响应时间(毫秒) + ActiveSessions int `json:"activeSessions"` // 活跃会话数 + QueuedRequests int `json:"queuedRequests"` // 排队请求数 +} diff --git a/server/router/pet/enter.go b/server/router/pet/enter.go index c53c7d4a..7259e881 100644 --- a/server/router/pet/enter.go +++ b/server/router/pet/enter.go @@ -13,6 +13,7 @@ type RouterGroup struct { PetFamilyPetsRouter PetPetsRouter PetRecordsRouter + PetAssistantRouter } var ( @@ -26,4 +27,5 @@ var ( petFamilyPetsApi = api.ApiGroupApp.PetApiGroup.PetFamilyPetsApi petPetsApi = api.ApiGroupApp.PetApiGroup.PetPetsApi petRecordsApi = api.ApiGroupApp.PetApiGroup.PetRecordsApi + petUserApiGroup = api.ApiGroupApp.PetApiGroup.PetUserApiGroup ) diff --git a/server/router/pet/pet_assistant_router.go b/server/router/pet/pet_assistant_router.go new file mode 100644 index 00000000..4e084a4d --- /dev/null +++ b/server/router/pet/pet_assistant_router.go @@ -0,0 +1,25 @@ +package pet + +import ( + "github.com/gin-gonic/gin" +) + +type PetAssistantRouter struct{} + +// InitPetAssistantRouter 初始化宠物助手路由信息 +func (p *PetAssistantRouter) InitPetAssistantRouter(UserRouter *gin.RouterGroup, PublicRouter *gin.RouterGroup) { + // 宠物助手路由组,UserRouter已经应用了UserJWTAuth中间件 + petAssistantRouter := UserRouter.Group("pet/user/assistant") + + // 获取宠物助手API实例 + petAssistantApi := petUserApiGroup.PetAssistantApi + + { + // 宠物助手问答相关路由 + petAssistantRouter.POST("ask", petAssistantApi.AskPetAssistant) // 向宠物助手提问 + petAssistantRouter.POST("stream-ask", petAssistantApi.StreamAskPetAssistant) // 向宠物助手流式提问 + petAssistantRouter.GET("history", petAssistantApi.GetAssistantHistory) // 获取宠物助手对话历史 + petAssistantRouter.DELETE("clear-history", petAssistantApi.ClearAssistantHistory) // 清空宠物助手对话历史 + petAssistantRouter.GET("sessions", petAssistantApi.GetAssistantSessions) // 获取宠物助手会话列表 + } +} diff --git a/server/service/pet/pet_chat_service.go b/server/service/pet/pet_chat_service.go index b853c31b..49d613ec 100644 --- a/server/service/pet/pet_chat_service.go +++ b/server/service/pet/pet_chat_service.go @@ -7,36 +7,17 @@ import ( "github.com/flipped-aurora/gin-vue-admin/server/global" "github.com/flipped-aurora/gin-vue-admin/server/model/pet" + 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/utils" "github.com/google/uuid" "go.uber.org/zap" ) -// ChatRequest 聊天请求结构体 -type ChatRequest struct { - Message string `json:"message" binding:"required"` // 用户消息 - SessionId string `json:"sessionId"` // 会话ID,可选 - Stream bool `json:"stream"` // 是否流式响应 - Temperature float64 `json:"temperature"` // 温度参数 - MaxTokens int `json:"maxTokens"` // 最大token数 - Model string `json:"model"` // 模型名称 -} - -// ChatResponse 聊天响应结构体 -type ChatResponse struct { - Message string `json:"message"` // AI回复消息 - SessionId string `json:"sessionId"` // 会话ID - IsSensitive bool `json:"isSensitive"` // 是否包含敏感词 - TokenCount int `json:"tokenCount"` // Token消耗数量 - ResponseTime int64 `json:"responseTime"` // 响应时间(ms) - RequestId string `json:"requestId,omitempty"` // 请求ID -} - -// StreamEvent 流式事件结构体 -type StreamEvent struct { - Event string `json:"event"` // 事件类型: message, error, done - Data interface{} `json:"data"` // 事件数据 -} +// 使用新定义的模型结构 +type ChatRequest = petRequest.ChatRequest +type ChatResponse = petResponse.ChatResponse +type StreamEvent = petResponse.StreamEvent // PetChatService 宠物聊天服务 type PetChatService struct{}