UI: add quick action buttons to benchmark screen's result card
This commit is contained in:
parent
659f59e22a
commit
c848005d11
|
|
@ -259,9 +259,7 @@ fun AppContent(
|
|||
|
||||
// Benchmark screen
|
||||
currentRoute.startsWith(AppDestinations.BENCHMARK_ROUTE) -> {
|
||||
val engineState by benchmarkViewModel.engineState.collectAsState()
|
||||
val showModelCard by benchmarkViewModel.showModelCard.collectAsState()
|
||||
val benchmarkResults by benchmarkViewModel.benchmarkResults.collectAsState()
|
||||
|
||||
ScaffoldConfig(
|
||||
topBarConfig = TopBarConfig.Performance(
|
||||
|
|
@ -274,22 +272,9 @@ fun AppContent(
|
|||
),
|
||||
bottomBarConfig = BottomBarConfig.Benchmark(
|
||||
engineIdle = !engineState.isUninterruptible,
|
||||
onShare = {
|
||||
benchmarkResults.lastOrNull()?.let {
|
||||
handleScaffoldEvent(ScaffoldEvent.ShareText(it.text))
|
||||
}
|
||||
},
|
||||
onRerun = {
|
||||
if (engineState.isUninterruptible) {
|
||||
handleScaffoldEvent(ScaffoldEvent.ShowSnackbar(
|
||||
message = "Benchmark already in progress!\n" +
|
||||
"Please wait for the current run to complete."
|
||||
))
|
||||
} else {
|
||||
benchmarkViewModel.runBenchmark()
|
||||
}
|
||||
},
|
||||
onClear = benchmarkViewModel::clearResults,
|
||||
onShare = { benchmarkViewModel.shareResult(handleScaffoldEvent) },
|
||||
onRerun = { benchmarkViewModel.rerunBenchmark(handleScaffoldEvent) },
|
||||
onClear = { benchmarkViewModel.clearResults(handleScaffoldEvent) },
|
||||
showModelCard = showModelCard,
|
||||
onToggleModelCard = benchmarkViewModel::toggleModelCard,
|
||||
)
|
||||
|
|
@ -478,6 +463,7 @@ fun AppContent(
|
|||
|
||||
BenchmarkScreen(
|
||||
loadingMetrics = metrics,
|
||||
onScaffoldEvent = handleScaffoldEvent,
|
||||
onNavigateBack = { navigationActions.navigateUp() },
|
||||
viewModel = benchmarkViewModel
|
||||
)
|
||||
|
|
|
|||
|
|
@ -27,22 +27,25 @@ fun BenchmarkBottomBar(
|
|||
showModelCard: Boolean,
|
||||
onToggleModelCard: (Boolean) -> Unit,
|
||||
) {
|
||||
val controlTint =
|
||||
if (engineIdle) MaterialTheme.colorScheme.onSurface
|
||||
else MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.3f)
|
||||
|
||||
BottomAppBar(
|
||||
actions = {
|
||||
IconButton(onClick = onRerun) {
|
||||
Icon(
|
||||
imageVector = Icons.Default.Replay,
|
||||
contentDescription = "Run the benchmark again",
|
||||
tint =
|
||||
if (engineIdle) MaterialTheme.colorScheme.onSurface
|
||||
else MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.3f)
|
||||
tint = controlTint
|
||||
)
|
||||
}
|
||||
|
||||
IconButton(onClick = onClear) {
|
||||
Icon(
|
||||
imageVector = Icons.Default.ClearAll,
|
||||
contentDescription = "Clear benchmark results"
|
||||
contentDescription = "Clear benchmark results",
|
||||
tint = controlTint
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
package com.example.llama.ui.screens
|
||||
|
||||
import android.content.Intent
|
||||
import android.llama.cpp.InferenceEngine.State
|
||||
import android.widget.Toast
|
||||
import androidx.activity.compose.BackHandler
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.border
|
||||
|
|
@ -19,11 +21,17 @@ import androidx.compose.foundation.layout.width
|
|||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Info
|
||||
import androidx.compose.material.icons.filled.Replay
|
||||
import androidx.compose.material3.Card
|
||||
import androidx.compose.material3.CardDefaults
|
||||
import androidx.compose.material3.CircularProgressIndicator
|
||||
import androidx.compose.material3.FilledTonalButton
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.OutlinedButton
|
||||
import androidx.compose.material3.ProgressIndicatorDefaults
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
|
|
@ -36,10 +44,12 @@ import androidx.compose.runtime.saveable.rememberSaveable
|
|||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.text.font.FontStyle
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.core.net.toUri
|
||||
import com.example.llama.data.model.ModelInfo
|
||||
import com.example.llama.engine.ModelLoadingMetrics
|
||||
import com.example.llama.ui.components.ModelCardContentArchitectureRow
|
||||
|
|
@ -47,6 +57,7 @@ import com.example.llama.ui.components.ModelCardContentContextRow
|
|||
import com.example.llama.ui.components.ModelCardContentField
|
||||
import com.example.llama.ui.components.ModelCardCoreExpandable
|
||||
import com.example.llama.ui.components.ModelUnloadDialogHandler
|
||||
import com.example.llama.ui.scaffold.ScaffoldEvent
|
||||
import com.example.llama.util.TableData
|
||||
import com.example.llama.util.formatMilliSeconds
|
||||
import com.example.llama.util.parseMarkdownTable
|
||||
|
|
@ -57,9 +68,12 @@ import com.example.llama.viewmodel.BenchmarkViewModel
|
|||
@Composable
|
||||
fun BenchmarkScreen(
|
||||
loadingMetrics: ModelLoadingMetrics,
|
||||
onScaffoldEvent: (ScaffoldEvent) -> Unit,
|
||||
onNavigateBack: () -> Unit,
|
||||
viewModel: BenchmarkViewModel
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
|
||||
// View model states
|
||||
val engineState by viewModel.engineState.collectAsState()
|
||||
val unloadDialogState by viewModel.unloadModelState.collectAsState()
|
||||
|
|
@ -86,6 +100,12 @@ fun BenchmarkScreen(
|
|||
viewModel.onBackPressed(onNavigateBack)
|
||||
}
|
||||
|
||||
val onInfo = {
|
||||
Toast.makeText(context, "Please refer to this post for more details on the benchmark methodology", Toast.LENGTH_SHORT).show()
|
||||
val intent = Intent(Intent.ACTION_VIEW, "https://blog.steelph0enix.dev/posts/llama-cpp-guide/#llama-bench".toUri())
|
||||
context.startActivity(intent)
|
||||
}
|
||||
|
||||
Box(
|
||||
modifier = Modifier.fillMaxSize()
|
||||
) {
|
||||
|
|
@ -96,7 +116,11 @@ fun BenchmarkScreen(
|
|||
verticalArrangement = Arrangement.Bottom,
|
||||
) {
|
||||
items(items = benchmarkResults) {
|
||||
BenchmarkResultCard(it)
|
||||
BenchmarkResultCard(
|
||||
result = it,
|
||||
onRerun = { viewModel.rerunBenchmark(onScaffoldEvent) },
|
||||
onInfo = onInfo,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -186,7 +210,11 @@ private fun ModelCardWithLoadingMetrics(
|
|||
|
||||
|
||||
@Composable
|
||||
fun BenchmarkResultCard(result: BenchmarkResult) {
|
||||
fun BenchmarkResultCard(
|
||||
result: BenchmarkResult,
|
||||
onRerun: () -> Unit,
|
||||
onInfo: () -> Unit,
|
||||
) {
|
||||
val rawTable = parseMarkdownTable(result.text.trimIndent())
|
||||
val model = rawTable.getColumn("model").firstOrNull() ?: "Unknown"
|
||||
val parameters = rawTable.getColumn("params").firstOrNull() ?: "-"
|
||||
|
|
@ -236,6 +264,28 @@ fun BenchmarkResultCard(result: BenchmarkResult) {
|
|||
BenchmarkResultTable(rawTable)
|
||||
|
||||
ModelCardContentField("Time spent: ", formatMilliSeconds(result.duration))
|
||||
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
|
||||
Row {
|
||||
OutlinedButton(onClick = onRerun) {
|
||||
Icon(
|
||||
imageVector = Icons.Default.Replay,
|
||||
contentDescription = "Run the benchmark again"
|
||||
)
|
||||
Text("Run again", modifier = Modifier.padding(start = 6.dp))
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
|
||||
FilledTonalButton(onClick = onInfo) {
|
||||
Icon(
|
||||
imageVector = Icons.Default.Info,
|
||||
contentDescription = "Information about what the result means"
|
||||
)
|
||||
Text("How to interpret", modifier = Modifier.padding(start = 6.dp))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import android.llama.cpp.isUninterruptible
|
|||
import androidx.lifecycle.viewModelScope
|
||||
import com.example.llama.data.model.ModelInfo
|
||||
import com.example.llama.engine.BenchmarkService
|
||||
import com.example.llama.ui.scaffold.ScaffoldEvent
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
|
|
@ -30,7 +31,7 @@ class BenchmarkViewModel @Inject constructor(
|
|||
val benchmarkResults: StateFlow<List<BenchmarkResult>> = _benchmarkResults.asStateFlow()
|
||||
|
||||
// UI state: Model card
|
||||
private val _showModelCard = MutableStateFlow(true)
|
||||
private val _showModelCard = MutableStateFlow(false)
|
||||
val showModelCard = _showModelCard.asStateFlow()
|
||||
|
||||
fun toggleModelCard(show: Boolean) {
|
||||
|
|
@ -68,10 +69,37 @@ class BenchmarkViewModel @Inject constructor(
|
|||
return true
|
||||
}
|
||||
|
||||
override suspend fun performCleanup() = clearResults()
|
||||
override suspend fun performCleanup() { clearResults(null) }
|
||||
|
||||
fun clearResults() {
|
||||
_benchmarkResults.value = emptyList()
|
||||
fun clearResults(onScaffoldEvent: ((ScaffoldEvent) -> Unit)?) =
|
||||
if (engineState.value.isUninterruptible) {
|
||||
false
|
||||
} else {
|
||||
_benchmarkResults.value = emptyList()
|
||||
onScaffoldEvent?.invoke(ScaffoldEvent.ShowSnackbar(
|
||||
message = "All benchmark results cleared."
|
||||
))
|
||||
true
|
||||
}
|
||||
|
||||
/**
|
||||
* Rerun the benchmark
|
||||
*/
|
||||
fun rerunBenchmark(onScaffoldEvent: (ScaffoldEvent) -> Unit) {
|
||||
if (engineState.value.isUninterruptible) {
|
||||
onScaffoldEvent(ScaffoldEvent.ShowSnackbar(
|
||||
message = "Benchmark already in progress!\n" +
|
||||
"Please wait for the current run to complete."
|
||||
))
|
||||
} else {
|
||||
runBenchmark()
|
||||
}
|
||||
}
|
||||
|
||||
fun shareResult(onScaffoldEvent: (ScaffoldEvent) -> Unit) {
|
||||
_benchmarkResults.value.lastOrNull()?.let{
|
||||
onScaffoldEvent(ScaffoldEvent.ShareText(it.text))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue