1use futures_util::StreamExt;
2use reqwest::Method;
3use serde_json::Value;
4
5use crate::{
6 client::Client,
7 error::Result,
8 http::encode_model_path,
9 request::set_stream,
10 streaming::{events_from_bytes, text_from_event, EventStream, StreamProtocol, TextStream},
11 ChatModelList,
12};
13
14pub type ChatRequest = Value;
16
17pub type ChatResponse = Value;
19
20#[derive(Clone, Debug)]
22pub struct ChatService {
23 client: Client,
24}
25
26impl ChatService {
27 pub(crate) fn new(client: Client) -> Self {
28 Self { client }
29 }
30
31 pub fn models(&self) -> ChatModelsService {
33 ChatModelsService::new(self.client.clone())
34 }
35
36 pub fn completions(&self) -> ChatCompletionsService {
38 ChatCompletionsService::new(self.client.clone())
39 }
40
41 pub fn messages(&self) -> MessagesService {
43 MessagesService::new(self.client.clone())
44 }
45
46 pub fn gemini(&self) -> GeminiService {
48 GeminiService::new(self.client.clone())
49 }
50}
51
52#[derive(Clone, Debug)]
54pub struct ChatModelsService {
55 client: Client,
56}
57
58impl ChatModelsService {
59 pub(crate) fn new(client: Client) -> Self {
60 Self { client }
61 }
62
63 pub async fn list(&self) -> Result<ChatModelList> {
65 self.client
66 .request_json::<ChatModelList, ()>(Method::GET, "/api/v1/models", None, None)
67 .await
68 }
69}
70
71#[derive(Clone, Debug)]
73pub struct ChatCompletionsService {
74 client: Client,
75}
76
77impl ChatCompletionsService {
78 pub(crate) fn new(client: Client) -> Self {
79 Self { client }
80 }
81
82 pub async fn create(&self, mut body: ChatRequest) -> Result<ChatResponse> {
84 set_stream(&mut body, false);
85 self.client
86 .request_value(Method::POST, "/api/v1/chat/completions", None, Some(&body))
87 .await
88 }
89
90 pub async fn stream(&self, mut body: ChatRequest) -> Result<EventStream> {
92 set_stream(&mut body, true);
93 let bytes = self
94 .client
95 .stream_json(Method::POST, "/api/v1/chat/completions", Some(&body))
96 .await?;
97 Ok(events_from_bytes(bytes))
98 }
99
100 pub async fn stream_text(&self, body: ChatRequest) -> Result<TextStream> {
102 let stream = self.stream(body).await?;
103 Ok(Box::pin(stream.filter_map(|event| async move {
104 match event {
105 Ok(event) => {
106 let text = text_from_event(&event, StreamProtocol::OpenAi);
107 if text.is_empty() {
108 None
109 } else {
110 Some(Ok(text))
111 }
112 }
113 Err(error) => Some(Err(error)),
114 }
115 })))
116 }
117}
118
119#[derive(Clone, Debug)]
121pub struct MessagesService {
122 client: Client,
123}
124
125impl MessagesService {
126 pub(crate) fn new(client: Client) -> Self {
127 Self { client }
128 }
129
130 pub async fn create(&self, mut body: ChatRequest) -> Result<ChatResponse> {
132 set_stream(&mut body, false);
133 self.client
134 .request_value(Method::POST, "/api/v1/messages", None, Some(&body))
135 .await
136 }
137
138 pub async fn stream(&self, mut body: ChatRequest) -> Result<EventStream> {
140 set_stream(&mut body, true);
141 let bytes = self
142 .client
143 .stream_json(Method::POST, "/api/v1/messages", Some(&body))
144 .await?;
145 Ok(events_from_bytes(bytes))
146 }
147
148 pub async fn stream_text(&self, body: ChatRequest) -> Result<TextStream> {
150 let stream = self.stream(body).await?;
151 Ok(Box::pin(stream.filter_map(|event| async move {
152 match event {
153 Ok(event) => {
154 let text = text_from_event(&event, StreamProtocol::Anthropic);
155 if text.is_empty() {
156 None
157 } else {
158 Some(Ok(text))
159 }
160 }
161 Err(error) => Some(Err(error)),
162 }
163 })))
164 }
165}
166
167#[derive(Clone, Debug)]
169pub struct GeminiService {
170 client: Client,
171}
172
173impl GeminiService {
174 pub(crate) fn new(client: Client) -> Self {
175 Self { client }
176 }
177
178 pub async fn generate_content(&self, model: &str, body: ChatRequest) -> Result<ChatResponse> {
180 let path = format!(
181 "/api/v1beta/models/{}:generateContent",
182 encode_model_path(model)
183 );
184 self.client
185 .request_value(Method::POST, &path, None, Some(&body))
186 .await
187 }
188
189 pub async fn stream_generate_content(
191 &self,
192 model: &str,
193 body: ChatRequest,
194 ) -> Result<EventStream> {
195 let path = format!(
196 "/api/v1beta/models/{}:streamGenerateContent",
197 encode_model_path(model)
198 );
199 let bytes = self
200 .client
201 .stream_json(Method::POST, &path, Some(&body))
202 .await?;
203 Ok(events_from_bytes(bytes))
204 }
205
206 pub async fn stream_text(&self, model: &str, body: ChatRequest) -> Result<TextStream> {
208 let stream = self.stream_generate_content(model, body).await?;
209 Ok(Box::pin(stream.filter_map(|event| async move {
210 match event {
211 Ok(event) => {
212 let text = text_from_event(&event, StreamProtocol::Gemini);
213 if text.is_empty() {
214 None
215 } else {
216 Some(Ok(text))
217 }
218 }
219 Err(error) => Some(Err(error)),
220 }
221 })))
222 }
223}