1use std::collections::HashMap;
2
3use serde::{Deserialize, Serialize};
4
5use crate::client::Client;
6use crate::error::Result;
7
8#[derive(Debug, Clone, Serialize, Default)]
10pub struct DocumentRequest {
11 pub file_base64: String,
13
14 pub filename: String,
16
17 #[serde(skip_serializing_if = "Option::is_none")]
19 pub output_format: Option<String>,
20}
21
22#[derive(Debug, Clone, Deserialize)]
24pub struct DocumentResponse {
25 pub content: String,
27
28 pub format: String,
30
31 #[serde(default)]
33 pub meta: Option<HashMap<String, serde_json::Value>>,
34
35 #[serde(default)]
37 pub cost_ticks: i64,
38
39 #[serde(default)]
41 pub request_id: String,
42}
43
44#[derive(Debug, Clone, Serialize, Default)]
46pub struct ChunkRequest {
47 pub file_base64: String,
49
50 pub filename: String,
52
53 #[serde(skip_serializing_if = "Option::is_none")]
55 pub max_chunk_tokens: Option<i32>,
56
57 #[serde(skip_serializing_if = "Option::is_none")]
59 pub overlap_tokens: Option<i32>,
60}
61
62#[derive(Debug, Clone, Deserialize)]
64pub struct DocumentChunk {
65 pub index: i32,
67
68 pub text: String,
70
71 #[serde(default)]
73 pub token_count: Option<i32>,
74}
75
76#[derive(Debug, Clone, Deserialize)]
78pub struct ChunkResponse {
79 pub chunks: Vec<DocumentChunk>,
81
82 #[serde(default)]
84 pub total_chunks: Option<i32>,
85
86 #[serde(default)]
88 pub cost_ticks: i64,
89
90 #[serde(default)]
92 pub request_id: String,
93}
94
95#[derive(Debug, Clone, Serialize, Default)]
97pub struct ProcessRequest {
98 pub file_base64: String,
100
101 pub filename: String,
103
104 #[serde(skip_serializing_if = "Option::is_none")]
106 pub prompt: Option<String>,
107
108 #[serde(skip_serializing_if = "Option::is_none")]
110 pub model: Option<String>,
111}
112
113#[derive(Debug, Clone, Deserialize)]
115pub struct ProcessResponse {
116 pub content: String,
118
119 #[serde(default)]
121 pub model: Option<String>,
122
123 #[serde(default)]
125 pub cost_ticks: i64,
126
127 #[serde(default)]
129 pub request_id: String,
130}
131
132impl Client {
133 pub async fn extract_document(&self, req: &DocumentRequest) -> Result<DocumentResponse> {
135 let (mut resp, meta) = self
136 .post_json::<DocumentRequest, DocumentResponse>("/qai/v1/documents/extract", req)
137 .await?;
138 if resp.cost_ticks == 0 {
139 resp.cost_ticks = meta.cost_ticks;
140 }
141 if resp.request_id.is_empty() {
142 resp.request_id = meta.request_id;
143 }
144 Ok(resp)
145 }
146
147 pub async fn chunk_document(&self, req: &ChunkRequest) -> Result<ChunkResponse> {
149 let (mut resp, meta) = self
150 .post_json::<ChunkRequest, ChunkResponse>("/qai/v1/documents/chunk", req)
151 .await?;
152 if resp.cost_ticks == 0 {
153 resp.cost_ticks = meta.cost_ticks;
154 }
155 if resp.request_id.is_empty() {
156 resp.request_id = meta.request_id;
157 }
158 Ok(resp)
159 }
160
161 pub async fn process_document(&self, req: &ProcessRequest) -> Result<ProcessResponse> {
163 let (mut resp, meta) = self
164 .post_json::<ProcessRequest, ProcessResponse>("/qai/v1/documents/process", req)
165 .await?;
166 if resp.cost_ticks == 0 {
167 resp.cost_ticks = meta.cost_ticks;
168 }
169 if resp.request_id.is_empty() {
170 resp.request_id = meta.request_id;
171 }
172 Ok(resp)
173 }
174}