2026-05-27 09:36:26 +08:00
|
|
|
|
package session
|
2026-05-12 13:59:15 +08:00
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
|
"context"
|
2026-05-15 09:45:51 +08:00
|
|
|
|
"fmt"
|
2026-05-18 19:19:17 +08:00
|
|
|
|
|
2026-06-10 16:32:42 +08:00
|
|
|
|
"gitea.redpowerfuture.com/red-future/common/beans"
|
|
|
|
|
|
"gitea.redpowerfuture.com/red-future/common/utils"
|
2026-05-12 13:59:15 +08:00
|
|
|
|
"github.com/gogf/gf/v2/frame/g"
|
2026-05-15 09:45:51 +08:00
|
|
|
|
"github.com/gogf/gf/v2/util/gconv"
|
2026-05-20 11:36:39 +08:00
|
|
|
|
|
|
|
|
|
|
"prompts-core/common/util"
|
|
|
|
|
|
"prompts-core/dao"
|
|
|
|
|
|
"prompts-core/model/dto"
|
|
|
|
|
|
"prompts-core/model/entity"
|
2026-05-12 13:59:15 +08:00
|
|
|
|
)
|
|
|
|
|
|
|
2026-06-09 15:46:09 +08:00
|
|
|
|
// ============================================
|
|
|
|
|
|
// 回调存储
|
|
|
|
|
|
// ============================================
|
|
|
|
|
|
|
2026-05-27 09:36:26 +08:00
|
|
|
|
// Callback 会话回调
|
|
|
|
|
|
func Callback(ctx context.Context, req *dto.SessionCallbackReq) (*dto.SessionCallbackRes, error) {
|
|
|
|
|
|
req.Messages["role"] = "assistant"
|
2026-06-09 14:00:01 +08:00
|
|
|
|
// 1) 更新 DB
|
2026-05-20 11:36:39 +08:00
|
|
|
|
_, err := dao.ComposeSession.Update(ctx, &entity.ComposeSession{
|
2026-05-27 09:36:26 +08:00
|
|
|
|
SQLBaseDO: beans.SQLBaseDO{Id: req.EpicycleId},
|
|
|
|
|
|
ResponseContent: req.Messages,
|
2026-05-18 19:19:17 +08:00
|
|
|
|
})
|
2026-05-12 13:59:15 +08:00
|
|
|
|
if err != nil {
|
2026-05-27 09:36:26 +08:00
|
|
|
|
g.Log().Errorf(ctx, "[会话回调] 更新数据库失败 epicycleId=%d err=%v", req.EpicycleId, err)
|
|
|
|
|
|
return nil, fmt.Errorf("更新数据库失败: %w", err)
|
2026-05-20 11:36:39 +08:00
|
|
|
|
}
|
2026-06-09 14:00:01 +08:00
|
|
|
|
|
|
|
|
|
|
// 2) 查询完整记录
|
2026-05-20 11:36:39 +08:00
|
|
|
|
session, err := dao.ComposeSession.Get(ctx, &entity.ComposeSession{
|
2026-05-27 09:36:26 +08:00
|
|
|
|
SQLBaseDO: beans.SQLBaseDO{Id: req.EpicycleId},
|
2026-05-20 11:36:39 +08:00
|
|
|
|
})
|
2026-06-09 14:00:01 +08:00
|
|
|
|
if err != nil || session == nil {
|
2026-05-27 09:36:26 +08:00
|
|
|
|
return nil, fmt.Errorf("会话不存在: epicycleId=%d", req.EpicycleId)
|
|
|
|
|
|
}
|
2026-06-09 14:00:01 +08:00
|
|
|
|
|
2026-06-09 15:46:09 +08:00
|
|
|
|
// 3) entity → HistoryRound → 写入 Redis
|
|
|
|
|
|
round := entityToHistoryRound(session)
|
|
|
|
|
|
round.Assistant = req.Messages
|
2026-06-10 16:48:35 +08:00
|
|
|
|
if err = SaveToRedis(ctx, session.TenantId, session.SessionId, session.NodeId, round); err != nil {
|
2026-05-27 09:36:26 +08:00
|
|
|
|
return nil, fmt.Errorf("redis存储失败: %w", err)
|
2026-05-12 13:59:15 +08:00
|
|
|
|
}
|
2026-06-09 14:00:01 +08:00
|
|
|
|
|
|
|
|
|
|
g.Log().Infof(ctx, "[会话回调] 存储成功 sessionId=%s id=%d", session.SessionId, session.Id)
|
|
|
|
|
|
return &dto.SessionCallbackRes{Status: true, SessionId: session.SessionId}, nil
|
2026-05-12 13:59:15 +08:00
|
|
|
|
}
|
2026-05-15 09:45:51 +08:00
|
|
|
|
|
2026-06-09 15:46:09 +08:00
|
|
|
|
// ============================================
|
|
|
|
|
|
// 场景1:前端历史列表(按 creator)
|
|
|
|
|
|
// ============================================
|
|
|
|
|
|
|
|
|
|
|
|
// GetHistoryList 获取历史列表
|
|
|
|
|
|
func GetHistoryList(ctx context.Context, req *dto.GetHistoryListReq) (*dto.GetHistoryListRes, error) {
|
|
|
|
|
|
user, err := utils.GetUserInfo(ctx)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return nil, err
|
|
|
|
|
|
}
|
|
|
|
|
|
sessions, total, err := dao.ComposeSession.List(ctx, &entity.ComposeSession{
|
|
|
|
|
|
SQLBaseDO: beans.SQLBaseDO{Creator: user.UserName},
|
|
|
|
|
|
}, req.Page, req.Size)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return nil, fmt.Errorf("DB获取历史列表失败: %w", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
rounds := sessionsToHistoryRounds(sessions)
|
|
|
|
|
|
return &dto.GetHistoryListRes{List: rounds, Total: total}, nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ============================================
|
|
|
|
|
|
// 场景2:提示词拼接(按 sessionId + nodeId)
|
|
|
|
|
|
// ============================================
|
|
|
|
|
|
|
|
|
|
|
|
// GetHistoryMessages 获取历史消息(Redis → DB → 异步回种)
|
2026-06-09 14:00:01 +08:00
|
|
|
|
func GetHistoryMessages(ctx context.Context, req *dto.GetHistoryMessagesReq) (*dto.GetHistoryMessagesRes, error) {
|
|
|
|
|
|
user, err := utils.GetUserInfo(ctx)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return nil, err
|
|
|
|
|
|
}
|
2026-05-15 09:45:51 +08:00
|
|
|
|
|
2026-06-09 14:00:01 +08:00
|
|
|
|
// 1) Redis
|
2026-06-10 16:48:35 +08:00
|
|
|
|
if rounds, err := GetFromRedis(ctx, user.TenantId, req.SessionId, req.NodeId); err == nil && len(rounds) > 0 {
|
2026-06-09 15:46:09 +08:00
|
|
|
|
g.Log().Debugf(ctx, "[历史消息] Redis命中 sessionId=%s count=%d", req.SessionId, len(rounds))
|
|
|
|
|
|
return &dto.GetHistoryMessagesRes{Messages: flattenRounds(rounds)}, nil
|
2026-05-15 09:45:51 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-06-09 14:00:01 +08:00
|
|
|
|
// 2) DB
|
|
|
|
|
|
maxRounds := util.GetMaxRounds(ctx)
|
2026-06-08 18:01:54 +08:00
|
|
|
|
sessions, _, err := dao.ComposeSession.List(ctx, &entity.ComposeSession{
|
2026-06-09 14:00:01 +08:00
|
|
|
|
SQLBaseDO: beans.SQLBaseDO{Creator: user.UserName},
|
|
|
|
|
|
SessionId: req.SessionId,
|
2026-06-09 15:46:09 +08:00
|
|
|
|
NodeId: req.NodeId,
|
2026-06-08 18:01:54 +08:00
|
|
|
|
}, 1, maxRounds)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return nil, fmt.Errorf("DB获取历史失败: %w", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
if len(sessions) == 0 {
|
2026-06-09 15:46:09 +08:00
|
|
|
|
return &dto.GetHistoryMessagesRes{Messages: []dto.FlatMessage{}}, nil
|
2026-06-08 18:01:54 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-06-09 14:00:01 +08:00
|
|
|
|
// 3) 转换 + 异步回种
|
|
|
|
|
|
rounds := sessionsToHistoryRounds(sessions)
|
2026-06-10 16:48:35 +08:00
|
|
|
|
go asyncCacheToRedis(context.WithoutCancel(ctx), user.TenantId, req.SessionId, req.NodeId, rounds)
|
2026-06-08 18:01:54 +08:00
|
|
|
|
|
2026-06-09 15:46:09 +08:00
|
|
|
|
return &dto.GetHistoryMessagesRes{Messages: flattenRounds(rounds)}, nil
|
2026-05-20 11:36:39 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-06-09 15:46:09 +08:00
|
|
|
|
// ============================================
|
|
|
|
|
|
// 删除
|
|
|
|
|
|
// ============================================
|
2026-06-09 14:00:01 +08:00
|
|
|
|
|
2026-06-10 16:48:35 +08:00
|
|
|
|
// DeleteMessages 删除消息
|
2026-06-09 15:46:09 +08:00
|
|
|
|
func DeleteMessages(ctx context.Context, req *dto.DeleteMessagesReq) (*dto.DeleteMessagesRes, error) {
|
|
|
|
|
|
if len(req.MsgIds) == 0 {
|
|
|
|
|
|
return &dto.DeleteMessagesRes{Ok: false}, fmt.Errorf("msgIds不能为空")
|
|
|
|
|
|
}
|
2026-06-09 14:00:01 +08:00
|
|
|
|
|
2026-06-10 16:48:35 +08:00
|
|
|
|
user, _ := utils.GetUserInfo(ctx)
|
|
|
|
|
|
|
|
|
|
|
|
// 1) 批量查询
|
|
|
|
|
|
sessions, _ := dao.ComposeSession.ListByIds(ctx, req.MsgIds, user.UserName, req.SessionId)
|
|
|
|
|
|
|
|
|
|
|
|
// 2) 批量删 DB
|
|
|
|
|
|
_, _ = dao.ComposeSession.DeleteByIds(ctx, req.MsgIds, user.UserName, req.SessionId)
|
2026-06-09 15:46:09 +08:00
|
|
|
|
|
2026-06-10 16:48:35 +08:00
|
|
|
|
// 3) 按 nodeId 分组删 Redis
|
|
|
|
|
|
for _, s := range sessions {
|
|
|
|
|
|
_ = DeleteRedisMessages(ctx, user.TenantId, req.SessionId, s.NodeId, req.MsgIds)
|
|
|
|
|
|
}
|
2026-06-09 15:46:09 +08:00
|
|
|
|
return &dto.DeleteMessagesRes{Ok: true}, nil
|
2026-06-09 14:00:01 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-06-09 15:46:09 +08:00
|
|
|
|
// DeleteSession 删除整个会话
|
2026-06-09 14:00:01 +08:00
|
|
|
|
func DeleteSession(ctx context.Context, req *dto.DeleteSessionReq) (*dto.DeleteSessionRes, error) {
|
2026-06-09 15:46:09 +08:00
|
|
|
|
// 1) 删 DB
|
|
|
|
|
|
if _, err := dao.ComposeSession.Delete(ctx, &entity.ComposeSession{
|
2026-06-09 14:00:01 +08:00
|
|
|
|
SessionId: req.SessionId,
|
2026-06-09 15:46:09 +08:00
|
|
|
|
}); err != nil {
|
2026-06-09 14:00:01 +08:00
|
|
|
|
return nil, fmt.Errorf("DB删除失败: %w", err)
|
|
|
|
|
|
}
|
2026-05-20 11:36:39 +08:00
|
|
|
|
|
2026-06-09 15:46:09 +08:00
|
|
|
|
user, err := utils.GetUserInfo(ctx)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return nil, err
|
|
|
|
|
|
}
|
|
|
|
|
|
// 2) 删 Redis
|
|
|
|
|
|
if err := DeleteSessionHistory(ctx, user.TenantId, req.SessionId); err != nil {
|
|
|
|
|
|
g.Log().Warningf(ctx, "[删除会话] Redis删除失败 sessionId=%s err=%v", req.SessionId, err)
|
2026-06-09 14:00:01 +08:00
|
|
|
|
}
|
2026-05-20 11:36:39 +08:00
|
|
|
|
|
2026-06-09 14:00:01 +08:00
|
|
|
|
return &dto.DeleteSessionRes{Ok: true}, nil
|
2026-05-20 11:36:39 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-06-09 14:00:01 +08:00
|
|
|
|
// ============================================
|
2026-06-09 15:46:09 +08:00
|
|
|
|
// 转换方法(entity ↔ dto,集中管理)
|
2026-06-09 14:00:01 +08:00
|
|
|
|
// ============================================
|
|
|
|
|
|
|
2026-06-09 15:46:09 +08:00
|
|
|
|
// entityToHistoryRound entity → HistoryRound
|
|
|
|
|
|
func entityToHistoryRound(s *entity.ComposeSession) *dto.HistoryRound {
|
2026-06-10 14:51:25 +08:00
|
|
|
|
return &dto.HistoryRound{
|
2026-06-09 15:46:09 +08:00
|
|
|
|
Id: s.Id,
|
|
|
|
|
|
SessionId: s.SessionId,
|
|
|
|
|
|
NodeId: s.NodeId,
|
|
|
|
|
|
CreatedAt: gconv.String(s.CreatedAt),
|
|
|
|
|
|
UpdatedAt: gconv.String(s.UpdatedAt),
|
2026-06-10 14:51:25 +08:00
|
|
|
|
User: s.RequestContent,
|
|
|
|
|
|
Assistant: s.ResponseContent,
|
2026-05-20 11:36:39 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-06-09 15:46:09 +08:00
|
|
|
|
// sessionsToHistoryRounds 批量转换
|
|
|
|
|
|
func sessionsToHistoryRounds(sessions []*entity.ComposeSession) []dto.HistoryRound {
|
|
|
|
|
|
rounds := make([]dto.HistoryRound, 0, len(sessions))
|
|
|
|
|
|
for _, s := range sessions {
|
|
|
|
|
|
rounds = append(rounds, *entityToHistoryRound(s))
|
2026-05-15 09:45:51 +08:00
|
|
|
|
}
|
2026-06-09 15:46:09 +08:00
|
|
|
|
return rounds
|
2026-05-20 11:36:39 +08:00
|
|
|
|
}
|
2026-05-15 09:45:51 +08:00
|
|
|
|
|
2026-06-09 15:46:09 +08:00
|
|
|
|
// asyncCacheToRedis 异步缓存到 Redis
|
2026-06-10 16:48:35 +08:00
|
|
|
|
func asyncCacheToRedis(ctx context.Context, tenantID uint64, sessionID, nodeID string, rounds []dto.HistoryRound) {
|
2026-06-09 15:46:09 +08:00
|
|
|
|
for i := range rounds {
|
|
|
|
|
|
if rounds[i].User != nil || rounds[i].Assistant != nil {
|
2026-06-10 16:48:35 +08:00
|
|
|
|
_ = SaveToRedis(ctx, tenantID, sessionID, nodeID, &rounds[i])
|
2026-05-15 09:45:51 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|