o2o-castad-backend/app/utils/chatgpt_prompt.py

404 lines
15 KiB
Python

import json
import logging
import re
from openai import AsyncOpenAI
from config import apikey_settings
# 로거 설정
logger = logging.getLogger(__name__)
# fmt: off
LYRICS_PROMPT_TEMPLATE_ORI = """
1.Act as a content marketing expert with domain knowledges in [pension/staying services] in Korea, Goal: plan viral content creation that lead online reservations and promotion
2.Conduct an in-depth analysis of [업체명:{customer_name}] in [지역명:{region}] by examining their official website or informations, photos on never map and online presence. Create a comprehensive "[지역 상세: {detail_region_info}]_Brand & Marketing Intelligence Report in Korean, that includes:
**Core Analysis:**
- Target customer segments & personas
- Unique Selling Propositions (USPs) and competitive differentiators
- Comprehensive competitor landscape analysis (direct & indirect competitors)
- Market positioning assessment
**Content Strategy Framework:**
- Seasonal content calendar with trend integration
- Visual storytelling direction (shot-by-shot creative guidance)
- Brand tone & voice guidelines
- Content themes aligned with target audience behaviors
**SEO & AEO Optimization:**
- Recommended primary and long-tail keywords
- SEO-optimized taglines and meta descriptions
- Answer Engine Optimization (AEO) content suggestions
- Local search optimization strategies
**Actionable Recommendations:**
- Content distribution strategy across platforms
- KPI measurement framework
- Budget allocation recommendations by content type
콘텐츠 기획(Lyrics, Prompt for SUNO)
1. Based on the Brand & Marketing Intelligence Report for [업체명 + 지역명 / {customer_name} ({region})], create original lyrics and define music attributes (song mood, BPM, genres, and key musical motifs, Prompt for Suno.com) specifically tailored for viral content.
2. The lyrics should include, the name of [ Promotion Subject], [location], [main target],[Famous place, accessible in 10min], promotional words including but not limited to [인스타 감성], [사진같은 하루]
Deliver outputs optimized for three formats:1 minute. Ensure that each version aligns with the brand's core identity and is suitable for use in digital marketing and social media campaigns, in Korean
""".strip()
# fmt: on
LYRICS_PROMPT_TEMPLATE = """
[ROLE]
Content marketing expert and creative songwriter specializing in pension/accommodation services
[INPUT]
- Business Name: {customer_name}
- Region: {region}
- Region Details: {detail_region_info}
- Output Language: {language}
[INTERNAL ANALYSIS - DO NOT OUTPUT]
Analyze the following internally to inform lyrics creation:
- Target customer segments and personas
- Unique Selling Propositions (USPs)
- Regional characteristics and nearby attractions (within 10 min access)
- Seasonal appeal points
- Emotional triggers for the target audience
[LYRICS REQUIREMENTS]
1. Must Include Elements:
- Business name (TRANSLATED or TRANSLITERATED to {language})
- Region name (TRANSLATED or TRANSLITERATED to {language})
- Main target audience appeal
- Nearby famous places or regional characteristics
2. Keywords Selection:
<<CRITICAL: Use ONLY the keywords for {language}. DO NOT transliterate or use keywords from other languages.>>
Select keywords based on {language}:
- IF Korean: 인스타 감성, 사진같은 하루, 힐링, 여행, 감성 숙소
- IF English: Instagram vibes, picture-perfect day, healing, travel, getaway
- IF Chinese: 网红打卡, 治愈系, 旅行, 度假, 拍照圣地
- IF Japanese: インスタ映え, 写真のような一日, 癒し, 旅行, 絶景
- IF Thai: ที่พักสวย, ฮีลใจ, เที่ยว, ถ่ายรูป, วิวสวย
- IF Vietnamese: check-in đẹp, healing, du lịch, nghỉ dưỡng, view đẹp
<<FORBIDDEN: Never transliterate keywords from other languages (e.g., "왕홍다카", "인스타바에", "티팍수아이" are WRONG)>>
3. Structure:
- Length: For 1-minute video (approximately 8-12 lines)
- Flow: Verse structure suitable for music
- Rhythm: Natural speech rhythm in the specified language
4. Tone:
- Emotional and heartfelt
- Trendy and viral-friendly
- Relatable to target audience
[CRITICAL LANGUAGE REQUIREMENT - ABSOLUTE RULE]
ALL OUTPUT MUST BE 100% WRITTEN IN {language} - NO EXCEPTIONS
- ALL lyrics content: {language} ONLY
- ALL proper nouns (business names, region names, place names): MUST be translated or transliterated to {language}
- Korean input like "군산" must become "Gunsan" in English, "群山" in Chinese, "グンサン" in Japanese, etc.
- Korean input like "스테이 머뭄" must become "Stay Meoum" in English, "住留" in Chinese, "ステイモーム" in Japanese, etc.
- ZERO Korean characters (한글) allowed when output language is NOT Korean
- ZERO mixing of languages - the entire output must be monolingual in {language}
- This is a NON-NEGOTIABLE requirement
- Any output containing characters from other languages is considered a COMPLETE FAILURE
- Violation of this rule invalidates the entire response
[OUTPUT RULES - STRICTLY ENFORCED]
- Output lyrics ONLY
- Lyrics MUST be written ENTIRELY in {language} - NO EXCEPTIONS
- ALL names and places MUST be in {language} script/alphabet
- NO Korean (한글), Chinese (漢字), Japanese (仮名), Thai (ไทย), or Vietnamese (Tiếng Việt) characters unless that is the selected output language
- NO titles, descriptions, analysis, or explanations
- NO greetings or closing remarks
- NO additional commentary before or after lyrics
- NO line numbers or labels
- Follow the exact format below
[OUTPUT FORMAT - SUCCESS]
[Lyrics ENTIRELY in {language} here - no other language characters allowed]
[OUTPUT FORMAT - FAILURE]
If you cannot generate lyrics due to insufficient information, invalid input, or any other reason:
ERROR: [Brief reason for failure in English]
""".strip()
# fmt: on
MARKETING_ANALYSIS_PROMPT_TEMPLATE = """
[ROLE]
Content marketing expert specializing in pension/accommodation services in Korea
[INPUT]
- Business Name: {customer_name}
- Region: {region}
- Region Details: {detail_region_info}
[ANALYSIS REQUIREMENTS]
Provide comprehensive marketing analysis including:
1. Target Customer Segments
- Primary and secondary target personas
- Age groups, travel preferences, booking patterns
2. Unique Selling Propositions (USPs)
- Key differentiators based on location and region details
- Competitive advantages
3. Regional Characteristics
- Nearby attractions and famous places (within 10 min access)
- Local food, activities, and experiences
- Transportation accessibility
4. Seasonal Appeal Points
- Best seasons to visit
- Seasonal activities and events
- Peak/off-peak marketing opportunities
5. Marketing Keywords
- Recommended hashtags and search keywords
- Trending terms relevant to the property
[ADDITIONAL REQUIREMENTS]
1. Recommended Tags
- Generate 5 recommended hashtags/tags based on the business characteristics
- Tags should be trendy, searchable, and relevant to accommodation marketing
- Return as JSON with key "tags"
- **MUST be written in Korean (한국어)**
2. Facilities
- Based on the business name and region details, identify 5 likely facilities/amenities
- Consider typical facilities for accommodations in the given region
- Examples: 바베큐장, 수영장, 주차장, 와이파이, 주방, 테라스, 정원, etc.
- Return as JSON with key "facilities"
- **MUST be written in Korean (한국어)**
[CRITICAL LANGUAGE REQUIREMENT - ABSOLUTE RULE]
ALL OUTPUT MUST BE WRITTEN IN KOREAN (한국어)
- Analysis sections: Korean only
- Tags: Korean only
- Facilities: Korean only
- This is a NON-NEGOTIABLE requirement
- Any output in English or other languages is considered a FAILURE
- Violation of this rule invalidates the entire response
[OUTPUT RULES - STRICTLY ENFORCED]
- Output analysis ONLY
- ALL content MUST be written in Korean (한국어) - NO EXCEPTIONS
- NO greetings or closing remarks
- NO additional commentary before or after analysis
- Follow the exact format below
[OUTPUT FORMAT - SUCCESS]
---
## 타겟 고객 분석
[한국어로 작성된 타겟 고객 분석]
## 핵심 차별점 (USP)
[한국어로 작성된 USP 분석]
## 지역 특성
[한국어로 작성된 지역 특성 분석]
## 시즌별 매력 포인트
[한국어로 작성된 시즌별 분석]
## 마케팅 키워드
[한국어로 작성된 마케팅 키워드]
## JSON Data
```json
{{
"tags": ["태그1", "태그2", "태그3", "태그4", "태그5"],
"facilities": ["부대시설1", "부대시설2", "부대시설3", "부대시설4", "부대시설5"]
}}
```
---
[OUTPUT FORMAT - FAILURE]
If you cannot generate analysis due to insufficient information, invalid input, or any other reason:
---
ERROR: [Brief reason for failure in English]
---
""".strip()
# fmt: on
class ChatgptService:
"""ChatGPT API 서비스 클래스
GPT 5.0 모델을 사용하여 마케팅 가사 및 분석을 생성합니다.
"""
def __init__(
self,
customer_name: str,
region: str,
detail_region_info: str = "",
language: str = "Korean",
):
# 최신 모델: gpt-5-mini
self.model = "gpt-5-mini"
self.client = AsyncOpenAI(api_key=apikey_settings.CHATGPT_API_KEY)
self.customer_name = customer_name
self.region = region
self.detail_region_info = detail_region_info
self.language = language
def build_lyrics_prompt(self) -> str:
"""LYRICS_PROMPT_TEMPLATE에 고객 정보를 대입하여 완성된 프롬프트 반환"""
return LYRICS_PROMPT_TEMPLATE.format(
customer_name=self.customer_name,
region=self.region,
detail_region_info=self.detail_region_info,
language=self.language,
)
def build_market_analysis_prompt(self) -> str:
"""MARKETING_ANALYSIS_PROMPT_TEMPLATE에 고객 정보를 대입하여 완성된 프롬프트 반환"""
return MARKETING_ANALYSIS_PROMPT_TEMPLATE.format(
customer_name=self.customer_name,
region=self.region,
detail_region_info=self.detail_region_info,
)
async def _call_gpt_api(self, prompt: str) -> str:
"""GPT API를 직접 호출합니다 (내부 메서드).
Args:
prompt: GPT에 전달할 프롬프트
Returns:
GPT 응답 문자열
Raises:
APIError, APIConnectionError, RateLimitError: OpenAI API 오류
"""
completion = await self.client.chat.completions.create(
model=self.model, messages=[{"role": "user", "content": prompt}]
)
message = completion.choices[0].message.content
return message or ""
async def generate(
self,
prompt: str | None = None,
) -> str:
"""GPT에게 프롬프트를 전달하여 결과를 반환합니다.
Args:
prompt: GPT에 전달할 프롬프트 (None이면 기본 가사 프롬프트 사용)
Returns:
GPT 응답 문자열
Raises:
APIError, APIConnectionError, RateLimitError: OpenAI API 오류
"""
if prompt is None:
prompt = self.build_lyrics_prompt()
print(f"[ChatgptService] Generated Prompt (length: {len(prompt)})")
logger.info(f"[ChatgptService] Starting GPT request with model: {self.model}")
# GPT API 호출
response = await self._call_gpt_api(prompt)
print(f"[ChatgptService] SUCCESS - Response length: {len(response)}")
logger.info(f"[ChatgptService] SUCCESS - Response length: {len(response)}")
return response
async def summarize_marketing(self, text: str) -> str:
"""마케팅 텍스트를 항목으로 구분하여 500자로 요약 정리.
Args:
text: 요약할 마케팅 텍스트
Returns:
요약된 텍스트
Raises:
APIError, APIConnectionError, RateLimitError: OpenAI API 오류
"""
prompt = f"""[ROLE]
마케팅 콘텐츠 요약 전문가
[INPUT]
{text}
[TASK]
위 텍스트를 분석하여 핵심 내용을 항목별로 구분하여 500자 이내로 요약해주세요.
[OUTPUT REQUIREMENTS]
- 5개 항목으로 구분: 타겟 고객, 핵심 차별점, 지역 특성, 시즌별 포인트
- 각 항목은 줄바꿈으로 구분
- 총 500자 이내로 요약
- 내용의 누락이 있어서는 안된다
- 문장이 자연스러워야 한다
- 핵심 정보만 간결하게 포함
- 한국어로 작성
- 특수문자 사용 금지 (괄호, 슬래시, 하이픈, 물결표 등 제외)
- 쉼표와 마침표만 사용하여 자연스러운 문장으로 작성
[OUTPUT FORMAT - 반드시 아래 형식 준수]
타겟 고객
[대상 고객층을 자연스러운 문장으로 설명]
핵심 차별점
[숙소의 차별화 포인트를 자연스러운 문장으로 설명]
지역 특성
[주변 관광지와 지역 특색을 자연스러운 문장으로 설명]
시즌별 포인트
[계절별 매력 포인트를 자연스러운 문장으로 설명]
"""
# 추천 키워드
# [마케팅에 활용할 키워드를 쉼표로 구분하여 나열]
result = await self.generate(prompt=prompt)
# --- 구분자 제거
if result.startswith("---"):
result = result[3:].strip()
if result.endswith("---"):
result = result[:-3].strip()
return result
async def parse_marketing_analysis(self, raw_response: str) -> dict:
"""ChatGPT 마케팅 분석 응답을 파싱하고 요약하여 딕셔너리로 반환
Returns:
dict: {"report": str, "tags": list[str], "facilities": list[str]}
"""
tags: list[str] = []
facilities: list[str] = []
report = raw_response
# JSON 블록 추출 시도
json_match = re.search(r"```json\s*(\{.*?\})\s*```", raw_response, re.DOTALL)
if json_match:
try:
json_data = json.loads(json_match.group(1))
tags = json_data.get("tags", [])
facilities = json_data.get("facilities", [])
# JSON 블록을 제외한 리포트 부분 추출
report = raw_response[: json_match.start()].strip()
# --- 구분자 제거
if report.startswith("---"):
report = report[3:].strip()
if report.endswith("---"):
report = report[:-3].strip()
except json.JSONDecodeError:
pass
# 리포트 내용을 500자로 요약
if report:
report = await self.summarize_marketing(report)
return {"report": report, "tags": tags, "facilities": facilities}