ai-seo-analyzer / models.py
lsdf's picture
feat(optimizer): stage and goal selection controls
55a7978
from pydantic import BaseModel, Field
from typing import List, Dict, Optional, Any
class CompetitorText(BaseModel):
id: int
text: str
class AnalysisRequest(BaseModel):
target_text: str # Текст пользователя
competitors: List[str] # Список текстов конкурентов
keywords: List[str] # Список ключевых фраз (сырых)
language: str = "en" # en, ru, de, es, it, pl, pt
target_title: str = "" # Title пользователя
competitor_titles: List[str] = Field(default_factory=list) # Title конкурентов
class AnalysisResponse(BaseModel):
ngram_stats: dict # Статистика униграм/биграм
bm25_recommendations: List[dict] # Рекомендации "добавить/убрать"
bert_analysis: Dict[str, Any] # Векторный анализ
word_counts: Dict[str, Any] # {'target': 500, 'competitors': [600, 450], 'avg': 525}
title_analysis: Dict[str, Any] = Field(default_factory=dict) # Анализ Title
class SemanticAnalyzeRequest(BaseModel):
text: str
competitors: List[str] = Field(default_factory=list)
language: str = "ru"
threshold: int = 50
compression_ratio: float = 0.1
class SemanticAnalyzeResponse(BaseModel):
target: Dict[str, Any]
competitors: List[Dict[str, Any]]
comparison: Dict[str, Any]
class SemanticSearchRequest(BaseModel):
query_text: str
text: str
language: str = "ru"
top_n: int = 20
class SemanticSearchResponse(BaseModel):
results: List[Dict[str, Any]]
class UrlFetchRequest(BaseModel):
url: str
user_agent: str = "chrome_desktop"
timeout_seconds: int = 15
class UrlFetchResponse(BaseModel):
ok: bool = False
url: str = ""
final_url: str = ""
status_code: int = 0
user_agent_key: str = ""
user_agent_value: str = ""
title: str = ""
text: str = ""
error: str = ""
class UserAgentInfo(BaseModel):
key: str
name: str
value: str
class UserAgentsResponse(BaseModel):
user_agents: List[UserAgentInfo] = Field(default_factory=list)
class OptimizerRequest(BaseModel):
target_text: str
competitors: List[str] = Field(default_factory=list)
keywords: List[str] = Field(default_factory=list)
language: str = "en"
target_title: str = ""
competitor_titles: List[str] = Field(default_factory=list)
# Base for highlighting what changed in this optimization run.
# - diff_from_input: compare with `target_text` passed in this request (snapshot before optimization)
# - diff_from_original: compare with `original_target_text` from the first snapshot in session
diff_mode: str = "diff_from_input" # diff_from_input | diff_from_original
original_target_text: Optional[str] = None
original_target_title: Optional[str] = None
api_key: str
api_base_url: str = "https://api.deepseek.com/v1"
model: str = "deepseek-chat"
max_iterations: int = 2
candidates_per_iteration: int = 2
temperature: float = 0.25
optimization_mode: str = "balanced"
phrase_strategy_mode: str = "auto" # auto | exact_preferred | distributed_preferred | ensemble
bert_stage_target: float = 0.70
# Optional stage control. If empty -> default full pipeline order.
enabled_stages: List[str] = Field(default_factory=list) # bert|bm25|ngram|semantic|title
# Per-stage manual goal selection and custom additions.
# Example:
# {
# "bm25": {"mode":"mixed","selected":["canadian online casino"],"custom_add":["online casinos canada"]},
# "bert": {"mode":"manual","selected":["best payout casinos"],"custom_add":[]}
# }
stage_goal_overrides: Dict[str, Dict[str, Any]] = Field(default_factory=dict)
class OptimizerResponse(BaseModel):
ok: bool = True
optimized_text: str = ""
optimized_title: str = ""
baseline_metrics: Dict[str, Any] = Field(default_factory=dict)
final_metrics: Dict[str, Any] = Field(default_factory=dict)
iterations: List[Dict[str, Any]] = Field(default_factory=list)
applied_changes: int = 0
optimization_mode: str = "balanced"
phrase_strategy_mode: str = "auto"
bert_stage_target: float = 0.70
diff_mode: str = ""
# HTML with <mark class="diff-changed"> around changed parts.
diff_body_html: str = ""
diff_title_html: str = ""
# List of (type/from/to) blocks for "что именно поменять".
diff_changes: List[Dict[str, str]] = Field(default_factory=list)
diff_title_changes: List[Dict[str, str]] = Field(default_factory=list)
error: str = ""
stopped_early: bool = False
stop_reason: str = ""
class OptimizerCancelRequest(BaseModel):
job_id: str = Field(..., min_length=8)