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 ChunkDocumentRequest {
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
76pub type ChunkRequest = ChunkDocumentRequest;
78
79#[derive(Debug, Clone, Deserialize)]
81pub struct ChunkDocumentResponse {
82 pub chunks: Vec<DocumentChunk>,
84
85 #[serde(default)]
87 pub total_chunks: Option<i32>,
88
89 #[serde(default)]
91 pub cost_ticks: i64,
92
93 #[serde(default)]
95 pub request_id: String,
96}
97
98pub type ChunkResponse = ChunkDocumentResponse;
100
101#[derive(Debug, Clone, Serialize, Default)]
103pub struct ProcessDocumentRequest {
104 pub file_base64: String,
106
107 pub filename: String,
109
110 #[serde(skip_serializing_if = "Option::is_none")]
112 pub prompt: Option<String>,
113
114 #[serde(skip_serializing_if = "Option::is_none")]
116 pub model: Option<String>,
117}
118
119pub type ProcessRequest = ProcessDocumentRequest;
121
122#[derive(Debug, Clone, Deserialize)]
124pub struct ProcessDocumentResponse {
125 pub content: String,
127
128 #[serde(default)]
130 pub model: Option<String>,
131
132 #[serde(default)]
134 pub cost_ticks: i64,
135
136 #[serde(default)]
138 pub request_id: String,
139}
140
141pub type ProcessResponse = ProcessDocumentResponse;
143
144impl Client {
145 pub async fn extract_document(&self, req: &DocumentRequest) -> Result<DocumentResponse> {
147 let (mut resp, meta) = self
148 .post_json::<DocumentRequest, DocumentResponse>("/qai/v1/documents/extract", req)
149 .await?;
150 if resp.cost_ticks == 0 {
151 resp.cost_ticks = meta.cost_ticks;
152 }
153 if resp.request_id.is_empty() {
154 resp.request_id = meta.request_id;
155 }
156 Ok(resp)
157 }
158
159 pub async fn chunk_document(&self, req: &ChunkDocumentRequest) -> Result<ChunkDocumentResponse> {
161 let (mut resp, meta) = self
162 .post_json::<ChunkDocumentRequest, ChunkDocumentResponse>("/qai/v1/documents/chunk", req)
163 .await?;
164 if resp.cost_ticks == 0 {
165 resp.cost_ticks = meta.cost_ticks;
166 }
167 if resp.request_id.is_empty() {
168 resp.request_id = meta.request_id;
169 }
170 Ok(resp)
171 }
172
173 pub async fn process_document(&self, req: &ProcessDocumentRequest) -> Result<ProcessDocumentResponse> {
175 let (mut resp, meta) = self
176 .post_json::<ProcessDocumentRequest, ProcessDocumentResponse>("/qai/v1/documents/process", req)
177 .await?;
178 if resp.cost_ticks == 0 {
179 resp.cost_ticks = meta.cost_ticks;
180 }
181 if resp.request_id.is_empty() {
182 resp.request_id = meta.request_id;
183 }
184 Ok(resp)
185 }
186}