1pub mod sub;
2use crate::config::Config;
3use crate::config::Profile;
4use crate::models::Backend;
5use crate::models::{
6 BenchTuneConfig, DiscoveredModel, ListSort, ModelSettings, ModelState, SearchResult,
7 SearchSort, ServerMetrics,
8};
9use ratatui::layout::Rect;
10use ratatui::text::Line;
11use serde::{Deserialize, Serialize};
12use std::collections::HashMap;
13use std::sync::atomic::AtomicBool;
14use std::sync::{Arc, Mutex};
15
16pub use sub::{
18 BenchTuneState, DownloadState, EditState, LoadingState, LogState, PendingOperations,
19 PickerState, SearchState, ServerState, SettingsState, UIState,
20};
21
22pub static API_PORT_CACHE: Mutex<(u16, String)> = Mutex::new((0, String::new()));
24
25pub struct ResizeState {
27 pub start_x: u16,
29 pub start_pct: u16,
31 pub container: Rect,
33}
34
35pub struct SettingsRenderCache {
37 pub hash: u64,
38 pub selected: usize,
39 pub lines: Vec<Line<'static>>,
40 pub selected_content_line: usize,
41}
42
43#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
45pub enum ActivePanel {
46 #[default]
47 Models,
48 Log,
49 ServerSettings,
50 LlmSettings,
51 Profiles,
52 SystemPromptPresets,
53 SearchReadme,
54 ActiveModel,
55 ModelInfo,
56 Downloads,
57}
58
59#[derive(Debug, Clone)]
61pub enum ModelsMode {
62 List { sort_by: ListSort },
64 Search {
66 query: String,
67 results: Vec<SearchResult>,
68 sort_by: SearchSort,
69 show_readme: bool,
70 page: usize,
71 loading: bool,
73 has_more: bool,
75 },
76 Files {
78 model_id: String,
79 files: Vec<(String, u64, String)>, selected_idx: Option<usize>,
81 previous_query: String,
82 previous_results: Vec<SearchResult>,
83 selected_result: Option<SearchResult>,
84 },
85 BenchTune,
87}
88
89#[derive(Debug, Clone, PartialEq)]
91pub enum GlobalMode {
92 Normal,
93 CmdLine {
94 cmd_line: String,
95 },
96 HostPicker {
97 entries: Vec<(String, String)>, selected: usize,
99 },
100 BackendPicker {
101 entries: Vec<(Backend, Option<String>)>,
102 selected: usize,
103 },
104 Confirmation {
105 selected: bool,
106 kind: ConfirmationKind,
107 display_name: String,
108 detail: Option<String>,
109 },
110 RpcManager,
111 About,
112 MaxConcurrentPicker {
113 value: String,
114 },
115 SpecTypePicker {
116 entries: Vec<String>,
117 selected: usize,
118 },
119 YarnRoPESettings {
120 scale: String,
121 freq_base: String,
122 freq_scale: String,
123 selected_field: i32, editing: bool,
125 edit_buffer: String,
126 edit_cursor_pos: usize,
127 },
128 BenchTuneSetup {
129 config: BenchTuneConfig,
130 selected_idx: usize,
131 editing_param: bool,
132 editing_param_field: i32,
133 param_edit_buffer: String,
134 param_edit_cursor_pos: usize,
135 bench_mode_selection: usize,
136 editing_prompt: bool,
137 editing_kwargs: bool,
138 },
139 PromptPicker {
140 entries: Vec<(String, String)>, selected: usize,
142 editing: bool,
143 edit_buffer: String,
144 edit_cursor_pos: usize,
145 confirm_delete: bool,
146 },
147 ProfilePicker {
148 entries: Vec<(String, String)>, selected: usize,
150 profiles: Vec<Profile>,
151 },
152 DashboardPicker {
153 enabled: bool,
154 port: String,
155 auth_key: String,
156 tls_enabled: bool,
157 tls_cert: String,
158 tls_key: String,
159 selected_field: i32, editing: bool,
161 edit_buffer: String,
162 edit_cursor_pos: usize,
163 },
164 ApiEndpointPicker {
165 enabled: bool,
166 port: String,
167 api_key: String,
168 tls_enabled: bool,
169 tls_cert: String,
170 tls_key: String,
171 selected_field: i32, editing: bool,
173 edit_buffer: String,
174 edit_cursor_pos: usize,
175 },
176 DashboardUrl {
177 host: String,
178 ws_port: String,
179 api_port: u16,
180 llm_port: u16,
181 auth_key: String,
182 ws_enabled: bool,
183 tls_enabled: bool,
184 },
185 SearchInput {
186 buffer: String,
187 cursor_pos: usize,
188 },
189 GgufNaming {
190 explanation: crate::tui::gguf_naming::GgufExplanation,
191 filename: String,
192 },
193 Onboarding {
194 step: usize,
195 },
196 ChatTemplatePicker {
197 entries: Vec<String>,
198 selected: usize,
199 },
200 ChatTemplateFilePicker {
201 entries: Vec<(String, String)>, selected: usize,
203 },
204 WebSearchPicker {
205 enabled: bool,
206 engine: String,
207 engine_url: String,
208 api_key: Option<String>,
209 selected_field: i32, engine_picker_selected: usize,
211 editing: bool,
212 edit_buffer: String,
213 edit_cursor_pos: usize,
214 check_status: Option<WebSearchCheckStatus>,
215 },
216 }
217
218 #[derive(Debug, Clone, PartialEq)]
219pub enum WebSearchCheckStatus {
220 Checking,
221 Ok,
222 Error(String),
223}
224
225#[derive(Debug, Clone, Copy, PartialEq, Eq)]
226pub enum ConfirmationKind {
227 Exit,
228 Reset,
229 Delete,
230 Unload,
231 DeleteBackend,
232}
233
234#[derive(Debug, Clone)]
236pub struct TextScrollState {
237 pub offset: usize,
238 pub last_tick: std::time::Instant,
239 pub direction: i8,
240 pub hold_count: u8,
241 pub max_offset: usize,
242 pub visible: bool,
243 pub cached_output: Option<String>,
245 pub cached_width: u16,
247 pub cached_offset: usize,
249}
250
251#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
253pub enum LoadingPhase {
254 ServerStarting,
255 LoadingModel,
256 LoadingMeta,
257 LoadingTensors,
258 ServerListening,
259 Complete,
260}
261
262impl LoadingPhase {
263 pub fn label(&self) -> &'static str {
264 match self {
265 LoadingPhase::ServerStarting => "Server starting...",
266 LoadingPhase::LoadingModel => "Loading model weights...",
267 LoadingPhase::LoadingMeta => "Loading metadata...",
268 LoadingPhase::LoadingTensors => "Loading tensors...",
269 LoadingPhase::ServerListening => "Server listening...",
270 LoadingPhase::Complete => "Ready",
271 }
272 }
273}
274
275pub struct App {
277 pub running: bool,
279 pub config: Config,
280 pub models: Vec<DiscoveredModel>,
281 pub selected_model_idx: Option<usize>,
282 pub models_mode: ModelsMode,
283 pub settings: ModelSettings,
284 pub model_settings_cache: ModelSettings,
285 pub model_states: HashMap<String, ModelState>,
286 pub metrics: ServerMetrics,
287 pub max_threads: u32,
288 pub cancelled: Option<Arc<AtomicBool>>,
289 pub server_mode: crate::models::ServerMode,
290 pub router_max_models: u32,
291 pub ws_server_handle: Option<tokio::task::JoinHandle<()>>,
292 pub ws_shutdown_tx: Option<tokio::sync::watch::Sender<bool>>,
293 pub background_tasks: HashMap<String, tokio::task::JoinHandle<()>>,
294
295 pub settings_state: SettingsState,
297 pub picker: PickerState,
298 pub download: DownloadState,
299 pub server: ServerState,
300 pub bench_tune: BenchTuneState,
301 pub log: LogState,
302 pub loading: LoadingState,
303 pub pending: PendingOperations,
304 pub search: SearchState,
305 pub ui: UIState,
306 pub edit: EditState,
307
308 pub active_model_hint: Option<(String, crate::models::ModelState)>,
311
312 pub pending_tx: tokio::sync::mpsc::Sender<super::pending_events::PendingEvent>,
314 pub pending_rx: tokio::sync::mpsc::Receiver<super::pending_events::PendingEvent>,
315 pub server_ready: bool,
316}