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