xbp 10.28.0

XBP is a zero-config build pack that can also interact with proxies, kafka, sockets, synthetic monitors.
Documentation
use reqwest::header::{AUTHORIZATION, CONTENT_TYPE};

pub(crate) const OPENROUTER_URL: &str = "https://openrouter.ai/api/v1/chat/completions";
pub(crate) const DEFAULT_MODEL: &str = "openai/gpt-4o-mini";

pub(crate) async fn complete_user_prompt(
    api_key: &str,
    model: &str,
    prompt: &str,
    title: Option<&str>,
) -> Option<String> {
    let trimmed_api_key = api_key.trim();
    if trimmed_api_key.is_empty() {
        return None;
    }

    let mut request = reqwest::Client::new()
        .post(OPENROUTER_URL)
        .header(AUTHORIZATION, format!("Bearer {}", trimmed_api_key))
        .header(CONTENT_TYPE, "application/json");

    if let Some(title) = title.map(str::trim).filter(|value| !value.is_empty()) {
        request = request.header("X-OpenRouter-Title", title);
    }

    let response = request
        .json(&serde_json::json!({
            "model": model,
            "messages": [{
                "role": "user",
                "content": prompt,
            }]
        }))
        .send()
        .await
        .ok()?;

    if !response.status().is_success() {
        return None;
    }

    let data: serde_json::Value = response.json().await.ok()?;
    data.get("choices")?
        .as_array()?
        .first()?
        .get("message")?
        .get("content")?
        .as_str()
        .map(|content| content.trim().to_string())
}