feat(chat): implement ChatViewModel for state management

This commit is contained in:
844143714@qq,com 2026-05-19 21:18:41 +08:00
parent fcf63c6175
commit 62ef1e2c38
1 changed files with 98 additions and 0 deletions

View File

@ -0,0 +1,98 @@
package com.stand.standapp.ui.chat
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.stand.standapp.ui.chat.model.ChatMessage
import com.stand.standapp.ui.chat.model.ChatSession
import com.stand.standapp.ui.chat.repo.AiChatRepository
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.onCompletion
import kotlinx.coroutines.launch
import java.util.UUID
class ChatViewModel : ViewModel() {
private val repository = AiChatRepository()
private val _sessions = MutableStateFlow<List<ChatSession>>(emptyList())
val sessions: StateFlow<List<ChatSession>> = _sessions.asStateFlow()
private val _currentSessionId = MutableStateFlow<String?>(null)
val currentSessionId: StateFlow<String?> = _currentSessionId.asStateFlow()
private val _messages = MutableStateFlow<List<ChatMessage>>(emptyList())
val messages: StateFlow<List<ChatMessage>> = _messages.asStateFlow()
init {
createNewSession()
}
fun createNewSession() {
val newSession = ChatSession()
_sessions.value = listOf(newSession) + _sessions.value
_currentSessionId.value = newSession.id
}
fun switchSession(sessionId: String) {
_currentSessionId.value = sessionId
}
fun sendMessage(content: String) {
val sessionId = _currentSessionId.value ?: return
// 1. 如果是新会话,更新标题
updateSessionTitleIfFirstMessage(sessionId, content)
// 2. 添加用户消息
val userMsg = ChatMessage(sessionId = sessionId, role = ChatMessage.Role.USER, content = content)
// 3. 准备 AI 空消息,处于 streaming 状态
val aiMsgId = UUID.randomUUID().toString()
val aiMsg = ChatMessage(id = aiMsgId, sessionId = sessionId, role = ChatMessage.Role.AI, content = "", isStreaming = true)
_messages.value = _messages.value + userMsg + aiMsg
// 4. 发起网络请求,流式追加内容
viewModelScope.launch {
repository.streamChat(content)
.catch { e ->
appendAiMessageChunk(aiMsgId, "\n[请求异常: ${e.message}]")
finalizeAiMessage(aiMsgId)
}
.onCompletion {
finalizeAiMessage(aiMsgId)
}
.collect { chunk ->
appendAiMessageChunk(aiMsgId, chunk)
}
}
}
private fun appendAiMessageChunk(messageId: String, chunk: String) {
_messages.value = _messages.value.map { msg ->
if (msg.id == messageId) {
msg.copy(content = msg.content + chunk)
} else msg
}
}
private fun finalizeAiMessage(messageId: String) {
_messages.value = _messages.value.map { msg ->
if (msg.id == messageId) {
msg.copy(isStreaming = false)
} else msg
}
}
private fun updateSessionTitleIfFirstMessage(sessionId: String, content: String) {
val isFirst = _messages.value.none { it.sessionId == sessionId }
if (isFirst) {
val title = if (content.length > 10) content.take(10) + "..." else content
_sessions.value = _sessions.value.map {
if (it.id == sessionId) it.copy(title = title) else it
}
}
}
}