from dataclasses import dataclass, field from typing import Optional, List, Dict, Any @dataclass class ChannelCategory: id: Optional[int] name: str type: str = "both" # "source", "target", "both" description: str = "" created_at: Optional[str] = None @dataclass class SourceChannel: id: Optional[int] channel_id: int username: Optional[str] title: Optional[str] category_id: Optional[int] = None context_message_count: int = 0 is_active: bool = True created_at: Optional[str] = None @dataclass class TargetChannel: id: Optional[int] channel_id: int title: Optional[str] username: Optional[str] category_id: Optional[int] = None post_interval_min: int = 30 personality: str = "" custom_footer: str = "" custom_prompt: str = "" sleep_start_hour: int = 0 sleep_end_hour: int = 0 is_sleep_enabled: bool = False # Telegram channel_ids of sources whose posts are queued to this target automatically. auto_source_ids: List[int] = field(default_factory=list) language: str = "fa" last_post_time: Optional[str] = None is_active: bool = True created_at: Optional[str] = None @dataclass class Post: id: Optional[int] source_channel_id: int source_message_id: int raw_text: Optional[str] media_path: Optional[str] = None media_type: Optional[str] = None content_hash: Optional[str] = None tags: List[str] = field(default_factory=list) is_duplicate: bool = False duplicate_of_id: Optional[int] = None similarity_reason: Optional[str] = None subject: Optional[str] = None ai_text: Optional[str] = None suggested_target_id: Optional[int] = None target_channel_id: Optional[int] = None status: str = "pending_review" # pending_review, published, rejected, deleted rejection_reason: Optional[str] = None published_to: List[Dict[str, Any]] = field(default_factory=list) is_deleted: bool = False review_message_id: Optional[int] = None scheduled_at: Optional[str] = None published_at: Optional[str] = None source_created_at: Optional[str] = None created_at: Optional[str] = None @dataclass class Setting: key: str value: str description: Optional[str] = None @dataclass class AILog: id: Optional[int] action_name: str provider: str model: str prompt: str system_prompt: Optional[str] = None response_text: Optional[str] = None duration_sec: float = 0.0 status: str = "success" error_message: Optional[str] = None created_at: Optional[str] = None @dataclass class AIProviderProfile: id: Optional[int] name: str provider_type: str model: str base_url: str = "" api_key: str = "" reasoning_effort: str = "" is_active: bool = False fallback_provider_id: Optional[int] = None fallback_provider_name: Optional[str] = None supports_vision: bool = False created_at: Optional[str] = None