Skip to main content

llm_manager/tui/app/
types.rs

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 std::collections::HashMap;
12use std::sync::atomic::AtomicBool;
13use std::sync::{Arc, Mutex};
14
15// Re-export sub-structs
16pub use sub::{
17    BenchTuneState, DownloadState, EditState, LoadingState, LogState, PendingOperations,
18    PickerState, SearchState, ServerState, SettingsState, UIState,
19};
20
21/// Static cell for caching the API port string in help text.
22pub static API_PORT_CACHE: Mutex<(u16, String)> = Mutex::new((0, String::new()));
23
24/// State for an in-progress panel resize drag.
25pub struct ResizeState {
26    /// Starting X position of the mouse when drag began.
27    pub start_x: u16,
28    /// Starting left_pct value when drag began.
29    pub start_pct: u16,
30    /// The area of the top panels container (for border detection).
31    pub container: Rect,
32}
33
34/// Cache for the settings panel render output.
35pub struct SettingsRenderCache {
36    pub hash: u64,
37    pub selected: usize,
38    pub lines: Vec<Line<'static>>,
39}
40
41/// Which panel has focus.
42#[derive(Debug, Clone, Copy, PartialEq, Eq)]
43pub enum ActivePanel {
44    Models,
45    Log,
46    ServerSettings,
47    LlmSettings,
48    Profiles,
49    SystemPromptPresets,
50    SearchReadme,
51    ActiveModel,
52    ModelInfo,
53    Downloads,
54}
55
56/// Mode for the models panel.
57#[derive(Debug, Clone)]
58pub enum ModelsMode {
59    /// Normal mode: list of local models.
60    List,
61    /// Search mode: searching HuggingFace.
62    Search {
63        query: String,
64        results: Vec<SearchResult>,
65        sort_by: SearchSort,
66        show_readme: bool,
67        page: usize,
68        /// Whether results are currently being loaded.
69        loading: bool,
70        /// Whether more results are available.
71        has_more: bool,
72    },
73    /// Files mode: listing available GGUF files for a model.
74    Files {
75        model_id: String,
76        files: Vec<(String, u64, String)>, // (filename, size, url)
77        selected_idx: Option<usize>,
78        previous_query: String,
79        previous_results: Vec<SearchResult>,
80        selected_result: Option<SearchResult>,
81    },
82    /// Benchmark tuning mode: running bench_tune on a model.
83    BenchTune,
84}
85
86/// Global mode that overlays all panels.
87#[derive(Debug, Clone, PartialEq)]
88pub enum GlobalMode {
89    Normal,
90    CmdLine {
91        cmd_line: String,
92    },
93    HostPicker {
94        entries: Vec<(String, String)>, // (ip, interface_name)
95        selected: usize,
96    },
97    BackendPicker {
98        entries: Vec<(Backend, Option<String>)>,
99        selected: usize,
100    },
101    Confirmation {
102        selected: bool,
103        kind: ConfirmationKind,
104    },
105    RpcManager,
106    About,
107    MaxConcurrentPicker {
108        value: String,
109    },
110    SpecTypePicker {
111        entries: Vec<String>,
112        selected: usize,
113    },
114    YarnRoPESettings {
115        scale: String,
116        freq_base: String,
117        freq_scale: String,
118        selected_field: i32, // -1=enabled, 0=scale, 1=freq_base, 2=freq_scale
119        editing: bool,
120        edit_buffer: String,
121        edit_cursor_pos: usize,
122    },
123    BenchTuneSetup {
124        config: BenchTuneConfig,
125        selected_idx: usize,
126        editing_param: bool,
127        editing_param_field: i32,
128        param_edit_buffer: String,
129        param_edit_cursor_pos: usize,
130        bench_mode_selection: usize,
131        editing_prompt: bool,
132        editing_kwargs: bool,
133    },
134    PromptPicker {
135        entries: Vec<(String, String)>, // (name, description)
136        selected: usize,
137        editing: bool,
138        edit_buffer: String,
139        edit_cursor_pos: usize,
140        confirm_delete: bool,
141    },
142    ProfilePicker {
143        entries: Vec<(String, String)>, // (name, description)
144        selected: usize,
145        profiles: Vec<Profile>,
146    },
147    DashboardPicker {
148        enabled: bool,
149        port: String,
150        auth_key: String,
151        tls_enabled: bool,
152        tls_cert: String,
153        tls_key: String,
154        selected_field: i32, // -1=enabled, 0=port, 1=auth_key, 2=tls_enabled, 3=tls_cert, 4=tls_key
155        editing: bool,
156        edit_buffer: String,
157        edit_cursor_pos: usize,
158    },
159    DashboardUrl {
160        host: String,
161        port: String,
162        auth_key: String,
163        ws_enabled: bool,
164        tls_enabled: bool,
165    },
166    SearchInput {
167        buffer: String,
168        cursor_pos: usize,
169    },
170}
171
172#[derive(Debug, Clone, Copy, PartialEq, Eq)]
173pub enum ConfirmationKind {
174    Exit,
175    Reset,
176    Delete,
177    Unload,
178    DeleteBackend,
179}
180
181/// Scroll state for text that exceeds display width.
182#[derive(Debug, Clone)]
183pub struct TextScrollState {
184    pub offset: usize,
185    pub last_tick: std::time::Instant,
186    pub direction: i8,
187    pub hold_count: u8,
188    pub max_offset: usize,
189    pub visible: bool,
190}
191
192/// Phase of model loading.
193#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
194pub enum LoadingPhase {
195    ServerStarting,
196    LoadingModel,
197    LoadingMeta,
198    LoadingTensors,
199    ServerListening,
200    Complete,
201}
202
203impl LoadingPhase {
204    pub fn label(&self) -> &'static str {
205        match self {
206            LoadingPhase::ServerStarting => "Server starting...",
207            LoadingPhase::LoadingModel => "Loading model weights...",
208            LoadingPhase::LoadingMeta => "Loading metadata...",
209            LoadingPhase::LoadingTensors => "Loading tensors...",
210            LoadingPhase::ServerListening => "Server listening...",
211            LoadingPhase::Complete => "Ready",
212        }
213    }
214}
215
216/// The main application state.
217pub struct App {
218    // Core state
219    pub running: bool,
220    pub config: Config,
221    pub models: Vec<DiscoveredModel>,
222    pub selected_model_idx: Option<usize>,
223    pub models_mode: ModelsMode,
224    pub settings: ModelSettings,
225    pub model_settings_cache: ModelSettings,
226    pub model_states: HashMap<String, ModelState>,
227    pub metrics: ServerMetrics,
228    pub max_threads: u32,
229    pub cancelled: Option<Arc<AtomicBool>>,
230    pub server_mode: crate::models::ServerMode,
231    pub router_max_models: u32,
232    pub ws_server_handle: Option<tokio::task::JoinHandle<()>>,
233    pub background_tasks: HashMap<String, tokio::task::JoinHandle<()>>,
234
235    // Sub-structs
236    pub settings_state: SettingsState,
237    pub picker: PickerState,
238    pub download: DownloadState,
239    pub server: ServerState,
240    pub bench_tune: BenchTuneState,
241    pub log: LogState,
242    pub loading: LoadingState,
243    pub pending: PendingOperations,
244    pub search: SearchState,
245    pub ui: UIState,
246    pub edit: EditState,
247}