1use serde::{Deserialize, Serialize};
2
3use crate::client::Client;
4use crate::error::Result;
5
6#[derive(Debug, Clone, Serialize, Default)]
12pub struct SearchOptions {
13 #[serde(skip_serializing_if = "Option::is_none")]
15 pub count: Option<i32>,
16
17 #[serde(skip_serializing_if = "Option::is_none")]
19 pub offset: Option<i32>,
20
21 #[serde(skip_serializing_if = "Option::is_none")]
23 pub country: Option<String>,
24
25 #[serde(skip_serializing_if = "Option::is_none")]
27 pub language: Option<String>,
28
29 #[serde(skip_serializing_if = "Option::is_none")]
31 pub freshness: Option<String>,
32
33 #[serde(skip_serializing_if = "Option::is_none")]
35 pub safe_search: Option<String>,
36}
37
38#[derive(Debug, Clone, Serialize, Default)]
40pub struct ContextOptions {
41 #[serde(skip_serializing_if = "Option::is_none")]
43 pub count: Option<i32>,
44
45 #[serde(skip_serializing_if = "Option::is_none")]
47 pub country: Option<String>,
48
49 #[serde(skip_serializing_if = "Option::is_none")]
51 pub language: Option<String>,
52
53 #[serde(skip_serializing_if = "Option::is_none")]
55 pub freshness: Option<String>,
56}
57
58#[derive(Debug, Clone, Serialize, Deserialize)]
60pub struct SearchMessage {
61 pub role: String,
63
64 pub content: String,
66}
67
68#[derive(Debug, Clone, Serialize, Default)]
74pub struct WebSearchRequest {
75 pub query: String,
77
78 #[serde(skip_serializing_if = "Option::is_none")]
80 pub count: Option<i32>,
81
82 #[serde(skip_serializing_if = "Option::is_none")]
84 pub offset: Option<i32>,
85
86 #[serde(skip_serializing_if = "Option::is_none")]
88 pub country: Option<String>,
89
90 #[serde(skip_serializing_if = "Option::is_none")]
92 pub language: Option<String>,
93
94 #[serde(skip_serializing_if = "Option::is_none")]
96 pub freshness: Option<String>,
97
98 #[serde(skip_serializing_if = "Option::is_none")]
100 pub safesearch: Option<String>,
101}
102
103#[derive(Debug, Clone, Serialize, Deserialize)]
105pub struct WebResult {
106 pub title: String,
108
109 pub url: String,
111
112 #[serde(default)]
114 pub description: String,
115
116 #[serde(default)]
118 pub age: Option<String>,
119
120 #[serde(default)]
122 pub favicon: Option<String>,
123}
124
125#[derive(Debug, Clone, Serialize, Deserialize)]
127pub struct NewsResult {
128 pub title: String,
130
131 pub url: String,
133
134 #[serde(default)]
136 pub description: String,
137
138 #[serde(default)]
140 pub age: Option<String>,
141
142 #[serde(default)]
144 pub source: Option<String>,
145}
146
147#[derive(Debug, Clone, Serialize, Deserialize)]
149pub struct VideoResult {
150 pub title: String,
152
153 pub url: String,
155
156 #[serde(default)]
158 pub description: String,
159
160 #[serde(default)]
162 pub thumbnail: Option<String>,
163
164 #[serde(default)]
166 pub age: Option<String>,
167}
168
169#[derive(Debug, Clone, Serialize, Deserialize)]
171pub struct Infobox {
172 pub title: String,
174
175 #[serde(default)]
177 pub description: String,
178
179 #[serde(default)]
181 pub url: Option<String>,
182}
183
184pub type InfoboxResult = Infobox;
186
187#[derive(Debug, Clone, Serialize, Deserialize)]
189pub struct Discussion {
190 pub title: String,
192
193 pub url: String,
195
196 #[serde(default)]
198 pub description: String,
199
200 #[serde(default)]
202 pub age: Option<String>,
203
204 #[serde(default)]
206 pub forum: Option<String>,
207}
208
209pub type DiscussionResult = Discussion;
211
212#[derive(Debug, Clone, Deserialize)]
214pub struct WebSearchResponse {
215 pub query: String,
217
218 #[serde(default)]
220 pub web: Vec<WebResult>,
221
222 #[serde(default)]
224 pub news: Vec<NewsResult>,
225
226 #[serde(default)]
228 pub videos: Vec<VideoResult>,
229
230 #[serde(default)]
232 pub infobox: Vec<Infobox>,
233
234 #[serde(default)]
236 pub discussions: Vec<Discussion>,
237}
238
239#[derive(Debug, Clone, Serialize, Default)]
245pub struct SearchContextRequest {
246 pub query: String,
248
249 #[serde(skip_serializing_if = "Option::is_none")]
251 pub count: Option<i32>,
252
253 #[serde(skip_serializing_if = "Option::is_none")]
255 pub country: Option<String>,
256
257 #[serde(skip_serializing_if = "Option::is_none")]
259 pub language: Option<String>,
260
261 #[serde(skip_serializing_if = "Option::is_none")]
263 pub freshness: Option<String>,
264}
265
266#[derive(Debug, Clone, Serialize, Deserialize)]
268pub struct SearchContextChunk {
269 pub content: String,
271
272 pub url: String,
274
275 #[serde(default)]
277 pub title: String,
278
279 #[serde(default)]
281 pub score: f64,
282
283 #[serde(default)]
285 pub content_type: Option<String>,
286}
287
288#[derive(Debug, Clone, Serialize, Deserialize)]
290pub struct SearchContextSource {
291 pub url: String,
293
294 #[serde(default)]
296 pub title: String,
297}
298
299#[derive(Debug, Clone, Deserialize)]
301pub struct SearchContextResponse {
302 pub chunks: Vec<SearchContextChunk>,
304
305 #[serde(default)]
307 pub sources: Vec<SearchContextSource>,
308
309 pub query: String,
311}
312
313#[derive(Debug, Clone, Deserialize)]
318pub struct LLMContextResponse {
319 pub query: String,
321
322 #[serde(default)]
324 pub chunks: Vec<ContextChunk>,
325
326 #[serde(default)]
328 pub sources: Vec<String>,
329}
330
331#[derive(Debug, Clone, Serialize, Deserialize)]
333pub struct ContextChunk {
334 pub content: String,
336
337 pub url: String,
339
340 #[serde(default)]
342 pub title: String,
343
344 #[serde(default)]
346 pub score: f64,
347
348 #[serde(default)]
350 pub content_type: Option<String>,
351}
352
353#[derive(Debug, Clone, Serialize, Deserialize)]
359pub struct SearchAnswerMessage {
360 pub role: String,
362
363 pub content: String,
365}
366
367#[derive(Debug, Clone, Serialize, Default)]
369pub struct SearchAnswerRequest {
370 pub messages: Vec<SearchAnswerMessage>,
372
373 #[serde(skip_serializing_if = "Option::is_none")]
375 pub model: Option<String>,
376}
377
378#[derive(Debug, Clone, Serialize, Deserialize)]
380pub struct SearchAnswerCitation {
381 pub url: String,
383
384 #[serde(default)]
386 pub title: String,
387
388 #[serde(default)]
390 pub snippet: Option<String>,
391}
392
393#[derive(Debug, Clone, Deserialize)]
395pub struct SearchAnswerChoice {
396 pub index: i32,
398
399 pub message: SearchAnswerMessage,
401
402 #[serde(default)]
404 pub finish_reason: Option<String>,
405}
406
407#[derive(Debug, Clone, Deserialize)]
409pub struct SearchAnswerResponse {
410 pub choices: Vec<SearchAnswerChoice>,
412
413 #[serde(default)]
415 pub model: String,
416
417 #[serde(default)]
419 pub id: String,
420
421 #[serde(default)]
423 pub citations: Vec<SearchAnswerCitation>,
424}
425
426impl Client {
431 pub async fn web_search(&self, req: &WebSearchRequest) -> Result<WebSearchResponse> {
434 let (resp, _meta) = self
435 .post_json::<WebSearchRequest, WebSearchResponse>("/qai/v1/search/web", req)
436 .await?;
437 Ok(resp)
438 }
439
440 pub async fn search_context(
443 &self,
444 req: &SearchContextRequest,
445 ) -> Result<SearchContextResponse> {
446 let (resp, _meta) = self
447 .post_json::<SearchContextRequest, SearchContextResponse>(
448 "/qai/v1/search/context",
449 req,
450 )
451 .await?;
452 Ok(resp)
453 }
454
455 pub async fn search_answer(&self, req: &SearchAnswerRequest) -> Result<SearchAnswerResponse> {
458 let (resp, _meta) = self
459 .post_json::<SearchAnswerRequest, SearchAnswerResponse>(
460 "/qai/v1/search/answer",
461 req,
462 )
463 .await?;
464 Ok(resp)
465 }
466}