|
|
@ -120,6 +120,13 @@ class AgentController extends GetxController { |
|
|
// 会话ID |
|
|
// 会话ID |
|
|
final String sessionId = 'default_agent'; |
|
|
final String sessionId = 'default_agent'; |
|
|
|
|
|
|
|
|
|
|
|
// 分页加载相关状态 |
|
|
|
|
|
final isLoadingMore = false.obs; // 是否正在加载更多消息 |
|
|
|
|
|
final hasMoreMessages = true.obs; // 是否还有更多消息 |
|
|
|
|
|
final currentPage = 1.obs; // 当前页码 |
|
|
|
|
|
final pageSize = 20; // 每页消息数量 |
|
|
|
|
|
final isLoadingMoreError = false.obs; // 加载更多时是否出错 |
|
|
|
|
|
|
|
|
// 是否已加载聊天记录 |
|
|
// 是否已加载聊天记录 |
|
|
final isHistoryLoaded = false.obs; |
|
|
final isHistoryLoaded = false.obs; |
|
|
|
|
|
|
|
|
@ -137,6 +144,7 @@ class AgentController extends GetxController { |
|
|
void onInit() { |
|
|
void onInit() { |
|
|
super.onInit(); |
|
|
super.onInit(); |
|
|
_loadTtsPreference(); //加载TTS偏好设置 |
|
|
_loadTtsPreference(); //加载TTS偏好设置 |
|
|
|
|
|
_setupScrollListener(); //设置滚动监听器 |
|
|
_loadChatHistory(); //加载聊天历史记录 |
|
|
_loadChatHistory(); //加载聊天历史记录 |
|
|
_subscribeToEvents(); //订阅代理服务事件 |
|
|
_subscribeToEvents(); //订阅代理服务事件 |
|
|
_initMusicStatus(); //初始化音乐状态 |
|
|
_initMusicStatus(); //初始化音乐状态 |
|
|
@ -270,63 +278,33 @@ class AgentController extends GetxController { |
|
|
final result = await ChatStorage.getMessages( |
|
|
final result = await ChatStorage.getMessages( |
|
|
sessionId: sessionId, //会话ID |
|
|
sessionId: sessionId, //会话ID |
|
|
page: 1, //从第一页开始 |
|
|
page: 1, //从第一页开始 |
|
|
pageSize: 20, //每页20条记录 |
|
|
pageSize: pageSize, //每页20条记录 |
|
|
); |
|
|
); |
|
|
|
|
|
|
|
|
if (result.messages.isNotEmpty) { |
|
|
if (result.messages.isNotEmpty) { |
|
|
// 转换并添加消息到列表 |
|
|
// 转换并添加消息到列表 |
|
|
final historyMessages = result.messages.map((msg) { |
|
|
final historyMessages = _convertChatMessagesToMessages(result.messages); |
|
|
final meta = msg.metadata != null && msg.metadata != "" |
|
|
|
|
|
? jsonDecode(msg.metadata!) |
|
|
|
|
|
: null; // 如果为空,使用空对象 |
|
|
|
|
|
|
|
|
|
|
|
// 从元数据中提取图片信息 |
|
|
|
|
|
final hasImage = meta != null && meta.containsKey('hasImage') |
|
|
|
|
|
? meta['hasImage'] as bool |
|
|
|
|
|
: false; |
|
|
|
|
|
final imagePath = meta != null && meta.containsKey('imagePath') |
|
|
|
|
|
? meta['imagePath'] as String? |
|
|
|
|
|
: null; |
|
|
|
|
|
|
|
|
|
|
|
return Message( |
|
|
|
|
|
isUser: msg.sender == 'user', |
|
|
|
|
|
text: msg.message, |
|
|
|
|
|
meta: meta, |
|
|
|
|
|
timestamp: DateTime.parse(msg.timestamp), |
|
|
|
|
|
hasImage: hasImage, |
|
|
|
|
|
imagePath: imagePath, |
|
|
|
|
|
); |
|
|
|
|
|
}).toList(); |
|
|
|
|
|
|
|
|
|
|
|
// 消息按时间排序,最新的消息在底部 |
|
|
// 消息按时间排序,最新的消息在底部 |
|
|
historyMessages.sort((a, b) => a.timestamp.compareTo(b.timestamp)); |
|
|
historyMessages.sort((a, b) => a.timestamp.compareTo(b.timestamp)); |
|
|
messages.assignAll(historyMessages); |
|
|
messages.assignAll(historyMessages); |
|
|
|
|
|
|
|
|
Logger.i(TAG, '成功加载 ${historyMessages.length} 条聊天记录'); |
|
|
// 更新分页状态 |
|
|
// 详细打印每条消息的内容和属性,便于调试 |
|
|
currentPage.value = 1; |
|
|
Logger.d(TAG, '===== 历史消息详情开始 ====='); |
|
|
hasMoreMessages.value = result.totalPages > 1; |
|
|
for (int i = 0; i < historyMessages.length; i++) { |
|
|
|
|
|
final msg = historyMessages[i]; |
|
|
Logger.i(TAG, '成功加载 ${historyMessages.length} 条聊天记录,总页数: ${result.totalPages}'); |
|
|
Logger.d( |
|
|
_logMessageDetails(historyMessages); |
|
|
TAG, |
|
|
|
|
|
'消息[$i]: {' |
|
|
|
|
|
'isUser: ${msg.isUser}, ' |
|
|
|
|
|
'text: "${msg.text.length > 50 ? msg.text.substring(0, 50) + "..." : msg.text}", ' |
|
|
|
|
|
'time: ${msg.timestamp}, ' |
|
|
|
|
|
'hasImage: ${msg.hasImage}, ' |
|
|
|
|
|
'imagePath: ${msg.imagePath ?? "无"}, ' |
|
|
|
|
|
'meta: ${msg.meta != null ? "有" : "无"}' |
|
|
|
|
|
'}'); |
|
|
|
|
|
} |
|
|
|
|
|
Logger.d(TAG, '===== 历史消息详情结束 ====='); |
|
|
|
|
|
} else { |
|
|
} else { |
|
|
// 没有历史记录时添加欢迎消息 |
|
|
// 没有历史记录时添加欢迎消息 |
|
|
_addWelcomeMessage(); |
|
|
_addWelcomeMessage(); |
|
|
|
|
|
hasMoreMessages.value = false; |
|
|
Logger.i(TAG, '没有历史记录,添加欢迎消息'); |
|
|
Logger.i(TAG, '没有历史记录,添加欢迎消息'); |
|
|
} |
|
|
} |
|
|
} catch (e) { |
|
|
} catch (e) { |
|
|
Logger.e(TAG, '加载聊天历史失败: $e'); |
|
|
Logger.e(TAG, '加载聊天历史失败: $e'); |
|
|
_addWelcomeMessage(); |
|
|
_addWelcomeMessage(); |
|
|
|
|
|
hasMoreMessages.value = false; |
|
|
} finally { |
|
|
} finally { |
|
|
isHistoryLoaded.value = true; |
|
|
isHistoryLoaded.value = true; |
|
|
messages.refresh(); |
|
|
messages.refresh(); |
|
|
@ -334,6 +312,137 @@ class AgentController extends GetxController { |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 加载更多历史消息(分页加载) |
|
|
|
|
|
Future<void> loadMoreMessages() async { |
|
|
|
|
|
// 防止重复加载 |
|
|
|
|
|
if (isLoadingMore.value || !hasMoreMessages.value) { |
|
|
|
|
|
Logger.d(TAG, '跳过加载更多:isLoadingMore=${isLoadingMore.value}, hasMoreMessages=${hasMoreMessages.value}'); |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
try { |
|
|
|
|
|
isLoadingMore.value = true; |
|
|
|
|
|
isLoadingMoreError.value = false; |
|
|
|
|
|
|
|
|
|
|
|
final nextPage = currentPage.value + 1; |
|
|
|
|
|
Logger.i(TAG, '正在加载第 $nextPage 页历史消息...'); |
|
|
|
|
|
|
|
|
|
|
|
final result = await ChatStorage.getMessages( |
|
|
|
|
|
sessionId: sessionId, |
|
|
|
|
|
page: nextPage, |
|
|
|
|
|
pageSize: pageSize, |
|
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
if (result.messages.isNotEmpty) { |
|
|
|
|
|
// 转换新消息 |
|
|
|
|
|
final newMessages = _convertChatMessagesToMessages(result.messages); |
|
|
|
|
|
|
|
|
|
|
|
// 按时间排序新消息 |
|
|
|
|
|
newMessages.sort((a, b) => a.timestamp.compareTo(b.timestamp)); |
|
|
|
|
|
|
|
|
|
|
|
// 添加短暂延迟,让用户感知到加载过程 |
|
|
|
|
|
await Future.delayed(const Duration(milliseconds: 300)); |
|
|
|
|
|
|
|
|
|
|
|
// 将新消息插入到现有消息列表的开头(因为是历史消息) |
|
|
|
|
|
final updatedMessages = [...newMessages, ...messages]; |
|
|
|
|
|
messages.assignAll(updatedMessages); |
|
|
|
|
|
|
|
|
|
|
|
// 更新分页状态 |
|
|
|
|
|
currentPage.value = nextPage; |
|
|
|
|
|
hasMoreMessages.value = nextPage < result.totalPages; |
|
|
|
|
|
|
|
|
|
|
|
Logger.i(TAG, '成功加载 ${newMessages.length} 条历史消息,当前页: $nextPage/${result.totalPages}'); |
|
|
|
|
|
} else { |
|
|
|
|
|
// 没有更多消息 |
|
|
|
|
|
hasMoreMessages.value = false; |
|
|
|
|
|
Logger.i(TAG, '没有更多历史消息'); |
|
|
|
|
|
} |
|
|
|
|
|
} catch (e) { |
|
|
|
|
|
Logger.e(TAG, '加载更多消息失败: $e'); |
|
|
|
|
|
isLoadingMoreError.value = true; |
|
|
|
|
|
} finally { |
|
|
|
|
|
isLoadingMore.value = false; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 转换ChatMessage到Message的通用方法 |
|
|
|
|
|
List<Message> _convertChatMessagesToMessages(List<ChatMessage> chatMessages) { |
|
|
|
|
|
return chatMessages.map((msg) { |
|
|
|
|
|
final meta = msg.metadata != null && msg.metadata != "" |
|
|
|
|
|
? jsonDecode(msg.metadata!) |
|
|
|
|
|
: null; // 如果为空,使用空对象 |
|
|
|
|
|
|
|
|
|
|
|
// 从元数据中提取图片信息 |
|
|
|
|
|
final hasImage = meta != null && meta.containsKey('hasImage') |
|
|
|
|
|
? meta['hasImage'] as bool |
|
|
|
|
|
: false; |
|
|
|
|
|
final imagePath = meta != null && meta.containsKey('imagePath') |
|
|
|
|
|
? meta['imagePath'] as String? |
|
|
|
|
|
: null; |
|
|
|
|
|
|
|
|
|
|
|
return Message( |
|
|
|
|
|
isUser: msg.sender == 'user', |
|
|
|
|
|
text: msg.message, |
|
|
|
|
|
meta: meta, |
|
|
|
|
|
timestamp: DateTime.parse(msg.timestamp), |
|
|
|
|
|
hasImage: hasImage, |
|
|
|
|
|
imagePath: imagePath, |
|
|
|
|
|
); |
|
|
|
|
|
}).toList(); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 打印消息详情的通用方法 |
|
|
|
|
|
void _logMessageDetails(List<Message> messageList) { |
|
|
|
|
|
Logger.d(TAG, '===== 历史消息详情开始 ====='); |
|
|
|
|
|
for (int i = 0; i < messageList.length; i++) { |
|
|
|
|
|
final msg = messageList[i]; |
|
|
|
|
|
Logger.d( |
|
|
|
|
|
TAG, |
|
|
|
|
|
'消息[$i]: {' |
|
|
|
|
|
'isUser: ${msg.isUser}, ' |
|
|
|
|
|
'text: "${msg.text.length > 50 ? msg.text.substring(0, 50) + "..." : msg.text}", ' |
|
|
|
|
|
'time: ${msg.timestamp}, ' |
|
|
|
|
|
'hasImage: ${msg.hasImage}, ' |
|
|
|
|
|
'imagePath: ${msg.imagePath ?? "无"}, ' |
|
|
|
|
|
'meta: ${msg.meta != null ? "有" : "无"}' |
|
|
|
|
|
'}'); |
|
|
|
|
|
} |
|
|
|
|
|
Logger.d(TAG, '===== 历史消息详情结束 ====='); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 设置滚动监听器 |
|
|
|
|
|
void _setupScrollListener() { |
|
|
|
|
|
scrollController.addListener(() { |
|
|
|
|
|
// 检查是否滚动到顶部(因为使用了reverse: true,顶部实际是最大滚动位置) |
|
|
|
|
|
if (scrollController.position.pixels >= scrollController.position.maxScrollExtent - 100) { |
|
|
|
|
|
// 当距离顶部100像素时触发加载更多 |
|
|
|
|
|
if (hasMoreMessages.value && !isLoadingMore.value) { |
|
|
|
|
|
Logger.d(TAG, '触发加载更多历史消息'); |
|
|
|
|
|
loadMoreMessages(); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
}); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 手动触发加载更多(用于测试或手动调用) |
|
|
|
|
|
void triggerLoadMore() { |
|
|
|
|
|
if (hasMoreMessages.value && !isLoadingMore.value) { |
|
|
|
|
|
Logger.i(TAG, '手动触发加载更多历史消息'); |
|
|
|
|
|
loadMoreMessages(); |
|
|
|
|
|
} else { |
|
|
|
|
|
Logger.w(TAG, '无法加载更多:hasMoreMessages=${hasMoreMessages.value}, isLoadingMore=${isLoadingMore.value}'); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 重置分页状态(用于刷新聊天记录) |
|
|
|
|
|
void resetPagination() { |
|
|
|
|
|
currentPage.value = 1; |
|
|
|
|
|
hasMoreMessages.value = true; |
|
|
|
|
|
isLoadingMore.value = false; |
|
|
|
|
|
isLoadingMoreError.value = false; |
|
|
|
|
|
Logger.i(TAG, '分页状态已重置'); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
// 添加初始欢迎消息 |
|
|
// 添加初始欢迎消息 |
|
|
void _addWelcomeMessage() { |
|
|
void _addWelcomeMessage() { |
|
|
messages.add(Message( |
|
|
messages.add(Message( |
|
|
|