4g3gf-2 / info_blog.py
ssboost's picture
Create info_blog.py
86582c0 verified
import os
import random
import re
import logging
import tempfile
from datetime import datetime
from zoneinfo import ZoneInfo
import html
from PIL import Image
from urllib.request import urlopen
import markdown2
# ๋กœ๊น… ์„ค์ • (INFO ๋ ˆ๋ฒจ)
logging.basicConfig(level=logging.INFO)
# -------------------------------
# ์ƒ์ˆ˜ ์ •์˜ (ํ–ฅํ›„ ์กฐ์ • ๋ฐ ์œ ์ง€๋ณด์ˆ˜ ์šฉ์ดํ•˜๋„๋ก)
# -------------------------------
TARGET_CHAR_LENGTH = 4000 # ์ •๋ณด์„ฑ ๋ธ”๋กœ๊ทธ ์ตœ์†Œ ๊ธ€์ž์ˆ˜
MIN_SECTION_LENGTH = 600 # ๊ฐ ์†Œ์ œ๋ชฉ ์•„๋ž˜ ์ตœ์†Œ ๊ธ€์ž์ˆ˜
MAX_TOKENS = 15000 # Gemini API ์ตœ๋Œ€ ํ† ํฐ ์ˆ˜
TEMPERATURE = 0.75 # Gemini API ์˜จ๋„ ๊ฐ’
TOP_P = 0.95 # Gemini API top_p ๊ฐ’
# Gemini API ์„ค์ •
gemini_api_key = os.getenv("GEMINI_API_KEY")
# --- Google Gemini SDK ์ดˆ๊ธฐํ™” ---
from google import genai
from google.genai import types
client = genai.Client(api_key=gemini_api_key)
# -------------------------------
# ๊ธฐ๋ณธ ๋„์šฐ๋ฏธ ํ•จ์ˆ˜๋“ค
# -------------------------------
def remove_unwanted_phrases(text):
"""๋ถˆํ•„์š”ํ•œ ํ‘œํ˜„ ์ œ๊ฑฐ ํ•จ์ˆ˜"""
unwanted_phrases = [
'์—ฌ๋Ÿฌ๋ถ„', '์ตœ๊ทผ', '๋งˆ์ง€๋ง‰์œผ๋กœ', '๊ฒฐ๋ก ์ ์œผ๋กœ', '๊ฒฐ๊ตญ',
'์ข…ํ•ฉ์ ์œผ๋กœ', '๋”ฐ๋ผ์„œ', '๋งˆ๋ฌด๋ฆฌ', '๋์œผ๋กœ', '์š”์•ฝ',
'ํ•œ ์ค„ ์š”์•ฝ', '์ •๋ฆฌํ•˜์ž๋ฉด', '์ด์ •๋ฆฌ', '๊ธ€์„ ๋งˆ์น˜๋ฉฐ',
'์ด์ƒ์œผ๋กœ', '์ถ”์ฒœ๋“œ๋ฆฝ๋‹ˆ๋‹ค', '์ฐธ๊ณ ํ•˜์„ธ์š”', '๋„์›€์ด ๋˜์…จ๊ธธ',
'์ข‹์€ ํ•˜๋ฃจ ๋˜์„ธ์š”', '๋‹ค์Œ ๊ธ€์—์„œ', '๋„์›€์ด ๋˜์—ˆ๊ธธ',
'์ฆ๊ฑฐ์šด ํ•˜๋ฃจ ๋˜์„ธ์š”', '๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค'
]
# ๋ฌธ๋‹จ๋ณ„๋กœ ๋‚˜๋ˆ„์–ด ์ฒ˜๋ฆฌ
lines = text.split('\n')
result_lines = []
for line in lines:
if "๋‹ค์Œ ์„น์…˜์—์„œ๋Š”" in line:
parts = line.split("๋‹ค์Œ ์„น์…˜์—์„œ๋Š”")
if parts[0].strip():
result_lines.append(parts[0].strip())
else:
# ๋ถˆํ•„์š”ํ•œ ํ‘œํ˜„ ์ œ๊ฑฐ (๊ตฌ๋‘์  ํฌํ•จ)
for phrase in unwanted_phrases:
# ๋ถˆํ•„์š”ํ•œ ํ‘œํ˜„ ์•ž๋’ค์˜ ๊ตฌ๋‘์ ๊ณผ ๊ณต๋ฐฑ๊นŒ์ง€ ํฌํ•จํ•˜์—ฌ ์ œ๊ฑฐ
pattern = rf'(\b{re.escape(phrase)}\b[\s,.!?]*)|([,.!?]*\b{re.escape(phrase)}\b)'
line = re.sub(pattern, '', line)
# ๋ฌธ์žฅ ๋‚ด ์ž”์—ฌ ๊ณต๋ฐฑ ๋ฐ ๊ตฌ๋‘์  ์ •๋ฆฌ
line = re.sub(r'\s{2,}', ' ', line) # ์—ฐ์† ๊ณต๋ฐฑ ์ œ๊ฑฐ
line = line.strip() # ์•ž๋’ค ๊ณต๋ฐฑ ์ œ๊ฑฐ
result_lines.append(line)
return '\n'.join(result_lines)
def convert_to_html(text):
"""๋งˆํฌ๋‹ค์šด ํ˜•์‹์„ HTML๋กœ ๋ณ€ํ™˜"""
text = re.sub(r'^\s*[-*]\s+', '', text, flags=re.MULTILINE)
text = re.sub(r'^\s*\d+\.\s+', '', text, flags=re.MULTILINE)
text = re.sub(r'^\s*#{1,6}\s+', '', text, flags=re.MULTILINE)
return markdown2.markdown(text)
def extract_text_from_html(html_content):
"""HTML์—์„œ ์ˆœ์ˆ˜ ํ…์ŠคํŠธ๋งŒ ์ถ”์ถœํ•˜๋Š” ํ•จ์ˆ˜"""
if not html_content:
return ""
# HTML ํƒœ๊ทธ ์ œ๊ฑฐ
text = re.sub(r'<[^>]+>', '', html_content)
# HTML ์—”ํ‹ฐํ‹ฐ ๋””์ฝ”๋”ฉ
text = html.unescape(text)
# ์—ฐ์†๋œ ๊ณต๋ฐฑ ์ œ๊ฑฐ
text = re.sub(r'\s+', ' ', text)
return text.strip()
def format_blog_post(blog_post, query="", with_title=False):
"""๋ธ”๋กœ๊ทธ ํฌ์ŠคํŠธ ํฌ๋งทํŒ… ํ•จ์ˆ˜ - ์†Œ์ œ๋ชฉ ๊ฐ•ํ™” ๋ฒ„์ „"""
blog_post = re.sub(r'^#+\s+', '', blog_post, flags=re.MULTILINE)
blog_post = re.sub(r'^\d+\.\s+', '', blog_post, flags=re.MULTILINE)
blog_post = re.sub(r'^[\*\-]\s+', '', blog_post, flags=re.MULTILINE)
# ์ฒซ ์ค„(์›๋ณธ ์ œ๋ชฉ)๊ณผ ๋น„์Šทํ•œ ํŒจํ„ด์ด ์žˆ๋‹ค๋ฉด ์ œ๊ฑฐ
lines = blog_post.split('\n')
if lines and len(lines) > 0:
first_line = lines[0].strip()
# ์ฒซ ์ค„์ด ์ œ๋ชฉ์ธ ๊ฒฝ์šฐ, ๋น„์Šทํ•œ ๋‚ด์šฉ์˜ ๋ผ์ธ์„ ๋ชจ๋‘ ์ œ๊ฑฐ
if first_line and len(first_line) > 5:
# ์ฒซ ์ค„๊ณผ ์œ ์‚ฌํ•œ ๋‚ด์šฉ์„ ๊ฐ€์ง„ ๋ผ์ธ ์ฐพ์•„ ์ œ๊ฑฐ
filtered_lines = []
for line in lines:
# ์ฒซ ์ค„๊ณผ ์œ ์‚ฌํ•˜๋ฉด ์ œ๊ฑฐ
if line.strip() and (first_line in line or line in first_line):
continue
filtered_lines.append(line)
lines = filtered_lines
# ๋„์ž…๋ถ€, ๊ฒฐ๋ก  ์†Œ์ œ๋ชฉ ํŒจํ„ด
intro_pattern = r'(?i)๋„์ž…๋ถ€\s*[:]?\s*(.*?)$'
conclusion_pattern = r'(?i)๊ฒฐ๋ก \s*[:]?\s*(.*?)$'
# ๋„์ž…๋ถ€, ๊ฒฐ๋ก  ์†Œ์ œ๋ชฉ ์ œ๊ฑฐ
filtered_lines = []
for line in lines:
if re.match(intro_pattern, line) or re.match(conclusion_pattern, line):
continue
filtered_lines.append(line)
lines = filtered_lines
# ๋ณธ๋ก  ์†Œ์ œ๋ชฉ ํŒจํ„ด ๊ฐ•ํ™”
section_patterns = [
r'^๋ณธ๋ก \d+\s*[:]?\s*(.*?)$', # ๋ณธ๋ก 1: ๋‚ด์šฉ ํŒจํ„ด
r'^.{5,50}์˜ [๊ฐ€-ํžฃ\s]+$', # ~์˜ ~ ํŒจํ„ด
r'^[๊ฐ€-ํžฃ\s]{5,30}(์ด๋ž€|์ด๋ž€\?|์ด๋ž€\s๋ฌด์—‡์ธ๊ฐ€|์ด๋ž€\s๋ฌด์—‡์ผ๊นŒ)[\?\s]*$', # ~์ด๋ž€? ํŒจํ„ด
r'^[๊ฐ€-ํžฃ\s]{5,50}\s[-โ€“]\s.{5,30}$', # ๊ฐ•์กฐ ํ‘œํ˜„ ํŒจํ„ด (์˜ˆ: ํšจ๊ณผ์ ์ธ ๋ฐฉ๋ฒ• - ์‹ค์ฒœํ•˜๊ธฐ)
r'^[๊ฐ€-ํžฃA-Za-z\s]{10,50}[\.!\?]$', # ๊ธด ๋ฌธ์žฅ์œผ๋กœ ๋œ ์†Œ์ œ๋ชฉ ํŒจํ„ด
]
formatted_lines = []
in_paragraph = False
# ๋ณธ๋ก  ์„น์…˜ ๋ฒˆํ˜ธ ์ถ”์ 
section_number = 1
for i, line in enumerate(lines):
line = line.strip()
if not line:
if in_paragraph:
formatted_lines.append("</p>")
in_paragraph = False
formatted_lines.append("<br>")
continue
# ๋‹ค์Œ ์ค„๊ณผ ์ด์ „ ์ค„์ด ๋น„์–ด์žˆ๋Š”์ง€ ํ™•์ธ
prev_empty = i == 0 or not lines[i-1].strip()
next_empty = i == len(lines) - 1 or not lines[i+1].strip()
# ์†Œ์ œ๋ชฉ์ธ์ง€ ์ฒดํฌ
is_subtitle = False
clean_subtitle = line
# ํŒจํ„ด ๋งค์นญ์œผ๋กœ ์†Œ์ œ๋ชฉ ํ™•์ธ
for pattern in section_patterns:
if re.match(pattern, line):
is_subtitle = True
# ๋ณธ๋ก X: ํŒจํ„ด์ธ ๊ฒฝ์šฐ ์ •๋ฆฌ
if "๋ณธ๋ก " in line:
clean_subtitle = re.sub(r'^๋ณธ๋ก \d+\s*[:]?\s*', '', line)
break
# ํŒจํ„ด์— ๋งค์นญ๋˜์ง€ ์•Š์•˜์ง€๋งŒ ๋‹ค์Œ ๊ทœ์น™์œผ๋กœ ์†Œ์ œ๋ชฉ์œผ๋กœ ํŒ๋‹จํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒฝ์šฐ
if not is_subtitle:
# ์•ž๋’ค ์ค„์ด ๋น„์–ด์žˆ๊ณ , ๊ธธ์ด๊ฐ€ ์งง์€(5-50์ž) ๋ฌธ์žฅ์€ ์†Œ์ œ๋ชฉ์œผ๋กœ ์ฒ˜๋ฆฌ
if prev_empty and next_empty and 5 <= len(line) <= 50:
is_subtitle = True
# ์ด์ „์— ์žˆ๋˜ ์†Œ์ œ๋ชฉ๋“ค๊ณผ ๋น„์Šทํ•œ ๊ธธ์ด๋ฅผ ๊ฐ€์ง„ ๊ฒฝ์šฐ๋„ ์†Œ์ œ๋ชฉ์œผ๋กœ ๊ฐ„์ฃผ
elif section_number > 1 and prev_empty and 5 <= len(line) <= 50:
is_subtitle = True
if is_subtitle and clean_subtitle.strip():
if in_paragraph:
formatted_lines.append("</p>")
in_paragraph = False
# ์†Œ์ œ๋ชฉ์ด ์—†๊ฑฐ๋‚˜ ๋„ˆ๋ฌด ์งง์€ ๊ฒฝ์šฐ ๊ธฐ๋ณธ ์†Œ์ œ๋ชฉ ์‚ฌ์šฉ
if not clean_subtitle.strip() or len(clean_subtitle.strip()) < 2:
clean_subtitle = f"์ฃผ์š” ํฌ์ธํŠธ {section_number}"
# ์†Œ์ œ๋ชฉ ํ˜•์‹ ๊ฐ•ํ™” - ํ•ญ์ƒ ๋ณผ๋“œ์ฒ˜๋ฆฌ์™€ ์Šคํƒ€์ผ๋ง ์ ์šฉ
formatted_lines.append(
f'<h2 style="font-size: 1.4em; margin-top: 30px; margin-bottom: 15px; font-weight: bold; color: #333; border-bottom: 1px solid #eee; padding-bottom: 8px;">{html.escape(clean_subtitle)}</h2>'
)
section_number += 1
else:
# ์ผ๋ฐ˜ ํ…์ŠคํŠธ ์ฒ˜๋ฆฌ
if not in_paragraph:
formatted_lines.append("<p>")
in_paragraph = True
content = html.escape(line)
bold_content = re.sub(r'\*\*(.*?)\*\*', r'<strong>\1</strong>', content)
formatted_lines.append(bold_content)
if in_paragraph:
formatted_lines.append("</p>")
return '\n'.join(formatted_lines)
# -------------------------------
# ์Šคํƒ€์ผ ๋ฐ ํ”„๋กฌํ”„ํŠธ ๊ฐ€์ด๋“œ ํ•จ์ˆ˜
# -------------------------------
def get_style_prompt(style="์นœ๊ทผํ•œ"):
"""๋ธ”๋กœ๊ทธ ๊ธ€์˜ ์Šคํƒ€์ผ ํ”„๋กฌํ”„ํŠธ๋ฅผ ๋ฐ˜ํ™˜"""
prompts = {
"์นœ๊ทผํ•œ": """
[์นœ๊ทผํ•œ ์ •๋ณด์„ฑ ๋ธ”๋กœ๊ทธ ์Šคํƒ€์ผ ๊ฐ€์ด๋“œ]
1. ํ†ค๊ณผ ์–ด์กฐ
- ๋Œ€ํ™”ํ•˜๋“ฏ ํŽธ์•ˆํ•˜๊ณ  ์นœ๊ทผํ•œ ๋งํˆฌ ์‚ฌ์šฉ
- ์ฃผ์ œ์— ๋Œ€ํ•œ ๊ด€์‹ฌ๊ณผ ํ˜ธ๊ธฐ์‹ฌ์„ ๋‹ด์€ ํ‘œํ˜„ ์‚ฌ์šฉ
2. ๋ฌธ์žฅ ๋ฐ ์–ดํˆฌ
- ๋ฐ˜๋“œ์‹œ 'ํ•ด์š”์ฒด'๋กœ ์ž‘์„ฑ, ์ ˆ๋Œ€ '์Šต๋‹ˆ๋‹ค'์ฒด๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ๋ง ๊ฒƒ
- '~์š”'๋กœ ๋๋‚˜๋„๋ก ์ž‘์„ฑ, '~๋‹ค'๋กœ ๋๋‚˜์ง€ ์•Š๊ฒŒ ํ•˜๋ผ
- ๊ตฌ์–ด์ฒด ํ‘œํ˜„ ์‚ฌ์šฉ (์˜ˆ: "~ํ–ˆ์–ด์š”", "~์ธ ๊ฒƒ ๊ฐ™์•„์š”")
- ์ ์ ˆํ•œ ๊ฐ์ • ํ‘œํ˜„๊ณผ ๊ณต๊ฐ๋Œ€ ํ˜•์„ฑ
3. ์šฉ์–ด ๋ฐ ์„ค๋ช… ๋ฐฉ์‹
- ์ „๋ฌธ ์šฉ์–ด๋Š” ์‰ฌ์šด ๋‹จ์–ด๋กœ ํ’€์–ด์„œ ์„ค๋ช…
- ๋น„์œ ๋‚˜ ์€์œ ๋ฅผ ํ™œ์šฉํ•˜์—ฌ ๋ณต์žกํ•œ ๊ฐœ๋… ์„ค๋ช…
- ์ˆ˜์‚ฌ์˜๋ฌธ๋ฌธ ํ™œ์šฉํ•˜์—ฌ ๋…์ž์™€ ์†Œํ†ตํ•˜๋Š” ๋А๋‚Œ ์ฃผ๊ธฐ (์˜ˆ: "์–ด๋–ป๊ฒŒ ์ƒ๊ฐํ•˜์„ธ์š”?", "์ด๋Ÿฐ ๊ฒฝํ—˜ ์žˆ์œผ์‹ ๊ฐ€์š”?")
- ๊ตฌ์ฒด์  ์‚ฌ๋ก€์™€ ์˜ˆ์‹œ๋ฅผ ํ†ตํ•œ ๊ฐœ๋… ์„ค๋ช…
4. ์ •๋ณด ์ „๋‹ฌ ๋ฐฉ์‹
- ๊ฐœ์ธ์ ์ธ ๊ด€์ ์— ๋…น์—ฌ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ์ •๋ณด ์ „๋‹ฌ
- ๋ณต์žกํ•œ ๊ฐœ๋…์„ ๋‹จ๊ณ„์ ์œผ๋กœ ์„ค๋ช…
- ๋…์ž๊ฐ€ ์‹ค์ œ๋กœ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์‹ค์šฉ์  ์ •๋ณด ์ œ๊ณต
5. ๋…์ž์™€์˜ ์ƒํ˜ธ์ž‘์šฉ
- ๋…์ž์˜ ์˜๊ฒฌ์„ ๋ฌผ์–ด๋ณด๋Š” ์งˆ๋ฌธ ํฌํ•จ
- ์‹ค์ƒํ™œ์— ์ ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ํŒ์ด๋‚˜ ์กฐ์–ธ ์ œ๊ณต
์ฃผ์˜์‚ฌํ•ญ: ์ž์—ฐ์Šค๋Ÿฌ์šด ๋Œ€ํ™”์ฒด๋ฅผ ์œ ์ง€ํ•˜๋ฉด์„œ ์ •๋ณด์˜ ์งˆ๊ณผ ๋‚ด์šฉ์˜ ๊นŠ์ด๋ฅผ ์žƒ์ง€ ์•Š๋„๋ก ํ•œ๋‹ค
""",
"์ผ๋ฐ˜": """
[์ผ๋ฐ˜์ ์ธ ์ •๋ณด์„ฑ ๋ธ”๋กœ๊ทธ ์Šคํƒ€์ผ ๊ฐ€์ด๋“œ]
1. ํ†ค๊ณผ ์–ด์กฐ
- ์ค‘๋ฆฝ์ ์ด๊ณ  ๊ฐ๊ด€์ ์ธ ํ†ค ์œ ์ง€
- ์ ์ ˆํ•œ ์กด๋Œ“๋ง ์‚ฌ์šฉ (์˜ˆ: "~ํ•ฉ๋‹ˆ๋‹ค", "~์ž…๋‹ˆ๋‹ค")
- ์ •๋ณด ์ „๋‹ฌ ์ค‘์‹ฌ์˜ ๋ช…ํ™•ํ•œ ์–ดํˆฌ
2. ๋‚ด์šฉ ๊ตฌ์กฐ ๋ฐ ์ „๊ฐœ
- ๋ช…ํ™•ํ•œ ์ฃผ์ œ ์†Œ๊ฐœ๋กœ ์‹œ์ž‘
- ๋…ผ๋ฆฌ์ ์ธ ์ˆœ์„œ๋กœ ์ •๋ณด ์ „๊ฐœ (๋ฐฐ๊ฒฝ โ†’ ์ฃผ์š” ๊ฐœ๋… โ†’ ๋ถ„์„ โ†’ ์ ์šฉ ๋“ฑ)
- ํ•ต์‹ฌ ํฌ์ธํŠธ๋ฅผ ๊ฐ•์กฐํ•˜๋Š” ์†Œ์ œ๋ชฉ ํ™œ์šฉ
- ์ ์ ˆํ•œ ๊ธธ์ด์˜ ๋‹จ๋ฝ์œผ๋กœ ๊ตฌ์„ฑ
3. ์šฉ์–ด ๋ฐ ์„ค๋ช… ๋ฐฉ์‹
- ์ผ๋ฐ˜์ ์œผ๋กœ ์ดํ•ดํ•˜๊ธฐ ์‰ฌ์šด ์šฉ์–ด ์„ ํƒ
- ํ•„์š”์‹œ ์ „๋ฌธ ์šฉ์–ด์— ๊ฐ„๋‹จํ•œ ์„ค๋ช… ์ถ”๊ฐ€
- ๊ฐ๊ด€์ ์ธ ์ •๋ณด ์ œ๊ณต์— ์ค‘์ 
- ๊ท ํ˜• ์žกํžŒ ์‹œ๊ฐ์—์„œ ๋‹ค์–‘ํ•œ ๊ด€์  ์ œ์‹œ
4. ์ •๋ณด ์ „๋‹ฌ ๋ฐฉ์‹
- ์ฃผ์ œ์˜ ๊ธฐ๋ณธ ๊ฐœ๋…๊ณผ ์›๋ฆฌ ๋ช…ํ™•ํ•˜๊ฒŒ ์ œ๊ณต
- ๊ตฌ์ฒด์ ์ธ ์˜ˆ์‹œ์™€ ์‚ฌ๋ก€ ํฌํ•จ
- ์ตœ์‹  ์—ฐ๊ตฌ๋‚˜ ๋™ํ–ฅ ์ฐธ๊ณ 
5. ๋…์ž ์ƒํ˜ธ์ž‘์šฉ
- ์ ์ ˆํžˆ ๋…์ž์˜ ์ƒ๊ฐ์„ ๋ฌป๋Š” ์งˆ๋ฌธ ํฌํ•จ
- ์ถ”๊ฐ€ ์ •๋ณด๋ฅผ ์ฐพ์„ ์ˆ˜ ์žˆ๋Š” ํ‚ค์›Œ๋“œ ์ œ์‹œ
- ์‹ค์šฉ์ ์ธ ์ ์šฉ ๋ฐฉ์•ˆ ์ œ๊ณต
์ฃผ์˜์‚ฌํ•ญ: ๊ฐ๊ด€์  ์ •๋ณด ์ œ๊ณต์„ ์ค‘์‹ฌ์œผ๋กœ ํ•˜๋˜, ๋…์ž์˜ ์ดํ•ด์™€ ํ™œ์šฉ์„ ๋„์šธ ์ˆ˜ ์žˆ๋Š” ๋งฅ๋ฝ๊ณผ ์„ค๋ช…์„ ์ถฉ๋ถ„ํžˆ ์ œ๊ณตํ•œ๋‹ค
""",
"์ „๋ฌธ์ ์ธ": """
[์ „๋ฌธ์ ์ธ ์ •๋ณด์„ฑ ๋ธ”๋กœ๊ทธ ์Šคํƒ€์ผ ๊ฐ€์ด๋“œ]
1. ํ†ค๊ณผ ๊ตฌ์กฐ
- ๊ณต์‹์ ์ด๊ณ  ์ „๋ฌธ์ ์ธ ํ†ค ์‚ฌ์šฉ
- ๊ฐ๊ด€์ ์ด๊ณ  ๋ถ„์„์ ์ธ ์ ‘๊ทผ ์œ ์ง€
- ๋ช…ํ™•ํ•œ ์„œ๋ก (๊ฐœ์š”), ๋ณธ๋ก (์ƒ์„ธ ๋ถ„์„), ๊ฒฐ๋ก (์ข…ํ•ฉ ํ‰๊ฐ€) ๊ตฌ์กฐ
- ์ฒด๊ณ„์ ์ธ ์ •๋ณด ์ „๊ฐœ
- ์„ธ๋ถ€ ์„น์…˜์„ ์œ„ํ•œ ๋ช…ํ™•ํ•œ ์†Œ์ œ๋ชฉ ์‚ฌ์šฉ
2. ๋‚ด์šฉ ๊ตฌ์„ฑ ๋ฐ ์ „๊ฐœ
- ์ฃผ์ œ์˜ ์—ญ์‚ฌ์  ๋ฐฐ๊ฒฝ, ์ด๋ก ์  ๊ธฐ๋ฐ˜, ํ˜„์žฌ ๋™ํ–ฅ ๋“ฑ ์‹ฌ์ธต์  ์ •๋ณด ํฌํ•จ
- ๋…ผ๋ฆฌ์  ์—ฐ๊ฒฐ์„ ์œ„ํ•œ ์ „ํ™˜์–ด ํ™œ์šฉ
- ์ „๋ฌธ ์šฉ์–ด ์ ์ ˆํžˆ ํ™œ์šฉ (ํ•„์š”์‹œ ๊ฐ„๋žตํ•œ ์„ค๋ช… ์ œ๊ณต)
- ์‹ฌ์ธต์ ์ธ ๋ถ„์„๊ณผ ๋น„ํŒ์  ํ‰๊ฐ€ ์ œ๊ณต
- ๋‹ค์–‘ํ•œ ๊ด€์ ๊ณผ ์ด๋ก ์  ํ”„๋ ˆ์ž„์›Œํฌ ์ œ์‹œ
3. ๋ฐ์ดํ„ฐ ๋ฐ ๊ทผ๊ฑฐ ํ™œ์šฉ
- ํ†ต๊ณ„, ์—ฐ๊ตฌ ๊ฒฐ๊ณผ, ์‚ฌ๋ก€ ์—ฐ๊ตฌ ๋“ฑ ๊ฐ๊ด€์  ๋ฐ์ดํ„ฐ ํ™œ์šฉ
- ์ฃผ์ œ ๋ถ„์„์„ ์œ„ํ•œ ์ฒด๊ณ„์ ์ธ ํ”„๋ ˆ์ž„์›Œํฌ ์ œ์‹œ
- ์ˆ˜์น˜ ๋ฐ์ดํ„ฐ๋Š” ๋ช…ํ™•ํžˆ ์„ค๋ช… (์ถ”์„ธ, ์ƒ๊ด€๊ด€๊ณ„, ์ธ๊ณผ๊ด€๊ณ„ ๋“ฑ)
- ํ•™์ˆ ์  ๊ทผ๊ฑฐ์™€ ํ˜„์‹ค ์ ์šฉ์˜ ๊ท ํ˜•
4. ์ „๋ฌธ์  ์ •๋ณด ์ œ๊ณต
- ์ตœ์‹  ์—ฐ๊ตฌ ๋™ํ–ฅ ๋ฐ ๋ฐœ์ „ ๋ฐฉํ–ฅ ๋ถ„์„
- ์ด๋ก ๊ณผ ์‹ค์ œ ์ ์šฉ ์‚ฌ์ด์˜ ๊ฐ„๊ทน ๋ถ„์„
- ์ฃผ์ œ ๊ด€๋ จ ์Ÿ์ ๊ณผ ๋…ผ์Ÿ์  ์†Œ๊ฐœ
- ์ฒด๊ณ„์ ์ธ ๋ฌธ์ œ ํ•ด๊ฒฐ ์ ‘๊ทผ๋ฒ• ์ œ์‹œ
์ฃผ์˜์‚ฌํ•ญ: ์ „๋ฌธ์„ฑ๊ณผ ๊นŠ์ด๋ฅผ ์œ ์ง€ํ•˜๋ฉด์„œ๋„ ์ดํ•ด ๊ฐ€๋Šฅํ•œ ์šฉ์–ด์™€ ์„ค๋ช…์„ ํ†ตํ•ด ์ ‘๊ทผ์„ฑ์„ ๋†’์ธ๋‹ค
"""
}
return prompts.get(style, prompts["์นœ๊ทผํ•œ"])
def get_category_outline_prompt(category="์ผ๋ฐ˜"):
"""์นดํ…Œ๊ณ ๋ฆฌ๋ณ„ ์•„์›ƒ๋ผ์ธ ์ƒ์„ฑ ํ”„๋กฌํ”„ํŠธ"""
prompts = {
"์ผ๋ฐ˜": """
[์ผ๋ฐ˜ ์ฃผ์ œ ์†Œ์ฃผ์ œ(Outline) ์ƒ์„ฑ ๊ทœ์น™]
[์‹œ์Šคํ…œ ์—ญํ• ]
๋‹น์‹ ์€ ์ˆ˜๋…„๊ฐ„์˜ ๊ฒฝํ—˜์„ ๊ฐ€์ง„ ์ „๋ฌธ ์ •๋ณด์„ฑ ๋ธ”๋กœ๊ทธ ์ž‘๊ฐ€์ž…๋‹ˆ๋‹ค. ๋‹ค์–‘ํ•œ ์ฃผ์ œ์— ๋Œ€ํ•œ ๊นŠ์ด ์žˆ๋Š” ๋ถ„์„๊ณผ ์œ ์šฉํ•œ ์ •๋ณด๋ฅผ ์ œ๊ณตํ•˜์—ฌ ๋งŽ์€ ๋…์ž๋“ค์˜ ์‹ ๋ขฐ๋ฅผ ๋ฐ›๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.
[๋ถ„์„ ๋‹จ๊ณ„]
1. ์ฐธ๊ณ  ์ž๋ฃŒ 3๊ฐœ๋ฅผ ์ฒ ์ €ํžˆ ๋ถ„์„ํ•˜์—ฌ ํ•ต์‹ฌ ์ฃผ์ œ์™€ ์ค‘์š” ์ •๋ณด ํŒŒ์•…
2. ํฌ์ŠคํŒ… ์ฃผ์ œ์˜ ์œ ํ˜•๊ณผ ํŠน์„ฑ ์‹๋ณ„ (๊ฑด๊ฐ•, ๊ธฐ์ˆ , ๊ต์œก, ์ทจ๋ฏธ, ๊ฒฝ์ œ ๋“ฑ)
3. ํฌ์ŠคํŒ…์˜ ํ•ต์‹ฌ์ด ๋  5๊ฐ€์ง€ ์ฃผ์š” ์š”์†Œ ํŒŒ์•… (๊ฐœ๋… ์„ค๋ช…, ์ฃผ์š” ์ด์ , ์‹ค์šฉ์  ์ ์šฉ, ์ตœ์‹  ํŠธ๋ Œ๋“œ, ์ „๋ฌธ๊ฐ€ ๊ฒฌํ•ด ๋“ฑ)
[์•„์›ƒ๋ผ์ธ ๊ตฌ์„ฑ ์›์น™]
1. ๋„์ž…๋ถ€(1๊ฐœ) - ๋…์ž์˜ ๊ด€์‹ฌ์„ ๋„๋Š” ๋งค๋ ฅ์ ์ธ ์ œ๋ชฉ์œผ๋กœ ์‹œ์ž‘
2. ๋ณธ๋ก (4-5๊ฐœ) - ์ฐธ๊ณ  ์ž๋ฃŒ ๋ถ„์„์„ ํ†ตํ•ด ๋ฐœ๊ฒฌํ•œ ์ฃผ์ œ์˜ ํ•ต์‹ฌ ๊ฐ€์น˜์™€ ์ค‘์š” ์ •๋ณด๋ฅผ ๋‹ด์€ ์†Œ์ œ๋ชฉ
- ์ฃผ์ œ์˜ ๊ธฐ๋ณธ ๊ฐœ๋…๊ณผ ๋ฐฐ๊ฒฝ ์ง€์‹
- ๋…์ž๋“ค์ด ๊ฐ€์žฅ ์œ ์šฉํ•˜๊ฒŒ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์ •๋ณด
- ์ตœ์‹  ํŠธ๋ Œ๋“œ๋‚˜ ์—ฐ๊ตฌ ๊ฒฐ๊ณผ
- ์‹ค์šฉ์ ์ธ ์ ์šฉ ๋ฐฉ๋ฒ•์ด๋‚˜ ํŒ
- (์œ„ ํ•ญ๋ชฉ๋“ค์€ ์˜ˆ์‹œ์ผ ๋ฟ, ์ฐธ๊ณ  ์ž๋ฃŒ ๋ถ„์„์„ ํ†ตํ•ด ์ž์œ ๋กญ๊ฒŒ ๊ฒฐ์ •)
3. ๊ฒฐ๋ก (1๊ฐœ) - ์ „์ฒด ๋‚ด์šฉ์„ ์š”์•ฝํ•˜๊ณ  ๋…์ž์—๊ฒŒ ์œ ์šฉํ•œ ์ธ์‚ฌ์ดํŠธ๋ฅผ ์ œ๊ณตํ•˜๋Š” ์ œ๋ชฉ
[ํ•ต์‹ฌ ์ง€์นจ]
1. ์™„์ „ํžˆ ํ•œ๊ตญ์–ด๋กœ๋งŒ ์ž‘์„ฑํ•  ๊ฒƒ
2. ์†Œ์ œ๋ชฉ์€ ์ตœ๋Œ€ 30์ž ์ด๋‚ด๋กœ ๊ฐ„๊ฒฐํ•˜๊ฒŒ ์ž‘์„ฑ
3. ๋…์ž์˜ ํ˜ธ๊ธฐ์‹ฌ๊ณผ ๊ด€์‹ฌ์„ ์ž๊ทนํ•˜๋Š” ํ‘œํ˜„ ์‚ฌ์šฉ (์˜ˆ: "๋ฐ˜๋“œ์‹œ ์•Œ์•„์•ผ ํ• ", "๋†€๋ผ์šด ์‚ฌ์‹ค", "์ „๋ฌธ๊ฐ€๋“ค์ด ์ถ”์ฒœํ•˜๋Š”")
4. ์ฃผ์ œ์˜ ๊ฐ€์žฅ ๊ฐ€์น˜ ์žˆ๋Š” ์ •๋ณด๊ฐ€ ์†Œ์ œ๋ชฉ์— ๋ฐ˜์˜๋˜๋„๋ก ๊ตฌ์„ฑ
5. ํ‚ค์›Œ๋“œ๋Š” ์†Œ์ œ๋ชฉ ๊ฒฐ์ •์— ์˜ํ–ฅ์„ ์ฃผ์ง€ ์•Š์Œ (๋ณธ๋ฌธ ์ž‘์„ฑ ์‹œ ์ฐธ๊ณ ์‚ฌํ•ญ์œผ๋กœ๋งŒ ํ™œ์šฉ)
6. ์ „์ฒด ์•„์›ƒ๋ผ์ธ์€ ๋„์ž…๋ถ€(1) + ๋ณธ๋ก (์ตœ๋Œ€ 5๊ฐœ) + ๊ฒฐ๋ก (1)์œผ๋กœ ๊ตฌ์„ฑ
[์ถœ๋ ฅ ํ˜•์‹]
1. ์ฐธ๊ณ  ์ž๋ฃŒ ๋ถ„์„์„ ํ†ตํ•ด ๊ฐ€์žฅ ํ•ต์‹ฌ์ ์ธ ์ฃผ์ œ์™€ ์ •๋ณด๋ฅผ ํŒŒ์•…ํ•˜์—ฌ ์ž์œ ๋กญ๊ฒŒ ์•„์›ƒ๋ผ์ธ ๊ตฌ์„ฑ
2. ํ•˜์ง€๋งŒ ๋ฐ˜๋“œ์‹œ ๋‹ค์Œ ๊ตฌ์กฐ๋ฅผ ์œ ์ง€ํ•  ๊ฒƒ:(๊ฐ ํ•ญ๋ชฉ๋‹น 1๋ฒˆ ์—”ํ„ฐ๋ฅผ ์ ์šฉํ•˜์—ฌ ๋นˆ์นธ์ด ๋‚˜์˜ค์ง€ ์•Š๋„๋กํ•˜๋ผ.)
3. ๋„์ž…๋ถ€: 1๊ฐœ (๋…์ž์˜ ๊ด€์‹ฌ์„ ๋„๋Š” ๋งค๋ ฅ์ ์ธ ์ œ๋ชฉ)
4. ๋ณธ๋ก : 4-5๊ฐœ (์ฃผ์ œ์˜ ๊ฐ€์žฅ ์ค‘์š”ํ•œ ์ •๋ณด์™€ ๊ฐ€์น˜๋ฅผ ๋ฐ˜์˜ํ•œ ์ œ๋ชฉ)
5. ๊ฒฐ๋ก : 1๊ฐœ (์ „์ฒด ๋‚ด์šฉ ์š”์•ฝ ์ œ๋ชฉ)
6. ์†Œ์ œ๋ชฉ์€ ์ฃผ์ œ์˜ ํ•ต์‹ฌ ์ •๋ณด์™€ ๊ฐ€์น˜์— ๋งž๊ฒŒ ์ž์œ ๋กญ๊ฒŒ ๊ตฌ์„ฑ
7. ํ‚ค์›Œ๋“œ์— ๋งž์ถ”์ง€ ๋ง๊ณ , ์ฐธ๊ณ  ์ž๋ฃŒ ๋ถ„์„์„ ํ†ตํ•ด ๋ฐœ๊ฒฌํ•œ ํ•ต์‹ฌ ๊ฐ€์น˜์™€ ์ •๋ณด ๊ธฐ๋ฐ˜์œผ๋กœ ๊ตฌ์„ฑ
8. ์˜ˆ์‹œ ํ˜•์‹ (์ฐธ๊ณ ์šฉ์ผ ๋ฟ, ๋‚ด์šฉ์€ ์ฐธ๊ณ  ์ž๋ฃŒ์— ๋”ฐ๋ผ ์™„์ „ํžˆ ๋‹ฌ๋ผ์งˆ ์ˆ˜ ์žˆ์Œ):
- ๋„์ž…๋ถ€: [๊ด€์‹ฌ์„ ๋„๋Š” ๋„์ž… ์ œ๋ชฉ]
- ๋ณธ๋ก 1: [ํ•ต์‹ฌ ๊ฐœ๋…/๋ฐฐ๊ฒฝ ๊ด€๋ จ ์ œ๋ชฉ]
- ๋ณธ๋ก 2: [์ฃผ์š” ์ด์ /๊ฐ€์น˜ ๊ด€๋ จ ์ œ๋ชฉ]
- ๋ณธ๋ก 3: [์ตœ์‹  ํŠธ๋ Œ๋“œ/์—ฐ๊ตฌ ๊ด€๋ จ ์ œ๋ชฉ]
- ๋ณธ๋ก 4: [์‹ค์šฉ์  ์ ์šฉ/ํŒ ๊ด€๋ จ ์ œ๋ชฉ]
- ๋ณธ๋ก 5: [์ „๋ฌธ๊ฐ€ ๊ฒฌํ•ด/์ฃผ์š” ์‚ฌ๋ก€ ๊ด€๋ จ ์ œ๋ชฉ] (ํ•„์š”์‹œ)
- ๊ฒฐ๋ก : [์ „์ฒด ๋‚ด์šฉ ์š”์•ฝ ๋ฐ ์ธ์‚ฌ์ดํŠธ ์ œ๋ชฉ]
""",
"์ƒํ™œ๊ฑด๊ฐ•": """
[์ƒํ™œ๊ฑด๊ฐ• ์ฃผ์ œ ์†Œ์ฃผ์ œ(Outline) ์ƒ์„ฑ ๊ทœ์น™]
[์‹œ์Šคํ…œ ์—ญํ• ]
๋‹น์‹ ์€ ์ˆ˜๋…„๊ฐ„์˜ ๊ฒฝํ—˜์„ ๊ฐ€์ง„ ์ƒํ™œ๊ฑด๊ฐ• ์ „๋ฌธ ๋ธ”๋กœ๊ฑฐ์ž…๋‹ˆ๋‹ค. ์˜์–‘, ์šด๋™, ์ •์‹ ๊ฑด๊ฐ•, ์ˆ˜๋ฉด, ์ž์—ฐ์น˜์œ ๋ฒ• ๋“ฑ ์ผ์ƒ์—์„œ ์‹ค์ฒœํ•  ์ˆ˜ ์žˆ๋Š” ๊ฑด๊ฐ• ์ •๋ณด๋กœ ๋งŽ์€ ๋…์ž๋“ค์˜ ์‹ ๋ขฐ๋ฅผ ๋ฐ›๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.
[๋ถ„์„ ๋‹จ๊ณ„]
1. ์ฐธ๊ณ  ์ž๋ฃŒ 3๊ฐœ๋ฅผ ์ฒ ์ €ํžˆ ๋ถ„์„ํ•˜์—ฌ ํ•ต์‹ฌ ๊ฑด๊ฐ• ์ฃผ์ œ์™€ ์ค‘์š” ์ •๋ณด ํŒŒ์•…
2. ๊ฑด๊ฐ• ์ฃผ์ œ์˜ ์œ ํ˜•๊ณผ ํŠน์„ฑ ์‹๋ณ„ (์˜์–‘, ์šด๋™, ์ŠคํŠธ๋ ˆ์Šค ๊ด€๋ฆฌ, ์ˆ˜๋ฉด, ๋ฉด์—ญ๋ ฅ ๋“ฑ)
3. ํฌ์ŠคํŒ…์˜ ํ•ต์‹ฌ์ด ๋  5๊ฐ€์ง€ ์ฃผ์š” ์š”์†Œ ํŒŒ์•… (๊ณผํ•™์  ๊ทผ๊ฑฐ, ์‹ค์ฒœ ๋ฐฉ๋ฒ•, ๊ธฐ๋Œ€ ํšจ๊ณผ, ์ฃผ์˜์‚ฌํ•ญ, ์ „๋ฌธ๊ฐ€ ์กฐ์–ธ ๋“ฑ)
[์•„์›ƒ๋ผ์ธ ๊ตฌ์„ฑ ์›์น™]
1. ๋„์ž…๋ถ€(1๊ฐœ) - ๊ฑด๊ฐ• ๋ฌธ์ œ๋‚˜ ๊ด€์‹ฌ์‚ฌ์— ๋Œ€ํ•œ ๊ณต๊ฐ๋Œ€๋ฅผ ํ˜•์„ฑํ•˜๋Š” ์ œ๋ชฉ์œผ๋กœ ์‹œ์ž‘
2. ๋ณธ๋ก (4-5๊ฐœ) - ์ฐธ๊ณ  ์ž๋ฃŒ ๋ถ„์„์„ ํ†ตํ•ด ๋ฐœ๊ฒฌํ•œ ๊ฑด๊ฐ• ๊ด€๋ จ ํ•ต์‹ฌ ์ •๋ณด์™€ ์‹ค์ฒœ ๋ฐฉ๋ฒ•์„ ๋‹ด์€ ์†Œ์ œ๋ชฉ
- ๊ฑด๊ฐ• ์ด์Šˆ์˜ ์›์ธ๊ณผ ๊ณผํ•™์  ๋ฐฐ๊ฒฝ]
- ์ผ์ƒ์—์„œ ์‰ฝ๊ฒŒ ์‹ค์ฒœํ•  ์ˆ˜ ์žˆ๋Š” ๊ฐœ์„  ๋ฐฉ๋ฒ•
- ๊ฑด๊ฐ• ์Šต๊ด€์ด ๊ฐ€์ ธ์˜ค๋Š” ๊ตฌ์ฒด์  ์ด์ 
- ํ”ํ•œ ์˜คํ•ด์™€ ์ฃผ์˜์‚ฌํ•ญ
- ์ „๋ฌธ๊ฐ€ ์กฐ์–ธ์ด๋‚˜ ์ตœ์‹  ์—ฐ๊ตฌ ๊ฒฐ๊ณผ
- (์œ„ ํ•ญ๋ชฉ๋“ค์€ ์˜ˆ์‹œ์ผ ๋ฟ, ์ฐธ๊ณ  ์ž๋ฃŒ ๋ถ„์„์„ ํ†ตํ•ด ์ž์œ ๋กญ๊ฒŒ ๊ฒฐ์ •)
3. ๊ฒฐ๋ก (1๊ฐœ) - ์ „์ฒด ๊ฑด๊ฐ• ์ •๋ณด๋ฅผ ์š”์•ฝํ•˜๊ณ  ์ง€์†์ ์ธ ์‹ค์ฒœ์„ ๋…๋ คํ•˜๋Š” ์ œ๋ชฉ
[ํ•ต์‹ฌ ์ง€์นจ]
1. ์™„์ „ํžˆ ํ•œ๊ตญ์–ด๋กœ๋งŒ ์ž‘์„ฑํ•  ๊ฒƒ
2. ์†Œ์ œ๋ชฉ์€ ์ตœ๋Œ€ 30์ž ์ด๋‚ด๋กœ ๊ฐ„๊ฒฐํ•˜๊ฒŒ ์ž‘์„ฑ
3. ๋…์ž์˜ ๊ฑด๊ฐ• ๊ฐœ์„  ์˜์ง€๋ฅผ ์ž๊ทนํ•˜๋Š” ํ‘œํ˜„ ์‚ฌ์šฉ (์˜ˆ: "ํ•˜๋ฃจ 5๋ถ„๋งŒ ํˆฌ์žํ•˜๋ฉด", "์ „๋ฌธ์˜๊ฐ€ ๊ถŒ์žฅํ•˜๋Š”", "์ž˜๋ชป๋œ ๊ฑด๊ฐ• ์ƒ์‹")
4. ๊ณผํ•™์  ๊ทผ๊ฑฐ์™€ ์‹ค์ƒํ™œ ์ ์šฉ ๋ฐฉ๋ฒ•์ด ์†Œ์ œ๋ชฉ์— ๋ฐ˜์˜๋˜๋„๋ก ๊ตฌ์„ฑ
5. ๊ฑด๊ฐ• ํ‚ค์›Œ๋“œ๋Š” ์†Œ์ œ๋ชฉ ๊ฒฐ์ •์— ์˜ํ–ฅ์„ ์ฃผ์ง€ ์•Š์Œ (๋ณธ๋ฌธ ์ž‘์„ฑ ์‹œ ์ฐธ๊ณ ์‚ฌํ•ญ์œผ๋กœ๋งŒ ํ™œ์šฉ)
6. ์ „์ฒด ์•„์›ƒ๋ผ์ธ์€ ๋„์ž…๋ถ€(1) + ๋ณธ๋ก (์ตœ๋Œ€ 5๊ฐœ) + ๊ฒฐ๋ก (1)์œผ๋กœ ๊ตฌ์„ฑ
[์ถœ๋ ฅ ํ˜•์‹]
1. ์ฐธ๊ณ  ์ž๋ฃŒ ๋ถ„์„์„ ํ†ตํ•ด ๊ฐ€์žฅ ํ•ต์‹ฌ์ ์ธ ๊ฑด๊ฐ• ์ฃผ์ œ์™€ ์ •๋ณด๋ฅผ ํŒŒ์•…ํ•˜์—ฌ ์ž์œ ๋กญ๊ฒŒ ์•„์›ƒ๋ผ์ธ ๊ตฌ์„ฑ
2. ํ•˜์ง€๋งŒ ๋ฐ˜๋“œ์‹œ ๋‹ค์Œ ๊ตฌ์กฐ๋ฅผ ์œ ์ง€ํ•  ๊ฒƒ:(๊ฐ ํ•ญ๋ชฉ๋‹น 1๋ฒˆ ์—”ํ„ฐ๋ฅผ ์ ์šฉํ•˜์—ฌ ๋นˆ์นธ์ด ๋‚˜์˜ค์ง€ ์•Š๋„๋กํ•˜๋ผ.)
3. ๋„์ž…๋ถ€: 1๊ฐœ (๊ฑด๊ฐ• ๋ฌธ์ œ์— ๊ณต๊ฐํ•˜๊ณ  ๊ด€์‹ฌ์„ ๋„๋Š” ์ œ๋ชฉ)
4. ๋ณธ๋ก : 4-5๊ฐœ (๊ฑด๊ฐ• ๊ฐœ์„ ์„ ์œ„ํ•œ ํ•ต์‹ฌ ์ •๋ณด์™€ ์‹ค์ฒœ๋ฒ•์„ ๋ฐ˜์˜ํ•œ ์ œ๋ชฉ)
5. ๊ฒฐ๋ก : 1๊ฐœ (์ „์ฒด ๊ฑด๊ฐ• ์ •๋ณด ์š”์•ฝ ๋ฐ ์‹ค์ฒœ ๋…๋ ค ์ œ๋ชฉ)
6. ์†Œ์ œ๋ชฉ์€ ๊ฑด๊ฐ• ์ฃผ์ œ์˜ ๊ณผํ•™์  ๊ทผ๊ฑฐ์™€ ์‹ค์ฒœ ๋ฐฉ๋ฒ•์— ๋งž๊ฒŒ ์ž์œ ๋กญ๊ฒŒ ๊ตฌ์„ฑ
7. ํ‚ค์›Œ๋“œ์— ๋งž์ถ”์ง€ ๋ง๊ณ , ์ฐธ๊ณ  ์ž๋ฃŒ ๋ถ„์„์„ ํ†ตํ•ด ๋ฐœ๊ฒฌํ•œ ํ•ต์‹ฌ ๊ฑด๊ฐ• ๊ฐ€์น˜์™€ ์ •๋ณด ๊ธฐ๋ฐ˜์œผ๋กœ ๊ตฌ์„ฑ
8. ์˜ˆ์‹œ ํ˜•์‹ (์ฐธ๊ณ ์šฉ์ผ ๋ฟ, ๋‚ด์šฉ์€ ์ฐธ๊ณ  ์ž๋ฃŒ์— ๋”ฐ๋ผ ์™„์ „ํžˆ ๋‹ฌ๋ผ์งˆ ์ˆ˜ ์žˆ์Œ):
- ๋„์ž…๋ถ€: [๊ฑด๊ฐ• ๋ฌธ์ œ ๊ณต๊ฐ ๋ฐ ๊ด€์‹ฌ ์œ ๋„ ์ œ๋ชฉ]
- ๋ณธ๋ก 1: [๊ฑด๊ฐ• ์ด์Šˆ ์›์ธ/๋ฐฐ๊ฒฝ ๊ด€๋ จ ์ œ๋ชฉ]
- ๋ณธ๋ก 2: [์‹ค์ฒœ ๊ฐ€๋Šฅํ•œ ๊ฐœ์„  ๋ฐฉ๋ฒ• ๊ด€๋ จ ์ œ๋ชฉ]
- ๋ณธ๋ก 3: [๊ธฐ๋Œ€ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฑด๊ฐ• ์ด์  ๊ด€๋ จ ์ œ๋ชฉ]
- ๋ณธ๋ก 4: [์ฃผ์˜์‚ฌํ•ญ/ํ”ํ•œ ์˜คํ•ด ๊ด€๋ จ ์ œ๋ชฉ]
- ๋ณธ๋ก 5: [์ „๋ฌธ๊ฐ€ ์กฐ์–ธ/์ตœ์‹  ์—ฐ๊ตฌ ๊ด€๋ จ ์ œ๋ชฉ] (ํ•„์š”์‹œ)
- ๊ฒฐ๋ก : [๊ฑด๊ฐ• ์ •๋ณด ์š”์•ฝ ๋ฐ ์‹ค์ฒœ ๋…๋ ค ์ œ๋ชฉ]
"""
}
return prompts.get(category, prompts["์ผ๋ฐ˜"])
def get_category_blog_prompt(category="์ผ๋ฐ˜"):
"""์นดํ…Œ๊ณ ๋ฆฌ๋ณ„ ๋ธ”๋กœ๊ทธ ๊ธ€ ์ƒ์„ฑ ํ”„๋กฌํ”„ํŠธ"""
prompts = {
"์ผ๋ฐ˜": """
[์ผ๋ฐ˜ ์ฃผ์ œ ๋ธ”๋กœ๊ทธ ์ž‘์„ฑ ๊ฐ€์ด๋“œ]
1. ๋„ˆ๋Š” ์ตœ๊ณ ์˜ ๋ธ”๋กœ๊ทธ ์ž‘๊ฐ€์ด์ž ์ •๋ณด ์ „๋‹ฌ ์ „๋ฌธ๊ฐ€์ด๋‹ค.
2. ์ฃผ์–ด์ง„ ์•„์›ƒ๋ผ์ธ๊ณผ ์ฐธ๊ณ ๊ธ€์„ ๋ฐ”ํƒ•์œผ๋กœ ๋…์ž์—๊ฒŒ ๊ฐ€์น˜ ์žˆ๋Š” ์ •๋ณด๋ฅผ ์ œ๊ณตํ•˜๋ผ.
3. ์ •๋ณด์˜ ์ •ํ™•์„ฑ๊ณผ ๊นŠ์ด๋ฅผ ์œ ์ง€ํ•˜๋ฉด์„œ๋„ ์ดํ•ดํ•˜๊ธฐ ์‰ฝ๊ฒŒ ์„ค๋ช…ํ•˜๋ผ.
[์ฝ˜ํ…์ธ  ์ž‘์„ฑ ๊ทœ์น™]
1. ๊ฐ๊ด€์ ์ธ ์ •๋ณด ์ œ๊ณต์— ์ค‘์ ์„ ๋‘๋˜, ๋…์ž์˜ ๊ด€์‹ฌ๊ณผ ์ฐธ์—ฌ๋ฅผ ์œ ๋„ํ•˜๋ผ.
2. ๋ณต์žกํ•œ ๊ฐœ๋…์€ ๋น„์œ ์™€ ์˜ˆ์‹œ๋ฅผ ํ†ตํ•ด ์‰ฝ๊ฒŒ ์„ค๋ช…ํ•˜๋ผ.
3. ์ฃผ์ œ์— ๋Œ€ํ•œ ๋‹ค์–‘ํ•œ ๊ด€์ ๊ณผ ์ธก๋ฉด์„ ๊ท ํ˜• ์žˆ๊ฒŒ ๋‹ค๋ฃจ์–ด๋ผ.
4. ๋…์ž๊ฐ€ ์‹ค์ƒํ™œ์— ์ ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์‹ค์šฉ์ ์ธ ์ •๋ณด์™€ ํŒ์„ ์ œ๊ณตํ•˜๋ผ.
5. ์ฐธ๊ณ ๊ธ€์˜ ์ •๋ณด๋ฅผ ์žฌ๊ตฌ์„ฑํ•˜๋˜, ํ‘œํ˜„์„ ๋‹จ์ˆœํžˆ ๋ณต์‚ฌํ•˜์ง€ ๋ง๊ณ  ์ฐฝ์˜์ ์œผ๋กœ ์žฌ๊ตฌ์„ฑํ•˜๋ผ.
6. ๊ฐ ์„น์…˜์€ ์ตœ์†Œ {MIN_SECTION_LENGTH}์ž ์ด์ƒ์˜ ์ถฉ๋ถ„ํ•œ ๋‚ด์šฉ์œผ๋กœ ์ž‘์„ฑํ•˜๋ผ.
7. ๊ธ€ ์ „์ฒด ๊ธธ์ด๋Š” ์ตœ์†Œ {TARGET_CHAR_LENGTH}์ž๊ฐ€ ๋˜๋„๋ก ์ž‘์„ฑํ•˜๋ผ.
8. ๊ธ€ ์ „์ฒด ๊ธธ์ด๋Š” {TARGET_CHAR_LENGTH}์ž์—์„œ {TARGET_CHAR_LENGTH + 1000}์ž ์‚ฌ์ด๊ฐ€ ๋˜๋„๋ก ์ž‘์„ฑํ•˜๋ผ.
[์ค‘์š” ๊ทœ์น™]
1. ๋งˆํฌ๋‹ค์šด ํ˜•์‹(#, *, -, 1., 2. ๋“ฑ)์„ ์‚ฌ์šฉํ•˜์ง€ ๋ง๊ณ  ์ผ๋ฐ˜ ํ…์ŠคํŠธ๋กœ ์ž‘์„ฑํ•˜๋ผ.
2. ์†Œ์ œ๋ชฉ๊ณผ ๊ฒฐ๋ก ์€ ๋ฒˆํ˜ธ ์—†์ด ์ผ๋ฐ˜ ๋ฌธ์žฅ ํ˜•ํƒœ๋กœ ์ž‘์„ฑํ•˜๋ผ.
3. ๋ชฉ๋ก์€ ๋ถˆ๋ฆฟ์ด๋‚˜ ๋ฒˆํ˜ธ ๋Œ€์‹  ์ž์—ฐ์Šค๋Ÿฌ์šด ๋ฌธ์žฅ์œผ๋กœ ์„œ์ˆ ํ•˜๋ผ.
4. "์ฐธ๊ณ ๊ธ€", "์ฐธ๊ณ ๊ธ€์— ๋”ฐ๋ฅด๋ฉด" ๋“ฑ์˜ ํ‘œํ˜„์„ ์‚ฌ์šฉํ•˜์ง€ ๋ง๋ผ.
5. "์—ฌ๋Ÿฌ๋ถ„", "๋…์ž ์—ฌ๋Ÿฌ๋ถ„" ๋“ฑ์˜ ์ง์ ‘์ ์ธ ํ˜ธ์นญ์„ ์ง€์–‘ํ•˜๋ผ.
""",
"์ƒํ™œ๊ฑด๊ฐ•": """
[์ƒํ™œ๊ฑด๊ฐ• ์ฃผ์ œ ๋ธ”๋กœ๊ทธ ์ž‘์„ฑ ๊ฐ€์ด๋“œ]
1. ๋„ˆ๋Š” ์ƒํ™œ๊ฑด๊ฐ• ๋ฐ ์›ฐ๋น™ ์ „๋ฌธ ๋ธ”๋กœ๊ฑฐ์ด์ž ๊ฑด๊ฐ• ์ •๋ณด ์ „๋‹ฌ์ž์ด๋‹ค.
2. ๊ณผํ•™์  ๊ทผ๊ฑฐ๋ฅผ ๋ฐ”ํƒ•์œผ๋กœ ์ •ํ™•ํ•œ ๊ฑด๊ฐ• ์ •๋ณด๋ฅผ ์ œ๊ณตํ•˜๋ผ.
3. ๋ณต์žกํ•œ ๊ฑด๊ฐ• ๊ฐœ๋…์„ ์ผ์ƒ์  ๋งฅ๋ฝ์—์„œ ์ดํ•ดํ•˜๊ธฐ ์‰ฝ๊ฒŒ ์„ค๋ช…ํ•˜๋ผ.
[์ฝ˜ํ…์ธ  ์ž‘์„ฑ ๊ทœ์น™]
1. ๊ฑด๊ฐ• ์ •๋ณด์˜ ์ •ํ™•์„ฑ๊ณผ ์‹ ๋ขฐ์„ฑ์„ ์ตœ์šฐ์„ ์œผ๋กœ ํ•˜๋ผ.
2. ์˜ํ•™์  ์ฃผ์žฅ์€ ๊ณผํ•™์  ๊ทผ๊ฑฐ๋‚˜ ์—ฐ๊ตฌ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ”ํƒ•์œผ๋กœ ์„œ์ˆ ํ•˜๋ผ.
3. ๊ณผ๋„ํ•œ ์ฃผ์žฅ์ด๋‚˜ ๊ณผ์žฅ๋œ ํšจ๊ณผ๋ฅผ ์•ฝ์†ํ•˜์ง€ ๋ง๋ผ.
4. ์ผ์ƒ์ƒํ™œ์—์„œ ์‰ฝ๊ฒŒ ์‹ค์ฒœํ•  ์ˆ˜ ์žˆ๋Š” ๊ตฌ์ฒด์ ์ธ ๊ฑด๊ฐ• ๊ด€๋ฆฌ ๋ฐฉ๋ฒ•์„ ์ œ์‹œํ•˜๋ผ.
5. ๊ฑด๊ฐ• ๋ฌธ์ œ์˜ ์›์ธ, ์ฆ์ƒ, ์˜ˆ๋ฐฉ, ๊ด€๋ฆฌ ๋ฐฉ๋ฒ•์„ ์ฒด๊ณ„์ ์œผ๋กœ ์„ค๋ช…ํ•˜๋ผ.
6. ์ „๋ฌธ์ ์ธ ์˜ํ•™ ์šฉ์–ด๋Š” ์‰ฌ์šด ์„ค๋ช…๊ณผ ํ•จ๊ป˜ ์ œ๊ณตํ•˜๋ผ.
7. ๊ฐ ์„น์…˜์€ ์ตœ์†Œ {MIN_SECTION_LENGTH}์ž ์ด์ƒ์˜ ์ถฉ๋ถ„ํ•œ ๋‚ด์šฉ์œผ๋กœ ์ž‘์„ฑํ•˜๋ผ.
8. ๊ธ€ ์ „์ฒด ๊ธธ์ด๋Š” ์ตœ์†Œ {TARGET_CHAR_LENGTH}์ž๊ฐ€ ๋˜๋„๋ก ์ž‘์„ฑํ•˜๋ผ.
[์ค‘์š” ๊ทœ์น™]
1. ๋งˆํฌ๋‹ค์šด ํ˜•์‹(#, *, -, 1., 2. ๋“ฑ)์„ ์‚ฌ์šฉํ•˜์ง€ ๋ง๊ณ  ์ผ๋ฐ˜ ํ…์ŠคํŠธ๋กœ ์ž‘์„ฑํ•˜๋ผ.
2. ์†Œ์ œ๋ชฉ๊ณผ ๊ฒฐ๋ก ์€ ๋ฒˆํ˜ธ ์—†์ด ์ผ๋ฐ˜ ๋ฌธ์žฅ ํ˜•ํƒœ๋กœ ์ž‘์„ฑํ•˜๋ผ.
3. ๋ชฉ๋ก์€ ๋ถˆ๋ฆฟ์ด๋‚˜ ๋ฒˆํ˜ธ ๋Œ€์‹  ์ž์—ฐ์Šค๋Ÿฌ์šด ๋ฌธ์žฅ์œผ๋กœ ์„œ์ˆ ํ•˜๋ผ.
4. "์ฐธ๊ณ ๊ธ€", "์ฐธ๊ณ ๊ธ€์— ๋”ฐ๋ฅด๋ฉด" ๋“ฑ์˜ ํ‘œํ˜„์„ ์‚ฌ์šฉํ•˜์ง€ ๋ง๋ผ.
5. "์—ฌ๋Ÿฌ๋ถ„", "๋…์ž ์—ฌ๋Ÿฌ๋ถ„" ๋“ฑ์˜ ์ง์ ‘์ ์ธ ํ˜ธ์นญ์„ ์ง€์–‘ํ•˜๋ผ.
6. ์˜ํ•™์  ์กฐ์–ธ์ด ํ•„์š”ํ•œ ์‹ฌ๊ฐํ•œ ์ฆ์ƒ์˜ ๊ฒฝ์šฐ ์ „๋ฌธ์˜ ์ƒ๋‹ด์„ ๊ถŒ๊ณ ํ•˜๋ผ.
"""
}
return prompts.get(category, prompts["์ผ๋ฐ˜"])
# -------------------------------
# ๊ธ€ ์ƒ์„ฑ ๊ด€๋ จ ์ฃผ์š” ํ•จ์ˆ˜
# -------------------------------
def call_gemini_api(prompt, temperature=TEMPERATURE, top_p=TOP_P):
"""Gemini API ํ˜ธ์ถœ ํ•จ์ˆ˜"""
response = client.models.generate_content(
model="gemini-2.0-flash",
contents=[prompt],
config=types.GenerateContentConfig(
max_output_tokens=MAX_TOKENS,
temperature=temperature,
top_p=top_p
)
)
return response.text.strip()
def generate_outline(category, style, references1, references2, references3):
"""์•„์›ƒ๋ผ์ธ ์ƒ์„ฑ ํ•จ์ˆ˜"""
try:
category_prompt = get_category_outline_prompt(category)
style_prompt = get_style_prompt(style)
# ์ฐธ๊ณ ๊ธ€ ์ •๋ณด ์ค€๋น„
references = [
references1.strip() if references1.strip() else "์ฐธ๊ณ  ์ž๋ฃŒ ์—†์Œ",
references2.strip() if references2.strip() else "์ฐธ๊ณ  ์ž๋ฃŒ ์—†์Œ",
references3.strip() if references3.strip() else "์ฐธ๊ณ  ์ž๋ฃŒ ์—†์Œ"
]
# ์˜๋ฏธ ์žˆ๋Š” ์ฐธ๊ณ ๊ธ€๋งŒ ํ•„ํ„ฐ๋ง
meaningful_refs = [ref for ref in references if ref != "์ฐธ๊ณ  ์ž๋ฃŒ ์—†์Œ"]
if not meaningful_refs:
return "์ฐธ๊ณ  ์ž๋ฃŒ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ์ตœ์†Œ ํ•˜๋‚˜ ์ด์ƒ์˜ ์ฐธ๊ณ  ์ž๋ฃŒ๋ฅผ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”."
outline_prompt = f"""
[๋ธ”๋กœ๊ทธ ์•„์›ƒ๋ผ์ธ ์ƒ์„ฑ ์š”์ฒญ]
์นดํ…Œ๊ณ ๋ฆฌ: {category}
ํฌ์ŠคํŒ… ์Šคํƒ€์ผ: {style}
์ฐธ๊ณ ๊ธ€:
{references[0]}
{references[1] if len(meaningful_refs) > 1 else ""}
{references[2] if len(meaningful_refs) > 2 else ""}
{category_prompt}
์•„์›ƒ๋ผ์ธ ์ƒ์„ฑ ์‹œ ์ถ”๊ฐ€ ์ง€์นจ:
1. ์ฐธ๊ณ ๊ธ€์˜ ํ•ต์‹ฌ ์ฃผ์ œ์™€ ๊ฐ€์น˜ ์žˆ๋Š” ์ •๋ณด๋ฅผ ์ •ํ™•ํžˆ ํŒŒ์•…ํ•˜๋ผ.
2. ๊ฐ ์†Œ์ฃผ์ œ๋Š” 20์ž ์ด๋‚ด๋กœ ๋ช…ํ™•ํ•˜๊ณ  ๋งค๋ ฅ์ ์œผ๋กœ ์ž‘์„ฑํ•˜๋ผ.
3. ์ „์ฒด ์•„์›ƒ๋ผ์ธ์ด ๋…ผ๋ฆฌ์  ํ๋ฆ„๊ณผ ์ผ๊ด€์„ฑ์„ ๊ฐ€์ง€๋„๋ก ๊ตฌ์„ฑํ•˜๋ผ.
4. ๋…์ž์˜ ๊ด€์‹ฌ๊ณผ ํ˜ธ๊ธฐ์‹ฌ์„ ์œ ๋ฐœํ•˜๋Š” ์†Œ์ฃผ์ œ๋ฅผ ์„ค๊ณ„ํ•˜๋ผ.
5. ์†Œ์ฃผ์ œ๋งŒ ๊ฐ„๊ฒฐํ•˜๊ฒŒ ์ถœ๋ ฅํ•˜๊ณ  ์„ค๋ช…์€ ํฌํ•จํ•˜์ง€ ๋ง๋ผ.
6. ๊ฐ ์†Œ์ฃผ์ œ๊ฐ€ ์•ฝ์†๋œ ์„น์…˜(๋„์ž…๋ถ€, ๋ณธ๋ก 1~5, ๊ฒฐ๋ก )์— ์ ํ•ฉํ•œ์ง€ ํ™•์ธํ•˜๋ผ.
7. ๋ฐฑํ‹ฑ(```)์ด๋‚˜ ์ฝ”๋“œ ๋ธ”๋ก ํ‘œ์‹œ๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ๋ง๋ผ.
8. ์ •ํ™•ํžˆ 7์ค„๋กœ ๊ตฌ์„ฑํ•˜์—ฌ '๋„์ž…๋ถ€', '๋ณธ๋ก 1~5', '๊ฒฐ๋ก '๋งŒ ์ถœ๋ ฅํ•˜๋ผ.
"""
# Gemini API ํ˜ธ์ถœ
outline_result = call_gemini_api(outline_prompt, temperature=0.7)
# ๊ฒฐ๊ณผ ํ›„์ฒ˜๋ฆฌ (๋ถˆํ•„์š”ํ•œ ํ˜•์‹ ์ œ๊ฑฐ)
outline_result = re.sub(r'^\s*[-*]\s+', '', outline_result, flags=re.MULTILINE)
outline_result = re.sub(r'^\s*\d+\.\s+', '', outline_result, flags=re.MULTILINE)
# ๋ฐฑํ‹ฑ ๋ฐ ์ฝ”๋“œ ๋ธ”๋ก ์ œ๊ฑฐ
outline_result = re.sub(r'```[a-zA-Z]*\n?', '', outline_result)
outline_result = re.sub(r'```', '', outline_result)
# ์ •ํ™•ํžˆ 7์ค„ ํ˜•์‹์œผ๋กœ ์ •๋ฆฌ
lines = outline_result.strip().split('\n')
clean_lines = []
for line in lines:
line = line.strip()
if line and (line.startswith('๋„์ž…๋ถ€:') or
line.startswith('๋ณธ๋ก ') or
line.startswith('๊ฒฐ๋ก :')):
clean_lines.append(line)
# ์ •ํ™•ํžˆ 7์ค„์ด ๋‚˜์˜ค๋„๋ก ์กฐ์ •
if len(clean_lines) > 7:
clean_lines = clean_lines[:7]
elif len(clean_lines) < 7:
sections = ['๋„์ž…๋ถ€:', '๋ณธ๋ก 1:', '๋ณธ๋ก 2:', '๋ณธ๋ก 3:', '๋ณธ๋ก 4:', '๋ณธ๋ก 5:', '๊ฒฐ๋ก :']
while len(clean_lines) < 7:
missing_section = sections[len(clean_lines)]
clean_lines.append(f"{missing_section} ์ถ”๊ฐ€ ๋‚ด์šฉ ํ•„์š”")
return '\n'.join(clean_lines)
except Exception as e:
logging.error(f"์•„์›ƒ๋ผ์ธ ์ƒ์„ฑ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: {str(e)}")
return f"์•„์›ƒ๋ผ์ธ ์ƒ์„ฑ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: {str(e)}"
def post_process_blog(blog_content, style="์นœ๊ทผํ•œ"):
"""๋ธ”๋กœ๊ทธ ์ปจํ…์ธ  ํ›„์ฒ˜๋ฆฌ ํ•จ์ˆ˜"""
try:
# ๋ฒˆํ˜ธ ๋ชฉ๋ก, ๋ถˆ๋ฆฟ, ํ—ค๋”ฉ ๋“ฑ ์ œ๊ฑฐ
blog_content = re.sub(r'^\d+\.\s+', '', blog_content, flags=re.MULTILINE)
blog_content = re.sub(r'^[\*\-\โ€ข]\s+', '', blog_content, flags=re.MULTILINE)
blog_content = re.sub(r'^#+\s+', '', blog_content, flags=re.MULTILINE)
# ์Šคํƒ€์ผ์— ๋”ฐ๋ฅธ ์–ดํˆฌ ์กฐ์ •
if style == "์นœ๊ทผํ•œ":
blog_content = re.sub(r'([๊ฐ€-ํžฃ]+)๊ณ ์š”', r'\1๊ตฌ์š”', blog_content)
blog_content = re.sub(r'๋‹ต๋‹ˆ๋‹ค', '์–ด์š”', blog_content)
blog_content = re.sub(r'์˜€๋‹ต๋‹ˆ๋‹ค', '์˜€์–ด์š”', blog_content)
blog_content = re.sub(r'ํ–ˆ๋‹ต๋‹ˆ๋‹ค', 'ํ–ˆ์–ด์š”', blog_content)
blog_content = re.sub(r'์Šต๋‹ˆ๋‹ค', '์š”', blog_content)
blog_content = re.sub(r'ํ•ฉ๋‹ˆ๋‹ค', 'ํ•ด์š”', blog_content)
blog_content = re.sub(r'๋ฉ๋‹ˆ๋‹ค', '๋ผ์š”', blog_content)
blog_content = re.sub(r'์ž…๋‹ˆ๋‹ค', '์ด์—์š”', blog_content)
# ๊ณผ์žฅ๋œ ํ‘œํ˜„ ์ •๋ฆฌ
exaggerated_expressions = [
(r'ํ•„์ˆ˜์ ์ธ', r'์ค‘์š”ํ•œ'),
(r'ํ˜๋ช…์ ์ธ', r'์ค‘์š”ํ•œ'),
(r'๋†€๋ผ์šด', r'์ฃผ๋ชฉํ•  ๋งŒํ•œ'),
(r'๊ธฐ์ ์˜', r'ํšจ๊ณผ์ ์ธ'),
(r'์ตœ๊ณ ์˜', r'์ข‹์€'),
(r'์„ธ๊ณ„์ ์ธ', r'์œ ๋ช…ํ•œ'),
(r'์™„๋ฒฝํ•œ', r'์šฐ์ˆ˜ํ•œ'),
(r'๊ทน์ ์ธ', r'์ƒ๋‹นํ•œ'),
(r'๋ฌดํ•œํ•œ', r'๋งŽ์€'),
(r'์ ˆ๋Œ€์ ์ธ', r'์ƒ๋‹นํ•œ'),
(r'ํ˜์‹ ์ ์ธ', r'์ƒˆ๋กœ์šด'),
(r'ํ™˜์ƒ์ ์ธ', r'์ข‹์€'),
(r'๊ทผ๋ณธ์ ์ธ', r'๊ธฐ๋ณธ์ ์ธ'),
(r'ํš๊ธฐ์ ์ธ', r'์ค‘์š”ํ•œ'),
(r'์ „๋ก€์—†๋Š”', r'ํŠน๋ณ„ํ•œ'),
(r'์••๋„์ ์ธ', r'์ฃผ๋ชฉํ•  ๋งŒํ•œ'),
(r'ํ™ฉํ™€ํ•œ', r'์ข‹์€'),
(r'์ฒœ์ƒ์˜', r'์šฐ์ˆ˜ํ•œ'),
(r'๊ธฐ๊ฐ€ ๋ง‰ํžŒ', r'ํšจ๊ณผ์ ์ธ'),
(r'๋ํŒ์™•', r'์ตœ์ƒ์œ„'),
(r'๊ทธ ์ž์ฒด', r''),
(r'์ด .{1,10} ๊ทธ ์ž์ฒด์˜€์–ด์š”', r'์ด \1์˜€์–ด์š”'),
(r'๊ฐ€ .{1,10} ๊ทธ ์ž์ฒด์˜€์–ด์š”', r'๊ฐ€ \1์˜€์–ด์š”'),
(r'์••๋„์ ์ธ', r'์ค‘์š”ํ•œ'),
(r'์ฒœ๊ตญ', r'์ข‹์€ ๊ณณ'),
(r'ํ™ฉํ™€ํ–ˆ์–ด์š”', r'์ข‹์•˜์–ด์š”'),
(r'ํ™˜์ƒ์˜', r'์ข‹์€')
]
for pattern, replacement in exaggerated_expressions:
blog_content = re.sub(pattern, replacement, blog_content, flags=re.IGNORECASE)
blog_content = re.sub(r'์ฐธ๊ณ ๊ธ€์— ๋”ฐ๋ฅด๋ฉด', r'์•Œ๋ ค์ง„ ๋ฐ”๋กœ๋Š”', blog_content)
blog_content = re.sub(r'์ฐธ๊ณ ๊ธ€', r'๊ด€๋ จ ์ •๋ณด', blog_content)
return blog_content
except Exception as e:
logging.error(f"๋ธ”๋กœ๊ทธ ๊ธ€ ํ›„์ฒ˜๋ฆฌ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: {str(e)}")
return blog_content
def generate_blog_post(category, style, outline_input, references1, references2, references3):
"""ํ•œ ๋ฒˆ์˜ ํ˜ธ์ถœ๋กœ ์ „์ฒด ๋ธ”๋กœ๊ทธ ๊ธ€ ์ƒ์„ฑ ํ•จ์ˆ˜ (ํ‡ด๊ณ  ๋ฐ ํ™•์žฅ ๊ธฐ๋Šฅ ํฌํ•จ)"""
try:
# ์ฐธ๊ณ ๊ธ€ ์ค€๋น„
references = [
references1.strip() if references1.strip() else "์ฐธ๊ณ  ์ž๋ฃŒ ์—†์Œ",
references2.strip() if references2.strip() else "์ฐธ๊ณ  ์ž๋ฃŒ ์—†์Œ",
references3.strip() if references3.strip() else "์ฐธ๊ณ  ์ž๋ฃŒ ์—†์Œ"
]
# ์˜๋ฏธ ์žˆ๋Š” ์ฐธ๊ณ ๊ธ€๋งŒ ํ•„ํ„ฐ๋ง
references = [ref for ref in references if ref != "์ฐธ๊ณ  ์ž๋ฃŒ ์—†์Œ"]
if not references:
return "<p>์ฐธ๊ณ  ์ž๋ฃŒ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ์ตœ์†Œ ํ•˜๋‚˜ ์ด์ƒ์˜ ์ฐธ๊ณ  ์ž๋ฃŒ๋ฅผ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”.</p>", 0
if not outline_input.strip():
return "<p>์•„์›ƒ๋ผ์ธ์ด ์—†์Šต๋‹ˆ๋‹ค. ์•„์›ƒ๋ผ์ธ์„ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”.</p>", 0
# ์นดํ…Œ๊ณ ๋ฆฌ ๋ฐ ์Šคํƒ€์ผ ํ”„๋กฌํ”„ํŠธ ๊ฐ€์ ธ์˜ค๊ธฐ
category_prompt = get_category_blog_prompt(category)
style_prompt = get_style_prompt(style)
# Phase 1: ์ดˆ๊ธฐ ๋ธ”๋กœ๊ทธ ๊ธ€ ์ƒ์„ฑ
blog_prompt = f"""
[๋ธ”๋กœ๊ทธ ๊ธ€ ์ž‘์„ฑ ์š”์ฒญ]
์นดํ…Œ๊ณ ๋ฆฌ: {category}
ํฌ์ŠคํŒ… ์Šคํƒ€์ผ: {style}
์•„์›ƒ๋ผ์ธ:
{outline_input}
์ฐธ๊ณ ๊ธ€:
{references[0]}
{references[1] if len(references) > 1 else ""}
{references[2] if len(references) > 2 else ""}
{category_prompt}
{style_prompt}
[์†Œ์ œ๋ชฉ ์ž‘์„ฑ ๊ฐ€์ด๋“œ]
1. ๋ณธ๋ก ์˜ ๊ฐ ๋ถ€๋ถ„๋งˆ๋‹ค ๋ช…ํ™•ํ•œ ์†Œ์ œ๋ชฉ์„ ์‚ฌ์šฉํ•˜์„ธ์š”.
2. ์†Œ์ œ๋ชฉ์€ 10~20์ž ๋‚ด์™ธ๋กœ ๋ช…ํ™•ํ•˜๊ณ  ๊ฐ„๊ฒฐํ•˜๊ฒŒ ์ž‘์„ฑํ•˜์„ธ์š”.
3. ์†Œ์ œ๋ชฉ์€ ๋…๋ฆฝ๋œ ์ค„์— ์œ„์น˜ํ•˜๊ณ  ์•ž๋’ค์— ๋นˆ ์ค„์ด ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
4. ์†Œ์ œ๋ชฉ ์˜ˆ์‹œ: 'ํšจ๊ณผ์ ์ธ ์šด๋™ ๋ฐฉ๋ฒ•', '๊ฑด๊ฐ•ํ•œ ์‹์Šต๊ด€์˜ ์ค‘์š”์„ฑ', '์ŠคํŠธ๋ ˆ์Šค ๊ด€๋ฆฌ๋ž€?'
[์ค‘์š” ์ž‘์„ฑ ๊ทœ์น™]
1. ๋ฐ˜๋“œ์‹œ ์œ„์˜ ์•„์›ƒ๋ผ์ธ ์ˆœ์„œ์™€ ๊ตฌ์กฐ์— ๋”ฐ๋ผ ์ž‘์„ฑํ•˜๋ผ.
2. ๊ฐ ์„น์…˜์€ ๋ช…ํ™•ํžˆ ๊ตฌ๋ถ„๋˜์–ด์•ผ ํ•˜๋ฉฐ, ์„น์…˜ ์ œ๋ชฉ์„ ํฌํ•จํ•˜๋ผ.
3. ๋„์ž…๋ถ€๋Š” ๋…์ž์˜ ๊ด€์‹ฌ์„ ๋Œ๊ณ  ์ฃผ์ œ๋ฅผ ์†Œ๊ฐœํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ์ž‘์„ฑํ•˜๋ผ.
4. ๋ณธ๋ก  ๊ฐ ๋ถ€๋ถ„์€ ์ฃผ์ œ์˜ ์„œ๋กœ ๋‹ค๋ฅธ ์ธก๋ฉด์„ ๋‹ค๋ฃจ๋ฉฐ, ๊ตฌ์ฒด์ ์ธ ์ •๋ณด์™€ ์˜ˆ์‹œ๋ฅผ ํฌํ•จํ•˜๋ผ.
5. ๊ฒฐ๋ก ์€ ํ•ต์‹ฌ ๋‚ด์šฉ์„ ์š”์•ฝํ•˜๊ณ  ์ตœ์ข… ๋ฉ”์‹œ์ง€๋‚˜ ํ†ต์ฐฐ์„ ์ œ๊ณตํ•˜๋ผ.
6. ์ „์ฒด ๊ธ€์˜ ๊ธธ์ด๋Š” ์ตœ์†Œ {TARGET_CHAR_LENGTH}์ž๊ฐ€ ๋˜๋„๋ก ์ž‘์„ฑํ•˜๋ผ.
7. ๊ฐ ์„น์…˜์€ ์ตœ์†Œ {MIN_SECTION_LENGTH}์ž ์ด์ƒ์˜ ์ถฉ๋ถ„ํ•œ ๋‚ด์šฉ์œผ๋กœ ์ž‘์„ฑํ•˜๋ผ.
8. ๋งˆํฌ๋‹ค์šด ํ˜•์‹(#, *, -, 1., 2. ๋“ฑ)์„ ์‚ฌ์šฉํ•˜์ง€ ๋ง๊ณ  ์ผ๋ฐ˜ ํ…์ŠคํŠธ๋กœ ์ž‘์„ฑํ•˜๋ผ.
9. ์†Œ์ œ๋ชฉ๊ณผ ๊ฒฐ๋ก ์€ ๋ฒˆํ˜ธ ์—†์ด ์ผ๋ฐ˜ ๋ฌธ์žฅ ํ˜•ํƒœ๋กœ ์ž‘์„ฑํ•˜๋ผ.
10. ๋ชฉ๋ก์€ ๋ถˆ๋ฆฟ์ด๋‚˜ ๋ฒˆํ˜ธ ๋Œ€์‹  ์ž์—ฐ์Šค๋Ÿฌ์šด ๋ฌธ์žฅ์œผ๋กœ ์„œ์ˆ ํ•˜๋ผ.
11. "์ฐธ๊ณ ๊ธ€", "์ฐธ๊ณ ๊ธ€์— ๋”ฐ๋ฅด๋ฉด" ๋“ฑ์˜ ํ‘œํ˜„์„ ์‚ฌ์šฉํ•˜์ง€ ๋ง๋ผ.
12. "์—ฌ๋Ÿฌ๋ถ„", "๋…์ž ์—ฌ๋Ÿฌ๋ถ„" ๋“ฑ์˜ ์ง์ ‘์ ์ธ ํ˜ธ์นญ์„ ์ง€์–‘ํ•˜๋ผ.
13. ๊ณผ์žฅ๋œ ํ‘œํ˜„์ด๋‚˜ ๋ถˆํ•„์š”ํ•œ ๋ฐ˜๋ณต์„ ํ”ผํ•˜๋ผ.
14. ๊ฐ ์„น์…˜ ์‚ฌ์ด์— ์ž์—ฐ์Šค๋Ÿฌ์šด ์—ฐ๊ฒฐ์„ฑ์„ ์œ ์ง€ํ•˜๋ผ.
15. ๊ธ€์˜ ์ฒ˜์Œ์— ์ „์ฒด ๊ธ€์˜ ๋งค๋ ฅ์ ์ธ ์ œ๋ชฉ์„ ๋ฐ˜๋“œ์‹œ ์ถ”๊ฐ€ํ•˜๋ผ.
"""
# Gemini API ํ˜ธ์ถœ (ํ•œ ๋ฒˆ์˜ ํ˜ธ์ถœ๋กœ ์ „์ฒด ๊ธ€ ์ƒ์„ฑ)
logging.info("์ „์ฒด ๋ธ”๋กœ๊ทธ ๊ธ€ ์ƒ์„ฑ ์‹œ์ž‘")
blog_content = call_gemini_api(blog_prompt, temperature=0.7)
logging.info(f"์ƒ์„ฑ๋œ ์›๋ณธ ๊ธ€ ๊ธธ์ด: {len(blog_content)}")
# ํ›„์ฒ˜๋ฆฌ
processed_content = post_process_blog(blog_content, style)
# HTML ๋ณ€ํ™˜ํ•˜์—ฌ ๊ธ€์ž ์ˆ˜ ์ฒดํฌ
temp_html = format_blog_post(processed_content)
char_count = len(extract_text_from_html(temp_html))
logging.info(f"์ดˆ๊ธฐ ๋ธ”๋กœ๊ทธ ๊ธ€ ๊ธ€์ž ์ˆ˜: {char_count}")
# Phase 2: ๊ธ€์ž ์ˆ˜๊ฐ€ ๋ชฉํ‘œ์— ๋ฏธ๋‹ฌํ•˜๋ฉด ํ‡ด๊ณ  ๋ฐ ํ™•์žฅ
if char_count < TARGET_CHAR_LENGTH * 0.8: # ๋ชฉํ‘œ์˜ 80% ๋ฏธ๋งŒ์ด๋ฉด ํ™•์žฅ
logging.info(f"๊ธ€์ž ์ˆ˜ ๋ถ€์กฑ ({char_count} < {TARGET_CHAR_LENGTH * 0.8}), ํ™•์žฅ ์‹œ๋„")
# ๊ฐ€์žฅ ๊ธด ์ฐธ๊ณ ๊ธ€ ์„ ํƒ
longest_ref = max(references, key=len)
expansion_prompt = f"""
[๋ธ”๋กœ๊ทธ ๊ธ€ ํ™•์žฅ ์š”์ฒญ]
์นดํ…Œ๊ณ ๋ฆฌ: {category}
ํฌ์ŠคํŒ… ์Šคํƒ€์ผ: {style}
์›๋ณธ ๊ธ€:
{processed_content}
์ฐธ๊ณ ๊ธ€:
{longest_ref}
๋ฌธ์ œ์ :
์ด ๊ธ€์€ ๋ชฉํ‘œ ๊ธ€์ž์ˆ˜์ธ {TARGET_CHAR_LENGTH}์ž์— ๋ฏธ์น˜์ง€ ๋ชปํ•ฉ๋‹ˆ๋‹ค. ํ˜„์žฌ ๊ธ€์ž์ˆ˜๋Š” ์•ฝ {char_count}์ž์ž…๋‹ˆ๋‹ค.
๋‚ด์šฉ์ด ๋ถ€์‹คํ•˜์—ฌ ํ™•์žฅ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.
{style_prompt}
[ํ™•์žฅ ์š”๊ตฌ์‚ฌํ•ญ]
1. ์›๋ณธ ๊ธ€์˜ ๊ตฌ์กฐ์™€ ์•„์›ƒ๋ผ์ธ์„ ์œ ์ง€ํ•˜๋ฉด์„œ ๊ฐ ์„น์…˜์˜ ๋‚ด์šฉ์„ ๋Œ€ํญ ํ™•์žฅํ•˜๋ผ.
2. ๊ฐ ์„น์…˜์— ๋” ๊ตฌ์ฒด์ ์ธ ์ •๋ณด, ์˜ˆ์‹œ, ์‚ฌ๋ก€, ํ†ต๊ณ„ ๋“ฑ์„ ์ถ”๊ฐ€ํ•˜๋ผ.
3. ์ „์ฒด ๊ธ€์ž ์ˆ˜๋ฅผ ์ตœ์†Œ {TARGET_CHAR_LENGTH}์ž ์ด์ƒ ๋‹ฌ์„ฑํ•˜๋ผ.
4. ์Šคํƒ€์ผ๊ณผ ์–ด์กฐ๋Š” ์ผ๊ด€์„ฑ์„ ์œ ์ง€ํ•˜๋ผ.
5. ๋งˆํฌ๋‹ค์šด ํ˜•์‹(#, *, -, 1., 2. ๋“ฑ)์„ ์‚ฌ์šฉํ•˜์ง€ ๋ง๊ณ  ์ผ๋ฐ˜ ํ…์ŠคํŠธ๋กœ ์ž‘์„ฑํ•˜๋ผ.
6. ์†Œ์ œ๋ชฉ๊ณผ ๊ฒฐ๋ก ์€ ๋ฒˆํ˜ธ ์—†์ด ์ผ๋ฐ˜ ๋ฌธ์žฅ ํ˜•ํƒœ๋กœ ์ž‘์„ฑํ•˜๋ผ.
7. ๋ชฉ๋ก์€ ๋ถˆ๋ฆฟ์ด๋‚˜ ๋ฒˆํ˜ธ ๋Œ€์‹  ์ž์—ฐ์Šค๋Ÿฌ์šด ๋ฌธ์žฅ์œผ๋กœ ์„œ์ˆ ํ•˜๋ผ.
8. "์ฐธ๊ณ ๊ธ€" ๊ด€๋ จ ํ‘œํ˜„์„ ์‚ฌ์šฉํ•˜์ง€ ๋ง๋ผ.
9. ๋ถ€์ž์—ฐ์Šค๋Ÿฌ์šด ๋ฐ˜๋ณต์ด๋‚˜ ๊ณผ์žฅ๋œ ํ‘œํ˜„์„ ํ”ผํ•˜๋ผ.
"""
# ํ™•์žฅ ์‹œ๋„
expanded_content = call_gemini_api(expansion_prompt, temperature=0.75)
processed_content = post_process_blog(expanded_content, style)
# ๋‹ค์‹œ ๊ธ€์ž ์ˆ˜ ์ฒดํฌ
temp_html = format_blog_post(processed_content)
char_count = len(extract_text_from_html(temp_html))
logging.info(f"ํ™•์žฅ ํ›„ ๋ธ”๋กœ๊ทธ ๊ธ€ ๊ธ€์ž ์ˆ˜: {char_count}")
# Phase 3: ์—ฌ์ „ํžˆ ๋ถ€์กฑํ•˜๋ฉด ์ถ”๊ฐ€ ํ™•์žฅ ์‹œ๋„
if char_count < TARGET_CHAR_LENGTH * 0.9: # ๋ชฉํ‘œ์˜ 90% ๋ฏธ๋งŒ์ด๋ฉด ์ถ”๊ฐ€ ํ™•์žฅ
logging.info(f"์—ฌ์ „ํžˆ ๊ธ€์ž ์ˆ˜ ๋ถ€์กฑ ({char_count} < {TARGET_CHAR_LENGTH * 0.9}), ์ถ”๊ฐ€ ํ™•์žฅ ์‹œ๋„")
additional_expansion_prompt = f"""
[๋ธ”๋กœ๊ทธ ๊ธ€ ์ถ”๊ฐ€ ํ™•์žฅ ์š”์ฒญ]
์นดํ…Œ๊ณ ๋ฆฌ: {category}
ํฌ์ŠคํŒ… ์Šคํƒ€์ผ: {style}
์›๋ณธ ๊ธ€:
{processed_content}
๋ฌธ์ œ์ :
์ด ๊ธ€์€ ์—ฌ์ „ํžˆ ๋ชฉํ‘œ ๊ธ€์ž์ˆ˜์ธ {TARGET_CHAR_LENGTH}์ž์— ๋ฏธ์น˜์ง€ ๋ชปํ•ฉ๋‹ˆ๋‹ค. ํ˜„์žฌ ๊ธ€์ž์ˆ˜๋Š” ์•ฝ {char_count}์ž์ž…๋‹ˆ๋‹ค.
[์ถ”๊ฐ€ ํ™•์žฅ ์š”๊ตฌ์‚ฌํ•ญ]
1. ๋ณธ๋ก  ๋ถ€๋ถ„์„ ์ค‘์‹ฌ์œผ๋กœ ์„ธ๋ถ€ ๋‚ด์šฉ์„ ํฌ๊ฒŒ ํ™•์žฅํ•˜๋ผ.
2. ๊ฐ ๊ฐœ๋…์— ๋Œ€ํ•œ ๋” ๊นŠ์€ ์„ค๋ช…๊ณผ ์‹ค์šฉ์ ์ธ ์ ์šฉ ๋ฐฉ๋ฒ•์„ ์ถ”๊ฐ€ํ•˜๋ผ.
3. ๋…์ž์—๊ฒŒ ์œ ์šฉํ•œ ํ•ต์‹ฌ ์ •๋ณด์™€ ์ธ์‚ฌ์ดํŠธ๋ฅผ ๋” ํ’๋ถ€ํ•˜๊ฒŒ ์ œ๊ณตํ•˜๋ผ.
4. ์ „์ฒด ๊ธ€์ž ์ˆ˜๋ฅผ ์ตœ์†Œ {TARGET_CHAR_LENGTH}์ž ์ด์ƒ์œผ๋กœ ํ™•์žฅํ•˜๋ผ.
5. ์Šคํƒ€์ผ๊ณผ ์–ด์กฐ์˜ ์ผ๊ด€์„ฑ์„ ์œ ์ง€ํ•˜๋ผ.
6. ๋ฐ˜๋ณต๋˜๋Š” ๋‚ด์šฉ์ด๋‚˜ ์ค‘๋ณต์€ ํ”ผํ•˜๋ผ.
"""
# ์ถ”๊ฐ€ ํ™•์žฅ ์‹œ๋„
further_expanded_content = call_gemini_api(additional_expansion_prompt, temperature=0.8)
processed_content = post_process_blog(further_expanded_content, style)
# ์ตœ์ข… HTML ๋ณ€ํ™˜
final_html = format_blog_post(processed_content)
# ์ตœ์ข… ๊ธ€์ž ์ˆ˜ ๊ณ„์‚ฐ
final_char_count = len(extract_text_from_html(final_html))
logging.info(f"์ตœ์ข… ๋ธ”๋กœ๊ทธ ๊ธ€ ๊ธ€์ž ์ˆ˜: {final_char_count}")
return final_html, final_char_count
except Exception as e:
logging.error(f"๋ธ”๋กœ๊ทธ ๊ธ€ ์ƒ์„ฑ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: {str(e)}")
return f"<p>๋ธ”๋กœ๊ทธ ๊ธ€ ์ƒ์„ฑ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: {str(e)}</p>", 0
def format_filename(text):
text = re.sub(r'[^\w\s-]', '', text)
return text[:50].strip()
# API ํ•จ์ˆ˜๋“ค (์ฒซ ๋ฒˆ์งธ ํŒŒ์ผ์˜ API ์—”๋“œํฌ์ธํŠธ์™€ ์ •ํ™•ํžˆ ์ผ์น˜ํ•˜๋„๋ก ์ž‘์„ฑ)
def generate_outline_1(category, style, ref1, ref2, ref3):
"""API endpoint: /generate_outline_1"""
return generate_outline(category, style, ref1, ref2, ref3)
def generate_blog_post_1(category, style, ref1, ref2, ref3, outline):
"""API endpoint: /generate_blog_post_1"""
result = generate_blog_post(category, style, outline, ref1, ref2, ref3)
return result[0] # ํŠœํ”Œ์ด๋ฏ€๋กœ ์ฒซ ๋ฒˆ์งธ ์š”์†Œ(HTML)๋งŒ ๋ฐ˜ํ™˜