Spaces:
Running
Running
| from __future__ import annotations | |
| from enum import Enum | |
| from typing import Any, Dict, List, Literal, Optional | |
| from pydantic import BaseModel, Field, field_validator, model_validator | |
| class RouteConfig(BaseModel): | |
| name: str = Field(..., min_length=1, description="Route name") | |
| utterances: List[str] = Field(..., min_length=1, description="Example phrases for this route") | |
| models: List[str] = Field(default_factory=list, description="Model identifiers assigned to this route") | |
| class SemanticRouterRequest(BaseModel): | |
| query: str = Field(..., min_length=1, max_length=50000, description="User query to route") | |
| routes: List[RouteConfig] = Field(..., min_length=1, description="Route definitions") | |
| threshold: float = Field(default=0.3, ge=0.0, le=1.0, description="Minimum similarity score to match") | |
| class SemanticRouterResponse(BaseModel): | |
| success: bool | |
| time_ms: float | |
| name: Optional[str] = None | |
| models: List[str] = [] | |
| error: Optional[str] = None | |
| confidence: Optional[float] = None | |
| margin: Optional[float] = None | |
| threshold: Optional[float] = None | |
| matched_utterance: Optional[str] = None | |
| class TokenCountRequest(BaseModel): | |
| text: str = Field(..., min_length=1, max_length=1000000, description="Text to count tokens for") | |
| encoding: str = Field(default="o200k_base", description="TikToken encoding name") | |
| class TokenCountResponse(BaseModel): | |
| success: bool | |
| time_ms: float | |
| token_count: int = 0 | |
| char_count: int = 0 | |
| encoding: str = "o200k_base" | |
| error: Optional[str] = None | |
| class ConversionMetadata(BaseModel): | |
| source: str | |
| char_count: int | |
| word_count: int | |
| line_count: int | |
| file_size_bytes: int | |
| mime_type: str | |
| content_hash: str | |
| token_estimate: int | |
| class ConversionResponse(BaseModel): | |
| success: bool | |
| time_ms: float | |
| content: str | |
| return_json: bool = False | |
| json_content: Optional[Any] = None | |
| metadata: Optional[ConversionMetadata] = None | |
| error_message: Optional[str] = None | |
| class UrlRequest(BaseModel): | |
| url: str | |
| return_json: bool = False | |
| mappings: Optional[Dict[str, Dict[str, Any]]] = None | |
| model_config = {"populate_by_name": True} | |
| def validate_scheme(cls, v: str) -> str: | |
| if not v.startswith(("http://", "https://")): | |
| raise ValueError("Only http/https URLs are supported.") | |
| return v | |
| class BatchUrlRequest(BaseModel): | |
| urls: List[str] | |
| return_json: bool = False | |
| mappings: Optional[Dict[str, Dict[str, Any]]] = None | |
| def validate_urls(cls, v: List[str]) -> List[str]: | |
| for url in v: | |
| if not url.startswith(("http://", "https://")): | |
| raise ValueError(f"Invalid URL scheme: {url}") | |
| if len(v) > 20: | |
| raise ValueError("Maximum 20 URLs per batch request.") | |
| return v | |
| class BatchFileResult(BaseModel): | |
| filename: str | |
| success: bool | |
| time_ms: float | |
| content: Optional[str] = None | |
| json_content: Optional[Any] = None | |
| error: Optional[str] = None | |
| metadata: Optional[ConversionMetadata] = None | |
| class BatchResponse(BaseModel): | |
| total: int | |
| succeeded: int | |
| failed: int | |
| total_time_ms: float | |
| results: List[BatchFileResult] | |
| class HealthResponse(BaseModel): | |
| success: bool | |
| status: str | |
| version: str | |
| uptime_seconds: float | |
| timestamp: str | |
| class InfoResponse(BaseModel): | |
| success: bool | |
| app: str | |
| version: str | |
| python_version: str | |
| platform: str | |
| uptime_seconds: float | |
| max_upload_mb: int | |
| supported_extensions: int | |
| timestamp: str | |
| class SupportedFormatsResponse(BaseModel): | |
| success: bool | |
| total_count: int | |
| all_extensions: List[str] | |
| by_category: Dict[str, List[str]] | |
| class SpacyLabelsResponse(BaseModel): | |
| success: bool | |
| spacy_labels: Dict[str, str] | |
| source_types: Dict[str, str] | |
| example_mappings: Dict[str, Dict[str, Any]] | |
| class SSLConfig(BaseModel): | |
| enabled: bool = False | |
| ca_cert: Optional[str] = None | |
| cert: Optional[str] = None | |
| key: Optional[str] = None | |
| class DatabaseConnection(BaseModel): | |
| host: str | |
| port: Optional[int] = None | |
| database: str | |
| username: str | |
| password: str = Field(repr=False) | |
| selected_schema: str = Field(default="public", description="PostgreSQL schema (ignored for MySQL/MongoDB)") | |
| ssl: SSLConfig = SSLConfig() | |
| def host_not_empty(cls, v: str) -> str: | |
| stripped = v.strip() | |
| if not stripped: | |
| raise ValueError("host must not be empty") | |
| return stripped | |
| def validate_port(cls, v: Optional[int]) -> Optional[int]: | |
| if v is not None and (v < 1 or v > 65535): | |
| raise ValueError("port must be between 1 and 65535") | |
| return v | |
| def database_not_empty(cls, v: str) -> str: | |
| stripped = v.strip() | |
| if not stripped: | |
| raise ValueError("database must not be empty") | |
| return stripped | |
| def safe_repr(self) -> str: | |
| return ( | |
| f"host={self.host}, port={self.port}, " | |
| f"database={self.database}, username={self.username}" | |
| ) | |
| class DatabaseQueryRequest(BaseModel): | |
| db_type: Literal["mysql", "postgresql", "mongodb"] | |
| connection: DatabaseConnection | |
| query: List[Any] | |
| use_transaction: bool = True | |
| query_timeout_seconds: float = Field(default=10.0, ge=1.0, le=300.0) | |
| connection_timeout_seconds: float = Field(default=10.0, ge=1.0, le=60.0) | |
| max_rows: int = Field(default=10000, ge=1, le=1_000_000) | |
| def validate_query(self) -> "DatabaseQueryRequest": | |
| if not self.query: | |
| raise ValueError("query must not be empty") | |
| if self.db_type in ("mysql", "postgresql"): | |
| for i, q in enumerate(self.query): | |
| if not isinstance(q, str): | |
| raise ValueError(f"query[{i}] must be a string for {self.db_type}") | |
| if not q.strip(): | |
| raise ValueError(f"query[{i}] must not be empty") | |
| elif self.db_type == "mongodb": | |
| for i, q in enumerate(self.query): | |
| if not isinstance(q, dict): | |
| raise ValueError(f"query[{i}] must be an object with 'collection' and 'pipeline'") | |
| if "collection" not in q or "pipeline" not in q: | |
| raise ValueError(f"query[{i}] must have 'collection' and 'pipeline' fields") | |
| if not isinstance(q["pipeline"], list): | |
| raise ValueError(f"query[{i}].pipeline must be an array") | |
| return self | |
| def to_connection_config(self) -> Dict[str, Any]: | |
| return { | |
| "db_type": self.db_type, | |
| "host": self.connection.host, | |
| "port": self.connection.port or self._default_port(), | |
| "database": self.connection.database, | |
| "username": self.connection.username, | |
| "password": self.connection.password, | |
| "selected_schema": self.connection.selected_schema, | |
| "ssl_enabled": self.connection.ssl.enabled, | |
| "ssl_ca_cert": self.connection.ssl.ca_cert, | |
| "ssl_cert": self.connection.ssl.cert, | |
| "ssl_key": self.connection.ssl.key, | |
| "query_timeout_seconds": self.query_timeout_seconds, | |
| "connection_timeout_seconds": self.connection_timeout_seconds, | |
| "max_rows": self.max_rows, | |
| } | |
| def _default_port(self) -> int: | |
| return {"mysql": 3306, "postgresql": 5432, "mongodb": 27017}[self.db_type] | |
| class StatementResultSchema(BaseModel): | |
| success: bool | |
| rows: int = 0 | |
| data: List[Dict[str, Any]] = [] | |
| error: Optional[str] = None | |
| error_code: Optional[str] = None | |
| class DatabaseQueryError(BaseModel): | |
| message: str | |
| code: Optional[str] = None | |
| class DatabaseQueryResponse(BaseModel): | |
| success: bool | |
| execution_time_ms: float | |
| results: Optional[List[StatementResultSchema]] = None | |
| error: Optional[DatabaseQueryError] = None | |
| class TableValidationResult(BaseModel): | |
| name: str | |
| exists: bool | |
| error: Optional[str] = None | |
| class DatabaseValidateRequest(BaseModel): | |
| db_type: Literal["mysql", "postgresql", "mongodb"] | |
| connection: DatabaseConnection | |
| selected_schema: str = Field(default="public", description="PostgreSQL schema (ignored for MySQL/MongoDB)") | |
| table_or_collection_names: List[str] = Field(default_factory=list, description="Optional list of tables/collections to check for existence") | |
| def to_connection_config(self) -> Dict[str, Any]: | |
| return { | |
| "db_type": self.db_type, | |
| "host": self.connection.host, | |
| "port": self.connection.port or {"mysql": 3306, "postgresql": 5432, "mongodb": 27017}[self.db_type], | |
| "database": self.connection.database, | |
| "username": self.connection.username, | |
| "password": self.connection.password, | |
| "selected_schema": self.selected_schema, | |
| "ssl_enabled": self.connection.ssl.enabled, | |
| "ssl_ca_cert": self.connection.ssl.ca_cert, | |
| "ssl_cert": self.connection.ssl.cert, | |
| "ssl_key": self.connection.ssl.key, | |
| } | |
| class DatabaseValidateResponse(BaseModel): | |
| success: bool | |
| time_ms: float | |
| message: str | |
| connection_details: str | |
| error_message: Optional[str] = None | |
| tables: List[TableValidationResult] = [] | |
| class EmbeddingItem(BaseModel): | |
| success: bool | |
| time_ms: float | |
| embeddings: List[float] = Field(default_factory=list) | |
| dimension: int = 0 | |
| error_message: Optional[str] = None | |
| class EmbeddingRequest(BaseModel): | |
| content: List[str] = Field(..., min_length=1, max_length=10, description="Array of text strings to embed (max 10)") | |
| dimension: int = Field(default=384, ge=384, le=384, description="Target embedding dimension (384 only)") | |
| def validate_content_length(cls, v: List[str]) -> List[str]: | |
| if len(v) > 10: | |
| raise ValueError("Maximum 10 text items allowed per request.") | |
| if len(v) < 1: | |
| raise ValueError("At least 1 text item is required.") | |
| return v | |
| class EmbeddingResponse(BaseModel): | |
| success: bool | |
| time_ms: float | |
| success_count: int | |
| failed_count: int | |
| error_message: Optional[str] = None | |
| results: List[EmbeddingItem] | |
| # class VisionUrlRequest(BaseModel): # DISABLED (OOM mitigation) | |
| # urls: List[str] = Field(..., min_length=1, max_length=5, description="Array of image URLs to embed (max 5)") | |
| # | |
| # @field_validator("urls") | |
| # @classmethod | |
| # def validate_urls(cls, v: List[str]) -> List[str]: | |
| # for url in v: | |
| # if not url.startswith(("http://", "https://")): | |
| # raise ValueError(f"Invalid URL scheme: {url}") | |
| # return v | |
| class CodeItem(BaseModel): | |
| language: Literal["python", "javascript"] # "java" DISABLED (OOM mitigation) | |
| code: str = Field(..., min_length=1, max_length=65536, description="Source code to execute") | |
| class CodeExecutionRequest(BaseModel): | |
| items: List[CodeItem] = Field(..., min_length=1, max_length=5, description="Code execution items (max 5)") | |
| class CodeExecutionItemResult(BaseModel): | |
| success: bool | |
| output: str = "" | |
| error: Optional[str] = None | |
| exit_code: Optional[int] = None | |
| execution_time_ms: Optional[float] = None | |
| language: str | |
| timed_out: bool = False | |
| class CodeExecutionResponse(BaseModel): | |
| success: bool | |
| time_ms: float | |
| success_count: int | |
| failed_count: int | |
| error_message: Optional[str] = None | |
| results: List[CodeExecutionItemResult] | |
| # --------------------------------------------------------------------------- | |
| # Web Search (SearXNG) | |
| # --------------------------------------------------------------------------- | |
| class WebSearchResult(BaseModel): | |
| title: str | |
| url: str | |
| content: str = "" | |
| engine: str = "" | |
| category: str = "" | |
| published_date: Optional[str] = None | |
| class WebSearchSuggestion(BaseModel): | |
| suggestion: str | |
| class WebSearchInfobox(BaseModel): | |
| title: str = "" | |
| content: str = "" | |
| infobox: str = "" | |
| engine: str = "" | |
| urls: List[Dict[str, Any]] = [] | |
| class WebSearchRequest(BaseModel): | |
| q: str = Field(..., min_length=1, max_length=500, description="Search query") | |
| categories: str = Field(default="general", description="Comma-separated categories: general,images,videos,news,music,it,science,map,files,social media") | |
| language: str = Field(default="en", description="Language code (en, fr, de, hi, bn, etc.)") | |
| pageno: int = Field(default=1, ge=1, le=100, description="Page number") | |
| time_range: Optional[str] = Field(default=None, description="Time range: day, week, month, year") | |
| safesearch: int = Field(default=0, ge=0, le=2, description="Safe search level: 0=off, 1=moderate, 2=strict") | |
| engines: Optional[str] = Field(default=None, description="Comma-separated engine names to restrict to") | |
| max_results: int = Field(default=10, ge=1, le=50, description="Max results to return") | |
| class WebSearchResponse(BaseModel): | |
| success: bool | |
| time_ms: float | |
| query: str | |
| number_of_results: int | |
| results: List[WebSearchResult] | |
| suggestions: List[str] = [] | |
| infoboxes: List[WebSearchInfobox] = [] | |
| error: Optional[str] = None | |
| class WebSearchConfigResponse(BaseModel): | |
| success: bool | |
| time_ms: float | |
| instance_name: Optional[str] = None | |
| version: Optional[str] = None | |
| engines: List[Dict[str, Any]] = [] | |
| categories: List[str] = [] | |
| plugins: List[str] = [] | |
| error: Optional[str] = None | |
| # --------------------------------------------------------------------------- | |
| # Web Scraping (Scrapling) | |
| # --------------------------------------------------------------------------- | |
| class FetcherType(str, Enum): | |
| http = "http" | |
| dynamic = "dynamic" | |
| stealth = "stealth" | |
| class SelectorType(str, Enum): | |
| css = "css" | |
| xpath = "xpath" | |
| class ExtractionRule(BaseModel): | |
| field_name: str = Field(..., description="Key name in the output JSON.") | |
| selector: str = Field(..., description="CSS or XPath selector (e.g. '.price::text').") | |
| selector_type: SelectorType = Field(SelectorType.css) | |
| extract_all: bool = Field(False, description="Get a list of all matches.") | |
| auto_save: bool = Field(False, description="Commit element's DOM fingerprint to local SQLite.") | |
| auto_match: bool = Field(False, description="Use deterministic healing if layout breaks.") | |
| class ScrapeRequest(BaseModel): | |
| url: str = Field(..., description="Target URL to scrape.") | |
| fetcher_type: FetcherType = Field(FetcherType.http) | |
| rules: List[ExtractionRule] = Field(..., min_length=1, max_length=50) | |
| proxy: Optional[str] = Field(None, description="Proxy URL for this request.") | |
| network_idle: bool = Field(False, description="Wait for network idle (Dynamic/Stealth only).") | |
| class ScrapeResponse(BaseModel): | |
| success: bool | |
| time_ms: float | |
| url: str | |
| data: Dict[str, Any] | |
| fetcher: str | |
| error: Optional[str] = None | |
| class ScrapeHealthResponse(BaseModel): | |
| success: bool | |
| framework: str | |
| version: str | |
| fetchers_available: List[str] | |
| error: Optional[str] = None | |
| class WebSearchAutocompleteRequest(BaseModel): | |
| q: str = Field(..., min_length=1, max_length=200, description="Search query prefix for autocomplete") | |
| class WebSearchAutocompleteResponse(BaseModel): | |
| success: bool | |
| time_ms: float | |
| query: str | |
| suggestions: List[str] = [] | |
| error: Optional[str] = None | |
| class WebSearchStatsResponse(BaseModel): | |
| success: bool | |
| time_ms: float | |
| stats: Optional[Dict[str, Any]] = None | |
| error: Optional[str] = None | |
| class WebSearchEngineDescriptionsResponse(BaseModel): | |
| success: bool | |
| time_ms: float | |
| engines: Optional[Dict[str, Any]] = None | |
| error: Optional[str] = None | |
| class TokenGenerateRequest(BaseModel): | |
| subject: str = Field(..., min_length=1, max_length=256, description="Token subject (user ID, client ID, etc.)") | |
| role: Optional[str] = Field(None, max_length=64, description="User role for RBAC") | |
| permissions: Optional[List[str]] = Field(None, description="List of permission strings") | |
| issuer: Optional[str] = Field(None, max_length=128, description="Token issuer (overrides default)") | |
| audience: Optional[str] = Field(None, max_length=128, description="Token audience") | |
| expiry_minutes: Optional[int] = Field(None, ge=1, le=525600, description="Token lifetime in minutes") | |
| not_before_minutes: int = Field(default=0, ge=0, le=525600, description="Delay token validity by N minutes") | |
| extra_claims: Optional[Dict[str, Any]] = Field(None, description="Additional custom claims") | |
| secret: Optional[str] = Field(None, description="JWT signing secret (auto-generated if not provided)") | |
| algorithm: Optional[str] = Field(None, pattern="^(HS256|HS384|HS512)$", description="JWT signing algorithm (defaults to HS256)") | |
| class TokenGenerateResponse(BaseModel): | |
| success: bool | |
| time_ms: float | |
| token: Optional[str] = None | |
| claims: Optional[Dict[str, Any]] = None | |
| expires_at: Optional[str] = None | |
| valid_for: Optional[str] = None | |
| secret: Optional[str] = None | |
| algorithm: Optional[str] = None | |
| error: Optional[str] = None | |
| class TokenValidateRequest(BaseModel): | |
| token: str = Field(..., min_length=1, description="JWT token string to validate") | |
| audience: Optional[str] = Field(None, description="Expected audience to verify against") | |
| secret: Optional[str] = Field(None, description="Signing secret used during generation (uses server default if not provided)") | |
| algorithm: Optional[str] = Field(None, pattern="^(HS256|HS384|HS512)$", description="Algorithm used during generation (uses server default if not provided)") | |
| class TokenValidateResponse(BaseModel): | |
| success: bool | |
| time_ms: float | |
| valid: bool | |
| claims: Optional[Dict[str, Any]] = None | |
| error: Optional[str] = None | |
| class SqlValidationRequest(BaseModel): | |
| query: str = Field(..., min_length=1, max_length=100000, description="SQL query string to validate") | |
| dialect: Optional[str] = Field(None, description="SQL dialect (mysql, postgres, bigquery, snowflake, sqlite, etc.)") | |
| class SqlValidationResponse(BaseModel): | |
| success: bool | |
| time_ms: float | |
| valid: bool | |
| query_type: str | |
| dialect: Optional[str] = None | |
| is_read_only: bool | |
| errors: List[str] = [] | |
| warnings: List[str] = [] | |
| tables: List[str] = [] | |
| columns: List[str] = [] | |
| # --------------------------------------------------------------------------- | |
| # Vector Store (RAG) - Powered by Zvec | |
| # --------------------------------------------------------------------------- | |
| class VectorStoreCreate(BaseModel): | |
| name: str = Field(..., min_length=1, max_length=256, description="Human-readable name") | |
| description: Optional[str] = Field(None, max_length=1024) | |
| metadata: Dict[str, Any] = Field(default_factory=dict) | |
| class VectorStoreResponse(BaseModel): | |
| success: bool | |
| vector_store_id: str | |
| app_id: str | |
| name: str | |
| description: Optional[str] = None | |
| embedding_dimension: int | |
| document_count: int | |
| created_at: str | |
| metadata: Dict[str, Any] = {} | |
| warning: Optional[Dict[str, str]] = None | |
| class VectorStoreListResponse(BaseModel): | |
| success: bool | |
| total: int | |
| stores: List[VectorStoreResponse] | |
| class DocumentIngestRequest(BaseModel): | |
| doc_id: str = Field(..., min_length=1, max_length=256) | |
| text: str = Field(..., min_length=1) | |
| source: Optional[str] = Field(None, max_length=512) | |
| metadata: Dict[str, Any] = Field(default_factory=dict) | |
| chunk_size: Optional[int] = Field(None, ge=64, le=4096) | |
| chunk_overlap: Optional[int] = Field(None, ge=0, le=512) | |
| class DocumentIngestResponse(BaseModel): | |
| success: bool | |
| vector_store_id: str | |
| doc_id: str | |
| chunks_ingested: int | |
| time_ms: float | |
| error: Optional[str] = None | |
| class DocumentIngestUrlRequest(BaseModel): | |
| url: str = Field(..., min_length=1, description="URL of the PDF file to ingest") | |
| doc_id: str = Field(..., min_length=1, max_length=256) | |
| chunk_size: int = Field(512, ge=64, le=4096) | |
| chunk_overlap: int = Field(64, ge=0, le=512) | |
| class SearchRequest(BaseModel): | |
| query: str = Field(..., min_length=1, max_length=5000, description="Natural language query") | |
| top_k: int = Field(default=10, ge=1, le=100, description="Max results to return") | |
| filter: Optional[str] = Field(None, description="Filter expression (e.g. 'category = \"tech\"')") | |
| min_score: Optional[float] = Field(None, ge=0.0, le=1.0, description="Minimum similarity score threshold") | |
| include_vectors: bool = Field(default=False, description="Include vector embeddings in results") | |
| include_metadata: bool = Field(default=False, description="Include source metadata in results") | |
| class SearchResultItem(BaseModel): | |
| rank: int | |
| doc_id: str | |
| chunk_index: int | |
| text: str | |
| score: float | |
| source: Optional[str] = None | |
| metadata: Dict[str, Any] = {} | |
| vector: Optional[List[float]] = None | |
| class SearchResponse(BaseModel): | |
| success: bool | |
| vector_store_id: str | |
| query: str | |
| results: List[SearchResultItem] | |
| total_results: int | |
| time_ms: float | |
| error: Optional[str] = None | |
| class DeleteRequest(BaseModel): | |
| ids: Optional[List[str]] = Field(None) | |
| filter: Optional[str] = Field(None) | |
| class DeleteResponse(BaseModel): | |
| success: bool | |
| vector_store_id: str | |
| deleted_count: int | |
| time_ms: float | |
| error: Optional[str] = None | |
| # --------------------------------------------------------------------------- | |
| # Webhook / Socket | |
| # --------------------------------------------------------------------------- | |
| class ChannelCreateRequest(BaseModel): | |
| channel_id: Optional[str] = Field(None, min_length=1, max_length=64, description="Optional custom channel ID") | |
| secret: Optional[str] = Field(None, min_length=1, description="HMAC secret for webhook verification") | |
| buffer_size: Optional[int] = Field(None, ge=0, le=10000, description="Replay buffer size (0 = no replay)") | |
| class ChannelCreateResponse(BaseModel): | |
| channel_id: str | |
| webhook_url: str | |
| ws_url: str | |
| secret: Optional[str] = None | |
| buffer_size: int | |
| class ChannelInfoResponse(BaseModel): | |
| channel_id: str | |
| subscribers: int | |
| messages: int | |
| buffered: int | |
| buffer_size: int | |
| has_secret: bool | |
| created_at: float | |
| last_activity: float | |
| class ChannelListItem(BaseModel): | |
| channel_id: str | |
| subscribers: int | |
| messages: int | |
| buffered: int | |
| created_at: float | |
| last_activity: float | |
| class ChannelListResponse(BaseModel): | |
| channels: List[ChannelListItem] | |
| class ChannelDeleteResponse(BaseModel): | |
| deleted: str | |
| class WebhookResponse(BaseModel): | |
| status: str | |
| channel: str | |
| subscribers_notified: int | |
| message_id: int | |
| class WebhookSocketStatsResponse(BaseModel): | |
| channels: int | |
| total_messages: int | |
| total_subscribers: int | |
| channels_detail: Dict[str, Dict[str, Any]] | |