fix(report): ClinicSnapshot/YouTubeAudit/Instagram*/Facebook* Optional 완화
required로 두면 LLM 응답이나 수집 데이터 누락 시 pydantic ValidationError로 리포트 endpoint 전체가 500으로 죽음. 실제 테스트(청담오라클)에서 LLM이 weekly_view_growth, established 등 10개 필드를 null 반환하는 케이스 확인. - ClinicSnapshot/YouTubeAudit: schemas + models 양쪽 모두 Optional (LLM 입력 검증 + FastAPI 응답 검증 둘 다 통과 필요) - InstagramAccount/InstagramAudit/FacebookPage/FacebookAudit: models만 (인스타·페북 빈 계정/페이지 케이스 대응) - list[T] 필드는 기본값 [] 부여 트레이드오프: 스키마 레벨 데이터 완결성 보장 약화. 운영하며 자주 비는 필드 패턴 보고 collection 단계 보강 필요. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>main
parent
71b605eaa6
commit
5dbc7d7ffe
|
|
@ -68,16 +68,18 @@ class RegistryData(BaseModel):
|
|||
|
||||
|
||||
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
|
||||
# _build_clinic_snapshot은 source 데이터 있을 때만 채움 (`if x:` 가드).
|
||||
# required면 강남언니/홈페이지 누락 병원에서 ValidationError로 리포트 실패.
|
||||
name: str | None = None
|
||||
name_en: str | None = None
|
||||
staff_count: int | None = None
|
||||
lead_doctor: LeadDoctor | None = None
|
||||
overall_rating: float | None = None
|
||||
total_reviews: int | None = None
|
||||
certifications: list[str] = []
|
||||
location: str | None = None
|
||||
phone: str | None = None
|
||||
domain: str | None = None
|
||||
logo_images: LogoImages | None = None
|
||||
brand_colors: BrandColors | None = None
|
||||
source: DataSource | None = None
|
||||
|
|
@ -121,21 +123,23 @@ class TopVideo(BaseModel):
|
|||
|
||||
|
||||
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]
|
||||
# YouTube 미수집 병원에서 _build_youtube_audit가 채울 수 없는 필드 빔.
|
||||
# required면 ValidationError로 리포트 실패 → Optional로 받아 부분 응답 허용.
|
||||
channel_name: str | None = None
|
||||
handle: str | None = None
|
||||
subscribers: int | None = None
|
||||
total_videos: int | None = None
|
||||
total_views: int | None = None
|
||||
weekly_view_growth: WeeklyViewGrowth | None = None
|
||||
estimated_monthly_revenue: EstimatedRevenue | None = None
|
||||
avg_video_length: str | None = None
|
||||
upload_frequency: str | None = None
|
||||
channel_created_date: str | None = None
|
||||
channel_description: str | None = None
|
||||
linked_urls: list[LinkedUrl] = []
|
||||
playlists: list[str] = []
|
||||
top_videos: list[TopVideo] = []
|
||||
diagnosis: list[DiagnosisItem] = []
|
||||
|
||||
|
||||
# --- Instagram ---
|
||||
|
|
|
|||
|
|
@ -66,16 +66,18 @@ class RegistryData(CamelModel):
|
|||
|
||||
|
||||
class ClinicSnapshot(CamelModel):
|
||||
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
|
||||
# _build_clinic_snapshot은 source 데이터 있을 때만 필드 추가 (`if x:` 가드).
|
||||
# 강남언니/홈페이지 수집 누락된 병원에서 required면 ValidationError로 리포트 전체 실패.
|
||||
name: str | None = None
|
||||
name_en: str | None = None
|
||||
staff_count: int | None = None
|
||||
lead_doctor: LeadDoctor | None = None
|
||||
overall_rating: float | None = None
|
||||
total_reviews: int | None = None
|
||||
certifications: list[str] = []
|
||||
location: str | None = None
|
||||
phone: str | None = None
|
||||
domain: str | None = None
|
||||
logo_images: LogoImages | None = None
|
||||
brand_colors: BrandColors | None = None
|
||||
source: DataSource | None = None
|
||||
|
|
@ -115,42 +117,45 @@ class TopVideo(CamelModel):
|
|||
|
||||
|
||||
class YouTubeAudit(CamelModel):
|
||||
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]
|
||||
# YouTube 채널 없는 병원이면 _build_youtube_audit가 채울 수 없는 필드들 (channel_name 등)이 빔.
|
||||
# required면 ValidationError로 리포트 실패 → Optional로 받아 부분 응답 허용.
|
||||
channel_name: str | None = None
|
||||
handle: str | None = None
|
||||
subscribers: int | None = None
|
||||
total_videos: int | None = None
|
||||
total_views: int | None = None
|
||||
weekly_view_growth: WeeklyViewGrowth | None = None
|
||||
estimated_monthly_revenue: EstimatedRevenue | None = None
|
||||
avg_video_length: str | None = None
|
||||
upload_frequency: str | None = None
|
||||
channel_created_date: str | None = None
|
||||
channel_description: str | None = None
|
||||
linked_urls: list[LinkedUrl] = []
|
||||
playlists: list[str] = []
|
||||
top_videos: list[TopVideo] = []
|
||||
diagnosis: list[DiagnosisItem] = []
|
||||
|
||||
|
||||
class InstagramAccount(CamelModel):
|
||||
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
|
||||
# 인스타 계정(KR/EN) 미수집 시 빈 필드 가능 — Optional.
|
||||
handle: str | None = None
|
||||
language: Language | None = None
|
||||
label: str | None = None
|
||||
posts: int | None = None
|
||||
followers: int | None = None
|
||||
following: int | None = None
|
||||
category: str | None = None
|
||||
profile_link: str | None = None
|
||||
highlights: list[str] = []
|
||||
reels_count: int | None = None
|
||||
content_format: str | None = None
|
||||
profile_photo: str | None = None
|
||||
bio: str | None = None
|
||||
|
||||
|
||||
class InstagramAudit(CamelModel):
|
||||
accounts: list[InstagramAccount]
|
||||
diagnosis: list[DiagnosisItem]
|
||||
accounts: list[InstagramAccount] = []
|
||||
diagnosis: list[DiagnosisItem] = []
|
||||
|
||||
|
||||
class BrandInconsistencyValue(CamelModel):
|
||||
|
|
@ -167,31 +172,32 @@ class BrandInconsistency(CamelModel):
|
|||
|
||||
|
||||
class FacebookPage(CamelModel):
|
||||
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
|
||||
# 페북 페이지(KR/EN) 미수집 시 빈 필드 가능 — Optional.
|
||||
url: str | None = None
|
||||
page_name: str | None = None
|
||||
language: Language | None = None
|
||||
label: str | None = None
|
||||
followers: int | None = None
|
||||
following: int | None = None
|
||||
category: str | None = None
|
||||
bio: str | None = None
|
||||
logo: str | None = None
|
||||
logo_description: str | None = None
|
||||
link: str | None = None
|
||||
linked_domain: str | None = None
|
||||
reviews: int | None = None
|
||||
recent_post_age: str | None = None
|
||||
has_whatsapp: bool | None = None
|
||||
post_frequency: str | None = None
|
||||
top_content_type: str | None = None
|
||||
engagement: str | None = None
|
||||
|
||||
|
||||
class FacebookAudit(CamelModel):
|
||||
pages: list[FacebookPage]
|
||||
diagnosis: list[DiagnosisItem]
|
||||
brand_inconsistencies: list[BrandInconsistency]
|
||||
consolidation_recommendation: str
|
||||
pages: list[FacebookPage] = []
|
||||
diagnosis: list[DiagnosisItem] = []
|
||||
brand_inconsistencies: list[BrandInconsistency] = []
|
||||
consolidation_recommendation: str | None = None
|
||||
|
||||
|
||||
class OtherChannel(CamelModel):
|
||||
|
|
|
|||
Loading…
Reference in New Issue