1use crate::language::Language;
2use anyhow::Result;
3use base64::{engine::general_purpose, Engine as _};
4use image::DynamicImage;
5use serde::{Deserialize, Serialize};
6
7#[derive(Debug, Clone, Serialize, Deserialize)]
8pub struct Credentials {
9 pub api_url: String,
10 pub api_key: String,
11 pub timeout_ms: u64,
12}
13
14impl Default for Credentials {
15 fn default() -> Self {
16 Credentials {
17 api_url: "http://localhost:8000/ocr".to_string(),
18 api_key: "".to_string(),
19 timeout_ms: 5000,
20 }
21 }
22}
23
24pub async fn perform_ocr_custom(
25 image: &DynamicImage,
26 languages: Vec<Language>,
27 credentials: &Credentials,
28) -> Result<(String, String, Option<f64>)> {
29 let rgb_image = image.to_rgb8();
31
32 let mut buffer = Vec::new();
34 rgb_image.write_to(
35 &mut std::io::Cursor::new(&mut buffer),
36 image::ImageFormat::Jpeg,
37 )?;
38 let base64_image = general_purpose::STANDARD.encode(buffer);
39
40 let payload = serde_json::json!({
42 "image": base64_image,
43 "languages": languages.iter().map(|l| l.to_string()).collect::<Vec<_>>(),
44 });
45
46 let client = reqwest::Client::builder()
48 .timeout(std::time::Duration::from_millis(credentials.timeout_ms))
49 .build()?;
50
51 let response = client
53 .post(&credentials.api_url)
54 .header("Authorization", format!("Bearer {}", credentials.api_key))
55 .json(&payload)
56 .send()
57 .await?;
58
59 let ocr_result: OcrResponse = response.json().await?;
61
62 Ok((
63 ocr_result.text,
64 ocr_result.structured_data.to_string(),
65 Some(ocr_result.confidence),
66 ))
67}
68
69#[derive(Debug, Deserialize)]
70struct OcrResponse {
71 text: String,
72 structured_data: serde_json::Value,
73 confidence: f64,
74}