diff --git a/app/integrations/llm/prompt.py b/app/integrations/llm/prompt.py index 4d6a06b..e5397d5 100644 --- a/app/integrations/llm/prompt.py +++ b/app/integrations/llm/prompt.py @@ -7,6 +7,7 @@ from integrations.llm.schemas.report import ( YouTubeDiagnosisInput, YouTubeDiagnosisOutput, BrandConsistencyInput, BrandConsistencyOutput, TransformationInput, TransformationProposal, + RoadmapInput, RoadmapOutput, ) from integrations.llm.schemas.plan import PlanInput, PlanOutput from integrations.llm.schemas.market import ( @@ -114,3 +115,10 @@ transformation_prompt = Prompt( input_class=TransformationInput, output_class=TransformationProposal, ) + +roadmap_prompt = Prompt( + file_name="roadmap_prompt.txt", + prompt_model="REPORT_MODEL", + input_class=RoadmapInput, + output_class=RoadmapOutput, +) diff --git a/app/integrations/llm/schemas/report.py b/app/integrations/llm/schemas/report.py index f9dc896..be3be9b 100644 --- a/app/integrations/llm/schemas/report.py +++ b/app/integrations/llm/schemas/report.py @@ -368,6 +368,17 @@ class CriticalIssuesOutput(BaseModel): diagnosis: list[DiagnosisItem] +# --- Roadmap --- + +class RoadmapInput(BaseModel): + clinic_name: str | None = None + data: str | None = None + + +class RoadmapOutput(BaseModel): + roadmap: list[RoadmapMonth] + + # --- Transformation --- class TransformationInput(BaseModel): diff --git a/app/integrations/llm/temp-prompt/roadmap_prompt.txt b/app/integrations/llm/temp-prompt/roadmap_prompt.txt new file mode 100644 index 0000000..0a11d48 --- /dev/null +++ b/app/integrations/llm/temp-prompt/roadmap_prompt.txt @@ -0,0 +1,14 @@ +다음은 성형외과/피부과 {clinic_name} 의 전 채널 수집 데이터입니다. + +{data} + +위 데이터를 바탕으로 이 병원의 3개월 마케팅 실행 로드맵을 수립해줘. +month 1, 2, 3 각각 하나씩, 총 3개 항목을 포함한 roadmap JSON 배열로 출력해줘. + +각 항목은 아래 형식을 따라줘: +- month: 월 번호 (1, 2, 3) +- title: 해당 월의 핵심 테마 (예: "브랜드 정비") +- subtitle: 한 줄 부제 (예: "기반 구축 — 로고·계정 통일") +- tasks: 실행 과제 목록, 각 과제는 task(string)와 completed(false)로 구성 + +출처 번호([1], [2] 등)는 포함하지 마. diff --git a/app/services/analysis.py b/app/services/analysis.py index b6d67cc..2774fdc 100644 --- a/app/services/analysis.py +++ b/app/services/analysis.py @@ -8,8 +8,8 @@ from common.db.run import select_run, update_run_report, update_run_plan from common.db.source import select_run_raw_data, select_run_mainpage_url from common.db.market import select_market from integrations.llm.llm_service import LLMService -from integrations.llm.prompt import report_prompt, plan_prompt, youtube_diagnosis_prompt, brand_consistency_prompt, critical_issues_prompt, transformation_prompt -from integrations.llm.schemas.report import ReportOutput, ClinicSnapshot, YouTubeAudit, BrandConsistencyOutput, CriticalIssuesOutput, DiagnosisItem, TransformationProposal +from integrations.llm.prompt import report_prompt, plan_prompt, youtube_diagnosis_prompt, brand_consistency_prompt, critical_issues_prompt, transformation_prompt, roadmap_prompt +from integrations.llm.schemas.report import ReportOutput, ClinicSnapshot, YouTubeAudit, BrandConsistencyOutput, CriticalIssuesOutput, DiagnosisItem, TransformationProposal, RoadmapOutput, RoadmapMonth from integrations.llm.schemas.plan import PlanOutput logger = logging.getLogger(__name__) @@ -208,6 +208,17 @@ async def _build_youtube_audit(youtube: dict) -> dict: return YouTubeAudit.model_validate(yt_patch).model_dump() +async def _build_roadmap(analysis_run_id: str, raw: dict) -> list[dict]: + result: RoadmapOutput = await LLMService(provider="perplexity").generate( + roadmap_prompt, + { + "clinic_name": (raw.get("mainpage") or {}).get("clinicName"), + "data": json.dumps(raw, ensure_ascii=False), + }, + ) + return [RoadmapMonth.model_validate(item).model_dump() for item in result.roadmap] + + async def _build_transformation(analysis_run_id: str, raw: dict) -> dict: result: TransformationProposal = await LLMService(provider="perplexity").generate( transformation_prompt, @@ -267,6 +278,7 @@ async def _build_overrides(analysis_run_id: str) -> dict: brand_patch = brand.model_dump()["brand_inconsistencies"] critical_issues = await _build_critical_issues(analysis_run_id, raw) transformation = await _build_transformation(analysis_run_id, raw) + roadmap = await _build_roadmap(analysis_run_id, raw) fb_patch: dict = {} if fb_pages: @@ -287,6 +299,8 @@ async def _build_overrides(analysis_run_id: str) -> dict: overrides["problem_diagnosis"] = critical_issues if transformation: overrides["transformation"] = transformation + if roadmap: + overrides["roadmap"] = roadmap return overrides