Browse Source

上传聊天图片显示问题

newdev_shunjiawei
liwei1dao 1 year ago
parent
commit
f5b9044901
  1. 4
      lib/data/models/message_model.dart
  2. 41
      lib/modules/agent/controllers/agent_controller.dart
  3. 4
      lib/modules/agent/views/message_bubble.dart
  4. 4
      local_plugins/agent_service/android/src/main/kotlin/com/yunqiinnovation/agent_service/AgentService.kt
  5. 17
      local_plugins/agent_service/ios/agent_service/Sources/agent_service/AgentServiceImpl.swift
  6. 6
      local_plugins/chat_storage/ios/chat_storage/Sources/chat_storage/ChatStorageHelper.swift

4
lib/data/models/message_model.dart

@ -1,3 +1,7 @@
import 'dart:io';
import 'package:path_provider/path_provider.dart';
class Message { class Message {
final bool isUser; //标识信息是否来自用户还是AI final bool isUser; //标识信息是否来自用户还是AI
final String text; //信息文本内容 final String text; //信息文本内容

41
lib/modules/agent/controllers/agent_controller.dart

@ -126,7 +126,7 @@ class AgentController extends GetxController {
String _currentResponseId = ''; String _currentResponseId = '';
final TAG = 'AgentController'; final TAG = 'AgentController';
var AppDir = "".obs;
// 会话ID // 会话ID
final String sessionId = 'default_agent'; final String sessionId = 'default_agent';
@ -153,6 +153,7 @@ class AgentController extends GetxController {
@override @override
void onInit() { void onInit() {
super.onInit(); super.onInit();
_initAppDir();
_loadTtsPreference(); //加载TTS偏好设置 _loadTtsPreference(); //加载TTS偏好设置
_setupScrollListener(); //设置滚动监听器 _setupScrollListener(); //设置滚动监听器
_loadChatHistory(); //加载聊天历史记录 _loadChatHistory(); //加载聊天历史记录
@ -164,6 +165,10 @@ class AgentController extends GetxController {
startVoiceInput(); //开启语音输入 startVoiceInput(); //开启语音输入
} }
Future<void> _initAppDir() async {
AppDir.value = (await getApplicationDocumentsDirectory()).path;
}
// 初始化音乐播放状态 // 初始化音乐播放状态
Future<void> _initMusicStatus() async { Future<void> _initMusicStatus() async {
try { try {
@ -291,7 +296,7 @@ class AgentController extends GetxController {
page: 1, //从第一页开始 page: 1, //从第一页开始
pageSize: pageSize, //每页20条记录 pageSize: pageSize, //每页20条记录
); );
Logger.i(TAG, '加载聊天历史记录: $result');
if (result.messages.isNotEmpty) { if (result.messages.isNotEmpty) {
// 转换并添加消息到列表 // 转换并添加消息到列表
final historyMessages = _convertChatMessagesToMessages(result.messages); final historyMessages = _convertChatMessagesToMessages(result.messages);
@ -303,7 +308,8 @@ class AgentController extends GetxController {
// 更新分页状态 // 更新分页状态
currentPage.value = 1; currentPage.value = 1;
hasMoreMessages.value = result.totalPages > 1; hasMoreMessages.value = result.totalPages > 1;
print(
'liwei-------------读取历史记录 ${AppDir.value}${historyMessages[0].imagePath}');
Logger.i(TAG, Logger.i(TAG,
'成功加载 ${historyMessages.length} 条聊天记录,总页数: ${result.totalPages}'); '成功加载 ${historyMessages.length} 条聊天记录,总页数: ${result.totalPages}');
_logMessageDetails(historyMessages); _logMessageDetails(historyMessages);
@ -421,7 +427,7 @@ class AgentController extends GetxController {
'meta: ${msg.meta != null ? "有" : "无"}' 'meta: ${msg.meta != null ? "有" : "无"}'
'}'); '}');
} }
Logger.d(TAG, '===== 历史消息详情结束 ====='); Logger.d(TAG, '===== 历史消息详情结束 ==lishi===');
} }
// 设置滚动监听器 // 设置滚动监听器
@ -903,10 +909,14 @@ class AgentController extends GetxController {
} }
// 复制图片到应用永久存储目录 // 复制图片到应用永久存储目录
final permanentImagePath = await _copyImageToPermanentStorage(imagePath); // 复制图片到应用永久存储目录
final imagePathResult = await _copyImageToPermanentStorage(imagePath);
final permanentImagePath = imagePathResult['fullPath']!;
final relativeImagePath = imagePathResult['relativePath']!;
var ImageUrl = await UploadOss.upload( var ImageUrl = await UploadOss.upload(
filepath: imagePath, rootDir: 'User/${User.instance.uid}/ChatImages'); filepath: permanentImagePath,
Logger.i(TAG, '图片上传: $imagePath URL: $ImageUrl'); rootDir: 'User/${User.instance.uid}/ChatImages');
Logger.i(TAG, '图片上传: $permanentImagePath URL: $ImageUrl');
// 显示的文本,如果没有提供则使用默认值 // 显示的文本,如果没有提供则使用默认值
final displayText = text?.isNotEmpty == true ? text! : '[图片]'; final displayText = text?.isNotEmpty == true ? text! : '[图片]';
@ -915,7 +925,7 @@ class AgentController extends GetxController {
isUser: true, isUser: true,
text: displayText, text: displayText,
hasImage: true, hasImage: true,
imagePath: permanentImagePath, imagePath: relativeImagePath,
); );
messages.add(message); messages.add(message);
@ -935,7 +945,7 @@ class AgentController extends GetxController {
// 调用Agent Service处理图片,考虑TTS状态 // 调用Agent Service处理图片,考虑TTS状态
await AgentService.processImageInput( await AgentService.processImageInput(
permanentImagePath, relativeImagePath,
ImageUrl, ImageUrl,
text: text ?? '', text: text ?? '',
speakResponse: isTtsEnabled.value, speakResponse: isTtsEnabled.value,
@ -948,12 +958,16 @@ class AgentController extends GetxController {
} }
// 将图片复制到应用的永久存储目录 // 将图片复制到应用的永久存储目录
Future<String> _copyImageToPermanentStorage(String sourcePath) async { Future<Map<String, String>> _copyImageToPermanentStorage(
String sourcePath) async {
try { try {
final File sourceFile = File(sourcePath); final File sourceFile = File(sourcePath);
if (!await sourceFile.exists()) { if (!await sourceFile.exists()) {
Logger.e(TAG, '源图片文件不存在: $sourcePath'); Logger.e(TAG, '源图片文件不存在: $sourcePath');
return sourcePath; // 如果源文件不存在,返回原路径 return {
'fullPath': sourcePath,
'relativePath': sourcePath
}; // 如果源文件不存在,返回原路径
} }
// 创建应用文档目录下的chatImages文件夹 // 创建应用文档目录下的chatImages文件夹
@ -967,15 +981,16 @@ class AgentController extends GetxController {
final fileName = final fileName =
'${DateTime.now().millisecondsSinceEpoch}_${sourcePath.split('/').last}'; '${DateTime.now().millisecondsSinceEpoch}_${sourcePath.split('/').last}';
final targetPath = '${imagesDir.path}/$fileName'; final targetPath = '${imagesDir.path}/$fileName';
final relativePath = '/chatImages/$fileName';
// 复制文件 // 复制文件
await sourceFile.copy(targetPath); await sourceFile.copy(targetPath);
Logger.i(TAG, '图片已复制到永久存储: $targetPath'); Logger.i(TAG, '图片已复制到永久存储: $targetPath');
return targetPath; return {'fullPath': targetPath, 'relativePath': relativePath};
} catch (e) { } catch (e) {
Logger.e(TAG, '复制图片到永久存储失败: $e'); Logger.e(TAG, '复制图片到永久存储失败: $e');
return sourcePath; // 出错时返回原路径 return {'fullPath': sourcePath, 'relativePath': sourcePath}; // 出错时返回原路径
} }
} }

4
lib/modules/agent/views/message_bubble.dart

@ -169,7 +169,7 @@ class MessageBubble extends GetView<AgentController> {
child: ClipRRect( child: ClipRRect(
borderRadius: BorderRadius.circular(12), borderRadius: BorderRadius.circular(12),
child: Image.file( child: Image.file(
File(imagePath!), File('${controller.AppDir.value}$imagePath'),
width: 200, width: 200,
height: 200, height: 200,
fit: BoxFit.cover, fit: BoxFit.cover,
@ -202,7 +202,7 @@ class MessageBubble extends GetView<AgentController> {
child: ClipRRect( child: ClipRRect(
borderRadius: BorderRadius.circular(12), borderRadius: BorderRadius.circular(12),
child: Image.file( child: Image.file(
File(imagePath!), File('${controller.AppDir.value}$imagePath'),
width: 200, width: 200,
height: 200, height: 200,
fit: BoxFit.cover, fit: BoxFit.cover,

4
local_plugins/agent_service/android/src/main/kotlin/com/yunqiinnovation/agent_service/AgentService.kt

@ -526,8 +526,8 @@ object AgentService : CoroutineScope {
_hasSpeechDetected.set(true) _hasSpeechDetected.set(true)
if (!previousHasSpeech) { if (!previousHasSpeech) {
restartIdleCheck() restartIdleCheck()
} }
sendEvent( sendEvent(
"recognizing", mapOf( "recognizing", mapOf(

17
local_plugins/agent_service/ios/agent_service/Sources/agent_service/AgentServiceImpl.swift

@ -469,8 +469,8 @@ audioStream.saveAudioDataTo(data: audioData)
processWithChatApiServiceInternal(userMessage: userMessage, displayText: text, speakResponse: speakResponse) processWithChatApiServiceInternal(userMessage: userMessage, displayText: text, speakResponse: speakResponse)
} }
private func processWithChatApiServiceInternal(userMessage: [String: Any], displayText: String, speakResponse: Bool = true, hasImage: Bool = false) { private func processWithChatApiServiceInternal(userMessage: [String: Any], displayText: String, speakResponse: Bool = true, hasImage: Bool = false,imagePath:String = "") {
os_log("开始处理ChatAPI请求: displayText=%{public}@, speakResponse=%{public}@, hasImage=%{public}@", os_log("开始处理ChatAPI请求: displayText=%{public}@, speakResponse=%{public}@, hasImage=%{public}@",
log: logger, type: .info, displayText, speakResponse ? "是" : "否", hasImage ? "是" : "否") log: logger, type: .info, displayText, speakResponse ? "是" : "否", hasImage ? "是" : "否")
guard let chatApiService = chatApiService else { guard let chatApiService = chatApiService else {
@ -517,7 +517,8 @@ audioStream.saveAudioDataTo(data: audioData)
agentService: self, agentService: self,
speakResponse: speakResponse, speakResponse: speakResponse,
displayText: displayText, displayText: displayText,
hasImage: hasImage hasImage: hasImage,
imagePath: imagePath
) )
currsessionId = UUID().uuidString currsessionId = UUID().uuidString
os_log("设置回调并调用sendMessageStream", log: logger, type: .info) os_log("设置回调并调用sendMessageStream", log: logger, type: .info)
@ -574,7 +575,8 @@ audioStream.saveAudioDataTo(data: audioData)
userMessage: userMessage, userMessage: userMessage,
displayText: displayText, displayText: displayText,
speakResponse: speakResponse, speakResponse: speakResponse,
hasImage: true hasImage: true,
imagePath: imagePath
) )
} }
} }
@ -1132,19 +1134,22 @@ class ChatApiStreamCallback: StreamCallback {
private let speakResponse: Bool private let speakResponse: Bool
private let displayText: String private let displayText: String
private let hasImage: Bool private let hasImage: Bool
private let imagePath: String
private var responseBuilder = "" private var responseBuilder = ""
private var metadata = "" private var metadata = ""
private var userMetadata:[String: Any] = [:] private var userMetadata:[String: Any] = [:]
private var reply = true; //是否回复 private var reply = true; //是否回复
private var broadcast = true //是否播发 private var broadcast = true //是否播发
init(agentService: AgentServiceImpl, speakResponse: Bool, displayText: String, hasImage: Bool) { init(agentService: AgentServiceImpl, speakResponse: Bool, displayText: String, hasImage: Bool,imagePath:String) {
self.agentService = agentService self.agentService = agentService
self.speakResponse = speakResponse self.speakResponse = speakResponse
self.displayText = displayText self.displayText = displayText
self.hasImage = hasImage self.hasImage = hasImage
self.imagePath = imagePath
self.userMetadata["hasImage"] = hasImage
self.userMetadata["imagePath"] = imagePath
} }
func onUsage(_ sessionid: String,_ prompt_tokens: Int?,_ completion_tokens: Int?,_ total_tokens: Int?){ func onUsage(_ sessionid: String,_ prompt_tokens: Int?,_ completion_tokens: Int?,_ total_tokens: Int?){

6
local_plugins/chat_storage/ios/chat_storage/Sources/chat_storage/ChatStorageHelper.swift

@ -186,7 +186,7 @@ public class ChatStorageHelper {
"totalCount": totalCount, "totalCount": totalCount,
"totalPages": totalPages "totalPages": totalPages
] ]
os_log("getMessages: 读取历史记录: %{public}@", log: logger, type: .error, messagesArray)
do { do {
let jsonData = try JSONSerialization.data(withJSONObject: result, options: []) let jsonData = try JSONSerialization.data(withJSONObject: result, options: [])
if let jsonString = String(data: jsonData, encoding: .utf8) { if let jsonString = String(data: jsonData, encoding: .utf8) {
@ -199,7 +199,7 @@ public class ChatStorageHelper {
let errmsg = String(cString: sqlite3_errmsg(db)!) let errmsg = String(cString: sqlite3_errmsg(db)!)
os_log("getMessages: SQL准备失败: %{public}@", log: logger, type: .error, errmsg) os_log("getMessages: SQL准备失败: %{public}@", log: logger, type: .error, errmsg)
} }
// 返回空结果,但保持格式一致 // 返回空结果,但保持格式一致
let emptyResult: [String: Any] = [ let emptyResult: [String: Any] = [
"messages": [], "messages": [],
@ -370,4 +370,4 @@ public class ChatStorageHelper {
return messages return messages
} }
} }

Loading…
Cancel
Save