Skip to main content

walrus_model/openai/
mod.rs

1//! OpenAI-compatible LLM provider.
2//!
3//! Covers OpenAI, Grok (xAI), Qwen (Alibaba), Kimi (Moonshot), Ollama,
4//! and any other service exposing the OpenAI chat completions API.
5
6use reqwest::{Client, header::HeaderMap};
7
8mod provider;
9
10/// OpenAI-compatible endpoint URLs.
11pub mod endpoint {
12    /// OpenAI chat completions.
13    pub const OPENAI: &str = "https://api.openai.com/v1/chat/completions";
14    /// Grok (xAI) chat completions.
15    pub const GROK: &str = "https://api.x.ai/v1/chat/completions";
16    /// Qwen (Alibaba DashScope) chat completions.
17    pub const QWEN: &str = "https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions";
18    /// Kimi (Moonshot) chat completions.
19    pub const KIMI: &str = "https://api.moonshot.cn/v1/chat/completions";
20    /// Ollama local chat completions.
21    pub const OLLAMA: &str = "http://localhost:11434/v1/chat/completions";
22}
23
24/// An OpenAI-compatible LLM provider.
25#[derive(Clone)]
26pub struct OpenAI {
27    /// The HTTP client.
28    pub client: Client,
29    /// Request headers (authorization, content-type).
30    headers: HeaderMap,
31    /// Chat completions endpoint URL.
32    endpoint: String,
33}
34
35impl OpenAI {
36    /// Create a provider targeting the OpenAI API.
37    pub fn api(client: Client, key: &str) -> anyhow::Result<Self> {
38        Self::custom(client, key, endpoint::OPENAI)
39    }
40
41    /// Create a provider targeting the Grok (xAI) API.
42    pub fn grok(client: Client, key: &str) -> anyhow::Result<Self> {
43        Self::custom(client, key, endpoint::GROK)
44    }
45
46    /// Create a provider targeting the Qwen (DashScope) API.
47    pub fn qwen(client: Client, key: &str) -> anyhow::Result<Self> {
48        Self::custom(client, key, endpoint::QWEN)
49    }
50
51    /// Create a provider targeting the Kimi (Moonshot) API.
52    pub fn kimi(client: Client, key: &str) -> anyhow::Result<Self> {
53        Self::custom(client, key, endpoint::KIMI)
54    }
55
56    /// Create a provider targeting a local Ollama instance (no API key).
57    pub fn ollama(client: Client) -> anyhow::Result<Self> {
58        use reqwest::header;
59        let mut headers = HeaderMap::new();
60        headers.insert(header::CONTENT_TYPE, "application/json".parse()?);
61        headers.insert(header::ACCEPT, "application/json".parse()?);
62        Ok(Self {
63            client,
64            headers,
65            endpoint: endpoint::OLLAMA.to_owned(),
66        })
67    }
68
69    /// Create a provider targeting a custom OpenAI-compatible endpoint.
70    pub fn custom(client: Client, key: &str, endpoint: &str) -> anyhow::Result<Self> {
71        use reqwest::header;
72        let mut headers = HeaderMap::new();
73        headers.insert(header::CONTENT_TYPE, "application/json".parse()?);
74        headers.insert(header::ACCEPT, "application/json".parse()?);
75        headers.insert(header::AUTHORIZATION, format!("Bearer {key}").parse()?);
76        Ok(Self {
77            client,
78            headers,
79            endpoint: endpoint.to_owned(),
80        })
81    }
82}