|
1 | | -use anyhow::Result; |
2 | | -use reqwest::Client; |
3 | | -use std::time::Duration; |
4 | | - |
5 | | -use crate::config::Config; |
6 | | - |
7 | | -use super::super::system::check_system_resources; |
8 | | -use super::display::{print_configuration, print_endpoint_models, print_header, print_unreachable}; |
9 | | -use super::probe::probe_endpoint; |
10 | | -use super::recommend::inspect_recommended_model; |
11 | | - |
12 | | -pub async fn doctor_command(config: Config) -> Result<()> { |
13 | | - print_header(); |
14 | | - check_system_resources(); |
15 | | - print_configuration(&config); |
16 | | - |
17 | | - let base_url = config |
18 | | - .base_url |
19 | | - .clone() |
20 | | - .unwrap_or_else(|| "http://localhost:11434".to_string()); |
21 | | - |
22 | | - print!("Checking endpoint {}... ", base_url); |
23 | | - let client = Client::builder().timeout(Duration::from_secs(5)).build()?; |
24 | | - let Some(endpoint) = probe_endpoint(&client, &base_url).await? else { |
25 | | - return print_unreachable(&base_url); |
26 | | - }; |
27 | | - |
28 | | - println!("reachable ({})", endpoint.reachable_label); |
29 | | - print_endpoint_models(endpoint.endpoint_type, &endpoint.models); |
30 | | - inspect_recommended_model(&config, &base_url, &endpoint).await?; |
31 | | - Ok(()) |
32 | | -} |
33 | | - |
| 1 | +#[path = "run/command.rs"] |
| 2 | +mod command; |
| 3 | +#[path = "run/endpoint.rs"] |
| 4 | +mod endpoint; |
| 5 | +#[path = "run/recommendation.rs"] |
| 6 | +mod recommendation; |
34 | 7 | #[cfg(test)] |
35 | | -mod tests { |
36 | | - use super::*; |
37 | | - use serde_json::Value; |
38 | | - |
39 | | - #[test] |
40 | | - fn doctor_config_defaults() { |
41 | | - let config = Config::default(); |
42 | | - assert!(config.adapter.is_none()); |
43 | | - assert!(config.context_window.is_none()); |
44 | | - } |
45 | | - |
46 | | - #[test] |
47 | | - fn test_detect_context_window_from_parameters() { |
48 | | - let json = |
49 | | - r#"{"parameters":"stop [INST]\nstop [/INST]\nnum_ctx 4096\nrepeat_penalty 1.1"}"#; |
50 | | - let value: Value = serde_json::from_str(json).unwrap(); |
51 | | - assert_eq!(parse_context_window(&value), Some(4096)); |
52 | | - } |
53 | | - |
54 | | - #[test] |
55 | | - fn test_detect_context_window_from_model_info() { |
56 | | - let json = r#"{"model_info":{"llama.context_length":8192}}"#; |
57 | | - let value: Value = serde_json::from_str(json).unwrap(); |
58 | | - assert_eq!(parse_context_window(&value), Some(8192)); |
59 | | - } |
60 | | - |
61 | | - #[test] |
62 | | - fn test_detect_context_window_no_data() { |
63 | | - let json = r#"{"license":"MIT","modelfile":"..."}"#; |
64 | | - let value: Value = serde_json::from_str(json).unwrap(); |
65 | | - assert_eq!(parse_context_window(&value), None); |
66 | | - } |
67 | | - |
68 | | - fn parse_context_window(value: &Value) -> Option<usize> { |
69 | | - if let Some(params) = value |
70 | | - .get("parameters") |
71 | | - .and_then(|parameters| parameters.as_str()) |
72 | | - { |
73 | | - for line in params.lines() { |
74 | | - let trimmed = line.trim(); |
75 | | - if trimmed.starts_with("num_ctx") { |
76 | | - if let Some(raw_value) = trimmed.split_whitespace().nth(1) { |
77 | | - if let Ok(parsed) = raw_value.parse() { |
78 | | - return Some(parsed); |
79 | | - } |
80 | | - } |
81 | | - } |
82 | | - } |
83 | | - } |
84 | | - |
85 | | - let info = value.get("model_info")?; |
86 | | - for key in &[ |
87 | | - "context_length", |
88 | | - "llama.context_length", |
89 | | - "general.context_length", |
90 | | - ] { |
91 | | - if let Some(ctx) = info.get(*key).and_then(|value| value.as_u64()) { |
92 | | - return Some(ctx as usize); |
93 | | - } |
94 | | - } |
| 8 | +#[path = "run/tests.rs"] |
| 9 | +mod tests; |
95 | 10 |
|
96 | | - None |
97 | | - } |
98 | | -} |
| 11 | +pub use command::doctor_command; |
0 commit comments