330 lines
13 KiB
Python
330 lines
13 KiB
Python
import json
|
|
import re
|
|
|
|
from openai import AsyncOpenAI
|
|
|
|
from config import apikey_settings
|
|
|
|
# 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 to Incorporate (use language-appropriate trendy expressions):
|
|
- Korean: 인스타 감성, 사진같은 하루, 힐링, 여행, 감성 숙소
|
|
- English: Instagram vibes, picture-perfect day, healing, travel, getaway
|
|
- Chinese: 网红打卡, 治愈系, 旅行, 度假, 拍照圣地
|
|
- Japanese: インスタ映え, 写真のような一日, 癒し, 旅行, 絶景
|
|
- Thai: ที่พักสวย, ฮีลใจ, เที่ยว, ถ่ายรูป, วิวสวย
|
|
- Vietnamese: check-in đẹp, healing, du lịch, nghỉ dưỡng, view đẹp
|
|
|
|
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:
|
|
def __init__(
|
|
self,
|
|
customer_name: str,
|
|
region: str,
|
|
detail_region_info: str = "",
|
|
language: str = "Korean",
|
|
):
|
|
# 최신 모델: GPT-5, GPT-5 mini, GPT-5 nano, GPT-4.1, GPT-4.1 mini, GPT-4.1 nano
|
|
# 이전 세대: GPT-4o, GPT-4o mini, GPT-4 Turbo, GPT-3.5 Turbo
|
|
self.model = "gpt-4o"
|
|
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 generate(self, prompt: str | None = None) -> str:
|
|
"""GPT에게 프롬프트를 전달하여 결과를 반환"""
|
|
if prompt is None:
|
|
prompt = self.build_lyrics_prompt()
|
|
print("Generated Prompt: ", prompt)
|
|
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 summarize_marketing(self, text: str) -> str:
|
|
"""마케팅 텍스트를 항목으로 구분하여 500자로 요약 정리"""
|
|
prompt = f"""[ROLE]
|
|
마케팅 콘텐츠 요약 전문가
|
|
|
|
[INPUT]
|
|
{text}
|
|
|
|
[TASK]
|
|
위 텍스트를 분석하여 핵심 내용을 항목별로 구분하여 500자 이내로 요약해주세요.
|
|
|
|
[OUTPUT REQUIREMENTS]
|
|
- 항목별로 구분하여 정리 (예: 타겟 고객, 차별점, 지역 특성 등)
|
|
- 총 500자 이내로 요약
|
|
- 핵심 정보만 간결하게 포함
|
|
- 한국어로 작성
|
|
|
|
[OUTPUT FORMAT]
|
|
---
|
|
[항목별로 구분된 500자 이내 요약]
|
|
---
|
|
"""
|
|
completion = await self.client.chat.completions.create(
|
|
model=self.model, messages=[{"role": "user", "content": prompt}]
|
|
)
|
|
message = completion.choices[0].message.content
|
|
result = message or ""
|
|
|
|
# --- 구분자 제거
|
|
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}
|