You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
210 lines
6.0 KiB
C#
210 lines
6.0 KiB
C#
using System.Linq;
|
|
using AI.Models;
|
|
|
|
namespace AI.Service
|
|
{
|
|
/// <summary>
|
|
/// 管理多个聊天会话;会话存储以 YAML 文件持久化到 Sessions 目录。
|
|
/// </summary>
|
|
public class ChatSessionManager
|
|
{
|
|
private readonly Dictionary<string, ChatSession> _sessions = new();
|
|
private readonly object _lock = new object();
|
|
private ChatSession? _currentSession;
|
|
private readonly SessionStorage _storage;
|
|
|
|
public ChatSessionManager(SessionStorage? sessionStorage = null)
|
|
{
|
|
_storage = sessionStorage ?? new SessionStorage();
|
|
LoadSessionsFromDisk();
|
|
}
|
|
|
|
/// <summary>
|
|
/// 会话列表变化事件
|
|
/// </summary>
|
|
public event EventHandler? SessionsChanged;
|
|
|
|
/// <summary>
|
|
/// 当前会话变化事件
|
|
/// </summary>
|
|
public event EventHandler<ChatSession?>? CurrentSessionChanged;
|
|
|
|
/// <summary>
|
|
/// 获取所有会话(按更新时间倒序)
|
|
/// </summary>
|
|
public IEnumerable<ChatSession> GetAllSessions()
|
|
{
|
|
lock (_lock)
|
|
{
|
|
return _sessions.Values.OrderByDescending(s => s.UpdatedAt).ToList();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 根据ID获取会话
|
|
/// </summary>
|
|
public ChatSession? GetSession(string sessionId)
|
|
{
|
|
lock (_lock)
|
|
{
|
|
return _sessions.TryGetValue(sessionId, out var session) ? session : null;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取或设置当前活跃会话
|
|
/// </summary>
|
|
public ChatSession? CurrentSession
|
|
{
|
|
get
|
|
{
|
|
lock (_lock)
|
|
{
|
|
return _currentSession;
|
|
}
|
|
}
|
|
set
|
|
{
|
|
lock (_lock)
|
|
{
|
|
if (_currentSession != value)
|
|
{
|
|
_currentSession = value;
|
|
CurrentSessionChanged?.Invoke(this, value);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 创建新会话并设置为当前会话;会订阅存储变更并持久化到 YAML 文件。
|
|
/// </summary>
|
|
public ChatSession CreateSession(string? title = null)
|
|
{
|
|
var session = new ChatSession(title: title);
|
|
session.Store.StoreChanged += (_, _) => SaveSession(session);
|
|
lock (_lock)
|
|
{
|
|
_sessions[session.Id] = session;
|
|
}
|
|
SaveSession(session);
|
|
CurrentSession = session;
|
|
SessionsChanged?.Invoke(this, EventArgs.Empty);
|
|
return session;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 将会话保存到 YAML 文件
|
|
/// </summary>
|
|
public void SaveSession(ChatSession session)
|
|
{
|
|
if (session == null) return;
|
|
try
|
|
{
|
|
_storage.Save(session);
|
|
}
|
|
catch
|
|
{
|
|
// 持久化失败不抛,避免影响主流程
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 删除会话(同时删除对应 YAML 文件)
|
|
/// </summary>
|
|
public bool DeleteSession(string sessionId)
|
|
{
|
|
ChatSession? deletedSession = null;
|
|
lock (_lock)
|
|
{
|
|
if (_sessions.TryGetValue(sessionId, out deletedSession))
|
|
{
|
|
_sessions.Remove(sessionId);
|
|
if (_currentSession?.Id == sessionId)
|
|
{
|
|
_currentSession = _sessions.Values.OrderByDescending(s => s.UpdatedAt).FirstOrDefault();
|
|
CurrentSessionChanged?.Invoke(this, _currentSession);
|
|
}
|
|
}
|
|
}
|
|
if (deletedSession != null)
|
|
{
|
|
try { _storage.Delete(sessionId); } catch { }
|
|
SessionsChanged?.Invoke(this, EventArgs.Empty);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 切换当前会话
|
|
/// </summary>
|
|
public bool SwitchToSession(string sessionId)
|
|
{
|
|
var session = GetSession(sessionId);
|
|
if (session != null)
|
|
{
|
|
CurrentSession = session;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取当前活跃会话数量
|
|
/// </summary>
|
|
public int SessionCount
|
|
{
|
|
get
|
|
{
|
|
lock (_lock)
|
|
{
|
|
return _sessions.Count;
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 检查会话是否存在
|
|
/// </summary>
|
|
public bool SessionExists(string sessionId)
|
|
{
|
|
lock (_lock)
|
|
{
|
|
return _sessions.ContainsKey(sessionId);
|
|
}
|
|
}
|
|
|
|
private void LoadSessionsFromDisk()
|
|
{
|
|
try
|
|
{
|
|
var loaded = _storage.LoadAll().ToList();
|
|
if (loaded.Count == 0)
|
|
{
|
|
return;
|
|
}
|
|
lock (_lock)
|
|
{
|
|
foreach (var session in loaded)
|
|
{
|
|
session.Store.StoreChanged += (_, _) => SaveSession(session);
|
|
_sessions[session.Id] = session;
|
|
}
|
|
_currentSession = loaded.FirstOrDefault();
|
|
if (_currentSession != null)
|
|
{
|
|
CurrentSessionChanged?.Invoke(this, _currentSession);
|
|
}
|
|
}
|
|
SessionsChanged?.Invoke(this, EventArgs.Empty);
|
|
}
|
|
catch
|
|
{
|
|
// 加载失败则保持空列表,后续可新建会话
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|