o2o-infinith-backend/app/integrations/llm/schemas/report.py

384 lines
7.8 KiB
Python

from __future__ import annotations
from pydantic import BaseModel
from models.status import Severity, ChannelStatus, DataSource, Language, VideoType, AnnotationType
class ScreenshotAnnotation(BaseModel):
type: AnnotationType
x: float
y: float
width: float | None = None
height: float | None = None
label: str | None = None
color: str | None = None
class ScreenshotEvidence(BaseModel):
id: str
url: str
channel: str
captured_at: str
caption: str
source_url: str | None = None
annotations: list[ScreenshotAnnotation] | None = None
class DiagnosisItem(BaseModel):
category: str
detail: str
severity: Severity
evidence_ids: list[str] | None = None
# --- ClinicSnapshot ---
class LeadDoctor(BaseModel):
name: str
credentials: str
rating: float
review_count: int
class PriceRange(BaseModel):
min: str
max: str
currency: str
class LogoImages(BaseModel):
circle: str | None = None
horizontal: str | None = None
korean: str | None = None
class BrandColors(BaseModel):
primary: str
accent: str
text: str
class RegistryData(BaseModel):
district: str | None = None
branches: str | None = None
brand_group: str | None = None
website_en: str | None = None
naver_place_url: str | None = None
gangnam_unni_url: str | None = None
google_maps_url: str | None = None
class ClinicSnapshot(BaseModel):
name: str
name_en: str
staff_count: int
lead_doctor: LeadDoctor
overall_rating: float
total_reviews: int
certifications: list[str]
location: str
phone: str
domain: str
logo_images: LogoImages | None = None
brand_colors: BrandColors | None = None
source: DataSource | None = None
registry_data: RegistryData | None = None
# --- ChannelScore ---
class ChannelScore(BaseModel):
channel: str
icon: str
score: int
max_score: int
status: Severity
headline: str
# --- YouTube ---
class WeeklyViewGrowth(BaseModel):
absolute: int
percentage: float
class EstimatedRevenue(BaseModel):
min: int
max: int
class LinkedUrl(BaseModel):
label: str
url: str
class TopVideo(BaseModel):
title: str
views: int
uploaded_ago: str
type: VideoType
duration: str | None = None
class YouTubeAudit(BaseModel):
channel_name: str
handle: str
subscribers: int
total_videos: int
total_views: int
weekly_view_growth: WeeklyViewGrowth
estimated_monthly_revenue: EstimatedRevenue
avg_video_length: str
upload_frequency: str
channel_created_date: str
channel_description: str
linked_urls: list[LinkedUrl]
playlists: list[str]
top_videos: list[TopVideo]
diagnosis: list[DiagnosisItem]
# --- Instagram ---
class InstagramAccount(BaseModel):
handle: str
language: Language
label: str
posts: int
followers: int
following: int
category: str
profile_link: str
highlights: list[str]
reels_count: int
content_format: str
profile_photo: str
bio: str
class InstagramAudit(BaseModel):
accounts: list[InstagramAccount]
diagnosis: list[DiagnosisItem]
# --- Facebook ---
class BrandInconsistencyValue(BaseModel):
channel: str
value: str
is_correct: bool
class BrandInconsistency(BaseModel):
field: str
values: list[BrandInconsistencyValue]
impact: str
recommendation: str
class FacebookPage(BaseModel):
url: str
page_name: str
language: Language
label: str
followers: int
following: int
category: str
bio: str
logo: str
logo_description: str
link: str
linked_domain: str
reviews: int
recent_post_age: str
has_whatsapp: bool
post_frequency: str | None = None
top_content_type: str | None = None
engagement: str | None = None
class FacebookAudit(BaseModel):
pages: list[FacebookPage]
diagnosis: list[DiagnosisItem]
brand_inconsistencies: list[BrandInconsistency]
consolidation_recommendation: str
# --- 기타 채널 / 웹사이트 ---
class OtherChannel(BaseModel):
name: str
status: ChannelStatus
details: str
url: str | None = None
class TrackingPixel(BaseModel):
name: str
installed: bool
details: str | None = None
class SnsLink(BaseModel):
platform: str
url: str
location: str
class AdditionalDomain(BaseModel):
domain: str
purpose: str
class WebsiteAudit(BaseModel):
primary_domain: str
additional_domains: list[AdditionalDomain]
sns_links_on_site: bool
sns_links_detail: list[SnsLink] | None = None
tracking_pixels: list[TrackingPixel]
main_cta: str
# --- Transformation ---
class AsIsToBeItem(BaseModel):
area: str
as_is: str
to_be: str
class StrategyDetail(BaseModel):
strategy: str
detail: str
class PlatformStrategy(BaseModel):
platform: str
icon: str
current_metric: str
target_metric: str
strategies: list[StrategyDetail]
class NewChannelProposal(BaseModel):
channel: str
priority: str
rationale: str
class TransformationProposal(BaseModel):
brand_identity: list[AsIsToBeItem]
content_strategy: list[AsIsToBeItem]
platform_strategies: list[PlatformStrategy]
website_improvements: list[AsIsToBeItem]
new_channel_proposals: list[NewChannelProposal]
# --- Roadmap / KPI ---
class RoadmapTask(BaseModel):
task: str
completed: bool
class RoadmapMonth(BaseModel):
month: int
title: str
subtitle: str
tasks: list[RoadmapTask]
class KPIMetric(BaseModel):
metric: str
current: str
target_3_month: str
target_12_month: str
# --- ReportInput (prompt 템플릿 변수) ---
class ReportInput(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
instagram: str | None = None
facebook: str | None = None
naver_blog: str | None = None
youtube: str | None = None
gangnam_unni: str | None = None
market_competitors: str | None = None
market_keywords: str | None = None
market_trend: str | None = None
market_target_audience: str | None = None
# --- MarketingReport ---
class MarketingReport(BaseModel):
id: str
created_at: str
target_url: str
overall_score: int
clinic_snapshot: ClinicSnapshot
channel_scores: list[ChannelScore]
youtube_audit: YouTubeAudit
instagram_audit: InstagramAudit
facebook_audit: FacebookAudit
other_channels: list[OtherChannel]
website_audit: WebsiteAudit
problem_diagnosis: list[DiagnosisItem]
transformation: TransformationProposal
roadmap: list[RoadmapMonth]
kpi_dashboard: list[KPIMetric]
screenshots: list[ScreenshotEvidence] | None = None
ReportOutput = MarketingReport
# --- YouTubeDiagnosis ---
class YouTubeDiagnosisInput(BaseModel):
channel_name: str | None = None
subscribers: int | None = None
total_videos: int | None = None
total_views: int | None = None
avg_video_length: str | None = None
upload_frequency: str | None = None
top_videos: str | None = None
playlists: str | None = None
class YouTubeDiagnosisOutput(BaseModel):
diagnosis: list[DiagnosisItem]
# --- Diagnosis ---
class CriticalIssuesInput(BaseModel):
clinic_name: str | None = None
data: str | None = None
class CriticalIssuesOutput(BaseModel):
diagnosis: list[DiagnosisItem]
# --- BrandConsistency ---
class BrandConsistencyInput(BaseModel):
clinic_name: str | None = None
mainpage: str | None = None
instagram: str | None = None
facebook: str | None = None
youtube: str | None = None
gangnam_unni: str | None = None
class BrandConsistencyOutput(BaseModel):
brand_inconsistencies: list[BrandInconsistency]