1pub mod sub;
2use crate::config::Config;
3use crate::config::Profile;
4use crate::models::Backend;
5use crate::models::{
6 BenchTuneConfig, DiscoveredModel, ModelSettings, ModelState, SearchResult, SearchSort,
7 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}
41
42#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
44pub enum ActivePanel {
45 #[default]
46 Models,
47 Log,
48 ServerSettings,
49 LlmSettings,
50 Profiles,
51 SystemPromptPresets,
52 SearchReadme,
53 ActiveModel,
54 ModelInfo,
55 Downloads,
56}
57
58#[derive(Debug, Clone)]
60pub enum ModelsMode {
61 List,
63 Search {
65 query: String,
66 results: Vec<SearchResult>,
67 sort_by: SearchSort,
68 show_readme: bool,
69 page: usize,
70 loading: bool,
72 has_more: bool,
74 },
75 Files {
77 model_id: String,
78 files: Vec<(String, u64, String)>, selected_idx: Option<usize>,
80 previous_query: String,
81 previous_results: Vec<SearchResult>,
82 selected_result: Option<SearchResult>,
83 },
84 BenchTune,
86}
87
88#[derive(Debug, Clone, PartialEq)]
90pub enum GlobalMode {
91 Normal,
92 CmdLine {
93 cmd_line: String,
94 },
95 HostPicker {
96 entries: Vec<(String, String)>, selected: usize,
98 },
99 BackendPicker {
100 entries: Vec<(Backend, Option<String>)>,
101 selected: usize,
102 },
103 Confirmation {
104 selected: bool,
105 kind: ConfirmationKind,
106 display_name: String,
107 detail: Option<String>,
108 },
109 RpcManager,
110 About,
111 MaxConcurrentPicker {
112 value: String,
113 },
114 SpecTypePicker {
115 entries: Vec<String>,
116 selected: usize,
117 },
118 YarnRoPESettings {
119 scale: String,
120 freq_base: String,
121 freq_scale: String,
122 selected_field: i32, editing: bool,
124 edit_buffer: String,
125 edit_cursor_pos: usize,
126 },
127 BenchTuneSetup {
128 config: BenchTuneConfig,
129 selected_idx: usize,
130 editing_param: bool,
131 editing_param_field: i32,
132 param_edit_buffer: String,
133 param_edit_cursor_pos: usize,
134 bench_mode_selection: usize,
135 editing_prompt: bool,
136 editing_kwargs: bool,
137 },
138 PromptPicker {
139 entries: Vec<(String, String)>, selected: usize,
141 editing: bool,
142 edit_buffer: String,
143 edit_cursor_pos: usize,
144 confirm_delete: bool,
145 },
146 ProfilePicker {
147 entries: Vec<(String, String)>, selected: usize,
149 profiles: Vec<Profile>,
150 },
151 DashboardPicker {
152 enabled: bool,
153 port: String,
154 auth_key: String,
155 tls_enabled: bool,
156 tls_cert: String,
157 tls_key: String,
158 selected_field: i32, editing: bool,
160 edit_buffer: String,
161 edit_cursor_pos: usize,
162 },
163 DashboardUrl {
164 host: String,
165 port: String,
166 auth_key: String,
167 ws_enabled: bool,
168 tls_enabled: bool,
169 },
170 SearchInput {
171 buffer: String,
172 cursor_pos: usize,
173 },
174 GgufNaming {
175 explanation: crate::tui::gguf_naming::GgufExplanation,
176 filename: String,
177 },
178 Onboarding {
179 step: usize,
180 },
181}
182
183#[derive(Debug, Clone, Copy, PartialEq, Eq)]
184pub enum ConfirmationKind {
185 Exit,
186 Reset,
187 Delete,
188 Unload,
189 DeleteBackend,
190}
191
192#[derive(Debug, Clone)]
194pub struct TextScrollState {
195 pub offset: usize,
196 pub last_tick: std::time::Instant,
197 pub direction: i8,
198 pub hold_count: u8,
199 pub max_offset: usize,
200 pub visible: bool,
201}
202
203#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
205pub enum LoadingPhase {
206 ServerStarting,
207 LoadingModel,
208 LoadingMeta,
209 LoadingTensors,
210 ServerListening,
211 Complete,
212}
213
214impl LoadingPhase {
215 pub fn label(&self) -> &'static str {
216 match self {
217 LoadingPhase::ServerStarting => "Server starting...",
218 LoadingPhase::LoadingModel => "Loading model weights...",
219 LoadingPhase::LoadingMeta => "Loading metadata...",
220 LoadingPhase::LoadingTensors => "Loading tensors...",
221 LoadingPhase::ServerListening => "Server listening...",
222 LoadingPhase::Complete => "Ready",
223 }
224 }
225}
226
227pub struct App {
229 pub running: bool,
231 pub config: Config,
232 pub models: Vec<DiscoveredModel>,
233 pub selected_model_idx: Option<usize>,
234 pub models_mode: ModelsMode,
235 pub settings: ModelSettings,
236 pub model_settings_cache: ModelSettings,
237 pub model_states: HashMap<String, ModelState>,
238 pub metrics: ServerMetrics,
239 pub max_threads: u32,
240 pub cancelled: Option<Arc<AtomicBool>>,
241 pub server_mode: crate::models::ServerMode,
242 pub router_max_models: u32,
243 pub ws_server_handle: Option<tokio::task::JoinHandle<()>>,
244 pub background_tasks: HashMap<String, tokio::task::JoinHandle<()>>,
245
246 pub settings_state: SettingsState,
248 pub picker: PickerState,
249 pub download: DownloadState,
250 pub server: ServerState,
251 pub bench_tune: BenchTuneState,
252 pub log: LogState,
253 pub loading: LoadingState,
254 pub pending: PendingOperations,
255 pub search: SearchState,
256 pub ui: UIState,
257 pub edit: EditState,
258
259 pub pending_tx: tokio::sync::mpsc::Sender<super::pending_events::PendingEvent>,
261 pub pending_rx: tokio::sync::mpsc::Receiver<super::pending_events::PendingEvent>,
262 pub server_ready: bool,
263}