|
|
# -*- coding: utf-8 -*-
|
|
|
"""
|
|
|
对话管理器模块
|
|
|
|
|
|
该模块实现了对话的创建、切换、删除、保存和加载等功能,是应用程序中对话管理的核心组件。
|
|
|
它负责维护用户的对话历史,并提供与UI交互的接口来管理对话列表。
|
|
|
"""
|
|
|
|
|
|
# 标准库导入
|
|
|
import tkinter as tk
|
|
|
import customtkinter as ctk
|
|
|
from datetime import datetime
|
|
|
import json
|
|
|
import os
|
|
|
import uuid
|
|
|
|
|
|
|
|
|
class ConversationManager:
|
|
|
"""对话管理器类
|
|
|
|
|
|
负责管理用户的对话历史,包括创建新对话、切换对话、删除对话、
|
|
|
保存对话历史到本地文件以及从本地文件加载对话历史等功能。
|
|
|
|
|
|
属性:
|
|
|
app: 应用程序的主实例
|
|
|
root: 应用程序的根窗口
|
|
|
conversation_listbox: 对话列表框组件(预留)
|
|
|
messages: 当前对话的消息列表
|
|
|
chat_histories: 所有对话历史的字典
|
|
|
current_conversation_id: 当前对话的ID
|
|
|
conversations: 所有对话ID的列表
|
|
|
update_chat_display: 更新聊天显示的方法引用
|
|
|
scroll_to_bottom: 滚动聊天窗口到底部的方法引用
|
|
|
default_chat_history_file: 默认聊天历史文件路径
|
|
|
"""
|
|
|
|
|
|
def __init__(self, app):
|
|
|
"""初始化对话管理器
|
|
|
|
|
|
参数:
|
|
|
app: 应用程序的主实例,提供全局状态和UI访问
|
|
|
"""
|
|
|
# 应用程序引用
|
|
|
self.app = app
|
|
|
self.root = app.root
|
|
|
|
|
|
# 预留的UI组件引用
|
|
|
self.conversation_listbox = None
|
|
|
|
|
|
# 应用程序状态引用
|
|
|
self.messages = app.messages # 当前对话的消息列表
|
|
|
self.chat_histories = app.chat_histories # 所有对话历史的字典
|
|
|
self.current_conversation_id = app.current_conversation_id # 当前对话ID
|
|
|
self.conversations = app.conversations # 所有对话ID的列表
|
|
|
|
|
|
# 应用程序方法引用
|
|
|
self.update_chat_display = app.update_chat_display # 更新聊天显示的方法
|
|
|
self.scroll_to_bottom = app.scroll_to_bottom # 滚动到底部的方法
|
|
|
|
|
|
# 默认聊天历史文件路径
|
|
|
self.default_chat_history_file = "data/chat_history.json" # 默认保存位置
|
|
|
|
|
|
def create_new_conversation(self):
|
|
|
"""创建新对话
|
|
|
|
|
|
该方法执行以下操作:
|
|
|
1. 将当前消息列表同步到当前对话历史
|
|
|
2. 生成唯一的对话ID(使用UUID)
|
|
|
3. 清除当前消息列表
|
|
|
4. 添加默认欢迎消息
|
|
|
5. 创建新的对话记录并添加到聊天历史中
|
|
|
6. 更新对话列表显示
|
|
|
7. 更新聊天界面显示
|
|
|
8. 滚动到聊天窗口底部
|
|
|
9. 保存聊天历史到本地文件
|
|
|
"""
|
|
|
# 将当前消息列表同步到当前对话历史
|
|
|
if self.app.current_conversation_id and self.app.current_conversation_id in self.app.chat_histories:
|
|
|
self.app.chat_histories[self.app.current_conversation_id]["messages"] = self.app.messages.copy()
|
|
|
|
|
|
# 生成唯一的对话ID
|
|
|
conv_id = str(uuid.uuid4())
|
|
|
self.app.current_conversation_id = conv_id # 更新当前对话ID
|
|
|
|
|
|
# 添加默认欢迎消息
|
|
|
default_msg = {
|
|
|
"role": "assistant", # 消息角色:助手
|
|
|
"content": "你好!我是DeepSeek AI助手,有什么可以帮助你的吗?", # 欢迎消息内容
|
|
|
"timestamp": datetime.now().isoformat() # 消息时间戳
|
|
|
}
|
|
|
|
|
|
# 清空当前消息列表并添加默认消息
|
|
|
self.app.messages.clear()
|
|
|
self.app.messages.append(default_msg)
|
|
|
|
|
|
# 创建新的对话记录
|
|
|
self.app.chat_histories[conv_id] = {
|
|
|
"title": "新对话", # 默认对话标题
|
|
|
"last_updated": datetime.now().isoformat(), # 最后更新时间
|
|
|
"messages": [default_msg.copy()] # 复制默认消息到对话历史
|
|
|
}
|
|
|
|
|
|
# 将新对话ID添加到对话列表
|
|
|
self.app.conversations.append(conv_id)
|
|
|
|
|
|
# 更新UI界面(异步调用,确保在主线程执行)
|
|
|
self.root.after(0, self._update_conversation_list) # 更新对话列表显示
|
|
|
self.root.after(0, self.app.update_chat_display) # 更新聊天显示
|
|
|
self.root.after(0, self.app.scroll_to_bottom) # 滚动到底部
|
|
|
|
|
|
# 保存聊天历史(异步调用)
|
|
|
self.root.after(0, self._save_chat_history)
|
|
|
|
|
|
def switch_conversation(self, conv_id):
|
|
|
"""切换到指定对话
|
|
|
|
|
|
参数:
|
|
|
conv_id: 目标对话的唯一ID
|
|
|
|
|
|
该方法执行以下操作:
|
|
|
1. 将当前消息列表同步到当前对话历史
|
|
|
2. 更新当前对话ID
|
|
|
3. 清除当前消息列表
|
|
|
4. 将目标对话的消息复制到当前消息列表
|
|
|
5. 更新聊天界面显示
|
|
|
6. 保存聊天历史
|
|
|
"""
|
|
|
# 将当前消息列表同步到当前对话历史
|
|
|
if self.app.current_conversation_id and self.app.current_conversation_id in self.app.chat_histories:
|
|
|
self.app.chat_histories[self.app.current_conversation_id]["messages"] = self.app.messages.copy()
|
|
|
|
|
|
# 更新当前对话ID
|
|
|
self.app.current_conversation_id = conv_id
|
|
|
|
|
|
# 清空当前消息列表
|
|
|
self.app.messages.clear()
|
|
|
|
|
|
# 将目标对话的消息复制到当前消息列表
|
|
|
self.app.messages.extend(self.app.chat_histories[conv_id]["messages"])
|
|
|
|
|
|
# 更新聊天界面显示(异步调用)
|
|
|
self.root.after(0, self.app.update_chat_display)
|
|
|
|
|
|
# 更新对话列表显示(确保选中当前对话)(异步调用)
|
|
|
self.root.after(0, self._update_conversation_list)
|
|
|
|
|
|
# 保存聊天历史(异步调用)
|
|
|
self.root.after(0, self._save_chat_history)
|
|
|
|
|
|
def _update_conversation_list(self):
|
|
|
"""更新对话列表显示
|
|
|
|
|
|
该方法执行以下操作:
|
|
|
1. 检查UI组件是否已经初始化
|
|
|
2. 清空对话列表框
|
|
|
3. 按最后更新时间降序排序对话
|
|
|
4. 在列表框中显示所有对话(显示标题和ID的前8位)
|
|
|
5. 选中并激活当前对话
|
|
|
"""
|
|
|
# 安全检查:确保UI组件已经初始化
|
|
|
if not hasattr(self.app, 'ui_components'):
|
|
|
return
|
|
|
|
|
|
# 使用get_conversation_listbox()方法获取对话列表框
|
|
|
conversation_listbox = self.app.ui_components.get_conversation_listbox()
|
|
|
if not conversation_listbox:
|
|
|
return
|
|
|
|
|
|
# 清空对话列表框
|
|
|
conversation_listbox.delete(0, tk.END)
|
|
|
|
|
|
try:
|
|
|
# 确保数据一致性:过滤掉self.app.conversations中不存在于self.app.chat_histories的对话ID
|
|
|
valid_conversations = [conv_id for conv_id in self.app.conversations
|
|
|
if conv_id in self.app.chat_histories]
|
|
|
|
|
|
# 如果发现不一致的数据,更新self.app.conversations
|
|
|
if len(valid_conversations) != len(self.app.conversations):
|
|
|
self.app.conversations = valid_conversations
|
|
|
# 检查logger_manager是否存在
|
|
|
if hasattr(self.app, 'logger_manager'):
|
|
|
self.app.logger_manager.log("warning", "修复了对话列表与聊天历史之间的数据不一致问题")
|
|
|
|
|
|
# 确保时间戳统一格式(转换为datetime对象)以避免类型错误
|
|
|
def ensure_datetime(timestamp):
|
|
|
if isinstance(timestamp, datetime):
|
|
|
return timestamp
|
|
|
try:
|
|
|
return datetime.fromisoformat(timestamp)
|
|
|
except:
|
|
|
return datetime.now()
|
|
|
|
|
|
# 按最后更新时间降序排序对话
|
|
|
sorted_conversations = sorted(
|
|
|
valid_conversations,
|
|
|
key=lambda conv_id: ensure_datetime(self.app.chat_histories[conv_id]["last_updated"]),
|
|
|
reverse=True
|
|
|
)
|
|
|
|
|
|
# 更新对话列表显示
|
|
|
for conv_id in sorted_conversations:
|
|
|
title = self.app.chat_histories[conv_id]["title"]
|
|
|
# 显示标题和唯一ID的前8位(便于用户识别)
|
|
|
display_text = f"{title} [ID: {conv_id[:8]}]"
|
|
|
conversation_listbox.insert(tk.END, display_text)
|
|
|
|
|
|
# 选中并激活当前对话
|
|
|
if self.app.current_conversation_id:
|
|
|
try:
|
|
|
# 获取当前对话在排序后列表中的索引
|
|
|
index = sorted_conversations.index(self.app.current_conversation_id)
|
|
|
# 选中当前对话
|
|
|
conversation_listbox.select_set(index)
|
|
|
# 激活当前对话(滚动到可见位置)
|
|
|
conversation_listbox.activate(index)
|
|
|
except ValueError:
|
|
|
# 如果当前对话ID不在列表中,忽略错误
|
|
|
pass
|
|
|
except Exception as e:
|
|
|
# 记录错误日志
|
|
|
if hasattr(self.app, 'logger_manager'):
|
|
|
self.app.logger_manager.log("error", f"更新对话列表失败: {e}")
|
|
|
# 即使出错,也尝试显示可用的对话
|
|
|
try:
|
|
|
for conv_id in self.app.conversations:
|
|
|
if conv_id in self.app.chat_histories:
|
|
|
conversation_listbox.insert(tk.END, f"对话 {conv_id[:8]}")
|
|
|
except:
|
|
|
# 如果再次出错,至少显示一个默认消息
|
|
|
conversation_listbox.insert(tk.END, "对话列表加载失败")
|
|
|
|
|
|
def delete_conversation(self):
|
|
|
"""删除当前选中的对话
|
|
|
|
|
|
该方法执行以下操作:
|
|
|
1. 检查UI组件是否已经初始化
|
|
|
2. 获取当前选中的对话
|
|
|
3. 检查是否还有其他对话(不能删除最后一个对话)
|
|
|
4. 删除对话记录和对话ID
|
|
|
5. 如果删除的是当前对话,切换到第一个剩余对话
|
|
|
6. 更新对话列表显示
|
|
|
7. 更新聊天界面显示
|
|
|
8. 保存更新后的聊天历史
|
|
|
"""
|
|
|
# 安全检查:确保UI组件已经初始化
|
|
|
if not hasattr(self.app, 'ui_components') or not hasattr(self.app.ui_components, 'conversation_listbox'):
|
|
|
return
|
|
|
|
|
|
# 获取当前选中的对话索引
|
|
|
selection = self.app.ui_components.conversation_listbox.curselection()
|
|
|
if not selection: # 如果没有选中任何对话,直接返回
|
|
|
return
|
|
|
|
|
|
try:
|
|
|
# 获取选中的对话ID(需要考虑排序后的列表)
|
|
|
index = selection[0]
|
|
|
|
|
|
# 确保数据一致性:过滤掉self.app.conversations中不存在于self.app.chat_histories的对话ID
|
|
|
valid_conversations = [conv_id for conv_id in self.app.conversations
|
|
|
if conv_id in self.app.chat_histories]
|
|
|
|
|
|
# 确保时间戳统一格式(转换为datetime对象)以避免类型错误
|
|
|
def ensure_datetime(timestamp):
|
|
|
if isinstance(timestamp, datetime):
|
|
|
return timestamp
|
|
|
try:
|
|
|
return datetime.fromisoformat(timestamp)
|
|
|
except:
|
|
|
return datetime.now()
|
|
|
|
|
|
# 按最后更新时间降序排序对话(与_update_conversation_list保持一致)
|
|
|
sorted_conversations = sorted(
|
|
|
valid_conversations,
|
|
|
key=lambda conv_id: ensure_datetime(self.app.chat_histories[conv_id]["last_updated"]),
|
|
|
reverse=True
|
|
|
)
|
|
|
|
|
|
# 从排序后的列表中获取对话ID
|
|
|
conv_id = sorted_conversations[index]
|
|
|
|
|
|
# 保护机制:不能删除最后一个对话
|
|
|
if len(self.app.conversations) == 1:
|
|
|
return
|
|
|
|
|
|
# 删除对话记录
|
|
|
del self.app.chat_histories[conv_id] # 从聊天历史中删除
|
|
|
self.app.conversations.remove(conv_id) # 从对话列表中删除
|
|
|
|
|
|
# 如果删除的是当前对话,切换到第一个剩余对话
|
|
|
if conv_id == self.app.current_conversation_id:
|
|
|
self.switch_conversation(self.app.conversations[0])
|
|
|
|
|
|
# 更新UI界面
|
|
|
self._update_conversation_list() # 更新对话列表显示
|
|
|
self.app.update_chat_display() # 更新聊天显示
|
|
|
|
|
|
# 保存更新后的聊天历史
|
|
|
self._save_chat_history()
|
|
|
except (ValueError, KeyError):
|
|
|
# 如果出现错误(如对话ID不存在),忽略错误并返回
|
|
|
return
|
|
|
|
|
|
def clear_chat(self):
|
|
|
"""清空当前聊天记录
|
|
|
|
|
|
该方法执行以下操作:
|
|
|
1. 清除当前消息列表
|
|
|
2. 清除当前对话的所有消息记录
|
|
|
3. 更新当前对话的最后更新时间
|
|
|
4. 更新聊天界面显示
|
|
|
5. 保存更新后的聊天历史
|
|
|
6. 更新对话列表显示
|
|
|
"""
|
|
|
# 清除当前消息列表
|
|
|
self.app.messages.clear()
|
|
|
|
|
|
# 如果存在当前对话,清除其消息记录并更新最后更新时间
|
|
|
if self.app.current_conversation_id:
|
|
|
self.app.chat_histories[self.app.current_conversation_id]["messages"] = []
|
|
|
self.app.chat_histories[self.app.current_conversation_id]["last_updated"] = datetime.now().isoformat()
|
|
|
|
|
|
# 更新UI界面
|
|
|
self.app.update_chat_display() # 更新聊天显示
|
|
|
|
|
|
# 保存更新后的聊天历史
|
|
|
self._save_chat_history()
|
|
|
|
|
|
# 更新对话列表(反映最后更新时间的变化)
|
|
|
self._update_conversation_list()
|
|
|
|
|
|
def _save_chat_history(self):
|
|
|
"""保存聊天历史到本地文件
|
|
|
|
|
|
该方法执行以下操作:
|
|
|
1. 确保data目录存在
|
|
|
2. 根据当前登录用户选择合适的文件名(每个用户有独立的历史文件)
|
|
|
3. 准备要保存的数据结构
|
|
|
4. 遍历所有对话,筛选并处理要保存的消息
|
|
|
5. 将数据写入JSON文件
|
|
|
|
|
|
注意:
|
|
|
- 不保存"思考中"状态的消息
|
|
|
- 使用UTF-8编码确保中文正常显示
|
|
|
- 格式化JSON输出以便于人类阅读
|
|
|
"""
|
|
|
try:
|
|
|
# 确保data目录存在,如果不存在则创建
|
|
|
os.makedirs("data", exist_ok=True)
|
|
|
|
|
|
# 获取当前登录用户名
|
|
|
current_user = self.app.current_username
|
|
|
if not current_user:
|
|
|
# 如果没有登录用户,使用默认文件名
|
|
|
chat_history_file = self.default_chat_history_file
|
|
|
else:
|
|
|
# 为每个用户创建一个单独的聊天历史文件,使用os.path.join确保跨平台兼容
|
|
|
chat_history_file = os.path.join("data", f"chat_history_{current_user}.json")
|
|
|
|
|
|
# 准备要保存的数据结构
|
|
|
chat_data = {
|
|
|
"last_updated": datetime.now().isoformat(), # 保存时间
|
|
|
"current_conversation_id": self.app.current_conversation_id, # 当前对话ID
|
|
|
"conversations": self.app.conversations.copy(), # 对话列表顺序
|
|
|
"chat_histories": [] # 对话历史列表
|
|
|
}
|
|
|
|
|
|
# 遍历所有对话并保存
|
|
|
for conv_id, conv in self.app.chat_histories.items():
|
|
|
# 确保时间戳是字符串格式
|
|
|
last_updated = conv["last_updated"]
|
|
|
if hasattr(last_updated, "isoformat"):
|
|
|
last_updated = last_updated.isoformat()
|
|
|
|
|
|
conv_data = {
|
|
|
"id": conv_id, # 对话ID
|
|
|
"title": conv["title"], # 对话标题
|
|
|
"last_updated": last_updated, # 最后更新时间(确保是字符串)
|
|
|
"messages": [] # 消息列表
|
|
|
}
|
|
|
|
|
|
# 只保存用户和助手的实际消息,不保存"思考中"状态的临时消息
|
|
|
for msg in conv["messages"]:
|
|
|
if msg.get("thinking"): # 跳过思考中状态的消息
|
|
|
continue
|
|
|
|
|
|
# 确保时间戳是字符串格式
|
|
|
timestamp = msg["timestamp"]
|
|
|
if hasattr(timestamp, "isoformat"):
|
|
|
timestamp = timestamp.isoformat()
|
|
|
|
|
|
# 复制消息的关键字段
|
|
|
conv_data["messages"].append({
|
|
|
"role": msg["role"], # 角色(user/assistant)
|
|
|
"content": msg["content"], # 消息内容
|
|
|
"timestamp": timestamp # 时间戳(确保是字符串)
|
|
|
})
|
|
|
|
|
|
# 将对话添加到保存数据中
|
|
|
chat_data["chat_histories"].append(conv_data)
|
|
|
|
|
|
# 确保保存的是对话ID列表而不是对话数据
|
|
|
chat_data["conversations"] = self.app.conversations.copy()
|
|
|
|
|
|
# 将数据写入JSON文件
|
|
|
with open(chat_history_file, "w", encoding="utf-8") as f:
|
|
|
json.dump(chat_data, f, ensure_ascii=False, indent=2)
|
|
|
except Exception as e:
|
|
|
# 打印错误信息但不中断程序
|
|
|
print(f"保存聊天历史失败: {e}")
|
|
|
|
|
|
def load_chat_history(self):
|
|
|
"""从本地文件加载聊天历史
|
|
|
|
|
|
该方法执行以下操作:
|
|
|
1. 确保data目录存在
|
|
|
2. 根据当前登录用户选择合适的历史文件
|
|
|
3. 检查历史文件是否存在
|
|
|
4. 如果存在,加载并解析JSON数据
|
|
|
5. 清空现有对话和消息
|
|
|
6. 加载所有对话和消息
|
|
|
7. 处理时间戳格式转换
|
|
|
8. 更新对话列表显示
|
|
|
9. 兼容旧版本数据结构
|
|
|
10. 如果没有历史记录或加载失败,创建新对话
|
|
|
|
|
|
异常处理:
|
|
|
- 处理文件不存在的情况
|
|
|
- 处理JSON解析错误
|
|
|
- 处理时间戳格式错误
|
|
|
- 兼容旧版本数据结构
|
|
|
"""
|
|
|
try:
|
|
|
# 确保data目录存在,如果不存在则创建
|
|
|
os.makedirs("data", exist_ok=True)
|
|
|
|
|
|
# 获取当前登录用户名
|
|
|
current_user = self.app.current_username
|
|
|
if not current_user:
|
|
|
# 如果没有登录用户,使用默认文件名
|
|
|
chat_history_file = self.default_chat_history_file
|
|
|
else:
|
|
|
# 为每个用户创建一个单独的聊天历史文件
|
|
|
chat_history_file = f"data/chat_history_{current_user}.json"
|
|
|
|
|
|
# 检查历史文件是否存在,并且不是目录
|
|
|
if os.path.exists(chat_history_file) and not os.path.isdir(chat_history_file):
|
|
|
try:
|
|
|
# 读取并解析JSON文件
|
|
|
with open(chat_history_file, "r", encoding="utf-8") as f:
|
|
|
chat_data = json.load(f)
|
|
|
except json.JSONDecodeError as e:
|
|
|
# JSON解析错误,创建新对话
|
|
|
print(f"JSON解析错误: {e}")
|
|
|
self.create_new_conversation()
|
|
|
return
|
|
|
except Exception as e:
|
|
|
# 其他文件读取错误,创建新对话
|
|
|
print(f"读取聊天历史文件失败: {e}")
|
|
|
self.create_new_conversation()
|
|
|
return
|
|
|
else:
|
|
|
# 文件不存在或为目录,创建新对话
|
|
|
self.create_new_conversation()
|
|
|
return
|
|
|
|
|
|
# 清空现有对话和消息
|
|
|
self.app.conversations.clear()
|
|
|
self.app.chat_histories.clear()
|
|
|
|
|
|
# 加载所有对话历史
|
|
|
for conv in chat_data.get("chat_histories", []):
|
|
|
conv_id = conv.get("id")
|
|
|
if conv_id:
|
|
|
# 处理对话中的消息
|
|
|
messages = []
|
|
|
for msg in conv.get("messages", []):
|
|
|
# 确保消息角色有效
|
|
|
if msg.get("role") not in ["user", "assistant"]:
|
|
|
continue
|
|
|
|
|
|
# 确保消息内容不为空
|
|
|
if not msg.get("content"):
|
|
|
continue
|
|
|
|
|
|
# 确保时间戳存在
|
|
|
if not msg.get("timestamp"):
|
|
|
msg["timestamp"] = datetime.now().isoformat()
|
|
|
|
|
|
try:
|
|
|
# 将时间戳字符串转换为datetime对象
|
|
|
msg["timestamp"] = datetime.fromisoformat(msg["timestamp"])
|
|
|
except:
|
|
|
# 如果解析失败,使用当前时间
|
|
|
msg["timestamp"] = datetime.now()
|
|
|
|
|
|
messages.append(msg) # 添加到消息列表
|
|
|
|
|
|
# 处理对话的最后更新时间
|
|
|
try:
|
|
|
last_updated = datetime.fromisoformat(conv["last_updated"])
|
|
|
except:
|
|
|
last_updated = datetime.now()
|
|
|
|
|
|
# 将对话添加到聊天历史
|
|
|
self.app.chat_histories[conv_id] = {
|
|
|
"title": conv["title"], # 对话标题
|
|
|
"last_updated": last_updated, # 最后更新时间
|
|
|
"messages": messages # 消息列表
|
|
|
}
|
|
|
|
|
|
# 加载对话列表顺序
|
|
|
saved_conversations = chat_data.get("conversations", [])
|
|
|
if saved_conversations:
|
|
|
# 只保留存在于chat_histories中的对话ID
|
|
|
for conv_id in saved_conversations:
|
|
|
if conv_id in self.app.chat_histories:
|
|
|
self.app.conversations.append(conv_id)
|
|
|
|
|
|
# 更新对话列表显示
|
|
|
self._update_conversation_list()
|
|
|
|
|
|
# 设置当前对话ID和加载对应的消息列表
|
|
|
if self.app.conversations:
|
|
|
# 尝试加载保存的当前对话ID
|
|
|
saved_current_id = chat_data.get("current_conversation_id")
|
|
|
if saved_current_id and saved_current_id in self.app.conversations:
|
|
|
self.app.current_conversation_id = saved_current_id
|
|
|
else:
|
|
|
# 如果保存的当前对话ID无效,使用第一个对话
|
|
|
self.app.current_conversation_id = self.app.conversations[0]
|
|
|
|
|
|
# 加载当前对话的消息列表
|
|
|
self.app.messages.clear()
|
|
|
self.app.messages.extend(self.app.chat_histories[self.app.current_conversation_id]["messages"])
|
|
|
# 更新聊天显示
|
|
|
self.app.update_chat_display()
|
|
|
self.app.scroll_to_bottom()
|
|
|
else:
|
|
|
# 兼容旧版本数据结构(只有一个对话)或没有对话时
|
|
|
self.create_new_conversation() # 创建新对话
|
|
|
|
|
|
# 加载旧版本的消息
|
|
|
for msg in chat_data.get("messages", []):
|
|
|
try:
|
|
|
# 将时间戳字符串转换为datetime对象
|
|
|
msg["timestamp"] = datetime.fromisoformat(msg["timestamp"])
|
|
|
except:
|
|
|
# 如果解析失败,使用当前时间
|
|
|
msg["timestamp"] = datetime.now()
|
|
|
|
|
|
# 添加到当前消息列表和聊天历史
|
|
|
self.app.messages.append(msg)
|
|
|
self.app.chat_histories[self.app.current_conversation_id]["messages"].append(msg)
|
|
|
|
|
|
# 更新对话列表
|
|
|
self._update_conversation_list()
|
|
|
# 保存聊天历史(确保数据一致性)
|
|
|
self._save_chat_history()
|
|
|
except Exception as e:
|
|
|
# 处理任何未捕获的异常
|
|
|
print(f"加载聊天历史失败: {e}")
|
|
|
# 如果加载失败,创建新对话
|
|
|
self.create_new_conversation()
|