This commit is contained in:
Andras Schmelczer 2026-02-14 12:53:29 +00:00
parent 3a3f899ea2
commit 128b3191e7
68 changed files with 28060 additions and 1152 deletions

View file

@ -1,3 +1,75 @@
use axum::http::StatusCode;
use serde_json::Value;
use tracing::warn;
pub type LlmError = (StatusCode, String);
/// Send a chat request to Ollama and return the parsed JSON response.
///
/// Handles connection errors, non-success status codes, and JSON parse failures
/// uniformly as `BAD_GATEWAY` errors.
pub async fn ollama_chat(
client: &reqwest::Client,
url: &str,
body: &Value,
) -> Result<Value, LlmError> {
let response = client.post(url).json(body).send().await.map_err(|err| {
warn!(error = %err, "Failed to connect to Ollama");
(
StatusCode::BAD_GATEWAY,
format!("Failed to connect to Ollama: {}", err),
)
})?;
if !response.status().is_success() {
let status = response.status();
let body_text = response.text().await.unwrap_or_default();
warn!(status = %status, body = %body_text, "Ollama returned error");
return Err((
StatusCode::BAD_GATEWAY,
format!("Ollama error {}: {}", status, body_text),
));
}
response.json().await.map_err(|err| {
warn!(error = %err, "Failed to parse Ollama response");
(
StatusCode::BAD_GATEWAY,
format!("Failed to parse Ollama response: {}", err),
)
})
}
/// Extract content from OpenAI-compatible response (`choices[0].message.content`)
pub fn extract_openai_content(json: &Value) -> Result<&str, LlmError> {
json.get("choices")
.and_then(|ch| ch.get(0))
.and_then(|ch| ch.get("message"))
.and_then(|msg| msg.get("content"))
.and_then(|ct| ct.as_str())
.ok_or_else(|| {
warn!("Malformed OpenAI response: missing choices[0].message.content");
(
StatusCode::BAD_GATEWAY,
"Malformed LLM response: missing choices[0].message.content".into(),
)
})
}
/// Extract content from Ollama native response (`message.content`)
pub fn extract_ollama_content(json: &Value) -> Result<&str, LlmError> {
json.get("message")
.and_then(|msg| msg.get("content"))
.and_then(|ct| ct.as_str())
.ok_or_else(|| {
warn!("Malformed Ollama response: missing message.content");
(
StatusCode::BAD_GATEWAY,
"Malformed LLM response: missing message.content".into(),
)
})
}
/// Strip `<think>...</think>` blocks from model output
pub fn strip_think_blocks(text: &str) -> String {
let mut result = String::new();