1use serde::{Deserialize, Serialize};
4use serde_json::Value;
5use std::collections::BTreeMap;
6
7#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
9#[serde(rename_all = "camelCase")]
10pub struct CrawlSummary {
11 pub stop_reason: String,
14 #[serde(skip_serializing_if = "Option::is_none")]
16 pub coverage: Option<f64>,
17 #[serde(skip_serializing_if = "BTreeMap::is_empty", default)]
19 pub term_evidence: BTreeMap<String, usize>,
20 pub pages: usize,
22}
23
24#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
27#[serde(rename_all = "camelCase")]
28pub struct CrawlTrace {
29 pub depth: usize,
31 #[serde(skip_serializing_if = "Option::is_none")]
33 pub parent: Option<String>,
34 #[serde(skip_serializing_if = "Option::is_none")]
36 pub score: Option<f32>,
37 #[serde(skip_serializing_if = "Option::is_none")]
39 pub attachment_of: Option<String>,
40}
41
42#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
44#[serde(rename_all = "camelCase")]
45pub struct OcrMeta {
46 pub engine: String,
47 pub model: String,
48 pub device: String,
50 pub pages: usize,
52 pub fallback: bool,
54}
55
56#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
57#[serde(rename_all = "camelCase")]
58pub struct PagesiftMeta {
59 #[serde(skip_serializing_if = "Option::is_none")]
60 pub content_hash: Option<String>,
61 #[serde(skip_serializing_if = "Option::is_none")]
62 pub raw_hash: Option<String>,
63 #[serde(skip_serializing_if = "Option::is_none")]
64 pub text_hash: Option<String>,
65 #[serde(skip_serializing_if = "Vec::is_empty", default)]
66 pub redirect_chain: Vec<String>,
67 #[serde(skip_serializing_if = "Option::is_none")]
68 pub etag: Option<String>,
69 #[serde(skip_serializing_if = "Option::is_none")]
70 pub last_modified: Option<String>,
71 #[serde(skip_serializing_if = "std::ops::Not::not", default)]
72 pub not_modified: bool,
73 #[serde(skip_serializing_if = "Option::is_none")]
75 pub engine: Option<String>,
76 #[serde(skip_serializing_if = "Option::is_none")]
78 pub browser_engine: Option<String>,
79 #[serde(skip_serializing_if = "Option::is_none")]
81 pub browser_fingerprint: Option<String>,
82 #[serde(skip_serializing_if = "Option::is_none")]
84 pub itna: Option<Value>,
85 #[serde(skip_serializing_if = "Vec::is_empty", default)]
86 pub warnings: Vec<String>,
87 #[serde(skip_serializing_if = "BTreeMap::is_empty", default)]
89 pub timings: BTreeMap<String, f64>,
90 #[serde(skip_serializing_if = "Option::is_none")]
92 pub ocr: Option<OcrMeta>,
93 #[serde(skip_serializing_if = "Option::is_none")]
95 pub duplicate_of: Option<String>,
96 #[serde(skip_serializing_if = "Option::is_none")]
98 pub relevance: Option<f32>,
99 #[serde(skip_serializing_if = "Option::is_none")]
101 pub crawl: Option<CrawlTrace>,
102 #[serde(skip_serializing_if = "Option::is_none")]
104 pub query_filter: Option<QueryFilterStats>,
105 #[serde(skip_serializing_if = "Vec::is_empty", default)]
107 pub json_ld: Vec<Value>,
108 #[serde(skip_serializing_if = "Option::is_none")]
111 pub plan: Option<PlanTrace>,
112}
113
114#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
116#[serde(rename_all = "camelCase")]
117pub struct PlanTrace {
118 pub steps: Vec<PlanStep>,
119}
120
121#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
122#[serde(rename_all = "camelCase")]
123pub struct PlanStep {
124 pub action: String,
126 pub chosen: bool,
127 pub learned: bool,
129 #[serde(skip_serializing_if = "Option::is_none")]
131 pub p: Option<f64>,
132 #[serde(skip_serializing_if = "Option::is_none")]
134 pub value: Option<f64>,
135 #[serde(skip_serializing_if = "Option::is_none")]
137 pub charge: Option<f64>,
138 #[serde(skip_serializing_if = "Option::is_none")]
140 pub quality: Option<f64>,
141 #[serde(skip_serializing_if = "Option::is_none")]
143 pub blocks: Option<[usize; 3]>, }
145
146#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
147#[serde(rename_all = "camelCase")]
148pub struct QueryFilterStats {
149 pub kept_blocks: usize,
150 pub total_blocks: usize,
151 pub tokens_before: usize,
152 pub tokens_after: usize,
153}
154
155#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
157#[serde(rename_all = "camelCase")]
158pub struct ChangeTracking {
159 pub previous_scrape_at: Option<String>,
160 pub change_status: String,
162 pub visibility: String,
164 #[serde(skip_serializing_if = "Option::is_none")]
165 pub diff: Option<Value>,
166 #[serde(skip_serializing_if = "Option::is_none")]
167 pub json: Option<Value>,
168 #[serde(skip_serializing_if = "Option::is_none")]
169 pub pagesift: Option<Value>,
170}
171
172#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
173#[serde(rename_all = "camelCase")]
174pub struct Metadata {
175 #[serde(skip_serializing_if = "Option::is_none")]
177 pub scrape_id: Option<String>,
178 #[serde(skip_serializing_if = "Option::is_none")]
179 pub title: Option<String>,
180 #[serde(skip_serializing_if = "Option::is_none")]
181 pub description: Option<String>,
182 #[serde(skip_serializing_if = "Option::is_none")]
183 pub language: Option<String>,
184 #[serde(skip_serializing_if = "Option::is_none")]
185 pub keywords: Option<String>,
186 #[serde(skip_serializing_if = "Option::is_none")]
187 pub robots: Option<String>,
188 #[serde(skip_serializing_if = "Option::is_none")]
189 pub favicon: Option<String>,
190 #[serde(skip_serializing_if = "Option::is_none")]
191 pub published_time: Option<String>,
192 #[serde(skip_serializing_if = "Option::is_none")]
193 pub author: Option<String>,
194 #[serde(skip_serializing_if = "Option::is_none")]
195 pub modified_time: Option<String>,
196 #[serde(skip_serializing_if = "Option::is_none")]
197 pub url: Option<String>,
198 #[serde(rename = "sourceURL", skip_serializing_if = "Option::is_none")]
199 pub source_url: Option<String>,
200 pub status_code: u16,
201 #[serde(skip)]
203 pub retry_after: bool,
204 #[serde(skip_serializing_if = "Option::is_none")]
205 pub content_type: Option<String>,
206 #[serde(skip_serializing_if = "Option::is_none")]
207 pub error: Option<String>,
208 pub proxy_used: String,
209 #[serde(skip_serializing_if = "Option::is_none")]
210 pub cache_state: Option<String>,
211 #[serde(skip_serializing_if = "Option::is_none")]
212 pub cached_at: Option<String>,
213 #[serde(flatten)]
214 pub extra: BTreeMap<String, Value>,
215 #[serde(skip_serializing_if = "Option::is_none")]
216 pub pagesift: Option<PagesiftMeta>,
217}
218
219#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
220#[serde(rename_all = "camelCase")]
221pub struct Document {
222 #[serde(skip_serializing_if = "Option::is_none")]
223 pub markdown: Option<String>,
224 #[serde(skip_serializing_if = "Option::is_none")]
226 pub pages: Option<Vec<PageMarkdown>>,
227 #[serde(skip_serializing_if = "Option::is_none")]
228 pub html: Option<String>,
229 #[serde(skip_serializing_if = "Option::is_none")]
230 pub raw_html: Option<String>,
231 #[serde(skip_serializing_if = "Option::is_none")]
232 pub links: Option<Vec<String>>,
233 #[serde(skip)]
235 pub link_text: Option<Vec<String>>,
236 #[serde(skip)]
238 pub alternates: Vec<(String, String)>,
239 #[serde(skip)]
242 pub quality: Option<f64>,
243 #[serde(skip_serializing_if = "Option::is_none")]
244 pub images: Option<Vec<String>>,
245 #[serde(skip_serializing_if = "Option::is_none")]
246 pub screenshot: Option<String>,
247 #[serde(skip_serializing_if = "Option::is_none")]
248 pub json: Option<Value>,
249 #[serde(skip_serializing_if = "Option::is_none")]
251 pub extract: Option<Value>,
252 #[serde(skip_serializing_if = "Option::is_none")]
253 pub summary: Option<String>,
254 #[serde(skip_serializing_if = "Option::is_none")]
255 pub actions: Option<Value>,
256 #[serde(skip_serializing_if = "Option::is_none")]
257 pub warning: Option<String>,
258 #[serde(skip_serializing_if = "Option::is_none")]
259 pub change_tracking: Option<ChangeTracking>,
260 #[serde(skip_serializing_if = "Option::is_none")]
261 pub chunks: Option<Vec<DocChunk>>,
262 #[serde(skip_serializing_if = "Vec::is_empty", default)]
265 pub attachments: Vec<super::Attachment>,
266 #[serde(default, skip_serializing_if = "Vec::is_empty")]
268 pub image_assets: Vec<ImageAssetResult>,
269 pub metadata: Metadata,
270}
271
272#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
274#[serde(rename_all = "camelCase")]
275pub struct ImageAssetResult {
276 pub source: String,
277 pub status: ImageAssetStatus,
278 #[serde(skip_serializing_if = "Option::is_none")]
279 pub id: Option<String>,
280 #[serde(skip_serializing_if = "Option::is_none")]
281 pub mime: Option<String>,
282 #[serde(skip_serializing_if = "Option::is_none")]
283 pub bytes: Option<u64>,
284 #[serde(skip_serializing_if = "Option::is_none")]
285 pub reason: Option<String>,
286}
287
288#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
289#[serde(rename_all = "kebab-case")]
290pub enum ImageAssetStatus {
291 Ok,
292 SkippedLimit,
293 Failed,
294}
295
296#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
298#[serde(rename_all = "camelCase")]
299pub struct PageMarkdown {
300 pub page_number: usize,
302 pub markdown: String,
303}
304
305#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
306#[serde(rename_all = "camelCase")]
307pub struct DocChunk {
308 pub text: String,
309 pub heading_path: Vec<String>,
310 pub start: usize,
311 pub end: usize,
312 pub tokens: usize,
313}
314
315#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
316pub struct MapLink {
317 pub url: String,
318 #[serde(skip_serializing_if = "Option::is_none")]
319 pub title: Option<String>,
320 #[serde(skip_serializing_if = "Option::is_none")]
321 pub description: Option<String>,
322}
323
324#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
325pub struct ScrapeResponse {
326 pub success: bool,
327 pub data: Document,
328 #[serde(skip_serializing_if = "Option::is_none")]
329 pub warning: Option<String>,
330}
331
332#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
333#[serde(rename_all = "camelCase")]
334pub struct JobStarted {
335 pub success: bool,
336 pub id: String,
337 pub url: String,
338 #[serde(rename = "invalidURLs", skip_serializing_if = "Option::is_none")]
339 pub invalid_urls: Option<Vec<String>>,
340 #[serde(default, skip_serializing_if = "Vec::is_empty")]
342 pub warnings: Vec<String>,
343}
344
345#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
346#[serde(rename_all = "camelCase")]
347pub struct JobStatus {
348 pub success: bool,
349 pub status: String,
350 pub completed: usize,
351 pub total: usize,
352 pub credits_used: usize,
353 pub expires_at: String,
354 #[serde(skip_serializing_if = "Option::is_none")]
355 pub next: Option<String>,
356 pub data: Vec<Document>,
357 #[serde(skip_serializing_if = "Option::is_none")]
358 pub pagesift: Option<CrawlSummary>,
359}
360
361#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
362pub struct JobError {
363 pub id: String,
364 pub timestamp: String,
365 pub url: String,
366 pub code: String,
367 pub error: String,
368}
369
370#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
371#[serde(rename_all = "camelCase")]
372pub struct JobErrors {
373 pub errors: Vec<JobError>,
374 pub robots_blocked: Vec<String>,
375}
376
377#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
378pub struct MapResponse {
379 pub success: bool,
380 pub links: Vec<MapLink>,
381 #[serde(default, skip_serializing_if = "Vec::is_empty")]
383 pub warnings: Vec<String>,
384}