o2o-infinith-demo/doc/AI_PROMPTS_CATALOG.md

429 lines
15 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# INFINITH AI Prompts Catalog (v2 — Updated 2026-04-04)
현재 프로덕션에서 사용 중인 모든 AI 프롬프트.
Pipeline V2 아키텍처 기반 (discover → collect → generate).
---
## Pipeline Overview
```
Phase 1: discover-channels
├─ A. Firecrawl scrape+map (병원 정보 + 소셜 링크 추출)
├─ B1. YouTube Data API (채널 직접 검색)
├─ B2. Naver Search API (블로그 + 웹 검색)
├─ B3. Firecrawl Search (소셜 URL 웹 검색)
├─ B4. Perplexity sonar (Online Presence 통합 검색)
├─ B4b. Perplexity sonar (강남언니 URL 검색)
├─ B5. Apify Instagram (프로필 직접 검색)
└─ C. 핸들 검증 (HEAD 요청 + YouTube API)
Phase 2: collect-channel-data
├─ Instagram (Apify)
├─ YouTube (YouTube Data API v3)
├─ Facebook (Apify)
├─ 강남언니 (Firecrawl JSON 추출)
├─ Naver Blog + Place (Naver API)
├─ Google Maps (Apify)
└─ 시장 분석 (Perplexity × 4 병렬)
Phase 3: generate-report
└─ Perplexity sonar (실제 수집 데이터 기반 리포트 생성)
```
---
## Phase 1: discover-channels
### P1-A. Firecrawl — 병원 정보 + 소셜 링크 추출
**File**: `supabase/functions/discover-channels/index.ts` (Stage A)
**API**: Firecrawl `v1/scrape` (JSON + links)
**Wait**: 5000ms
**Extraction Prompt**:
```
Extract: clinic name (Korean), clinic name (English), address, phone,
services offered, doctors with specialties, ALL social media links
(instagram handles/URLs, youtube channel URL/handle, naver blog URL,
facebook page URL, tiktok, kakao channel), business hours, slogan
```
**Schema**: clinicName, clinicNameEn, address, phone, businessHours, slogan, services[], doctors[], socialMedia{}
**용도**: 병원 기본 정보 수집 + HTML에서 소셜 링크 직접 추출
---
### P1-A2. Firecrawl — 브랜딩 추출
**API**: Firecrawl `v1/scrape` (JSON)
**Wait**: 3000ms
**Extraction Prompt**:
```
Extract brand identity: primary/accent/background/text colors (hex),
heading/body fonts, logo URL, favicon URL, tagline
```
**Schema**: primaryColor, accentColor, backgroundColor, textColor, headingFont, bodyFont, logoUrl, faviconUrl, tagline
---
### P1-B1. YouTube Data API — 채널 직접 검색
**File**: `supabase/functions/discover-channels/index.ts` (Stage B1)
**API**: YouTube Data API v3 `search?type=channel`
**Prompt**: 없음 (API 직접 호출)
```
GET https://www.googleapis.com/youtube/v3/search
?part=snippet
&type=channel
&q={clinicName}
&maxResults=3
&key={YOUTUBE_API_KEY}
```
**매칭 로직**: 검색 결과 채널명이 병원명을 포함하면 channelId 추출
---
### P1-B2a. Naver Search API — 블로그 검색
**File**: `supabase/functions/discover-channels/index.ts` (Stage B2a)
**API**: Naver Search `blog.json`
```
GET https://openapi.naver.com/v1/search/blog.json
?query={clinicName} 공식 블로그
&display=5
&sort=sim
```
**추출**: `blog.naver.com/{blogId}` 패턴 매칭
---
### P1-B2b. Naver Search API — 웹 검색 (소셜 URL 발견)
**API**: Naver Search `webkr.json`
```
GET https://openapi.naver.com/v1/search/webkr.json
?query={clinicName} 인스타그램 유튜브 공식
&display=10
```
**추출**: 검색 결과 URL에서 instagram.com, youtube.com, facebook.com 패턴 매칭
---
### P1-B3. Firecrawl Search — 소셜 URL 웹 검색
**API**: Firecrawl `v1/search`
```json
{
"query": "{clinicName} 성형외과 instagram youtube 공식",
"limit": 10
}
```
**추출**: 검색 결과 URL에서 소셜 핸들 패턴 매칭 (extractSocialLinks)
---
### P1-B4. Perplexity — Online Presence 통합 검색 ⭐ (핵심 프롬프트)
**File**: `supabase/functions/discover-channels/index.ts` (Stage B4)
**API**: Perplexity `sonar`, temp=0.1
**목적**: 다른 API가 놓친 소셜 계정을 웹 검색으로 보충 발견
**System Message**:
```
You are a social media researcher. Search the web and find social media accounts. Respond ONLY with valid JSON.
```
**User Message** (template):
```
{clinicName} ({clinicNameEn}) 병원의 인스타그램, 유튜브, 페이스북, 틱톡, 네이버블로그 계정을 검색해서 찾아줘. 검색 결과에서 발견된 계정을 모두 알려줘. 인스타그램은 여러 계정이 있을 수 있어.
{"instagram": ["handle1", "handle2"], "youtube": "channel URL or handle", "facebook": "page name or URL", "tiktok": "handle", "naverBlog": "blog ID"}
```
**핵심 학습 (프롬프트 엔지니어링)**:
- ❌ 실패 패턴: "공식 계정만 찾아줘" / "확인된 계정만" / "Never guess" → 전부 null 반환
- ❌ 실패 패턴: sonar-pro + 장문 시스템 프롬프트 → 빈 결과
- ❌ 실패 패턴: 3개로 분리된 쿼리 → 각각 빈 결과
- ✅ 성공 패턴: 짧은 시스템 프롬프트 + 모든 채널 한 쿼리 + "검색해서 찾아줘" + 영문명 괄호 포함
- ✅ 성공 패턴: `sonar` 모델 (sonar-pro보다 오히려 나음)
- ✅ 성공 패턴: 예시 JSON을 user message 끝에 포함 (output 형식 유도)
**변수 구성**:
```typescript
const clinicNameEn = clinic.clinicNameEn || '';
const searchName = clinicNameEn
? `${resolvedName} (${clinicNameEn})` // "그랜드성형외과 (Grand Plastic Surgery)"
: resolvedName; // "그랜드성형외과"
```
---
### P1-B4b. Perplexity — 강남언니 URL 검색
**API**: Perplexity `sonar`, temp=0.1
**System Message**:
```
You search for clinic listings on medical platforms. Respond ONLY with valid JSON.
```
**User Message**:
```
{clinicName} 병원 강남언니 gangnamunni.com 페이지를 찾아줘.
{"gangnamUnni": {"url": "https://gangnamunni.com/hospitals/...", "rating": 9.5, "reviews": 1000}}
```
---
### P1-B5. Apify — Instagram 프로필 직접 검색
**File**: `supabase/functions/discover-channels/index.ts` (Stage B5)
**API**: Apify `instagram-profile-scraper`
**Timeout**: 30초 per candidate
**핸들 후보 생성 로직**:
```typescript
const baseName = clinicName.replace(/성형외과|병원|의원|클리닉|피부과/g, '').trim().toLowerCase();
const baseNameEn = clinic.clinicNameEn.replace(/\s+/g, '').toLowerCase();
candidates = [
baseNameEn, // "grandplasticsurgery"
`${baseNameEn}_official`, // "grandplasticsurgery_official"
`${baseNameEn}_ps`, // "grandplasticsurgery_ps"
`${baseNameEn}_clinic`, // "grandplasticsurgery_clinic"
domainBase, // "grandplasticsurgery" (from URL)
`${domainBase}_official`, // "grandplasticsurgery_official"
]
```
**유효성 조건**: `followersCount >= 50` → 후보로 채택
---
### P1-C. 병원명 추출 Fallback (Perplexity)
**조건**: Firecrawl이 clinicName을 추출하지 못한 경우
**API**: Perplexity `sonar`, temp=0.1
**System Message**:
```
Respond with ONLY the clinic name in Korean, nothing else.
```
**User Message**:
```
{url} 이 URL의 병원/클리닉 한국어 이름이 뭐야?
```
---
## Phase 2: collect-channel-data
### P2-1. Firecrawl — 강남언니 페이지 데이터 추출
**File**: `supabase/functions/collect-channel-data/index.ts`
**API**: Firecrawl `v1/scrape` (JSON)
**Wait**: 5000ms
**Extraction Prompt**:
```
Extract: hospital name, overall rating (out of 10), total review count,
doctors with names/ratings/review counts/specialties, procedures offered,
address, certifications/badges
```
**Schema**: hospitalName, rating(number), totalReviews(number), doctors[], procedures[], address, badges[]
---
### P2-2~5. Perplexity — 시장 분석 (4개 병렬)
**API**: Perplexity `sonar`, temp=0.3
**공통 System Message**:
```
You are a Korean medical marketing analyst. Always respond in Korean. Provide data in valid JSON format.
```
**쿼리 4개**:
| ID | User Prompt |
|----|-------------|
| competitors | `{address} 근처 {services} 전문 성형외과/피부과 경쟁 병원 5곳을 분석해줘. 각 병원의 이름, 주요 시술, 온라인 평판, 마케팅 채널을 JSON 형식으로 제공해줘.` |
| keywords | `한국 {services} 관련 검색 키워드 트렌드. 네이버와 구글에서 월간 검색량이 높은 키워드 20개, 경쟁 강도, 추천 롱테일 키워드를 JSON 형식으로 제공해줘.` |
| market | `한국 {services[0]} 시장 트렌드 2025-2026. 시장 규모, 성장률, 주요 트렌드, 마케팅 채널별 효과를 JSON 형식으로 제공해줘.` |
| targetAudience | `{clinicName}의 잠재 고객 분석. 연령대별, 성별, 관심 시술, 정보 탐색 채널, 의사결정 요인을 JSON 형식으로 제공해줘.` |
---
## Phase 3: generate-report
### P3. Perplexity — 마케팅 리포트 생성 (V2: 실제 데이터 기반)
**File**: `supabase/functions/generate-report/index.ts`
**API**: Perplexity `sonar`, temp=0.3
**System Message**:
```
You are a Korean medical marketing analyst. Respond ONLY with valid JSON, no markdown code blocks. Use Korean for text fields. 강남언니 rating is 10-point scale. Use ONLY the provided real data — never invent metrics.
```
**User Message** (template 구조):
```
당신은 프리미엄 의료 마케팅 전문 분석가입니다. 아래 **실제 수집된 데이터**를 기반으로 종합 마케팅 리포트를 생성해주세요.
⚠️ 중요: 아래 데이터에 없는 수치는 절대 추측하지 마세요. 데이터가 없으면 "데이터 없음"으로 표시하세요.
## 병원 기본 정보
- 병원명: {clinic.clinicName}
- 주소: {clinic.address}
- 전화: {clinic.phone}
- 시술: {services.join(", ")}
- 의료진: {doctors JSON}
- 슬로건: {clinic.slogan}
## 실제 채널 데이터 (수집 완료)
### Instagram @{handle}
- 팔로워: {followers}명, 게시물: {posts}개
- 비즈니스 계정: O/X
- Bio: {bio}
### YouTube {handle}
- 구독자: {subscribers}명, 영상: {totalVideos}개, 총 조회수: {totalViews}
- 인기 영상 TOP 5: [실제 제목+조회수]
### 강남언니 {name}
- 평점: {rating}/10, 리뷰: {totalReviews}건
- 등록 의사: [실제 이름+전문분야]
### Google Maps {name}
- 평점: {rating}/5, 리뷰: {reviewCount}건
### 네이버 블로그: 검색결과 {totalResults}건
### 네이버 플레이스: {name} ({category})
## 시장 분석 데이터
{market analysis JSON}
## 웹사이트 브랜딩
{branding JSON}
## 리포트 형식 (JSON 구조)
{
"clinicInfo": { ... },
"executiveSummary": "경영진 요약 (3-5문장)",
"overallScore": 0-100,
"channelAnalysis": {
"naverBlog": { score, status, posts, recommendation, diagnosis[] },
"instagram": { score, status, followers, posts, recommendation, diagnosis[] },
"youtube": { score, status, subscribers, recommendation, diagnosis[] },
"naverPlace": { score, rating, reviews, recommendation },
"gangnamUnni": { score, rating, ratingScale:10, reviews, status, recommendation },
"website": { score, issues[], recommendation, trackingPixels[], snsLinksOnSite, mainCTA }
},
"brandIdentity": [{ area, asIs, toBe }],
"kpiTargets": [{ metric, current, target3Month, target12Month }],
"recommendations": [{ priority, category, title, description, expectedImpact }],
"competitors": [],
"keywords": { primary: [], longTail: [] },
"targetAudience": {},
"marketTrends": [],
"newChannelProposals": [{ channel, priority, rationale }]
}
```
**핵심**: `channelSummary``buildChannelSummary()` 함수가 `channel_data` DB 컬럼에서 실제 수집된 데이터를 요약 텍스트로 변환. AI는 이 텍스트에 포함된 수치만 사용.
---
## 이미지 생성 (별도)
### Gemini — 마케팅 이미지 생성
**File**: `src/services/geminiImageGen.ts`
**API**: Google Gemini `gemini-2.5-flash-image`
**Prompt** (template):
```
Generate a premium medical marketing image for a plastic surgery clinic.
Theme: {pillarContext} // safety | expertise | results | care
Style: {channelHint} // youtube | instagram | naver_blog | tiktok | facebook
Color palette: soft purple (#7B2D8E), gold (#E8B931), warm white (#FAF8F5).
Premium, luxurious, trustworthy aesthetic.
No text or logos in the image.
Photorealistic, high quality, professional medical marketing.
```
**Pillar Context**:
- safety: "hospital safety systems, clean surgical rooms, CCTV monitoring"
- expertise: "medical expertise, advanced surgical equipment, certifications"
- results: "natural beautiful results, before and after transformation"
- care: "patient-centered care, warm consultation, personalized treatment"
---
## 프롬프트 엔지니어링 교훈
### 1. Perplexity sonar — 프롬프트 길이 vs 성능
| 프롬프트 길이 | 결과 |
|-------------|------|
| 시스템 1줄 + 유저 3줄 | ✅ Instagram, YouTube 등 잘 찾음 |
| 시스템 50줄 + 유저 30줄 | ❌ 전부 null/빈 배열 |
| 시스템 5줄 + 유저 10줄 (분리 3회) | ❌ 각각 빈 결과 |
### 2. 검색 키워드 패턴
| 패턴 | 결과 |
|------|------|
| `"{병원명}" 성형외과 공식 인스타그램` | ❌ null (너무 제한적) |
| `{병원명} 병원의 인스타그램...검색해서 찾아줘` | ✅ 핸들 발견 |
| `{병원명} ({영문명}) 병원의 인스타그램...` | ✅✅ 국제 계정도 발견 |
### 3. 모델 선택
| 모델 | 용도 | 온도 |
|------|------|------|
| sonar | 채널 검색, 강남언니 검색 | 0.1 |
| sonar | 시장 분석, 리포트 생성 | 0.3 |
| sonar-pro | ❌ 테스트 결과 오히려 성능 저하 | - |
### 4. JSON 응답 안정성
- 항상 시스템에 "Respond ONLY with valid JSON" 포함
- 유저 메시지 끝에 예시 JSON 구조를 포함하면 포맷 준수율 ↑
- `text.match(/\{[\s\S]*\}/)` 로 JSON 추출 (설명 텍스트 제거)
- `text.match(/```(?:json)?\n?([\s\S]*?)```/)` 로 코드 블록 내 JSON 추출
### 5. Verify 전략
- Instagram HEAD 요청은 불안정 → unverified도 후보로 유지
- YouTube `channels?part=id` API가 가장 정확한 검증
- Apify instagram-profile-scraper가 HEAD 요청보다 신뢰성 높음
- `UC`로 시작하는 channel ID에 `@` 붙이면 검증 실패
---
## Summary
| Phase | API | 프롬프트 수 | 주 용도 |
|-------|-----|-----------|---------|
| discover-channels | Perplexity sonar | 2~3개 | 소셜 채널 검색 + 강남언니 |
| discover-channels | Firecrawl | 2개 | 웹사이트 스크래핑 + 브랜딩 |
| discover-channels | YouTube API | 0 (직접 호출) | 채널 검색 |
| discover-channels | Naver API | 0 (직접 호출) | 블로그/웹 검색 |
| discover-channels | Apify | 0 (직접 호출) | Instagram 프로필 검색 |
| collect-channel-data | Perplexity sonar | 4개 | 시장/경쟁/키워드/타겟 분석 |
| collect-channel-data | Firecrawl | 1개 | 강남언니 데이터 추출 |
| generate-report | Perplexity sonar | 1개 | 종합 리포트 생성 |
| 이미지 생성 | Gemini | 1개 | 마케팅 이미지 |
| **합계** | | **~12개** | |