use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum JobStatus {
Pending,
InProgress,
Completed,
Failed,
Cancelled,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum RagProcessingStatus {
NotStarted,
InProgress,
Completed,
Failed,
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
#[schemars(deny_unknown_fields)]
pub struct ComputeTextEmbeddingRequest {
pub text: String,
#[serde(default = "default_clip_model")]
pub model: String,
}
fn default_clip_model() -> String {
"clip".to_string()
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
#[schemars(deny_unknown_fields)]
pub struct ComputeTextEmbeddingResponse {
pub success: bool,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub embedding: Option<Vec<f32>>,
#[serde(default = "default_embedding_dim")]
pub embedding_dim: i64,
#[serde(default)]
pub processing_time_ms: f64,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub error: Option<String>,
}
fn default_embedding_dim() -> i64 {
512
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
#[schemars(deny_unknown_fields)]
pub struct ComputeEmbeddingRequest {
pub image_data: String,
#[serde(default)]
pub compute_text_embedding: bool,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub text_description: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
#[schemars(deny_unknown_fields)]
pub struct ComputeEmbeddingResponse {
pub success: bool,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub image_embedding: Option<Vec<f32>>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub text_embedding: Option<Vec<f32>>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub text_description: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub ocr_text: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub ocr_confidence: Option<f64>,
#[serde(default)]
pub processing_time_ms: f64,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub error: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
#[schemars(deny_unknown_fields)]
pub struct BatchComputeEmbeddingRequest {
pub images: Vec<HashMap<String, serde_json::Value>>,
#[serde(default = "default_true")]
pub compute_text_embeddings: bool,
#[serde(default = "default_true")]
pub extract_ocr: bool,
}
fn default_true() -> bool {
true
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
#[schemars(deny_unknown_fields)]
pub struct BatchEmbeddingResult {
pub id: String,
pub success: bool,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub image_embedding: Option<Vec<f32>>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub text_embedding: Option<Vec<f32>>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub text_description: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub ocr_text: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub ocr_confidence: Option<f64>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub error: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
#[schemars(deny_unknown_fields)]
pub struct BatchComputeEmbeddingResponse {
pub success: bool,
pub results: Vec<BatchEmbeddingResult>,
pub total_processed: i64,
pub successful: i64,
pub failed: i64,
#[serde(default)]
pub processing_time_ms: f64,
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
#[schemars(deny_unknown_fields)]
pub struct EmbeddingResultItem {
pub state_image_id: String,
pub success: bool,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub image_embedding: Option<Vec<f32>>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub text_embedding: Option<Vec<f32>>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub text_description: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub ocr_text: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub ocr_confidence: Option<f64>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub error: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
#[schemars(deny_unknown_fields)]
pub struct EmbeddingResultsRequest {
pub project_id: String,
pub results: Vec<EmbeddingResultItem>,
pub total_processed: i64,
pub successful: i64,
pub failed: i64,
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
#[schemars(deny_unknown_fields)]
pub struct EmbeddingResultsResponse {
pub success: bool,
pub message: String,
pub applied: i64,
pub failed: i64,
pub not_found: i64,
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
#[schemars(deny_unknown_fields)]
pub struct RagProgressEvent {
pub project_id: String,
pub status: RagProcessingStatus,
pub message: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub percent: Option<f64>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub elements_processed: Option<i64>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub total_elements: Option<i64>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub error: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
#[schemars(deny_unknown_fields)]
pub struct RagCompletionEvent {
pub project_id: String,
pub success: bool,
pub results: Vec<EmbeddingResultItem>,
pub total_processed: i64,
pub successful: i64,
pub failed: i64,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub web_sync_success: Option<bool>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub web_sync_error: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
#[schemars(deny_unknown_fields)]
pub struct JobSummary {
pub id: String,
pub status: JobStatus,
pub progress_percent: f64,
pub total_patterns: i64,
pub processed_patterns: i64,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub started_at: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub error_message: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
#[schemars(deny_unknown_fields)]
pub struct RAGDashboardStats {
pub total_embeddings: i64,
pub total_states: i64,
pub total_patterns: i64,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub last_sync_at: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub active_job: Option<JobSummary>,
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
#[schemars(deny_unknown_fields)]
pub struct EmbeddingItem {
pub id: String,
pub pattern_id: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub pattern_name: Option<String>,
pub state_id: String,
pub state_name: String,
pub image_id: String,
pub image_storage_path: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub image_url: Option<String>,
pub embedding_model: String,
pub embedding_version: String,
pub image_width: i64,
pub image_height: i64,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub text_description: Option<String>,
#[serde(default)]
pub has_text_embedding: bool,
#[serde(default)]
pub pattern_metadata: HashMap<String, serde_json::Value>,
pub created_at: String,
pub updated_at: String,
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
#[schemars(deny_unknown_fields)]
pub struct EmbeddingListResponse {
pub items: Vec<EmbeddingItem>,
pub total: i64,
pub page: i64,
pub limit: i64,
pub has_more: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
#[schemars(deny_unknown_fields)]
pub struct JobItem {
pub id: String,
pub status: JobStatus,
pub total_patterns: i64,
pub processed_patterns: i64,
pub progress_percent: f64,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub error_message: Option<String>,
pub retry_count: i64,
pub max_retries: i64,
#[serde(default)]
pub job_metadata: HashMap<String, serde_json::Value>,
pub created_at: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub started_at: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub completed_at: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
#[schemars(deny_unknown_fields)]
pub struct JobListResponse {
pub items: Vec<JobItem>,
pub total: i64,
pub page: i64,
pub limit: i64,
pub has_more: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
#[schemars(deny_unknown_fields)]
pub struct SemanticSearchRequest {
pub query: String,
#[serde(default = "default_search_limit")]
pub limit: i64,
#[serde(default = "default_min_similarity")]
pub min_similarity: f64,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub state_filter: Option<String>,
}
fn default_search_limit() -> i64 {
20
}
fn default_min_similarity() -> f64 {
0.2
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
#[schemars(deny_unknown_fields)]
pub struct SearchResultItem {
pub embedding: EmbeddingItem,
pub similarity_score: f64,
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
#[schemars(deny_unknown_fields)]
pub struct SemanticSearchResponse {
pub results: Vec<SearchResultItem>,
pub query: String,
pub total_found: i64,
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
#[schemars(deny_unknown_fields)]
pub struct StateFilterItem {
pub state_id: String,
pub state_name: String,
pub count: i64,
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
#[schemars(deny_unknown_fields)]
pub struct StatesResponse {
pub states: Vec<StateFilterItem>,
pub count: i64,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum ElementType {
Button,
IconButton,
ToggleButton,
DropdownButton,
TextInput,
SearchInput,
PasswordInput,
Textarea,
Checkbox,
RadioButton,
Dropdown,
Combobox,
Slider,
Link,
Tab,
MenuItem,
Breadcrumb,
Modal,
Dialog,
Panel,
Card,
Icon,
Image,
Label,
Badge,
Tooltip,
TableCell,
TableHeader,
ListItem,
Progress,
Spinner,
Unknown,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
#[schemars(deny_unknown_fields)]
pub struct BoundingBox {
pub x: i64,
pub y: i64,
pub width: i64,
pub height: i64,
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
#[schemars(deny_unknown_fields)]
pub struct GUIElementChunk {
pub id: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub created_at: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub updated_at: Option<String>,
#[serde(default)]
pub source_app: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub source_state_id: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub source_screenshot_id: Option<String>,
#[serde(default = "default_extraction_method")]
pub extraction_method: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub bounding_box: Option<BoundingBox>,
#[serde(default)]
pub width: i64,
#[serde(default)]
pub height: i64,
#[serde(default)]
pub aspect_ratio: f64,
#[serde(default)]
pub area: i64,
#[serde(default)]
pub position_quadrant: String,
#[serde(default)]
pub dominant_colors: Vec<Vec<i64>>,
#[serde(default)]
pub color_histogram: Vec<i64>,
#[serde(default)]
pub average_brightness: f64,
#[serde(default)]
pub contrast_ratio: f64,
#[serde(default)]
pub edge_density: f64,
#[serde(default)]
pub has_text: bool,
#[serde(default)]
pub ocr_text: String,
#[serde(default)]
pub ocr_confidence: f64,
#[serde(default)]
pub text_length: i64,
#[serde(default = "default_element_type")]
pub element_type: ElementType,
#[serde(default)]
pub element_subtype: String,
#[serde(default)]
pub is_interactive: bool,
#[serde(default)]
pub interaction_type: String,
#[serde(default = "default_visual_state")]
pub visual_state: String,
#[serde(default = "default_true_element")]
pub is_enabled: bool,
#[serde(default)]
pub is_selected: bool,
#[serde(default)]
pub is_focused: bool,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub parent_region: Option<String>,
#[serde(default)]
pub depth_in_hierarchy: i64,
#[serde(default)]
pub sibling_count: i64,
#[serde(default)]
pub platform: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub text_embedding: Option<Vec<f32>>,
#[serde(default)]
pub text_description: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub image_embedding: Option<Vec<f32>>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub state_id: Option<String>,
#[serde(default)]
pub state_name: String,
#[serde(default)]
pub is_defining_element: bool,
#[serde(default)]
pub is_optional_element: bool,
#[serde(default = "default_similarity_threshold")]
pub similarity_threshold: f64,
#[serde(default)]
pub is_fixed_position: bool,
#[serde(default)]
pub is_shared: bool,
#[serde(default = "default_probability")]
pub probability: f64,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub search_region_id: Option<String>,
#[serde(default)]
pub semantic_role: String,
#[serde(default)]
pub semantic_action: String,
#[serde(default)]
pub style_family: String,
}
fn default_extraction_method() -> String {
"manual".to_string()
}
fn default_element_type() -> ElementType {
ElementType::Unknown
}
fn default_visual_state() -> String {
"normal".to_string()
}
fn default_true_element() -> bool {
true
}
fn default_similarity_threshold() -> f64 {
0.8
}
fn default_probability() -> f64 {
1.0
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
#[schemars(deny_unknown_fields)]
pub struct EmbeddedElement {
pub element: GUIElementChunk,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub text_embedding: Option<Vec<f32>>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub image_embedding: Option<Vec<f32>>,
#[serde(default)]
pub embedding_model: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub embedding_timestamp: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
#[schemars(deny_unknown_fields)]
pub struct VectorSearchResult {
pub element: GUIElementChunk,
pub score: f64,
#[serde(default)]
pub distance: f64,
#[serde(default)]
pub rank: i64,
#[serde(default = "default_matched_on")]
pub matched_on: String,
#[serde(default = "default_search_type")]
pub search_type: String,
#[serde(default)]
pub query_text: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub query_timestamp: Option<String>,
}
fn default_matched_on() -> String {
"text".to_string()
}
fn default_search_type() -> String {
"text".to_string()
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
#[schemars(deny_unknown_fields)]
pub struct ExportResult {
pub success: bool,
#[serde(default)]
pub exported_count: i64,
#[serde(default)]
pub failed_count: i64,
#[serde(default)]
pub skipped_count: i64,
#[serde(default)]
pub errors: Vec<String>,
#[serde(default)]
pub warnings: Vec<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub export_timestamp: Option<String>,
#[serde(default)]
pub export_path: String,
#[serde(default = "default_export_format")]
pub format: String,
}
fn default_export_format() -> String {
"json".to_string()
}