1use std::path::PathBuf;
2
3use a3s_use_core::{Artifact, Readiness};
4use serde::{Deserialize, Serialize};
5
6#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
7#[serde(rename_all = "camelCase")]
8pub struct OcrRequest {
9 #[schemars(description = "Local PNG, JPEG, WebP, GIF, BMP, or TIFF image path")]
10 pub path: PathBuf,
11}
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
14#[serde(rename_all = "camelCase")]
15pub struct OcrPoint {
16 pub x: u32,
17 pub y: u32,
18}
19
20#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
21#[serde(rename_all = "camelCase")]
22pub struct OcrBoundingBox {
23 pub x: u32,
24 pub y: u32,
25 pub width: u32,
26 pub height: u32,
27}
28
29#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, schemars::JsonSchema)]
30#[serde(rename_all = "camelCase")]
31pub struct OcrBlock {
32 pub page: u32,
33 pub text: String,
34 #[serde(default, skip_serializing_if = "Option::is_none")]
35 #[schemars(description = "Provider recognition confidence from 0 through 1, when available")]
36 pub confidence: Option<f32>,
37 #[serde(default, skip_serializing_if = "Option::is_none")]
38 #[schemars(
39 description = "Provider text-detection confidence from 0 through 1, when available"
40 )]
41 pub detection_confidence: Option<f32>,
42 #[serde(default, skip_serializing_if = "Option::is_none")]
43 #[schemars(description = "Four polygon vertices in source-image coordinates, when available")]
44 pub polygon: Option<[OcrPoint; 4]>,
45 #[serde(default, skip_serializing_if = "Option::is_none")]
46 pub bounding_box: Option<OcrBoundingBox>,
47}
48
49#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, schemars::JsonSchema)]
50#[serde(rename_all = "camelCase")]
51pub struct OcrResult {
52 pub provider: String,
53 pub engine: String,
54 #[serde(skip_serializing_if = "Option::is_none")]
55 pub model: Option<String>,
56 #[schemars(with = "OcrArtifactSchema")]
57 pub source: Artifact,
58 pub text: String,
59 #[serde(default, skip_serializing_if = "Vec::is_empty")]
60 pub blocks: Vec<OcrBlock>,
61 #[serde(default, skip_serializing_if = "Vec::is_empty")]
62 pub warnings: Vec<String>,
63}
64
65#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
66#[serde(rename_all = "camelCase")]
67pub struct OcrDiagnostic {
68 #[schemars(with = "OcrReadinessSchema")]
69 pub readiness: Readiness,
70 #[serde(skip_serializing_if = "Option::is_none")]
71 pub provider: Option<String>,
72 #[serde(skip_serializing_if = "Option::is_none")]
73 pub engine: Option<String>,
74 #[serde(skip_serializing_if = "Option::is_none")]
75 pub model: Option<String>,
76 #[serde(skip_serializing_if = "Option::is_none")]
77 pub model_dir: Option<PathBuf>,
78 pub sends_source_off_device: bool,
79 pub message: String,
80 #[serde(default, skip_serializing_if = "Vec::is_empty")]
81 pub suggestions: Vec<String>,
82}
83
84#[derive(schemars::JsonSchema)]
85#[allow(dead_code)]
86struct OcrArtifactSchema {
87 path: PathBuf,
88 media_type: String,
89 size: u64,
90 sha256: String,
91}
92
93#[derive(schemars::JsonSchema)]
94#[serde(rename_all = "kebab-case")]
95#[allow(dead_code)]
96enum OcrReadinessSchema {
97 Ready,
98 Missing,
99 Broken,
100 Unknown,
101}