1use serde::{Deserialize, Serialize};
2
3use crate::client::Client;
4use crate::error::Result;
5
6#[derive(Debug, Clone, Serialize, Default)]
12pub struct WebSearchRequest {
13 pub query: String,
15
16 #[serde(skip_serializing_if = "Option::is_none")]
18 pub count: Option<i32>,
19
20 #[serde(skip_serializing_if = "Option::is_none")]
22 pub offset: Option<i32>,
23
24 #[serde(skip_serializing_if = "Option::is_none")]
26 pub country: Option<String>,
27
28 #[serde(skip_serializing_if = "Option::is_none")]
30 pub language: Option<String>,
31
32 #[serde(skip_serializing_if = "Option::is_none")]
34 pub freshness: Option<String>,
35
36 #[serde(skip_serializing_if = "Option::is_none")]
38 pub safesearch: Option<String>,
39}
40
41#[derive(Debug, Clone, Serialize, Deserialize)]
43pub struct WebResult {
44 pub title: String,
46
47 pub url: String,
49
50 #[serde(default)]
52 pub description: String,
53
54 #[serde(default)]
56 pub age: Option<String>,
57
58 #[serde(default)]
60 pub favicon: Option<String>,
61}
62
63#[derive(Debug, Clone, Serialize, Deserialize)]
65pub struct NewsResult {
66 pub title: String,
68
69 pub url: String,
71
72 #[serde(default)]
74 pub description: String,
75
76 #[serde(default)]
78 pub age: Option<String>,
79
80 #[serde(default)]
82 pub source: Option<String>,
83}
84
85#[derive(Debug, Clone, Serialize, Deserialize)]
87pub struct VideoResult {
88 pub title: String,
90
91 pub url: String,
93
94 #[serde(default)]
96 pub description: String,
97
98 #[serde(default)]
100 pub thumbnail: Option<String>,
101
102 #[serde(default)]
104 pub age: Option<String>,
105}
106
107#[derive(Debug, Clone, Serialize, Deserialize)]
109pub struct InfoboxResult {
110 pub title: String,
112
113 #[serde(default)]
115 pub description: String,
116
117 #[serde(default)]
119 pub url: Option<String>,
120}
121
122#[derive(Debug, Clone, Serialize, Deserialize)]
124pub struct DiscussionResult {
125 pub title: String,
127
128 pub url: String,
130
131 #[serde(default)]
133 pub description: String,
134
135 #[serde(default)]
137 pub age: Option<String>,
138
139 #[serde(default)]
141 pub forum: Option<String>,
142}
143
144#[derive(Debug, Clone, Deserialize)]
146pub struct WebSearchResponse {
147 pub query: String,
149
150 #[serde(default)]
152 pub web: Vec<WebResult>,
153
154 #[serde(default)]
156 pub news: Vec<NewsResult>,
157
158 #[serde(default)]
160 pub videos: Vec<VideoResult>,
161
162 #[serde(default)]
164 pub infobox: Vec<InfoboxResult>,
165
166 #[serde(default)]
168 pub discussions: Vec<DiscussionResult>,
169}
170
171#[derive(Debug, Clone, Serialize, Default)]
177pub struct SearchContextRequest {
178 pub query: String,
180
181 #[serde(skip_serializing_if = "Option::is_none")]
183 pub count: Option<i32>,
184
185 #[serde(skip_serializing_if = "Option::is_none")]
187 pub country: Option<String>,
188
189 #[serde(skip_serializing_if = "Option::is_none")]
191 pub language: Option<String>,
192
193 #[serde(skip_serializing_if = "Option::is_none")]
195 pub freshness: Option<String>,
196}
197
198#[derive(Debug, Clone, Serialize, Deserialize)]
200pub struct SearchContextChunk {
201 pub content: String,
203
204 pub url: String,
206
207 #[serde(default)]
209 pub title: String,
210
211 #[serde(default)]
213 pub score: f64,
214
215 #[serde(default)]
217 pub content_type: Option<String>,
218}
219
220#[derive(Debug, Clone, Serialize, Deserialize)]
222pub struct SearchContextSource {
223 pub url: String,
225
226 #[serde(default)]
228 pub title: String,
229}
230
231#[derive(Debug, Clone, Deserialize)]
233pub struct SearchContextResponse {
234 pub chunks: Vec<SearchContextChunk>,
236
237 #[serde(default)]
239 pub sources: Vec<SearchContextSource>,
240
241 pub query: String,
243}
244
245#[derive(Debug, Clone, Serialize, Deserialize)]
251pub struct SearchAnswerMessage {
252 pub role: String,
254
255 pub content: String,
257}
258
259#[derive(Debug, Clone, Serialize, Default)]
261pub struct SearchAnswerRequest {
262 pub messages: Vec<SearchAnswerMessage>,
264
265 #[serde(skip_serializing_if = "Option::is_none")]
267 pub model: Option<String>,
268}
269
270#[derive(Debug, Clone, Serialize, Deserialize)]
272pub struct SearchAnswerCitation {
273 pub url: String,
275
276 #[serde(default)]
278 pub title: String,
279
280 #[serde(default)]
282 pub snippet: Option<String>,
283}
284
285#[derive(Debug, Clone, Deserialize)]
287pub struct SearchAnswerChoice {
288 pub index: i32,
290
291 pub message: SearchAnswerMessage,
293
294 #[serde(default)]
296 pub finish_reason: Option<String>,
297}
298
299#[derive(Debug, Clone, Deserialize)]
301pub struct SearchAnswerResponse {
302 pub choices: Vec<SearchAnswerChoice>,
304
305 #[serde(default)]
307 pub model: String,
308
309 #[serde(default)]
311 pub id: String,
312
313 #[serde(default)]
315 pub citations: Vec<SearchAnswerCitation>,
316}
317
318impl Client {
323 pub async fn web_search(&self, req: &WebSearchRequest) -> Result<WebSearchResponse> {
326 let (resp, _meta) = self
327 .post_json::<WebSearchRequest, WebSearchResponse>("/qai/v1/search/web", req)
328 .await?;
329 Ok(resp)
330 }
331
332 pub async fn search_context(
335 &self,
336 req: &SearchContextRequest,
337 ) -> Result<SearchContextResponse> {
338 let (resp, _meta) = self
339 .post_json::<SearchContextRequest, SearchContextResponse>(
340 "/qai/v1/search/context",
341 req,
342 )
343 .await?;
344 Ok(resp)
345 }
346
347 pub async fn search_answer(&self, req: &SearchAnswerRequest) -> Result<SearchAnswerResponse> {
350 let (resp, _meta) = self
351 .post_json::<SearchAnswerRequest, SearchAnswerResponse>(
352 "/qai/v1/search/answer",
353 req,
354 )
355 .await?;
356 Ok(resp)
357 }
358}