Files
ALwrity/backend/models/blog_models.py

218 lines
6.0 KiB
Python

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
index: Optional[int] = None
source_type: Optional[str] = None # e.g., 'web'
class GroundingChunk(BaseModel):
title: str
url: str
confidence_score: Optional[float] = None
class GroundingSupport(BaseModel):
confidence_scores: List[float] = []
grounding_chunk_indices: List[int] = []
segment_text: str = ""
start_index: Optional[int] = None
end_index: Optional[int] = None
class Citation(BaseModel):
citation_type: str # e.g., 'inline'
start_index: int
end_index: int
text: str
source_indices: List[int] = []
reference: str # e.g., 'Source 1'
class GroundingMetadata(BaseModel):
grounding_chunks: List[GroundingChunk] = []
grounding_supports: List[GroundingSupport] = []
citations: List[Citation] = []
search_entry_point: Optional[str] = None
web_search_queries: List[str] = []
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
grounding_metadata: Optional[GroundingMetadata] = None # Google grounding metadata
original_keywords: List[str] = [] # Original user-provided keywords for caching
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 SourceMappingStats(BaseModel):
total_sources_mapped: int = 0
coverage_percentage: float = 0.0
average_relevance_score: float = 0.0
high_confidence_mappings: int = 0
class GroundingInsights(BaseModel):
confidence_analysis: Optional[Dict[str, Any]] = None
authority_analysis: Optional[Dict[str, Any]] = None
temporal_analysis: Optional[Dict[str, Any]] = None
content_relationships: Optional[Dict[str, Any]] = None
citation_insights: Optional[Dict[str, Any]] = None
search_intent_insights: Optional[Dict[str, Any]] = None
quality_indicators: Optional[Dict[str, Any]] = None
class OptimizationResults(BaseModel):
overall_quality_score: float = 0.0
improvements_made: List[str] = []
optimization_focus: str = "general optimization"
class ResearchCoverage(BaseModel):
sources_utilized: int = 0
content_gaps_identified: int = 0
competitive_advantages: List[str] = []
class BlogOutlineResponse(BaseModel):
success: bool = True
title_options: List[str] = []
outline: List[BlogOutlineSection] = []
# Additional metadata for enhanced UI
source_mapping_stats: Optional[SourceMappingStats] = None
grounding_insights: Optional[GroundingInsights] = None
optimization_results: Optional[OptimizationResults] = None
research_coverage: Optional[ResearchCoverage] = None
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
mode: Optional[str] = "polished" # 'draft' | 'polished'
class BlogSectionResponse(BaseModel):
success: bool = True
markdown: str
citations: List[ResearchSource] = []
continuity_metrics: Optional[Dict[str, float]] = None
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]] = []