diff --git a/app/integrations/llm/prompt.py b/app/integrations/llm/prompt.py index 9c00c23..3ee76d4 100644 --- a/app/integrations/llm/prompt.py +++ b/app/integrations/llm/prompt.py @@ -1,7 +1,12 @@ import os from pydantic import BaseModel from common.utils import get_env -from integrations.llm.schemas.report import ReportInput, ReportOutput, YouTubeDiagnosisInput, YouTubeDiagnosisOutput, BrandConsistencyInput, BrandConsistencyOutput +from integrations.llm.schemas.report import ( + ReportInput, ReportOutput, + CriticalIssuesInput, CriticalIssuesOutput, + YouTubeDiagnosisInput, YouTubeDiagnosisOutput, + BrandConsistencyInput, BrandConsistencyOutput, +) from integrations.llm.schemas.plan import PlanInput, PlanOutput from integrations.llm.schemas.market import ( MarketCompetitorsInput, MarketCompetitorsOutput, @@ -94,3 +99,10 @@ brand_consistency_prompt = Prompt( input_class=BrandConsistencyInput, output_class=BrandConsistencyOutput, ) + +critical_issues_prompt = Prompt( + file_name="critical_issues_prompt.txt", + prompt_model="REPORT_MODEL", + input_class=CriticalIssuesInput, + output_class=CriticalIssuesOutput, +) diff --git a/app/integrations/llm/schemas/report.py b/app/integrations/llm/schemas/report.py index 5e6ee46..8bbee91 100644 --- a/app/integrations/llm/schemas/report.py +++ b/app/integrations/llm/schemas/report.py @@ -357,6 +357,17 @@ 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): diff --git a/app/integrations/llm/temp-prompt/critical_issues_prompt.txt b/app/integrations/llm/temp-prompt/critical_issues_prompt.txt new file mode 100644 index 0000000..bcb6f78 --- /dev/null +++ b/app/integrations/llm/temp-prompt/critical_issues_prompt.txt @@ -0,0 +1,13 @@ +다음은 성형외과/피부과 {clinic_name} 의 전 채널 수집 데이터입니다. + +{data} + +위 데이터를 바탕으로 이 병원의 마케팅 전반에 걸친 핵심 문제점과 개선사항을 진단해줘. +각 항목은 category(진단 카테고리), detail(상세 설명), severity(critical/warning/info) 형식의 JSON 배열로 출력해줘. + +현재 주요 진단 카테고리는 3개야. +브랜드 아이덴티티 파편화 +콘텐츠 전략 부재 +플랫폼 간 유입 단절 + +출처 번호([1], [2] 등)는 포함하지 마. diff --git a/app/services/analysis.py b/app/services/analysis.py index 1229047..48dcea9 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 -from integrations.llm.schemas.report import ReportOutput, ClinicSnapshot, YouTubeAudit, BrandConsistencyOutput +from integrations.llm.prompt import report_prompt, plan_prompt, youtube_diagnosis_prompt, brand_consistency_prompt, critical_issues_prompt +from integrations.llm.schemas.report import ReportOutput, ClinicSnapshot, YouTubeAudit, BrandConsistencyOutput, CriticalIssuesOutput, DiagnosisItem 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_critical_issues(analysis_run_id: str, raw: dict) -> list[dict]: + result: CriticalIssuesOutput = await LLMService(provider="perplexity").generate( + critical_issues_prompt, + { + "clinic_name": (raw.get("mainpage") or {}).get("clinicName"), + "data": json.dumps(raw, ensure_ascii=False), + }, + ) + return [DiagnosisItem.model_validate(item).model_dump() for item in result.diagnosis] + + async def _build_overrides(analysis_run_id: str) -> dict: raw = await select_run_raw_data(analysis_run_id) if not raw: @@ -243,6 +254,7 @@ async def _build_overrides(analysis_run_id: str) -> dict: brand = await generate_brand_consistency(analysis_run_id) brand_patch = brand.model_dump()["brand_inconsistencies"] + critical_issues = await _build_critical_issues(analysis_run_id, raw) fb_patch: dict = {} if fb_pages: @@ -259,6 +271,8 @@ async def _build_overrides(analysis_run_id: str) -> dict: overrides["facebook_audit"] = fb_patch if yt_patch: overrides["youtube_audit"] = yt_patch + if critical_issues: + overrides["problem_diagnosis"] = critical_issues return overrides