UI: migrate ConversationViewModel onto ModelLoadingViewModel; update & refine ConversationScreen
This commit is contained in:
parent
cb508be782
commit
9f1d26ac95
|
|
@ -1,6 +1,7 @@
|
||||||
package com.example.llama.revamp.ui.screens
|
package com.example.llama.revamp.ui.screens
|
||||||
|
|
||||||
import android.llama.cpp.InferenceEngine.State
|
import android.llama.cpp.InferenceEngine.State
|
||||||
|
import androidx.activity.compose.BackHandler
|
||||||
import androidx.compose.animation.core.LinearEasing
|
import androidx.compose.animation.core.LinearEasing
|
||||||
import androidx.compose.animation.core.RepeatMode
|
import androidx.compose.animation.core.RepeatMode
|
||||||
import androidx.compose.animation.core.animateFloat
|
import androidx.compose.animation.core.animateFloat
|
||||||
|
|
@ -55,7 +56,9 @@ import androidx.compose.ui.unit.dp
|
||||||
import androidx.lifecycle.Lifecycle
|
import androidx.lifecycle.Lifecycle
|
||||||
import androidx.lifecycle.LifecycleEventObserver
|
import androidx.lifecycle.LifecycleEventObserver
|
||||||
import androidx.lifecycle.compose.LocalLifecycleOwner
|
import androidx.lifecycle.compose.LocalLifecycleOwner
|
||||||
|
import com.example.llama.revamp.APP_NAME
|
||||||
import com.example.llama.revamp.ui.components.ModelCardWithSystemPrompt
|
import com.example.llama.revamp.ui.components.ModelCardWithSystemPrompt
|
||||||
|
import com.example.llama.revamp.ui.components.ModelUnloadDialogHandler
|
||||||
import com.example.llama.revamp.viewmodel.ConversationViewModel
|
import com.example.llama.revamp.viewmodel.ConversationViewModel
|
||||||
import com.example.llama.revamp.viewmodel.Message
|
import com.example.llama.revamp.viewmodel.Message
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
@ -65,13 +68,14 @@ import kotlinx.coroutines.launch
|
||||||
*/
|
*/
|
||||||
@Composable
|
@Composable
|
||||||
fun ConversationScreen(
|
fun ConversationScreen(
|
||||||
onBackPressed: () -> Unit,
|
onNavigateBack: () -> Unit,
|
||||||
viewModel: ConversationViewModel
|
viewModel: ConversationViewModel
|
||||||
) {
|
) {
|
||||||
val engineState by viewModel.engineState.collectAsState()
|
val engineState by viewModel.engineState.collectAsState()
|
||||||
val messages by viewModel.messages.collectAsState()
|
val messages by viewModel.messages.collectAsState()
|
||||||
val systemPrompt by viewModel.systemPrompt.collectAsState()
|
val systemPrompt by viewModel.systemPrompt.collectAsState()
|
||||||
val selectedModel by viewModel.selectedModel.collectAsState()
|
val selectedModel by viewModel.selectedModel.collectAsState()
|
||||||
|
val unloadDialogState by viewModel.unloadModelState.collectAsState()
|
||||||
|
|
||||||
val isProcessing = engineState is State.ProcessingUserPrompt
|
val isProcessing = engineState is State.ProcessingUserPrompt
|
||||||
val isGenerating = engineState is State.Generating
|
val isGenerating = engineState is State.Generating
|
||||||
|
|
@ -111,6 +115,11 @@ fun ConversationScreen(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handle back navigation requests
|
||||||
|
BackHandler {
|
||||||
|
viewModel.onBackPressed(onNavigateBack)
|
||||||
|
}
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
|
|
@ -145,10 +154,18 @@ fun ConversationScreen(
|
||||||
isEnabled = !isProcessing && !isGenerating
|
isEnabled = !isProcessing && !isGenerating
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Unload confirmation dialog
|
||||||
|
ModelUnloadDialogHandler(
|
||||||
|
unloadModelState = unloadDialogState,
|
||||||
|
onUnloadConfirmed = { viewModel.onUnloadConfirmed(onNavigateBack) },
|
||||||
|
onUnloadDismissed = { viewModel.onUnloadDismissed() },
|
||||||
|
onNavigateBack = onNavigateBack,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun ConversationMessageList(
|
private fun ConversationMessageList(
|
||||||
messages: List<Message>,
|
messages: List<Message>,
|
||||||
listState: LazyListState,
|
listState: LazyListState,
|
||||||
) {
|
) {
|
||||||
|
|
@ -172,7 +189,7 @@ fun ConversationMessageList(
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun MessageBubble(message: Message) {
|
private fun MessageBubble(message: Message) {
|
||||||
when (message) {
|
when (message) {
|
||||||
is Message.User -> UserMessageBubble(
|
is Message.User -> UserMessageBubble(
|
||||||
formattedTime = message.formattedTime,
|
formattedTime = message.formattedTime,
|
||||||
|
|
@ -198,7 +215,7 @@ fun MessageBubble(message: Message) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun UserMessageBubble(content: String, formattedTime: String) {
|
private fun UserMessageBubble(content: String, formattedTime: String) {
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
|
|
@ -235,7 +252,7 @@ fun UserMessageBubble(content: String, formattedTime: String) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun AssistantMessageBubble(
|
private fun AssistantMessageBubble(
|
||||||
formattedTime: String,
|
formattedTime: String,
|
||||||
content: String,
|
content: String,
|
||||||
isThinking: Boolean,
|
isThinking: Boolean,
|
||||||
|
|
@ -323,7 +340,7 @@ fun AssistantMessageBubble(
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun PulsatingDots(small: Boolean = false) {
|
private fun PulsatingDots(small: Boolean = false) {
|
||||||
val transition = rememberInfiniteTransition(label = "dots")
|
val transition = rememberInfiniteTransition(label = "dots")
|
||||||
|
|
||||||
val animations = List(3) { index ->
|
val animations = List(3) { index ->
|
||||||
|
|
@ -363,7 +380,7 @@ fun PulsatingDots(small: Boolean = false) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun ConversationInputField(
|
private fun ConversationInputField(
|
||||||
value: String,
|
value: String,
|
||||||
onValueChange: (String) -> Unit,
|
onValueChange: (String) -> Unit,
|
||||||
onSendClick: () -> Unit,
|
onSendClick: () -> Unit,
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
package com.example.llama.revamp.viewmodel
|
package com.example.llama.revamp.viewmodel
|
||||||
|
|
||||||
import androidx.lifecycle.ViewModel
|
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.example.llama.revamp.engine.ConversationService
|
import com.example.llama.revamp.engine.ConversationService
|
||||||
import com.example.llama.revamp.engine.GenerationUpdate
|
import com.example.llama.revamp.engine.GenerationUpdate
|
||||||
|
|
@ -22,9 +21,8 @@ import javax.inject.Inject
|
||||||
@HiltViewModel
|
@HiltViewModel
|
||||||
class ConversationViewModel @Inject constructor(
|
class ConversationViewModel @Inject constructor(
|
||||||
private val conversationService: ConversationService
|
private val conversationService: ConversationService
|
||||||
) : ViewModel() {
|
) : ModelUnloadingViewModel(conversationService) {
|
||||||
|
|
||||||
val engineState = conversationService.engineState
|
|
||||||
val selectedModel = conversationService.currentSelectedModel
|
val selectedModel = conversationService.currentSelectedModel
|
||||||
val systemPrompt = conversationService.systemPrompt
|
val systemPrompt = conversationService.systemPrompt
|
||||||
|
|
||||||
|
|
@ -150,8 +148,10 @@ class ConversationViewModel @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun performCleanup() = clearConversation()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clear conversation
|
* Stop ongoing generation if any, then clean up all messages in the current conversation
|
||||||
*/
|
*/
|
||||||
fun clearConversation() {
|
fun clearConversation() {
|
||||||
stopGeneration()
|
stopGeneration()
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue