gglib_core/domain/benchmark/compare.rs
1//! Compare-mode benchmark types: configuration and per-model results.
2
3use chrono::{DateTime, Utc};
4use serde::{Deserialize, Serialize};
5
6use crate::domain::inference::InferenceConfig;
7
8/// Configuration for a compare benchmark run.
9#[derive(Debug, Clone, Serialize, Deserialize)]
10pub struct CompareConfig {
11 /// Models to benchmark (by database ID), run sequentially.
12 pub model_ids: Vec<i64>,
13 /// Prompt text to send to every model.
14 pub prompt: String,
15 /// Optional system prompt.
16 pub system_prompt: Option<String>,
17 /// Per-request inference overrides (`temperature`, `max_tokens`, etc.).
18 pub inference: Option<InferenceConfig>,
19 /// Override the llama-server context window size for this run.
20 ///
21 /// When `None` the benchmark service falls back to the app-wide
22 /// `default_context_size` setting (same fallback the proxy uses).
23 #[serde(default)]
24 pub ctx_size: Option<u64>,
25}
26
27/// Result of running a single model through a compare (inference) benchmark.
28///
29/// All timing fields are `Option<f64>` — llama-server may omit the `timings`
30/// object. Missing values are stored as `NULL` in the database and surfaced as
31/// `None` in the API; they never cause a panic.
32#[derive(Debug, Clone, Serialize, Deserialize)]
33#[cfg_attr(feature = "ts-bindings", derive(ts_rs::TS), ts(export))]
34pub struct ModelCompareResult {
35 /// Database ID of this result row (set after persistence).
36 #[cfg_attr(feature = "ts-bindings", ts(type = "number | null"))]
37 pub id: Option<i64>,
38 /// Foreign key → `models.id`.
39 #[cfg_attr(feature = "ts-bindings", ts(type = "number"))]
40 pub model_id: i64,
41 /// Foreign key → `benchmark_runs.id` (nullable; SET NULL on run delete).
42 #[cfg_attr(feature = "ts-bindings", ts(type = "number | null"))]
43 pub run_id: Option<i64>,
44 /// Prompt text sent to this model.
45 pub prompt_text: String,
46 /// Optional system prompt.
47 pub system_prompt: Option<String>,
48 /// Full response text accumulated from the stream.
49 pub response_text: String,
50 /// `true` if the response was cut short (`finish_reason == "length"`).
51 pub was_truncated: bool,
52 /// Number of prompt tokens reported by the model.
53 #[cfg_attr(feature = "ts-bindings", ts(type = "number | null"))]
54 pub prompt_tokens: Option<i64>,
55 /// Number of completion tokens reported by the model.
56 #[cfg_attr(feature = "ts-bindings", ts(type = "number | null"))]
57 pub completion_tokens: Option<i64>,
58 /// Time spent processing the prompt (milliseconds).
59 pub prompt_ms: Option<f64>,
60 /// Time spent generating the response (milliseconds).
61 pub generation_ms: Option<f64>,
62 /// Prompt-processing throughput (tokens/sec). `None` if timings absent.
63 pub prompt_tps: Option<f64>,
64 /// Token-generation throughput (tokens/sec). `None` if timings absent.
65 pub generation_tps: Option<f64>,
66 /// UTC timestamp of this result.
67 pub created_at: DateTime<Utc>,
68}