240 lines
5.2 KiB
Python
240 lines
5.2 KiB
Python
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
|
|
|
|
|
|
# --- BrandGuide ---
|
|
|
|
class ColorSwatch(BaseModel):
|
|
name: str
|
|
hex: str
|
|
usage: str
|
|
|
|
|
|
class FontSpec(BaseModel):
|
|
family: str
|
|
weight: str
|
|
usage: str
|
|
sampleText: str
|
|
|
|
|
|
class LogoUsageRule(BaseModel):
|
|
rule: str
|
|
description: str
|
|
correct: bool
|
|
|
|
|
|
class ToneOfVoice(BaseModel):
|
|
personality: list[str]
|
|
communicationStyle: str
|
|
doExamples: list[str]
|
|
dontExamples: list[str]
|
|
|
|
|
|
class ChannelBrandingRule(BaseModel):
|
|
channel: str
|
|
icon: str
|
|
profilePhoto: str
|
|
bannerSpec: str
|
|
bioTemplate: str
|
|
currentStatus: Literal["correct", "incorrect", "missing"]
|
|
|
|
|
|
class BrandInconsistencyValue(BaseModel):
|
|
channel: str
|
|
value: str
|
|
isCorrect: bool
|
|
|
|
|
|
class BrandInconsistency(BaseModel):
|
|
field: str
|
|
values: list[BrandInconsistencyValue]
|
|
impact: str
|
|
recommendation: str
|
|
|
|
|
|
class BrandGuide(BaseModel):
|
|
colors: list[ColorSwatch]
|
|
fonts: list[FontSpec]
|
|
logoRules: list[LogoUsageRule]
|
|
toneOfVoice: ToneOfVoice
|
|
channelBranding: list[ChannelBrandingRule]
|
|
brandInconsistencies: list[BrandInconsistency]
|
|
|
|
|
|
# --- ChannelStrategy ---
|
|
|
|
class ChannelStrategyCard(BaseModel):
|
|
channelId: str
|
|
channelName: str
|
|
icon: str
|
|
currentStatus: str
|
|
targetGoal: str
|
|
contentTypes: list[str]
|
|
postingFrequency: str
|
|
tone: str
|
|
formatGuidelines: list[str]
|
|
priority: Literal["P0", "P1", "P2"]
|
|
customerJourneyStage: Literal["awareness", "interest", "consideration", "conversion", "loyalty"] | None = None
|
|
|
|
|
|
# --- ContentStrategy ---
|
|
|
|
class ContentPillar(BaseModel):
|
|
title: str
|
|
description: str
|
|
relatedUSP: str
|
|
exampleTopics: 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]
|
|
typeMatrix: list[ContentTypeRow]
|
|
workflow: list[WorkflowStep]
|
|
repurposingSource: str
|
|
repurposingOutputs: list[RepurposingOutput]
|
|
|
|
|
|
# --- Calendar ---
|
|
|
|
class CalendarEntry(BaseModel):
|
|
dayOfWeek: int
|
|
channel: str
|
|
channelIcon: str
|
|
contentType: 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
|
|
isManualEdit: bool | None = None
|
|
aiPromptSeed: str | None = None
|
|
|
|
|
|
class CalendarWeek(BaseModel):
|
|
weekNumber: 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]
|
|
monthlySummary: list[ContentCountSummary]
|
|
|
|
|
|
# --- AssetCollection ---
|
|
|
|
class AssetCard(BaseModel):
|
|
id: str
|
|
source: Literal["homepage", "naver_place", "blog", "social", "youtube"]
|
|
sourceLabel: str
|
|
type: Literal["photo", "video", "text"]
|
|
title: str
|
|
description: str
|
|
repurposingSuggestions: list[str]
|
|
status: Literal["collected", "pending", "needs_creation"]
|
|
|
|
|
|
class YouTubeRepurposeItem(BaseModel):
|
|
title: str
|
|
views: int
|
|
type: Literal["Short", "Long"]
|
|
repurposeAs: list[str]
|
|
|
|
|
|
class AssetCollectionData(BaseModel):
|
|
assets: list[AssetCard]
|
|
youtubeRepurpose: list[YouTubeRepurposeItem]
|
|
|
|
|
|
# --- Repurposing ---
|
|
|
|
class RepurposingProposalItem(BaseModel):
|
|
sourceVideo: YouTubeRepurposeItem
|
|
outputs: list[RepurposingOutput]
|
|
estimatedEffort: Literal["low", "medium", "high"]
|
|
priority: Literal["high", "medium", "low"]
|
|
|
|
|
|
# --- Workflow ---
|
|
|
|
class WorkflowVideoDraft(BaseModel):
|
|
script: str
|
|
shootingGuide: list[str]
|
|
duration: str
|
|
|
|
|
|
# class WorkflowImageTextDraft(BaseModel):
|
|
# type: Literal["cardnews", "blog"]
|
|
# headline: str
|
|
# copy: list[str]
|
|
# layoutHint: str | None = None
|
|
|
|
|
|
# class WorkflowItem(BaseModel):
|
|
# id: str
|
|
# title: str
|
|
# contentType: Literal["video", "image-text"]
|
|
# channel: str
|
|
# channelIcon: str
|
|
# stage: Literal["planning", "ai-draft", "review", "approved", "scheduled"]
|
|
# userNotes: str | None = None
|
|
# videoDraft: WorkflowVideoDraft | None = None
|
|
# imageTextDraft: WorkflowImageTextDraft | None = None
|
|
# scheduledDate: str | None = None
|
|
|
|
|
|
# class WorkflowData(BaseModel):
|
|
# items: list[WorkflowItem]
|
|
|
|
|
|
# --- PlanOutput ---
|
|
|
|
class PlanOutput(BaseModel):
|
|
brandGuide: BrandGuide
|
|
channelStrategies: list[ChannelStrategyCard]
|
|
contentStrategy: ContentStrategyData
|
|
calendar: CalendarData
|
|
assetCollection: AssetCollectionData
|
|
repurposingProposals: list[RepurposingProposalItem] | None = None
|
|
#workflow: WorkflowData | None = None
|