use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use crate::client::Client;
use crate::error::Result;
#[derive(Debug, Clone, Serialize, Default)]
pub struct VisionRequest {
#[serde(skip_serializing_if = "Option::is_none")]
pub image_base64: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub image_url: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub model: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub profile: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub context: Option<VisionContext>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct VisionContext {
#[serde(skip_serializing_if = "Option::is_none")]
pub installation_type: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub phase: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub expected_items: Option<Vec<String>>,
}
#[derive(Debug, Clone, Deserialize, Default)]
pub struct VisionResponse {
#[serde(default)]
pub caption: Option<String>,
#[serde(default)]
pub tags: Vec<String>,
#[serde(default)]
pub objects: Vec<DetectedObject>,
#[serde(default)]
pub quality: Option<QualityAssessment>,
#[serde(default)]
pub relevance: Option<RelevanceCheck>,
#[serde(default)]
pub ocr: Option<OcrResult>,
#[serde(default)]
pub model: String,
#[serde(default)]
pub cost_ticks: i64,
#[serde(default)]
pub request_id: String,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct DetectedObject {
pub label: String,
#[serde(default)]
pub confidence: f64,
#[serde(default)]
pub bounding_box: [i32; 4],
}
#[derive(Debug, Clone, Deserialize, Default)]
pub struct QualityAssessment {
#[serde(default)]
pub overall: String,
#[serde(default)]
pub score: f64,
#[serde(default)]
pub blur: String,
#[serde(default)]
pub darkness: String,
#[serde(default)]
pub resolution: String,
#[serde(default)]
pub exposure: String,
#[serde(default)]
pub issues: Vec<String>,
}
#[derive(Debug, Clone, Deserialize, Default)]
pub struct RelevanceCheck {
#[serde(default)]
pub relevant: bool,
#[serde(default)]
pub score: f64,
#[serde(default)]
pub expected_items: Vec<String>,
#[serde(default)]
pub found_items: Vec<String>,
#[serde(default)]
pub missing_items: Vec<String>,
#[serde(default)]
pub unexpected_items: Vec<String>,
#[serde(default)]
pub notes: Option<String>,
}
#[derive(Debug, Clone, Deserialize, Default)]
pub struct OcrResult {
#[serde(default)]
pub text: Option<String>,
#[serde(default)]
pub metadata: HashMap<String, String>,
#[serde(default)]
pub overlays: Vec<TextOverlay>,
}
#[derive(Debug, Clone, Deserialize, Default)]
pub struct TextOverlay {
#[serde(default)]
pub text: String,
#[serde(default)]
pub bounding_box: Option<[i32; 4]>,
#[serde(rename = "type", default)]
pub overlay_type: Option<String>,
}
impl Client {
pub async fn vision_analyze(&self, req: &VisionRequest) -> Result<VisionResponse> {
let (resp, _meta) = self
.post_json::<VisionRequest, VisionResponse>("/qai/v1/vision/analyze", req)
.await?;
Ok(resp)
}
pub async fn vision_detect(&self, req: &VisionRequest) -> Result<VisionResponse> {
let (resp, _meta) = self
.post_json::<VisionRequest, VisionResponse>("/qai/v1/vision/detect", req)
.await?;
Ok(resp)
}
pub async fn vision_describe(&self, req: &VisionRequest) -> Result<VisionResponse> {
let (resp, _meta) = self
.post_json::<VisionRequest, VisionResponse>("/qai/v1/vision/describe", req)
.await?;
Ok(resp)
}
pub async fn vision_ocr(&self, req: &VisionRequest) -> Result<VisionResponse> {
let (resp, _meta) = self
.post_json::<VisionRequest, VisionResponse>("/qai/v1/vision/ocr", req)
.await?;
Ok(resp)
}
pub async fn vision_quality(&self, req: &VisionRequest) -> Result<VisionResponse> {
let (resp, _meta) = self
.post_json::<VisionRequest, VisionResponse>("/qai/v1/vision/quality", req)
.await?;
Ok(resp)
}
}