minor UI fixes
This commit is contained in:
@@ -81,6 +81,72 @@ pub fn set_llm_config(state: tauri::State<'_, AppState>, config: crate::llm::Llm
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// ─── Connection test: list models from the configured endpoint ──
|
||||
// ponytail: Ollama exposes GET /api/tags, OpenAI-compatible exposes
|
||||
// GET /v1/models. Returns the model names so Settings can show a list and
|
||||
// a green/red pill. Best-effort — surface the error string on failure.
|
||||
#[derive(serde::Serialize)]
|
||||
pub struct ConnectionTest {
|
||||
pub ok: bool,
|
||||
pub models: Vec<String>,
|
||||
pub error: String,
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn test_connection(state: tauri::State<'_, AppState>) -> Result<ConnectionTest, String> {
|
||||
let config = state.config.lock().map_err(|e| e.to_string())?.clone();
|
||||
let client = reqwest::Client::builder()
|
||||
.timeout(std::time::Duration::from_secs(8))
|
||||
.build()
|
||||
.map_err(|e| e.to_string())?;
|
||||
|
||||
if llm::is_ollama(&config.api_url) {
|
||||
let url = format!("{}/api/tags", config.api_url.trim_end_matches('/'));
|
||||
let res = client.get(&url).send().await.map_err(|e| e.to_string())?;
|
||||
if !res.status().is_success() {
|
||||
return Ok(ConnectionTest {
|
||||
ok: false,
|
||||
models: vec![],
|
||||
error: format!("HTTP {}", res.status()),
|
||||
});
|
||||
}
|
||||
let body: serde_json::Value = res.json().await.map_err(|e| e.to_string())?;
|
||||
let models = body["models"]
|
||||
.as_array()
|
||||
.map(|a| {
|
||||
a.iter()
|
||||
.filter_map(|m| m["name"].as_str().map(|s| s.to_string()))
|
||||
.collect()
|
||||
})
|
||||
.unwrap_or_default();
|
||||
Ok(ConnectionTest { ok: true, models, error: String::new() })
|
||||
} else {
|
||||
let url = format!("{}/v1/models", config.api_url.trim_end_matches('/'));
|
||||
let mut req = client.get(&url);
|
||||
if !config.api_key.is_empty() {
|
||||
req = req.bearer_auth(&config.api_key);
|
||||
}
|
||||
let res = req.send().await.map_err(|e| e.to_string())?;
|
||||
if !res.status().is_success() {
|
||||
return Ok(ConnectionTest {
|
||||
ok: false,
|
||||
models: vec![],
|
||||
error: format!("HTTP {}", res.status()),
|
||||
});
|
||||
}
|
||||
let body: serde_json::Value = res.json().await.map_err(|e| e.to_string())?;
|
||||
let models = body["data"]
|
||||
.as_array()
|
||||
.map(|a| {
|
||||
a.iter()
|
||||
.filter_map(|m| m["id"].as_str().map(|s| s.to_string()))
|
||||
.collect()
|
||||
})
|
||||
.unwrap_or_default();
|
||||
Ok(ConnectionTest { ok: true, models, error: String::new() })
|
||||
}
|
||||
}
|
||||
|
||||
// ─── Lore RAG injection (shared by generate + generate_stream) ─
|
||||
|
||||
/// Best-effort: if `rag_query` is set, retrieve top lore chunks and fold them
|
||||
|
||||
@@ -36,6 +36,7 @@ pub fn run() {
|
||||
commands::llm_commands::generate_stream,
|
||||
commands::llm_commands::get_llm_config,
|
||||
commands::llm_commands::set_llm_config,
|
||||
commands::llm_commands::test_connection,
|
||||
commands::image_commands::generate_image,
|
||||
commands::rag_commands::rag_add,
|
||||
commands::rag_commands::rag_search,
|
||||
|
||||
Reference in New Issue
Block a user