This commit is contained in:
parent
c88252272c
commit
a416353c29
|
|
@ -1,6 +1,9 @@
|
||||||
package pet
|
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 {
|
type ApiGroup struct {
|
||||||
PetAdoptionApplicationsApi
|
PetAdoptionApplicationsApi
|
||||||
|
|
@ -13,6 +16,7 @@ type ApiGroup struct {
|
||||||
PetFamilyPetsApi
|
PetFamilyPetsApi
|
||||||
PetPetsApi
|
PetPetsApi
|
||||||
PetRecordsApi
|
PetRecordsApi
|
||||||
|
PetUserApiGroup user.ApiGroup
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ package user
|
||||||
import "github.com/flipped-aurora/gin-vue-admin/server/service"
|
import "github.com/flipped-aurora/gin-vue-admin/server/service"
|
||||||
|
|
||||||
type ApiGroup struct {
|
type ApiGroup struct {
|
||||||
|
PetAssistantApi
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
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)
|
||||||
|
}
|
||||||
|
|
@ -116,7 +116,7 @@ func Routers() *gin.Engine {
|
||||||
InstallPlugin(PrivateGroup, PublicGroup, Router)
|
InstallPlugin(PrivateGroup, PublicGroup, Router)
|
||||||
|
|
||||||
// 注册业务路由
|
// 注册业务路由
|
||||||
initBizRouter(PrivateGroup, PublicGroup)
|
initBizRouter(PrivateGroup, PublicGroup, UserGroup)
|
||||||
|
|
||||||
global.GVA_ROUTERS = Router.Routes()
|
global.GVA_ROUTERS = Router.Routes()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ func holder(routers ...*gin.RouterGroup) {
|
||||||
func initBizRouter(routers ...*gin.RouterGroup) {
|
func initBizRouter(routers ...*gin.RouterGroup) {
|
||||||
privateGroup := routers[0]
|
privateGroup := routers[0]
|
||||||
publicGroup := routers[1]
|
publicGroup := routers[1]
|
||||||
|
userGroup := routers[2]
|
||||||
holder(publicGroup, privateGroup)
|
holder(publicGroup, privateGroup)
|
||||||
{
|
{
|
||||||
petRouter := router.RouterGroupApp.Pet
|
petRouter := router.RouterGroupApp.Pet
|
||||||
|
|
@ -25,5 +26,10 @@ func initBizRouter(routers ...*gin.RouterGroup) {
|
||||||
petRouter.InitPetFamilyPetsRouter(privateGroup, publicGroup)
|
petRouter.InitPetFamilyPetsRouter(privateGroup, publicGroup)
|
||||||
petRouter.InitPetPetsRouter(privateGroup, publicGroup) // 占位方法,保证文件可以正确加载,避免go空变量检测报错,请勿删除。
|
petRouter.InitPetPetsRouter(privateGroup, publicGroup) // 占位方法,保证文件可以正确加载,避免go空变量检测报错,请勿删除。
|
||||||
petRouter.InitPetRecordsRouter(privateGroup, publicGroup)
|
petRouter.InitPetRecordsRouter(privateGroup, publicGroup)
|
||||||
|
|
||||||
|
// 用户相关路由(需要UserJWTAuth认证)
|
||||||
|
if userGroup != nil {
|
||||||
|
petRouter.InitPetAssistantRouter(userGroup, publicGroup)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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"` // 结束时间,可选
|
||||||
|
}
|
||||||
|
|
@ -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"` // 排队请求数
|
||||||
|
}
|
||||||
|
|
@ -13,6 +13,7 @@ type RouterGroup struct {
|
||||||
PetFamilyPetsRouter
|
PetFamilyPetsRouter
|
||||||
PetPetsRouter
|
PetPetsRouter
|
||||||
PetRecordsRouter
|
PetRecordsRouter
|
||||||
|
PetAssistantRouter
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
@ -26,4 +27,5 @@ var (
|
||||||
petFamilyPetsApi = api.ApiGroupApp.PetApiGroup.PetFamilyPetsApi
|
petFamilyPetsApi = api.ApiGroupApp.PetApiGroup.PetFamilyPetsApi
|
||||||
petPetsApi = api.ApiGroupApp.PetApiGroup.PetPetsApi
|
petPetsApi = api.ApiGroupApp.PetApiGroup.PetPetsApi
|
||||||
petRecordsApi = api.ApiGroupApp.PetApiGroup.PetRecordsApi
|
petRecordsApi = api.ApiGroupApp.PetApiGroup.PetRecordsApi
|
||||||
|
petUserApiGroup = api.ApiGroupApp.PetApiGroup.PetUserApiGroup
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -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) // 获取宠物助手会话列表
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -7,36 +7,17 @@ import (
|
||||||
|
|
||||||
"github.com/flipped-aurora/gin-vue-admin/server/global"
|
"github.com/flipped-aurora/gin-vue-admin/server/global"
|
||||||
"github.com/flipped-aurora/gin-vue-admin/server/model/pet"
|
"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/flipped-aurora/gin-vue-admin/server/utils"
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ChatRequest 聊天请求结构体
|
// 使用新定义的模型结构
|
||||||
type ChatRequest struct {
|
type ChatRequest = petRequest.ChatRequest
|
||||||
Message string `json:"message" binding:"required"` // 用户消息
|
type ChatResponse = petResponse.ChatResponse
|
||||||
SessionId string `json:"sessionId"` // 会话ID,可选
|
type StreamEvent = petResponse.StreamEvent
|
||||||
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"` // 事件数据
|
|
||||||
}
|
|
||||||
|
|
||||||
// PetChatService 宠物聊天服务
|
// PetChatService 宠物聊天服务
|
||||||
type PetChatService struct{}
|
type PetChatService struct{}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue