from typing import Literal from pydantic import BaseModel class PlanInput(BaseModel): clinic_name: str | None = None clinic_name_en: str | None = None address: str | None = None phone: str | None = None slogan: str | None = None services: str | None = None doctors: str | None = None report: str | None = None market_competitors: str | None = None market_keywords: str | None = None market_trend: str | None = None market_target_audience: str | None = None tiktok: str | None = None instagram_en: str | None = None facebook_en: str | None = None naver_blog: str | None = None naver_cafe: str | None = None kakao_talk: str | None = None channel_logos: str | None = None brand_assets: str | None = None # --- BrandGuide --- class ColorSwatch(BaseModel): name: str hex: str usage: str class FontSpec(BaseModel): family: str weight: str usage: str sample_text: str class LogoUsageRule(BaseModel): rule: str description: str correct: bool class ToneOfVoice(BaseModel): personality: list[str] communication_style: str do_examples: list[str] dont_examples: list[str] class ChannelBrandingRule(BaseModel): channel: str icon: str profile_photo: str banner_spec: str bio_template: str current_status: Literal["correct", "incorrect", "N/A"] class BrandPlanInconsistencyValue(BaseModel): channel: str value: str is_correct: bool class BrandPlanInconsistency(BaseModel): field: str values: list[BrandPlanInconsistencyValue] impact: str recommendation: str class BrandGuide(BaseModel): colors: list[ColorSwatch] fonts: list[FontSpec] logo_rules: list[LogoUsageRule] tone_of_voice: ToneOfVoice channel_branding: list[ChannelBrandingRule] brand_inconsistencies: list[BrandPlanInconsistency] # --- ChannelStrategy --- class ChannelStrategyCard(BaseModel): channel_id: str channel_name: str icon: str current_status: str target_goal: str content_types: list[str] posting_frequency: str tone: str format_guidelines: list[str] priority: Literal["P0", "P1", "P2"] customer_journey_stage: Literal["awareness", "interest", "consideration", "conversion", "loyalty"] | None = None # --- ContentStrategy --- class ContentPillar(BaseModel): title: str description: str related_usp: str example_topics: list[str] color: str class ContentTypeRow(BaseModel): format: str channels: list[str] frequency: str purpose: str class WorkflowStep(BaseModel): step: int name: str description: str owner: str duration: str class RepurposingOutput(BaseModel): format: str channel: str description: str class ContentStrategyData(BaseModel): pillars: list[ContentPillar] type_matrix: list[ContentTypeRow] workflow: list[WorkflowStep] repurposing_source: str repurposing_outputs: list[RepurposingOutput] # --- Calendar --- class CalendarEntry(BaseModel): day_of_week: int channel: str channel_icon: str content_type: Literal["video", "blog", "social", "ad"] title: str id: str | None = None description: str | None = None pillar: str | None = None status: Literal["draft", "approved", "published"] | None = None is_manual_edit: bool | None = None ai_prompt_seed: str | None = None class CalendarWeek(BaseModel): week_number: int label: str entries: list[CalendarEntry] class ContentCountSummary(BaseModel): type: Literal["video", "blog", "social", "ad"] label: str count: int color: str class CalendarData(BaseModel): weeks: list[CalendarWeek] monthly_summary: list[ContentCountSummary] # --- AssetCollection --- class AssetCard(BaseModel): id: str source: Literal["homepage", "naver_place", "blog", "social", "youtube"] source_label: str type: Literal["photo", "video", "text"] title: str description: str repurposing_suggestions: list[str] status: Literal["collected", "pending", "needs_creation"] class YouTubeRepurposeItem(BaseModel): title: str views: int type: Literal["Short", "Long"] repurpose_as: list[str] class AssetCollectionData(BaseModel): assets: list[AssetCard] youtube_repurpose: list[YouTubeRepurposeItem] # --- Repurposing --- class RepurposingProposalItem(BaseModel): source_video: YouTubeRepurposeItem outputs: list[RepurposingOutput] estimated_effort: Literal["low", "medium", "high"] priority: Literal["high", "medium", "low"] # --- PlanOutput --- class PlanOutput(BaseModel): brand_guide: BrandGuide channel_strategies: list[ChannelStrategyCard] content_strategy: ContentStrategyData calendar: CalendarData asset_collection: AssetCollectionData repurposing_proposals: list[RepurposingProposalItem] | None = None