from pydantic import BaseModel, Field from typing import List, Optional, Dict, Any class PersonaInfo(BaseModel): persona_id: Optional[str] = None tone: Optional[str] = None audience: Optional[str] = None industry: Optional[str] = None class ResearchSource(BaseModel): title: str url: str excerpt: Optional[str] = None credibility_score: Optional[float] = None published_at: Optional[str] = None class BlogResearchRequest(BaseModel): keywords: List[str] topic: Optional[str] = None industry: Optional[str] = None target_audience: Optional[str] = None tone: Optional[str] = None word_count_target: Optional[int] = 1500 persona: Optional[PersonaInfo] = None class BlogResearchResponse(BaseModel): success: bool = True sources: List[ResearchSource] = [] keyword_analysis: Dict[str, Any] = {} competitor_analysis: Dict[str, Any] = {} suggested_angles: List[str] = [] search_widget: Optional[str] = None # HTML content for search widget search_queries: List[str] = [] # Search queries generated by Gemini error_message: Optional[str] = None # Error message for graceful failures class BlogOutlineSection(BaseModel): id: str heading: str subheadings: List[str] = [] key_points: List[str] = [] references: List[ResearchSource] = [] target_words: Optional[int] = None keywords: List[str] = [] class BlogOutlineRequest(BaseModel): research: BlogResearchResponse persona: Optional[PersonaInfo] = None word_count: Optional[int] = 1500 custom_instructions: Optional[str] = None class BlogOutlineResponse(BaseModel): success: bool = True title_options: List[str] = [] outline: List[BlogOutlineSection] = [] class BlogOutlineRefineRequest(BaseModel): outline: List[BlogOutlineSection] operation: str section_id: Optional[str] = None payload: Optional[Dict[str, Any]] = None class BlogSectionRequest(BaseModel): section: BlogOutlineSection keywords: List[str] = [] tone: Optional[str] = None persona: Optional[PersonaInfo] = None class BlogSectionResponse(BaseModel): success: bool = True markdown: str citations: List[ResearchSource] = [] class BlogOptimizeRequest(BaseModel): content: str goals: List[str] = [] class BlogOptimizeResponse(BaseModel): success: bool = True optimized: str diff_preview: Optional[str] = None class BlogSEOAnalyzeRequest(BaseModel): content: str keywords: List[str] = [] class BlogSEOAnalyzeResponse(BaseModel): success: bool = True seo_score: float density: Dict[str, Any] = {} structure: Dict[str, Any] = {} readability: Dict[str, Any] = {} link_suggestions: List[Dict[str, Any]] = [] image_alt_status: Dict[str, Any] = {} recommendations: List[str] = [] class BlogSEOMetadataRequest(BaseModel): content: str title: Optional[str] = None keywords: List[str] = [] class BlogSEOMetadataResponse(BaseModel): success: bool = True title_options: List[str] meta_descriptions: List[str] open_graph: Dict[str, Any] twitter_card: Dict[str, Any] schema_data: Dict[str, Any] class BlogPublishRequest(BaseModel): platform: str = Field(pattern="^(wix|wordpress)$") html: str metadata: BlogSEOMetadataResponse schedule_time: Optional[str] = None class BlogPublishResponse(BaseModel): success: bool = True platform: str url: Optional[str] = None post_id: Optional[str] = None class HallucinationCheckRequest(BaseModel): content: str sources: List[str] = [] class HallucinationCheckResponse(BaseModel): success: bool = True claims: List[Dict[str, Any]] = [] suggestions: List[Dict[str, Any]] = []