diff --git a/app-android/app/src/main/java/com/huaga/life_echo/data/repository/MessageRepository.kt b/app-android/app/src/main/java/com/huaga/life_echo/data/repository/MessageRepository.kt index 7092a0c..dc813e5 100644 --- a/app-android/app/src/main/java/com/huaga/life_echo/data/repository/MessageRepository.kt +++ b/app-android/app/src/main/java/com/huaga/life_echo/data/repository/MessageRepository.kt @@ -19,10 +19,11 @@ class MessageRepository( return messageDao.getMessagesByConversationId(conversationId) } - /** 从 [conversationApi] 拉取消息并写入本地数据库 */ + /** 从 [conversationApi] 拉取消息并写入本地数据库,以服务端为准替换该会话的本地消息,避免与本地临时消息重复显示 */ suspend fun syncMessages(conversationId: String) { val result = conversationApi.getMessages(conversationId) result.getOrNull()?.let { messages -> + messageDao.deleteMessagesByConversationId(conversationId) val dbMessages = messages.map { dto -> Message( id = dto.id, diff --git a/app-android/app/src/main/java/com/huaga/life_echo/ui/viewmodel/CreateMemoryViewModel.kt b/app-android/app/src/main/java/com/huaga/life_echo/ui/viewmodel/CreateMemoryViewModel.kt index 6ef3277..c324694 100644 --- a/app-android/app/src/main/java/com/huaga/life_echo/ui/viewmodel/CreateMemoryViewModel.kt +++ b/app-android/app/src/main/java/com/huaga/life_echo/ui/viewmodel/CreateMemoryViewModel.kt @@ -658,37 +658,39 @@ class CreateMemoryViewModel( isTyping.value = false } - conversationId.value?.let { id -> - val messageTimestamp = System.currentTimeMillis() - val aiMessage = Message( - id = "ai_${System.currentTimeMillis()}_$index", - conversationId = id, - content = text, - senderType = "assistant", - timestamp = messageTimestamp, - messageType = "text" - ) - viewModelScope.launch { - messageRepository.insertMessage(aiMessage) - updateConversationLatestMessage( - conversationId = id, - messagePreview = text, - timestamp = messageTimestamp, - ) - } - } - + // 用 [SPLIT] 拼接多条,与后端约定一致,便于 UI 按 [SPLIT] 拆成多个气泡 if (index == 0) { agentResponse.value = text } else { - agentResponse.value += "\n\n$text" + agentResponse.value += "[SPLIT]$text" } + // 仅在完整收到一条 AI 回复时插入一次,避免按 index 多次插入导致同一条显示多遍 if (index >= total - 1) { isStreaming.value = false streamingText.value = "" isTyping.value = false conversationRealtime.setGenerating(false) + conversationId.value?.let { id -> + val messageTimestamp = System.currentTimeMillis() + val fullContent = agentResponse.value + val aiMessage = Message( + id = "ai_${System.currentTimeMillis()}", + conversationId = id, + content = fullContent, + senderType = "assistant", + timestamp = messageTimestamp, + messageType = "text" + ) + viewModelScope.launch { + messageRepository.insertMessage(aiMessage) + updateConversationLatestMessage( + conversationId = id, + messagePreview = fullContent, + timestamp = messageTimestamp, + ) + } + } } } MessageType.agent_response_start -> {