网站首页 网站源码
website
站点相关全部源代码,隐藏了一些关于服务器的信息
using Medallion.Threading;

namespace Dpz.Core.Service.RepositoryServiceImpl;

public class AiChatService(
    IRepository<AiChatRecord> chatRecordRepository,
    IRepository<AiChatSession> sessionRepository,
    IMapper mapper,
    IConfiguration configuration,
    IDistributedLockProvider distributedLockProvider
) : IAiChatService
{
    public async Task<VmAiChatSession> CreateSessionAsync(
        string userId,
        string sessionId,
        string sessionName,
        string modelType
    )
    {
        var lockKey = $"CreateSessionAsync.Chat.Lock:{userId}_{sessionId}";
        await using (await distributedLockProvider.AcquireLockAsync(lockKey))
        {
            var defaultSession = sessionRepository
                .SearchFor(x =>
                    x.UserId == userId && x.SessionId == sessionId && x.IsDeleted == false
                )
                .SingleOrDefault();
            if (defaultSession != null)
            {
                return mapper.Map<VmAiChatSession>(defaultSession);
            }

            var session = new AiChatSession
            {
                UserId = userId,
                SessionId = sessionId,
                SessionName = sessionName,
                ModelType = modelType,
                CreateTime = DateTime.Now,
                LastUpdateTime = DateTime.Now,
                IsDeleted = false,
            };

            await sessionRepository.InsertAsync(session);
            return mapper.Map<VmAiChatSession>(session);
        }
    }

    public async Task<List<VmAiChatSession>> GetSessionListAsync(string userId)
    {
        var sessions = await sessionRepository
            .SearchFor(x => x.UserId == userId && !x.IsDeleted)
            .OrderByDescending(x => x.LastUpdateTime)
            .ToListAsync();

        var vmSessions = mapper.Map<List<VmAiChatSession>>(sessions);

        // 获取每个会话的消息数量
        foreach (var session in vmSessions)
        {
            var count = await chatRecordRepository
                .SearchFor(x => x.SessionId == session.SessionId && !x.IsDeleted)
                .CountAsync();
            session.MessageCount = count;
        }

        return vmSessions;
    }

    public async Task<bool> DeleteSessionAsync(string userId, string sessionId)
    {
        var updateDef = Builders<AiChatSession>
            .Update.Set(x => x.IsDeleted, true)
            .Set(x => x.LastUpdateTime, DateTime.Now);

        var result = await sessionRepository.UpdateAsync(
            x => x.UserId == userId && x.SessionId == sessionId && !x.IsDeleted,
            updateDef
        );

        // 同时软删除该会话的所有聊天记录
        if (result.ModifiedCount > 0)
        {
            var chatUpdateDef = Builders<AiChatRecord>
                .Update.Set(x => x.IsDeleted, true)
                .Set(x => x.DeletedTime, DateTime.Now);

            await chatRecordRepository.UpdateAsync(
                x => x.SessionId == sessionId && !x.IsDeleted,
                chatUpdateDef
            );
        }

        return result.ModifiedCount > 0;
    }

    public async Task<VmAiChatSession?> GetSessionAsync(string userId, string sessionId)
    {
        var session = await sessionRepository
            .SearchFor(x => x.UserId == userId && x.SessionId == sessionId && !x.IsDeleted)
            .FirstOrDefaultAsync();

        if (session == null)
        {
            return null;
        }

        var vmSession = mapper.Map<VmAiChatSession>(session);

        // 获取消息数量
        var count = await chatRecordRepository
            .SearchFor(x => x.SessionId == sessionId && !x.IsDeleted)
            .CountAsync();
        vmSession.MessageCount = count;

        return vmSession;
    }

    public async Task SaveUserMessageAsync(
        string userId,
        string sessionId,
        string message,
        VmUserInfo sender
    )
    {
        // 使用会话ID作为AI用户的ID
        var receiver = CreateAiUserInfo(sessionId);
        var record = new AiChatRecord
        {
            SessionId = sessionId,
            Message = message,
            Sender = mapper.Map<UserInfo>(sender),
            Receiver = mapper.Map<UserInfo>(receiver),
            Type = "ai",
            SendTime = DateTime.Now,
            IsDeleted = false,
        };

        await chatRecordRepository.InsertAsync(record);

        // 更新会话的最后更新时间
        await UpdateSessionLastUpdateTime(userId, sessionId);
    }

    public async Task SaveAiMessageAsync(
        string userId,
        string sessionId,
        string message,
        VmUserInfo aiUser
    )
    {
        var userInfo = await GetUserInfoFromSession(userId, sessionId);
        if (userInfo == null)
        {
            return;
        }

        // 确保AI用户的ID使用会话ID
        aiUser.Id = sessionId;

        var record = new AiChatRecord
        {
            SessionId = sessionId,
            Message = message,
            Sender = mapper.Map<UserInfo>(aiUser),
            Receiver = mapper.Map<UserInfo>(userInfo),
            Type = "ai",
            SendTime = DateTime.Now,
            IsDeleted = false,
        };

        await chatRecordRepository.InsertAsync(record);

        // 更新会话的最后更新时间
        await UpdateSessionLastUpdateTime(userId, sessionId);
    }

    public async Task<IPagedList<VmAiChatRecord>> GetSessionMessagesAsync(
        string sessionId,
        int pageIndex,
        int pageSize
    )
    {
        return  await chatRecordRepository
            .SearchFor(x => x.SessionId == sessionId && !x.IsDeleted)
            .OrderByDescending(x => x.SendTime)
            .ToPagedListAsync<AiChatRecord, VmAiChatRecord>(pageIndex, pageSize);
    }

    public async Task<bool> UpdateSessionNameAsync(string userId, string sessionId, string newName)
    {
        var updateDef = Builders<AiChatSession>
            .Update.Set(x => x.SessionName, newName)
            .Set(x => x.LastUpdateTime, DateTime.Now);

        var result = await sessionRepository.UpdateAsync(
            x => x.UserId == userId && x.SessionId == sessionId && !x.IsDeleted,
            updateDef
        );

        return result.ModifiedCount > 0;
    }

    public async Task<bool> UpdateSessionModelTypeAsync(
        string userId,
        string sessionId,
        string modelType
    )
    {
        var updateDef = Builders<AiChatSession>
            .Update.Set(x => x.ModelType, modelType)
            .Set(x => x.LastUpdateTime, DateTime.Now);

        var result = await sessionRepository.UpdateAsync(
            x => x.UserId == userId && x.SessionId == sessionId && !x.IsDeleted,
            updateDef
        );

        return result.ModifiedCount > 0;
    }

    public async Task<ResponseResult> DeleteMessageAsync(string messageId, string account)
    {
        var record = await chatRecordRepository.TryGetAsync(messageId);
        if (record == null)
        {
            return ResponseResult.ToFail("聊天记录不存在");
        }

        if (record.Sender?.Id != account && record.Receiver?.Id != account)
        {
            return ResponseResult.ToFail("无权限删除该聊天记录");
        }

        var update = Builders<AiChatRecord>
            .Update.Set(x => x.IsDeleted, true)
            .Set(x => x.DeletedTime, DateTime.Now);
        await chatRecordRepository.UpdateAsync(x => x.Id == record.Id, update);

        return ResponseResult.ToSuccess();
    }

    private async Task UpdateSessionLastUpdateTime(string userId, string sessionId)
    {
        var updateDef = Builders<AiChatSession>.Update.Set(x => x.LastUpdateTime, DateTime.Now);

        await sessionRepository.UpdateAsync(
            x => x.UserId == userId && x.SessionId == sessionId,
            updateDef
        );
    }

    private async Task<VmUserInfo?> GetUserInfoFromSession(string userId, string sessionId)
    {
        // 从会话的聊天记录中获取用户信息
        var record = await chatRecordRepository
            .SearchFor(x => x.SessionId == sessionId && x.Sender != null && x.Sender.Id == userId)
            .FirstOrDefaultAsync();

        return record?.Sender != null ? mapper.Map<VmUserInfo>(record.Sender) : null;
    }

    private VmUserInfo CreateAiUserInfo(string sessionId)
    {
        return new VmUserInfo
        {
            // 使用会话ID作为AI用户的ID,确保一致性
            Avatar = $"{configuration["CDNBaseAddress"]}/images/ChatGPT.ico",
            Id = sessionId,
            Name = "AI Assistant",
            Enable = true,
            Key = string.Empty,
            LastAccessTime = DateTime.Now,
        };
    }
}
loading