"""Pydantic schemas for request / response models.""" from __future__ import annotations from typing import Dict, List, Optional from pydantic import BaseModel, Field from app.config import cfg # ═══════════════════════════════════════════════════════════════════════ # CORE SCHEMAS # ═══════════════════════════════════════════════════════════════════════ class ChatMessage(BaseModel): role: str = Field(..., pattern="^(system|user|assistant)$") content: str = Field(..., min_length=1, max_length=4000) class AnalysisResult(BaseModel): keyword: str kw_stemmed: str total_count: int by_surah: Dict[int, Dict] examples: List[dict] class SourceItem(BaseModel): source: str type: str grade: Optional[str] = None arabic: str english: str _score: float class AskResponse(BaseModel): question: str answer: str language: str intent: str analysis: Optional[AnalysisResult] = None sources: List[SourceItem] top_score: float latency_ms: int class HadithVerifyResponse(BaseModel): query: str found: bool collection: Optional[str] = None grade: Optional[str] = None reference: Optional[str] = None arabic: Optional[str] = None english: Optional[str] = None latency_ms: int # ═══════════════════════════════════════════════════════════════════════ # OPENAI-COMPATIBLE SCHEMAS # ═══════════════════════════════════════════════════════════════════════ class ChatCompletionMessage(BaseModel): role: str = Field(..., description="Message role: system, user, or assistant") content: str = Field(..., description="Message content") class ChatCompletionRequest(BaseModel): model: str = Field(default="QModel", description="Model name") messages: List[ChatCompletionMessage] = Field(..., description="Messages") temperature: Optional[float] = Field(default=cfg.TEMPERATURE, ge=0.0, le=2.0) top_p: Optional[float] = Field(default=1.0, ge=0.0, le=1.0) max_tokens: Optional[int] = Field(default=cfg.MAX_TOKENS, ge=1, le=8000) top_k: Optional[int] = Field(default=5, ge=1, le=20, description="Islamic sources to retrieve") stream: Optional[bool] = Field(default=False, description="Enable streaming responses") class ChatCompletionChoice(BaseModel): index: int message: ChatCompletionMessage finish_reason: str = "stop" class ChatCompletionResponse(BaseModel): id: str object: str = "chat.completion" created: int model: str choices: List[ChatCompletionChoice] usage: dict x_metadata: Optional[dict] = None class ModelInfo(BaseModel): id: str object: str = "model" created: int owned_by: str = "elgendy" permission: List[dict] = Field(default_factory=list) root: Optional[str] = None parent: Optional[str] = None class ModelsListResponse(BaseModel): object: str = "list" data: List[ModelInfo] # ═══════════════════════════════════════════════════════════════════════ # NEW ENDPOINT SCHEMAS # ═══════════════════════════════════════════════════════════════════════ class VerseItem(BaseModel): surah_number: Optional[int] = None surah_name_ar: str = "" surah_name_en: str = "" surah_name_transliteration: str = "" ayah: Optional[int] = None arabic: str = "" english: str = "" transliteration: str = "" tafsir_en: str = "" tafsir_ar: str = "" source: str = "" revelation_type: str = "" score: Optional[float] = None class HadithItem(BaseModel): collection: str = "" reference: str = "" hadith_number: Optional[int] = None chapter: str = "" arabic: str = "" english: str = "" grade: Optional[str] = None author: str = "" score: Optional[float] = None class TextSearchResponse(BaseModel): query: str count: int results: List[dict] class ChapterResponse(BaseModel): surah_number: int surah_name_ar: str surah_name_en: str surah_name_transliteration: str revelation_type: str total_verses: int verses: List[dict] class QuranAnalyticsResponse(BaseModel): total_verses_in_dataset: int total_surahs: int meccan_surahs: int medinan_surahs: int surahs: List[dict] class HadithAnalyticsResponse(BaseModel): total_hadiths: int collections: List[dict] grade_summary: dict class WordFrequencyResponse(BaseModel): keyword: str kw_stemmed: str total_count: int by_surah: dict examples: List[dict]