kmkm_1 / app.py
whispersound's picture
Update app.py
c1f7b85 verified
raw
history blame
28.9 kB
import gradio as gr
import random
import os
import re
import openai
import textwrap
from fpdf import FPDF
from datetime import datetime
from zoneinfo import ZoneInfo
from sklearn.feature_extraction.text import CountVectorizer
from weasyprint import HTML, CSS
from weasyprint.fonts import FontConfiguration
import tempfile
from bs4 import BeautifulSoup
# OpenAI API ํด๋ผ์ด์–ธํŠธ ์„ค์ •
openai.api_key = os.getenv("OPENAI_API_KEY")
def call_api(content, system_message, max_tokens, temperature, top_p, previous_messages=None):
try:
if previous_messages is None:
previous_messages = []
messages = []
if system_message:
messages.append({"role": "system", "content": system_message})
messages.extend(previous_messages)
messages.append({"role": "user", "content": content})
response = openai.ChatCompletion.create(
model="gpt-4o-mini",
messages=messages,
max_tokens=max_tokens,
temperature=temperature,
top_p=top_p,
request_timeout=50
)
return response.choices[0].message['content']
except Exception as e:
print(f"API ํ˜ธ์ถœ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: {str(e)}")
raise
def analyze_info(data):
return f"์„ ํƒํ•œ ์นดํ…Œ๊ณ ๋ฆฌ: {data['category']}\n์„ ํƒํ•œ ํฌ์ŠคํŒ… ์Šคํƒ€์ผ: {data['style']}\n์ฐธ๊ณ  ๊ธ€1: {data['references1']}\n์ฐธ๊ณ  ๊ธ€2: {data['references2']}\n์ฐธ๊ณ  ๊ธ€3: {data['references3']}"
def suggest_title(category, style, references1, references2, references3):
data = {
'category': category,
'style': style,
'references1': references1,
'references2': references2,
'references3': references3
}
full_content = analyze_info(data)
system_prompt = get_title_prompt(data['category']) + "\n\n" + get_style_prompt(data['style'])
modified_text = call_api(full_content, system_prompt, 1500, 0.75, 0.95)
return modified_text
def generate_outline(category, style, references1, references2, references3, title):
data = {
'category': category,
'style': style,
'references1': references1,
'references2': references2,
'references3': references3,
'title': title
}
full_content = analyze_info(data)
content = f"{full_content}\nTitle: {data['title']}"
system_prompt = get_outline_prompt(data['category']) + "\n\n" + get_style_prompt(data['style'])
modified_text = call_api(content, system_prompt, 2000, 0.7, 0.95)
return modified_text
def remove_unwanted_phrases(text):
unwanted_phrases = [
'์—ฌ๋Ÿฌ๋ถ„', '์ตœ๊ทผ', '๋งˆ์ง€๋ง‰์œผ๋กœ', '๊ฒฐ๋ก ์ ์œผ๋กœ', '๊ฒฐ๊ตญ',
'์ข…ํ•ฉ์ ์œผ๋กœ', '๋”ฐ๋ผ์„œ', '๋งˆ๋ฌด๋ฆฌ', '์š”์•ฝ'
]
words = re.findall(r'\S+|\n', text)
result_words = [word for word in words if not any(phrase in word for phrase in unwanted_phrases)]
return ' '.join(result_words).replace(' \n ', '\n').replace(' \n', '\n').replace('\n ', '\n')
def extract_keywords(text, top_n=5):
vectorizer = CountVectorizer(stop_words='english', ngram_range=(1,2))
count_matrix = vectorizer.fit_transform([text])
terms = vectorizer.get_feature_names_out()
counts = count_matrix.sum(axis=0).A1
term_counts = sorted(zip(terms, counts), key=lambda x: x[1], reverse=True)
return [term for term, count in term_counts[:top_n]]
def get_group_instruction(group_index):
instructions = [
"""
**์ „์ฒด ์ฝ˜ํ…์ธ ๋ฅผ ์ƒ์„ฑํ•˜๊ธฐ ์œ„ํ•œ ์•„์›ƒ๋ผ์ธ ์„น์…˜์˜ ์ผ๋ถ€์ด๋‹ค.**
1. ์ฃผ์–ด์ง„ ์•„์›ƒ๋ผ์ธ 1๊ทธ๋ฃน์˜ ์ฒซ๋ฒˆ์งธ์ค„์€ ๋„์ž…๋ถ€์ด๋‹ค.
2. ๋ฐ˜๋“œ์‹œ ๋„์ž…๋ถ€์— ๋Œ€ํ•ด์„œ๋งŒ ๊ฐ„๋žตํ•˜๊ฒŒ ์ž‘์„ฑํ•˜๋ผ.
3. ๋„์ž…๋ถ€์—์„œ๋Š” ์ฃผ์ œ๋ฅผ ์†Œ๊ฐœํ•˜๊ณ , ๋…์ž์˜ ๊ด€์‹ฌ์„ ๋Œ์–ด์•ผ ํ•œ๋‹ค(๋ฐ˜๋“œ์‹œ 200์ž ์ด๋‚ด๋กœ ์ž‘์„ฑ)
4. ์ฃผ์–ด์ง„ ์•„์›ƒ๋ผ์ธ 1๊ทธ๋ฃน์˜ ๋‘๋ฒˆ์งธ์ค„์€ ๋ณธ๋ฌธ1 ์ด๋‹ค.
5. ๋ฐ˜๋“œ์‹œ ๋ณธ๋ฌธ1๋กœ์„œ๋งŒ ์ž‘์„ฑํ•˜๋ผ.
6. ๋ฐ˜๋“œ์‹œ ๋‹ค์Œ ์„น์…˜์œผ๋กœ์˜ ์ „ํ™˜์„ ์—ผ๋‘์— ๋‘๊ณ  ์ž‘์„ฑํ•˜๋˜, ํ˜„์žฌ ์„น์…˜์„ ์™„์ „ํžˆ ๋งˆ๋ฌด๋ฆฌํ•˜์ง€ ๋ง ๊ฒƒ.
7. ๋ณธ๋ฌธ1 ์ฃผ์ œ์˜ ๋‚ด์šฉ์„ ์ƒ์„ธ ๋‹ด์•„ ์•ฝ 190๋‹จ์–ด๋กœ ์ž‘์„ฑํ•˜๋ผ.
""",
"""
**์ „์ฒด ์ฝ˜ํ…์ธ ๋ฅผ ์ƒ์„ฑํ•˜๊ธฐ ์œ„ํ•œ ์•„์›ƒ๋ผ์ธ ์„น์…˜์˜ ์ผ๋ถ€์ด๋‹ค.**
1. ์ฃผ์–ด์ง„ ์•„์›ƒ๋ผ์ธ 2๊ทธ๋ฃน์€ ๋ชจ๋‘ ๋ณธ๋ก (๋ณธ๋ก 2~4)์ด๋‹ค.
2. ๋ฐ˜๋“œ์‹œ ๋ณธ๋ก ์˜ ํ˜•ํƒœ๋กœ๋งŒ ๋‚ด์šฉ๊ณผ ์ •๋ณด๋ฅผ ๋งค์šฐ ์ž์„ธํ•˜๊ฒŒ ์ž‘์„ฑํ•˜๋ผ.
3. ์ด์ „ ์„น์…˜์—์„œ ์ œ์‹œ๋œ ๋‚ด์šฉ๊ณผ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ์—ฐ๊ฒฐ๋˜๊ฒŒ ํ๋ฆ„์„ ์œ ์ง€ํ•˜๋ผ.
4. ๋ฐ˜๋“œ์‹œ ๊ฒฐ๋ก ์œผ๋กœ ๋„˜์–ด๊ฐ€์ง€ ์•Š๋„๋ก ์ฃผ์˜ํ•˜๋ผ.
5. ๋ฐ˜๋“œ์‹œ ๊ฐ ์„น์…˜๋ณ„ ์ฃผ์ œ์— ๋งž๋Š” ๋‚ด์šฉ์œผ๋กœ๋กœ ์•ฝ 280~330๋‹จ์–ด๋กœ ์ž‘์„ฑํ•˜๋ผ.
""",
"""
**์ „์ฒด ์ฝ˜ํ…์ธ ๋ฅผ ์ƒ์„ฑํ•˜๊ธฐ ์œ„ํ•œ ์•„์›ƒ๋ผ์ธ ์„น์…˜์˜ ์ผ๋ถ€์ด๋‹ค.**
1. ์ฃผ์–ด์ง„ ์•„์›ƒ๋ผ์ธ 3๊ทธ๋ฃน์˜ ์ฒซ๋ฒˆ์งธ์ค„์€ ๋ณธ๋ก 5(๋งˆ์ง€๋ง‰ ๋ณธ๋ก )์ด๋‹ค.
2. ๋ฐ˜๋“œ์‹œ ๋ณธ๋ก ์˜ ํ˜•ํƒœ๋กœ๋งŒ ์ž‘์„ฑํ•˜๋ผ.
3. ๋ณธ๋ก ์€ ๋ฐ˜๋“œ์‹œ 190๋‹จ์–ด ์ดํ•˜๋กœ ์ž‘์„ฑํ•˜๋ผ.
4. ์ฃผ์–ด์ง„ ์•„์›ƒ๋ผ์ธ 3๊ทธ๋ฃน์˜ ๋‘๋ฒˆ์งธ์ค„์€ ์ „์ฒด ์ฝ˜ํ…์ธ ์˜ ๊ฒฐ๋ก ๋ถ€์ด๋‹ค.
5. ๋ฐ˜๋“œ์‹œ ๊ฒฐ๋ก ์˜ ํ˜•ํƒœ๋กœ๋งŒ ์ž‘์„ฑํ•˜๋ผ(์ธ์‚ฌ๋ง ๊ธˆ์ง€)
6. ๋ฐ˜๋“œ์‹œ ๊ฒฐ๋ก ์—์„œ๋Š” ์ „์ฒด ๋‚ด์šฉ์„ ์š”์•ฝํ•˜๊ณ  ์ตœ์ข… ๋ฉ”์‹œ์ง€๋ฅผ ์ „๋‹ฌํ•˜๋ผ.
7. ๊ฒฐ๋ก ์€ 200์ž ์ด๋‚ด๋กœ ์ž‘์„ฑํ•˜๋ผ.
"""
]
return instructions[group_index]
def generate_blog_post(category, style, references1, references2, references3, title, outline):
try:
data = {
'category': category,
'style': style,
'references1': references1,
'references2': references2,
'references3': references3,
'title': title,
'outline': outline
}
system_prompt = get_blog_post_prompt(data['category'])
style_prompt = get_style_prompt(data['style'])
outline_sections = data['outline'].split('\n')
grouped_sections = [
outline_sections[:2], # ๋„์ž…๋ถ€ + ๋ณธ๋ฌธ1
outline_sections[2:5], # ๋ณธ๋ฌธ2 + ๋ณธ๋ฌธ3 + ๋ณธ๋ฌธ4
outline_sections[5:] # ๋ณธ๋ฌธ5 + ๊ฒฐ๋ก 
]
sections = []
previous_content = ""
previous_messages = []
for i, section_group in enumerate(grouped_sections):
print(f"์„น์…˜ ๊ทธ๋ฃน {i+1}/{len(grouped_sections)} ์ƒ์„ฑ ์ค‘...")
max_tokens = [1000, 5000, 1000][i]
group_instruction = get_group_instruction(i)
user_prompt = f"""
์นดํ…Œ๊ณ ๋ฆฌ: {data['category']}
ํฌ์ŠคํŒ… ์Šคํƒ€์ผ: {data['style']}
์ฐธ๊ณ ๊ธ€1: {data['references1']}
์ฐธ๊ณ ๊ธ€2: {data['references2']}
์ฐธ๊ณ ๊ธ€3: {data['references3']}
ํ˜„์žฌ ์„น์…˜ ๊ทธ๋ฃน: {' / '.join(section_group)}
์ด์ „ ์„น์…˜์˜ ๋งˆ์ง€๋ง‰ ๋‚ด์šฉ: {previous_content}
์œ„์˜ ์ •๋ณด๋ฅผ ๋ฐ”ํƒ•์œผ๋กœ '{' / '.join(section_group)}' ์„น์…˜ ๊ทธ๋ฃน์˜ ๋‚ด์šฉ์„ ์ž‘์„ฑํ•˜๋˜, ๋‹ค์Œ ์ง€์นจ์„ ๋ฐ˜๋“œ์‹œ ์ค€์ˆ˜ํ•˜๋ผ:
1. {group_instruction}
2. ์ „์ฒด ์•„์›ƒ๋ผ์ธ์˜ ํ๋ฆ„์„ ๊ณ ๋ คํ•˜์—ฌ ์ผ๊ด€์„ฑ ์žˆ๊ฒŒ ์ž‘์„ฑ.
3. ๋ฐ˜๋“œ์‹œ ์ฐธ๊ณ ๊ธ€์˜ ๋‚ด์šฉ์„ ๋ฐ”ํƒ•์œผ๋กœ ๊ตฌ์„ฑํ•˜๋˜, ํ‘œํ˜„์„ ๊ทธ๋Œ€๋กœ ๋ณต์‚ฌํ•˜์ง€ ๋ง ๊ฒƒ.
4. ๊ฐ ์„น์…˜์˜ ์ฃผ์š” ๋‚ด์šฉ์„ ์ถฉ๋ถ„ํžˆ ๋‹ค๋ฃจ๋˜, ์ „์ฒด ๊ธ€์˜ ํ๋ฆ„์„ ํ•ด์น˜์ง€ ์•Š๋„๋ก ์ฃผ์˜.
5. ์ด์ „ ์„น์…˜๊ณผ์˜ ์—ฐ๊ฒฐ๋ถ€๋ถ„์„ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ์ด์–ด์ง€๋„๋ก ์ž‘์„ฑ.
6. ๊ฐ ์„น์…˜์˜ ์ œ๋ชฉ์„ ์ž‘์„ฑํ•˜๋ผ.
"""
try:
section_content = call_api(
user_prompt,
system_prompt + "\n" + style_prompt,
max_tokens,
0.7,
0.95,
previous_messages=previous_messages
)
sections.append(section_content)
lines = section_content.splitlines()
previous_content = "\n".join(lines[-2:])
previous_messages.append({"role": "user", "content": user_prompt})
previous_messages.append({"role": "assistant", "content": section_content})
except Exception as e:
print(f"์„น์…˜ ๊ทธ๋ฃน {i+1} ์ƒ์„ฑ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: {str(e)}")
sections.append(f"์„น์…˜ ๊ทธ๋ฃน {i+1} ์ƒ์„ฑ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ")
full_post = data['title'] + "\n\n" + "\n\n".join(sections)
print(f"GPT๊ฐ€ ์ƒ์„ฑํ•œ ์›๋ณธ ๋ธ”๋กœ๊ทธ ๊ธ€:\n{full_post}")
filtered_post = remove_unwanted_phrases(full_post)
filtered_post = filtered_post.lstrip()
# HTML๋กœ ๋ณ€ํ™˜
html_post = convert_to_html(filtered_post)
return html_post
except Exception as e:
print(f"๋ธ”๋กœ๊ทธ ํฌ์ŠคํŠธ ์ƒ์„ฑ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: {str(e)}")
import traceback
traceback.print_exc()
return ""
def convert_to_html(text):
soup = BeautifulSoup('<div class="blog-post"></div>', 'html.parser')
main_div = soup.find('div', class_='blog-post')
lines = text.split('\n')
for line in lines:
line = line.strip()
if line.startswith('# '):
main_div.append(soup.new_tag('h1'))
main_div.h1.string = line[2:]
elif line.startswith('## '):
main_div.append(soup.new_tag('h2'))
main_div.h2.string = line[3:]
elif line.startswith('### '):
main_div.append(soup.new_tag('h3'))
main_div.h3.string = line[4:]
elif line.startswith('- '):
if not main_div.find_all('ul'):
main_div.append(soup.new_tag('ul'))
li = soup.new_tag('li')
li.string = line[2:]
main_div.ul.append(li)
else:
p = soup.new_tag('p')
p.string = line
main_div.append(p)
return str(soup)
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 get_title_prompt(category):
if (category == "์ผ๋ฐ˜"):
return """
์ œ๋ชฉ ์ถ”์ฒœ์€ ์‚ฌ์šฉํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
"""
elif (category == "์ƒํ™œ๊ฑด๊ฐ•"):
return """
์ œ๋ชฉ ์ถ”์ฒœ์€ ์‚ฌ์šฉํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
"""
def get_outline_prompt(category):
if (category == "์ผ๋ฐ˜"):
return """
[์ƒํ’ˆ๋ฆฌ๋ทฐ ์†Œ์ฃผ์ œ(Outline) ์ƒ์„ฑ ๊ทœ์น™]
[๊ธฐ๋ณธ๊ทœ์น™]
1. ๋ฐ˜๋“œ์‹œ ํ•œ๊ตญ์–ด(ํ•œ๊ธ€)๋กœ ์ž‘์„ฑํ•˜๋ผ
2. ๋„ˆ๋Š” ๊ฐ€์žฅ ์ฃผ๋ชฉ๋ฐ›๋Š” ์ „๋ฌธ ๋ธ”๋กœ๊ฑฐ ๋งˆ์ผ€ํ„ฐ์ด๋‹ค.
3. ๋งˆ์ผ€ํ„ฐ๋กœ์„œ ์ •๋ณด์ œ๊ณต๊ณผ ๋งˆ์ผ€ํŒ…์— ์ดˆ์ ์„ ๋งž์ถฐ ์ž‘์„ฑํ•˜๋ผ.
5. ๋ฐ˜๋“œ์‹œ ๋งˆํฌ๋‹ค์šด ํ˜•์‹์ด ์•„๋‹Œ ์ˆœ์ˆ˜ํ•œ ํ…์ŠคํŠธ๋กœ ์ถœ๋ ฅํ•˜๋ผ
[์•„์›ƒ๋ผ์ธ ์ž‘์„ฑ ๊ทœ์น™]
1. ๋ธ”๋กœ๊ทธ ๊ธ€์„ ์ž‘์„ฑํ•˜๊ธฐ ์œ„ํ•œ ์†Œ์ฃผ์ œ(์„น์…˜)๋งŒ์„ ์ž‘์„ฑํ•˜๋ผ
2. ๋ฐ˜๋“œ์‹œ ์ž…๋ ฅ๋œ ์ฐธ๊ณ ๊ธ€๊ณผ ๋ธ”๋กœ๊ทธ ์ฃผ์ œ, ์ œ๋ชฉ์„ ๋ฐ”ํƒ•์œผ๋กœ ํ•ต์‹ฌ ์ฃผ์ œ๋ฅผ ํŒŒ์•…ํ•˜์—ฌ ์†Œ์ฃผ์ œ(์„น์…˜)๋ฅผ ๊ตฌ์„ฑํ•˜๋ผ
3. ์ „์ฒด ๋งฅ๋ฝ์— ๋งž๊ฒŒ ์†Œ์ฃผ์ œ(์„น์…˜)๋ฅผ ์ž‘์„ฑ
4. ๋ฐ˜๋“œ์‹œ ์†Œ์ œ๋ชฉ์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก 30์ž ์ด๋‚ด๋กœ ์ž‘์„ฑํ•˜๋ผ
5. ์ฐธ๊ณ ๊ธ€์„ ๋ถ„์„ํ•˜์—ฌ ๋…์ž๊ฐ€ ์–ป๊ณ ์ž ํ•˜๋Š” ํฅ๋ฏธ๋กœ์šด ์ •๋ณด, ๋„์›€์ด ๋˜๋Š” ์ •๋ณด๋ฅผ ์ œ๊ณตํ•˜๋„๋ก ์†Œ์ฃผ์ œ๋ฅผ ์ž‘์„ฑํ•˜๋ผ.
6. ๋ฐ˜๋“œ์‹œ [์†Œ์ฃผ์ œ ๊ตฌ์„ฑ]์— ๋งž๊ฒŒ ์†Œ์ฃผ์ œ๋งŒ ์ถœ๋ ฅํ•˜๋ผ
[์•„์›ƒ๋ผ์ธ ๊ตฌ์„ฑ]
1. ๋ฐ˜๋“œ์‹œ [๋„์ž…๋ถ€]-1๊ฐœ, [๋ณธ๋ก ]-5๊ฐœ, [๊ฒฐ๋ก ]-1๊ฐœ๋กœ ๊ตฌ์„ฑํ•˜์—ฌ ์ถœ๋ ฅํ•˜๋ผ
2. ๋ฐ˜๋“œ์‹œ [๋„์ž…๋ถ€]์™€ [๊ฒฐ๋ก ]์˜ ์ œ๋ชฉ์ด ์ค‘๋ณต๋˜์ง€ ์•Š๋„๋ก ์ž‘์„ฑํ•˜๋ผ
์ถœ๋ ฅ์˜ˆ์‹œ:
- ๋„์ž…๋ถ€: ์ œ๋ชฉ
- ๋ณธ๋ก 1: ์ œ๋ชฉ
...
- ๋ณธ๋ก 5: ์ œ๋ชฉ
- ๊ฒฐ๋ก : ์ œ๋ชฉ
"""
elif (category == "์ƒํ™œ๊ฑด๊ฐ•"):
return """
[์ƒํ’ˆ๋ฆฌ๋ทฐ ์†Œ์ฃผ์ œ(Outline) ์ƒ์„ฑ ๊ทœ์น™]
[๊ธฐ๋ณธ๊ทœ์น™]
1. ๋ฐ˜๋“œ์‹œ ํ•œ๊ตญ์–ด(ํ•œ๊ธ€)๋กœ ์ž‘์„ฑํ•˜๋ผ
2. ๋„ˆ๋Š” ๊ฐ€์žฅ ์ฃผ๋ชฉ๋ฐ›๋Š” '์ƒํ™œ๊ฑด๊ฐ•' ์ „๋ฌธ ๋ธ”๋กœ๊ฑฐ ๋งˆ์ผ€ํ„ฐ์ด๋‹ค.
3. ๋ฐ˜๋“œ์‹œ ์ƒํ™œ๊ฑด๊ฐ• ์ธก๋ฉด์—์„œ ์‹ค์šฉ์ ์ธ ์ •๋ณด ์ œ๊ณต์— ์ดˆ์ ์„ ๋งž์ถฐ ์ž‘์„ฑํ•˜๋ผ.
4. ๋ฐ˜๋“œ์‹œ ๋งˆํฌ๋‹ค์šด ํ˜•์‹์ด ์•„๋‹Œ ์ˆœ์ˆ˜ํ•œ ํ…์ŠคํŠธ๋กœ ์ถœ๋ ฅํ•˜๋ผ
[์•„์›ƒ๋ผ์ธ ์ž‘์„ฑ ๊ทœ์น™]
1. ๋ธ”๋กœ๊ทธ ๊ธ€์„ ์ž‘์„ฑํ•˜๊ธฐ ์œ„ํ•œ ์†Œ์ฃผ์ œ(์„น์…˜)๋งŒ์„ ์ž‘์„ฑํ•˜๋ผ
2. ๋ฐ˜๋“œ์‹œ ์ž…๋ ฅ๋œ ์ฐธ๊ณ ๊ธ€๊ณผ ๋ธ”๋กœ๊ทธ ์ฃผ์ œ, ์ œ๋ชฉ์„ ๋ฐ”ํƒ•์œผ๋กœ ํ•ต์‹ฌ ์ฃผ์ œ๋ฅผ ํŒŒ์•…ํ•˜์—ฌ ์†Œ์ฃผ์ œ(์„น์…˜)๋ฅผ ๊ตฌ์„ฑํ•˜๋ผ
3. ์ „์ฒด ๋งฅ๋ฝ์— ๋งž๊ฒŒ ์†Œ์ฃผ์ œ(์„น์…˜)๋ฅผ ์ž‘์„ฑ
4. ๋ฐ˜๋“œ์‹œ ์†Œ์ œ๋ชฉ์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก 30์ž ์ด๋‚ด๋กœ ์ž‘์„ฑํ•˜๋ผ
5. ์ฐธ๊ณ ๊ธ€์„ ๋ถ„์„ํ•˜์—ฌ ๋…์ž๊ฐ€ ์–ป๊ณ ์ž ํ•˜๋Š” ์ƒํ’ˆ์˜ ๊ธฐ๋Šฅ ์ค‘์—์„œ ํฅ๋ฏธ๋กญ๊ณ  ์‹ค์šฉ์ ์ธ ์ •๋ณด๋ฅผ ์ œ๊ณตํ•˜๋„๋ก ์†Œ์ฃผ์ œ๋ฅผ ์ž‘์„ฑํ•˜๋ผ.
6. ํ•„์š”ํ•œ ๊ฒฝ์šฐ ์—ฐ๊ตฌ ๊ฒฐ๊ณผ๋‚˜ ํ†ต๊ณ„๋“ฑ์„ ์ ์ ˆํžˆ ํ™œ์šฉํ•˜๋ผ
7. ๊ฐœ์ธ์˜ ๊ฒฝํ—˜์ด๋‚˜ ์‚ฌ๋ก€๋ฅผ ์ ์ ˆํžˆ ํ™œ์šฉํ•˜๋ผ
8. ๋ฌธ์ œ์— ๋Œ€ํ•œ ์›์ธ, ์ฆ์ƒ, ์˜ˆ๋ฐฉ ๋˜๋Š” ์น˜๋ฃŒ ๋ฐฉ๋ฒ•์— ๋Œ€ํ•œ ์‹ค์šฉ์ ์ธ ์ •๋ณด๋ฅผ ํฌํ•จํ•˜๋ผ
9. ์ „๋ฌธ์ ์ธ ์šฉ์–ด๋Š” ์ ์ ˆํ•œ ์„ค๋ช…๊ณผ ์‰ฌ์šด ์–ดํœ˜๋กœ ๋ณด์ถฉํ•˜๋ผ
10. ๋ฐ˜๋“œ์‹œ [์†Œ์ฃผ์ œ ๊ตฌ์„ฑ]์— ๋งž๊ฒŒ ์†Œ์ฃผ์ œ๋งŒ ์ถœ๋ ฅํ•˜๋ผ
[์•„์›ƒ๋ผ์ธ ๊ตฌ์„ฑ]
1. ๋ฐ˜๋“œ์‹œ [๋„์ž…๋ถ€]-1๊ฐœ, [๋ณธ๋ก ]-5๊ฐœ, [๊ฒฐ๋ก ]-1๊ฐœ๋กœ ๊ตฌ์„ฑํ•˜์—ฌ ์ถœ๋ ฅํ•˜๋ผ
2. ๋ฐ˜๋“œ์‹œ [๋„์ž…๋ถ€]์™€ [๊ฒฐ๋ก ]์˜ ์ œ๋ชฉ์ด ์ค‘๋ณต๋˜์ง€ ์•Š๋„๋ก ์ž‘์„ฑํ•˜๋ผ
์ถœ๋ ฅ์˜ˆ์‹œ:
- ๋„์ž…๋ถ€: ์ œ๋ชฉ
- ๋ณธ๋ก 1: ์ œ๋ชฉ
...
- ๋ณธ๋ก 5: ์ œ๋ชฉ
- ๊ฒฐ๋ก : ์ œ๋ชฉ
"""
def get_blog_post_prompt(category):
if (category == "์ผ๋ฐ˜"):
return """
[์ƒํ’ˆ๋ฆฌ๋ทฐ ์ฝ˜ํ…์ธ  ์ƒ์„ฑ ๊ทœ์น™]
[๊ธฐ๋ณธ๊ทœ์น™]
1. ๋ฐ˜๋“œ์‹œ ํ•œ๊ตญ์–ด(ํ•œ๊ธ€)๋กœ ์ž‘์„ฑํ•˜๋ผ
2. ๋„ˆ๋Š” ์ „๋ฌธ์ ์ธ ์ฝ˜ํ…์ธ  ์ž‘๊ฐ€์ด๋‹ค. ์ฃผ์–ด์ง„ ์ฃผ์ œ์— ๋Œ€ํ•ด ํ’๋ถ€ํ•˜๊ณ  ๋งค๋ ฅ์ ์ธ ๋‚ด์šฉ์„ ์ž‘์„ฑํ•˜๋ผ
3. ๊ฐ ์„น์…˜์„ ๋…๋ฆฝ์ ์ธ ์ •๋ณด ๋‹จ์œ„๋กœ ์ทจ๊ธ‰ํ•˜๋ผ
4. ๋‹ค๋ฅธ ์„น์…˜๊ณผ์˜ ์—ฐ๊ฒฐ์„ฑ์„ ๊ณ ๋ คํ•˜๋˜, ๊ฐ ์„น์…˜์ด ๋…๋ฆฝ์ ์œผ๋กœ๋„ ์ดํ•ด๋  ์ˆ˜ ์žˆ๊ฒŒ ์ž‘์„ฑํ•˜๋ผ
5. ์ด ์„น์…˜์€ ๋” ํฐ ์ฝ˜ํ…์ธ ์˜ ์ผ๋ถ€์ž„์„ ๋ช…์‹ฌํ•˜๋ผ, ์ „์ฒด์ ์ธ ํ๋ฆ„์„ ํ•ด์น˜์ง€ ์•Š์œผ๋ฉด์„œ ์ฃผ์–ด์ง„ ์ฃผ์ œ๋ฅผ ์ฒ ์ €ํžˆ ์ž‘์„ฑํ•˜๋ผ
[ํ…์ŠคํŠธ ์ž‘์„ฑ ๊ทœ์น™]
1. ๋ฐ˜๋“œ์‹œ ์ž…๋ ฅ๋œ ์†Œ์ฃผ์ œ(์•„์›ƒ๋ผ์ธ)์— ๋งž๊ฒŒ ๊ธ€์„ ์ž‘์„ฑํ•˜๋ผ
2. ๋ฐ˜๋“œ์‹œ ์ž…๋ ฅ๋œ ์ฐธ๊ณ ๊ธ€์˜ ๋‚ด์šฉ์œผ๋กœ๋งŒ ๊ตฌ์„ฑ
3. ์ „์ฒด ๋งฅ๋ฝ์„ ์ดํ•ดํ•˜๊ณ  ๋ฌธ์žฅ์˜ ์ผ๊ด€์„ฑ์„ ์œ ์ง€ํ•˜๋ผ
4. ์ œ๊ณต๋œ ์ฐธ๊ณ ๊ธ€์˜ ์–ดํˆฌ๋ฅผ ๋ฐ˜์˜ํ•˜๋˜, ์ ˆ๋Œ€๋กœ ํ•œ ๋ฌธ์žฅ ์ด์ƒ ๊ทธ๋Œ€๋กœ ์ถœ๋ ฅํ•˜์ง€ ๋ง ๊ฒƒ
5. ์‰ฝ๊ฒŒ ์ฝ์„ ์ˆ˜ ์žˆ๋„๋ก ์‰ฌ์šด ์–ดํœ˜๋กœ ์ž‘์„ฑ
6. ์ฐธ๊ณ ๊ธ€์„ ๊ธฐ๋ฐ˜์œผ๋กœ ๊ธ€์˜ ์ฃผ์ œ์™€ ์œ ์šฉํ•œ ์ •๋ณด๋ฅผ ํŒŒ์•…ํ•˜์—ฌ ์ž‘์„ฑ
7. ๋…์ž์—๊ฒŒ ๋„์›€์ด๋˜๊ณ  ์ด๋“์ด ๋˜๋Š” ์ •๋ณด๋ฅผ ์ž‘์„ฑ
8. ๋…์ž์˜ ๊ณต๊ฐ์„ ์–ป๊ณ  ๊ถ๊ธˆ์ฆ์„ ํ•ด๊ฒฐํ•˜๋„๋ก ์ž‘์„ฑ
"""
elif (category == "์ƒํ™œ๊ฑด๊ฐ•"):
return """
[์ƒํ’ˆ๋ฆฌ๋ทฐ ์ฝ˜ํ…์ธ  ์ƒ์„ฑ ๊ทœ์น™]
[๊ธฐ๋ณธ๊ทœ์น™]
1. ๋ฐ˜๋“œ์‹œ ํ•œ๊ตญ์–ด(ํ•œ๊ธ€)๋กœ ์ž‘์„ฑํ•˜๋ผ
2. ๋„ˆ๋Š” ์ „๋ฌธ์ ์ธ ์ƒํ™œ๊ฑด๊ฐ• ์ฝ˜ํ…์ธ  ์ž‘๊ฐ€์ด๋‹ค. ์ฃผ์–ด์ง„ ์ฃผ์ œ์— ๋Œ€ํ•ด ํ’๋ถ€ํ•˜๊ณ  ๋งค๋ ฅ์ ์ธ ๋‚ด์šฉ์„ ์ž‘์„ฑํ•˜๋ผ
3. ๊ฐ ์„น์…˜์„ ๋…๋ฆฝ์ ์ธ ์ •๋ณด ๋‹จ์œ„๋กœ ์ทจ๊ธ‰ํ•˜๋ผ
4. ๋‹ค๋ฅธ ์„น์…˜๊ณผ์˜ ์—ฐ๊ฒฐ์„ฑ์„ ๊ณ ๋ คํ•˜๋˜, ๊ฐ ์„น์…˜์ด ๋…๋ฆฝ์ ์œผ๋กœ๋„ ์ดํ•ด๋  ์ˆ˜ ์žˆ๊ฒŒ ์ž‘์„ฑํ•˜๋ผ
5. ์ด ์„น์…˜์€ ๋” ํฐ ์ฝ˜ํ…์ธ ์˜ ์ผ๋ถ€์ž„์„ ๋ช…์‹ฌํ•˜๋ผ, ์ „์ฒด์ ์ธ ํ๋ฆ„์„ ํ•ด์น˜์ง€ ์•Š์œผ๋ฉด์„œ ์ฃผ์–ด์ง„ ์ฃผ์ œ๋ฅผ ์ฒ ์ €ํžˆ ์ž‘์„ฑํ•˜๋ผ๋ผ
6. ๋ฐ˜๋“œ์‹œ ์ƒํ™œ๊ฑด๊ฐ• ๊ด€๋ จ ์ •๋ณด๋ฅผ ์ œ๊ณตํ•˜๋„๋ก ์ž‘์„ฑ
[ํ…์ŠคํŠธ ์ž‘์„ฑ ๊ทœ์น™]
1. ๋ฐ˜๋“œ์‹œ ์ž…๋ ฅ๋œ ์†Œ์ฃผ์ œ(์•„์›ƒ๋ผ์ธ)์— ๋งž๊ฒŒ ๊ธ€์„ ์ž‘์„ฑํ•˜๋ผ
2. ๋ฐ˜๋“œ์‹œ ์ž…๋ ฅ๋œ ์ฐธ๊ณ ๊ธ€์˜ ๋‚ด์šฉ์œผ๋กœ๋งŒ ๊ตฌ์„ฑ
3. ์ „์ฒด ๋งฅ๋ฝ์„ ์ดํ•ดํ•˜๊ณ  ๋ฌธ์žฅ์˜ ์ผ๊ด€์„ฑ์„ ์œ ์ง€ํ•˜๋ผ
4. ์ œ๊ณต๋œ ์ฐธ๊ณ ๊ธ€์˜ ์–ดํˆฌ๋ฅผ ๋ฐ˜์˜ํ•˜๋˜, ์ ˆ๋Œ€๋กœ ํ•œ ๋ฌธ์žฅ ์ด์ƒ ๊ทธ๋Œ€๋กœ ์ถœ๋ ฅํ•˜์ง€ ๋ง ๊ฒƒ
5. ์‰ฝ๊ฒŒ ์ฝ์„ ์ˆ˜ ์žˆ๋„๋ก ์‰ฌ์šด ์–ดํœ˜๋กœ ์ž‘์„ฑ
6. ๊ฐœ์ธ์˜ ๊ฒฝํ—˜์ด๋‚˜ ์‚ฌ๋ก€๋ฅผ ์ ์ ˆํžˆ ํ™œ์šฉํ•˜๋ผ
7. ๋ฌธ์ œ์— ๋Œ€ํ•œ ์›์ธ, ์ฆ์ƒ, ์˜ˆ๋ฐฉ ๋˜๋Š” ์น˜๋ฃŒ ๋ฐฉ๋ฒ•์— ๋Œ€ํ•œ ์‹ค์šฉ์ ์ธ ์ •๋ณด๋ฅผ ํฌํ•จํ•˜๋ผ
8. ์ „๋ฌธ์ ์ธ ์šฉ์–ด๋Š” ์ ์ ˆํ•œ ์„ค๋ช…๊ณผ ์‰ฌ์šด ์–ดํœ˜๋กœ ๋ณด์ถฉํ•˜๋ผ(ํ•„์š”์‹œ ์ถœ์ฒ˜๋ฅผ ํ‘œ๊ธฐํ•˜๋ผ)
"""
def get_style_prompt(style):
prompts = {
"์นœ๊ทผํ•œ": """
[์นœ๊ทผํ•œ ํฌ์ŠคํŒ… ์Šคํƒ€์ผ ๊ฐ€์ด๋“œ]
1. ํ†ค๊ณผ ์–ด์กฐ
- ๋Œ€ํ™”ํ•˜๋“ฏ ํŽธ์•ˆํ•˜๊ณ  ์นœ๊ทผํ•œ ๋งํˆฌ ์‚ฌ์šฉ
2. ๋ฌธ์žฅ ๋ฐ ์–ดํˆฌ
- ๋ฐ˜๋“œ์‹œ 'ํ•ด์š”์ฒด'๋กœ ์ž‘์„ฑ, ์ ˆ๋Œ€ '์Šต๋‹ˆ๋‹ค'์ฒด๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ๋ง ๊ฒƒ.
- '~์š”'๋กœ ๋๋‚˜๋„๋ก ์ž‘์„ฑ, '~๋‹ค'๋กœ ๋๋‚˜์ง€ ์•Š๊ฒŒ ํ•˜๋ผ
- ๊ตฌ์–ด์ฒด ํ‘œํ˜„ ์‚ฌ์šฉ (์˜ˆ: "~ํ–ˆ์–ด์š”", "~์ธ ๊ฒƒ ๊ฐ™์•„์š”")
3. ์šฉ์–ด ๋ฐ ์„ค๋ช… ๋ฐฉ์‹
- ์ „๋ฌธ ์šฉ์–ด ๋Œ€์‹  ์‰ฌ์šด ๋‹จ์–ด๋กœ ํ’€์–ด์„œ ์„ค๋ช…
- ๋น„์œ ๋‚˜ ์€์œ ๋ฅผ ํ™œ์šฉํ•˜์—ฌ ๋ณต์žกํ•œ ๊ฐœ๋… ์„ค๋ช…
- ์ˆ˜์‚ฌ์˜๋ฌธ๋ฌธ ํ™œ์šฉํ•˜์—ฌ ๋…์ž์™€ ์†Œํ†ตํ•˜๋Š” ๋Š๋‚Œ ์ฃผ๊ธฐ
์ฃผ์˜์‚ฌํ•ญ: ๋„ˆ๋ฌด ๊ฐ€๋ฒผ์šด ํ†ค์€ ์ง€์–‘ํ•˜๊ณ , ์ฃผ์ œ์˜ ์ค‘์š”์„ฑ์„ ํ•ด์น˜์ง€ ์•Š๋Š” ์„ ์—์„œ ์นœ๊ทผํ•จ ์œ ์ง€
(์˜ˆ์‹œ: ์ž‡๋‹˜๋“ค~ ์˜ค๋ ˆ์˜ค ์ฝ”์นด์ฝœ๋ผ๋ง›์ด์ƒˆ๋กœ ์ถœ์‹œ๊ฐ€ ๋๋‹ค๋Š”๊ฑฐ ์•Œ๊ณ  ๊ณ„์…จ๋‚˜์š”?!ใ…Ž ์˜ค๋ ˆ์˜ค ์ฝ”์นด์ฝœ๋ผ๋ง›์€ ์–ด๋–ค์ง€ ์†”์งํ‰๊ณผ๊ตฌ๋งค์ •๋ณด, ๊ฐ€๊ฒฉ, ์นผ๋กœ๋ฆฌ ๋“ฑ์— ๋Œ€ํ•ด ์ž์„ธ~ ํžˆ ์ ์–ด๋ณด๋„๋ก ํ• ๊ป˜์š”! ์˜ค๋ ˆ์˜ค๋ฅผ ์ข‹์•„ํ•˜๋Š” ์•„๋“ค์—๊ฒŒ๊ฐ„์‹์œผ๋กœ ์˜ค๋ ˆ์˜ค ์ฝ”์นด์ฝœ๋ผ๋ง›์„ ์คฌ๋”๋‹ˆ๋ง›์žˆ๋‹ค๊ณ  ์ข‹์•„ํ•˜๋”๋ผ๊ตฌ์š”. ์ฝœ๋ผํ–ฅ์ด ๋‚˜์„œ ๋” ๋งˆ์Œ์— ๋“ ๋‹ค๋ฉฐใ…Ž๊ฐœ์ธ์ ์œผ๋กœ๋Š” ๋ณ„ โญ๏ธโญ๏ธโญ๏ธ.์š”๊ฑด ๊ฐœ์ธ์ฐจ๊ฐ€ ์žˆ์„๊ฑฐ ๊ฐ™์•„์š”~)
""",
"์ผ๋ฐ˜": """
#์ผ๋ฐ˜์ ์ธ ๋ธ”๋กœ๊ทธ ํฌ์ŠคํŒ… ์Šคํƒ€์ผ ๊ฐ€์ด๋“œ
1. ํ†ค๊ณผ ์–ด์กฐ
- ์ค‘๋ฆฝ์ ์ด๊ณ  ๊ฐ๊ด€์ ์ธ ํ†ค ์œ ์ง€
- ์ ์ ˆํ•œ ์กด๋Œ“๋ง ์‚ฌ์šฉ (์˜ˆ: "~ํ•ฉ๋‹ˆ๋‹ค", "~์ž…๋‹ˆ๋‹ค")
2. ๋‚ด์šฉ ๊ตฌ์กฐ ๋ฐ ์ „๊ฐœ
- ๋ช…ํ™•ํ•œ ์ฃผ์ œ ์ œ์‹œ๋กœ ์‹œ์ž‘
- ๋…ผ๋ฆฌ์ ์ธ ์ˆœ์„œ๋กœ ์ •๋ณด ์ „๊ฐœ
- ์ฃผ์š” ํฌ์ธํŠธ๋ฅผ ๊ฐ•์กฐํ•˜๋Š” ์†Œ์ œ๋ชฉ ํ™œ์šฉ
- ์ ์ ˆํ•œ ๊ธธ์ด์˜ ๋‹จ๋ฝ์œผ๋กœ ๊ตฌ์„ฑ
3. ์šฉ์–ด ๋ฐ ์„ค๋ช… ๋ฐฉ์‹
- ์ผ๋ฐ˜์ ์œผ๋กœ ์ดํ•ดํ•˜๊ธฐ ์‰ฌ์šด ์šฉ์–ด ์„ ํƒ
- ํ•„์š”์‹œ ๊ฐ„๋‹จํ•œ ์„ค๋ช… ์ถ”๊ฐ€
- ๊ฐ๊ด€์ ์ธ ์ •๋ณด ์ œ๊ณต์— ์ค‘์ 
4. ํ…์ŠคํŠธ ๊ตฌ์กฐํ™”
- ๋ถˆ๋ฆฟ ํฌ์ธํŠธ๋‚˜ ๋ฒˆํ˜ธ ๋งค๊ธฐ๊ธฐ๋ฅผ ํ™œ์šฉํ•˜์—ฌ ์ •๋ณด ๊ตฌ์กฐํ™”
- ์ค‘์š”ํ•œ ์ •๋ณด๋Š” ๊ตต์€ ๊ธ€์”จ๋‚˜ ๊ธฐ์šธ์ž„๊ผด๋กœ ๊ฐ•์กฐ
5. ๋…์ž ์ƒํ˜ธ์ž‘์šฉ
- ์ ์ ˆํžˆ ๋…์ž์˜ ์ƒ๊ฐ์„ ๋ฌป๋Š” ์งˆ๋ฌธ ํฌํ•จ
- ์ถ”๊ฐ€ ์ •๋ณด๋ฅผ ์ฐพ์„ ์ˆ˜ ์žˆ๋Š” ํ‚ค์›Œ๋“œ ์ œ์‹œ
6. ๋งˆ๋ฌด๋ฆฌ
- ์ฃผ์š” ๋‚ด์šฉ ๊ฐ„๋‹จํžˆ ์š”์•ฝ
- ์ถ”๊ฐ€ ์ •๋ณด์— ๋Œ€ํ•œ ์•ˆ๋‚ด ์ œ๊ณต
์ฃผ์˜์‚ฌํ•ญ: ๋„ˆ๋ฌด ๋”ฑ๋”ฑํ•˜๊ฑฐ๋‚˜ ์ง€๋ฃจํ•˜์ง€ ์•Š๋„๋ก ๊ท ํ˜• ์œ ์ง€
์˜ˆ์‹œ: "์ตœ๊ทผ ํ™˜๊ฒฝ ๋ฌธ์ œ๊ฐ€ ๋Œ€๋‘๋˜๋ฉด์„œ '์ œ๋กœ ์›จ์ด์ŠคํŠธ' ๋ผ์ดํ”„์Šคํƒ€์ผ์— ๋Œ€ํ•œ ๊ด€์‹ฌ์ด ๋†’์•„์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์ œ๋กœ ์›จ์ด์ŠคํŠธ๋ž€ ์ผ์ƒ์ƒํ™œ์—์„œ ๋ฐœ์ƒํ•˜๋Š” ์“ฐ๋ ˆ๊ธฐ๋ฅผ ์ตœ์†Œํ™”ํ•˜๋Š” ์ƒํ™œ ๋ฐฉ์‹์„ ๋งํ•ฉ๋‹ˆ๋‹ค. ์ด ๊ธ€์—์„œ๋Š” ์ œ๋กœ ์›จ์ด์ŠคํŠธ์˜ ๊ฐœ๋…, ์‹ค์ฒœ ๋ฐฉ๋ฒ•, ๊ทธ๋ฆฌ๊ณ  ๊ทธ ํšจ๊ณผ์— ๋Œ€ํ•ด ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ๋จผ์ € ์ œ๋กœ ์›จ์ด์ŠคํŠธ์˜ ์ •์˜๋ถ€ํ„ฐ ์‚ดํŽด๋ณด๋ฉด...
""",
"์ „๋ฌธ์ ์ธ": """
#์ „๋ฌธ์ ์ธ ๋ธ”๋กœ๊ทธ ํฌ์ŠคํŒ… ์Šคํƒ€์ผ ๊ฐ€์ด๋“œ
1. ํ†ค๊ณผ ๊ตฌ์กฐ
- ๊ณต์‹์ ์ด๊ณ  ํ•™์ˆ ์ ์ธ ํ†ค ์‚ฌ์šฉ
- ๊ฐ๊ด€์ ์ด๊ณ  ๋ถ„์„์ ์ธ ์ ‘๊ทผ ์œ ์ง€
- ๋ช…ํ™•ํ•œ ์„œ๋ก , ๋ณธ๋ก , ๊ฒฐ๋ก  ๊ตฌ์กฐ
- ์ฒด๊ณ„์ ์ธ ๋…ผ์  ์ „๊ฐœ
- ์„ธ๋ถ€ ์„น์…˜์„ ์œ„ํ•œ ๋ช…ํ™•ํ•œ ์†Œ์ œ๋ชฉ ์‚ฌ์šฉ
2. ๋‚ด์šฉ ๊ตฌ์„ฑ ๋ฐ ์ „๊ฐœ
- ๋ณต์žกํ•œ ๊ฐœ๋…์„ ์ •ํ™•ํžˆ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ๋Š” ๋ฌธ์žฅ ๊ตฌ์กฐ ์‚ฌ์šฉ
- ๋…ผ๋ฆฌ์  ์—ฐ๊ฒฐ์„ ์œ„ํ•œ ์ „ํ™˜์–ด ํ™œ์šฉ
- ํ•ด๋‹น ๋ถ„์•ผ์˜ ์ „๋ฌธ ์šฉ์–ด ์ ๊ทน ํ™œ์šฉ (ํ•„์š”์‹œ ๊ฐ„๋žตํ•œ ์„ค๋ช… ์ œ๊ณต)
- ์‹ฌ์ธต์ ์ธ ๋ถ„์„๊ณผ ๋น„ํŒ์  ์‚ฌ๊ณ  ์ „๊ฐœ
- ๋‹ค์–‘ํ•œ ๊ด€์  ์ œ์‹œ ๋ฐ ๋น„๊ต
3. ๋ฐ์ดํ„ฐ ๋ฐ ๊ทผ๊ฑฐ ํ™œ์šฉ
- ํ†ต๊ณ„, ์—ฐ๊ตฌ ๊ฒฐ๊ณผ, ์ „๋ฌธ๊ฐ€ ์˜๊ฒฌ ๋“ฑ ์‹ ๋ขฐํ•  ์ˆ˜ ์žˆ๋Š” ์ถœ์ฒ˜ ์ธ์šฉ
- ํ•„์š”์‹œ ๊ฐ์ฃผ๋‚˜ ์ฐธ๊ณ ๋ฌธํ—Œ ๋ชฉ๋ก ํฌํ•จ
- ์ˆ˜์น˜ ๋ฐ์ดํ„ฐ๋Š” ํ…์ŠคํŠธ๋กœ ๋ช…ํ™•ํžˆ ์„ค๋ช…
4. ํ…์ŠคํŠธ ๊ตฌ์กฐํ™”
- ๋…ผ๋ฆฌ์  ๊ตฌ์กฐ๋ฅผ ๊ฐ•์กฐํ•˜๊ธฐ ์œ„ํ•ด ๋ฒˆํ˜ธ ๋งค๊ธฐ๊ธฐ ์‚ฌ์šฉ
- ํ•ต์‹ฌ ๊ฐœ๋…์ด๋‚˜ ์šฉ์–ด๋Š” ๊ธฐ์šธ์ž„๊ผด๋กœ ๊ฐ•์กฐ
- ๊ธด ์ธ์šฉ๋ฌธ์€ ๋“ค์—ฌ์“ฐ๊ธฐ๋กœ ๊ตฌ๋ถ„
5. ๋งˆ๋ฌด๋ฆฌ
- ํ•ต์‹ฌ ๋…ผ์  ์žฌ๊ฐ•์กฐ
- ํ–ฅํ›„ ์—ฐ๊ตฌ ๋ฐฉํ–ฅ์ด๋‚˜ ์‹ค๋ฌด์  ํ•จ์˜ ์ œ์‹œ
์ฃผ์˜์‚ฌํ•ญ: ์ „๋ฌธ์„ฑ์„ ์œ ์ง€ํ•˜๋˜, ์™„์ „ํžˆ ์ดํ•ดํ•˜๊ธฐ ์–ด๋ ค์šด ์ˆ˜์ค€์€ ์ง€์–‘
์˜ˆ์‹œ: "๋ณธ ์—ฐ๊ตฌ์—์„œ๋Š” ์ธ๊ณต์ง€๋Šฅ(AI)์˜ ์œค๋ฆฌ์  ํ•จ์˜์— ๋Œ€ํ•ด ๊ณ ์ฐฐํ•œ๋‹ค. ํŠนํžˆ, ์ž์œจ์ฃผํ–‰ ์ž๋™์ฐจ์˜ ์˜์‚ฌ๊ฒฐ์ • ์•Œ๊ณ ๋ฆฌ์ฆ˜์—์„œ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋Š” ์œค๋ฆฌ์  ๋”œ๋ ˆ๋งˆ์— ์ดˆ์ ์„ ๋งž์ถ˜๋‹ค. Bonnefon et al. (2016)์˜ ์—ฐ๊ตฌ์— ๋”ฐ๋ฅด๋ฉด, ์ž์œจ์ฃผํ–‰ ์ฐจ๋Ÿ‰์˜ ์•Œ๊ณ ๋ฆฌ์ฆ˜์ด ์ง๋ฉดํ•  ์ˆ˜ ์žˆ๋Š” ์œค๋ฆฌ์  ์„ ํƒ์˜ ๋ณต์žก์„ฑ์ด ์ง€์ ๋œ ๋ฐ” ์žˆ๋‹ค. ๋ณธ๊ณ ์—์„œ๋Š” ์ด๋Ÿฌํ•œ ์œค๋ฆฌ์  ๋”œ๋ ˆ๋งˆ๋ฅผ ์„ธ ๊ฐ€์ง€ ์ฃผ์š” ๊ด€์ ์—์„œ ๋ถ„์„ํ•œ๋‹ค: 1) ๊ณต๋ฆฌ์ฃผ์˜์  ์ ‘๊ทผ, 2) ์˜๋ฌด๋ก ์  ์ ‘๊ทผ, 3) ๋• ์œค๋ฆฌ์  ์ ‘๊ทผ. ๊ฐ ์ ‘๊ทผ๋ฒ•์˜ ์žฅ๋‹จ์ ์„ ๋น„๊ต ๋ถ„์„ํ•˜๊ณ , ์ด๋ฅผ ๋ฐ”ํƒ•์œผ๋กœ ์ž์œจ์ฃผํ–‰ ์ฐจ๋Ÿ‰์˜ ์œค๋ฆฌ์  ์˜์‚ฌ๊ฒฐ์ • ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ์ œ์•ˆํ•˜๊ณ ์ž ํ•œ๋‹ค...
"""
}
return prompts.get(style, "ํฌ์ŠคํŒ… ์Šคํƒ€์ผ ํ”„๋กฌํ”„ํŠธ")
def split_titles(suggested_titles):
titles = suggested_titles.split('\n')
titles = [re.sub(r'^(1\.|2\.|3\.|4\.|5\.|6\.|7\.|8\.|9\.|10\.|## |# |\* |\*\* |\*\*\*)', '', title.strip()) for title in titles if title.strip()]
titles = titles[::-1] # ๋ฆฌ์ŠคํŠธ๋ฅผ ์—ญ์ˆœ์œผ๋กœ ์ •๋ ฌ
titles += [""] * (10 - len(titles)) # 10๊ฐœ๋ณด๋‹ค ์ ์œผ๋ฉด ๋นˆ ๋ฌธ์ž์—ด๋กœ ์ฑ„์šฐ๊ธฐ
return titles[:10] # ์ตœ๋Œ€ 10๊ฐœ์˜ ์ œ๋ชฉ๋งŒ ๋ฐ˜ํ™˜
class PDF(FPDF):
def __init__(self):
super().__init__(orientation='P', unit='mm', format='A4')
self.set_margins(10, 10, 10)
current_dir = os.path.dirname(__file__)
self.add_font("NanumGothic", "", os.path.join(current_dir, "NanumGothic.ttf"))
self.add_font("NanumGothic", "B", os.path.join(current_dir, "NanumGothicBold.ttf"))
self.add_font("NanumGothicExtraBold", "", os.path.join(current_dir, "NanumGothicExtraBold.ttf"))
self.add_font("NanumGothicLight", "", os.path.join(current_dir, "NanumGothicLight.ttf"))
def header(self):
self.set_font('NanumGothic', '', 10)
# ํ—ค๋” ๋‚ด์šฉ ์ถ”๊ฐ€ (ํ•„์š”ํ•œ ๊ฒฝ์šฐ)
def footer(self):
self.set_y(-15)
self.set_font('NanumGothic', '', 8)
self.cell(0, 10, f'Page {self.page_no()}', 0, 0, 'C')
def chapter_title(self, title):
self.set_font("NanumGothic", 'B', 12)
self.cell(0, 6, title, 0, 1, 'L')
self.ln(4)
def chapter_body(self, body):
self.set_font("NanumGothic", '', 11)
self.multi_cell(0, 5, body)
self.ln()
def print_chapter(self, title, body):
self.add_page()
self.chapter_title(title)
self.chapter_body(body)
def format_filename(text):
if not isinstance(text, str):
text = str(text) # ๋ฌธ์ž์—ด์ด ์•„๋‹Œ ๊ฒฝ์šฐ ๋ฌธ์ž์—ด๋กœ ๋ณ€ํ™˜
text = re.sub(r'[^\w\s-]', '', text)
return text[:50].strip()
def save_to_pdf(blog_post, user_topic):
try:
# ์ž„์‹œ HTML ํŒŒ์ผ ์ƒ์„ฑ
with tempfile.NamedTemporaryFile(mode='w', suffix='.html', delete=False) as temp_html:
temp_html.write(blog_post)
temp_html_path = temp_html.name
# CSS ์„ค์ •
font_config = FontConfiguration()
css = CSS(string='''
@import url('https://fonts.googleapis.com/css2?family=Nanum+Gothic:wght@400;700&display=swap');
body {
font-family: 'Nanum Gothic', Arial, sans-serif;
line-height: 1.6;
color: #333;
padding: 20px;
}
h1 { font-size: 24px; margin-bottom: 15px; }
h2 { font-size: 20px; margin-bottom: 10px; }
h3 { font-size: 18px; margin-bottom: 10px; }
p { margin-bottom: 10px; }
ul { margin-bottom: 10px; padding-left: 20px; }
''', font_config=font_config)
# HTML์„ PDF๋กœ ๋ณ€ํ™˜
html = HTML(filename=temp_html_path)
pdf_bytes = html.write_pdf(stylesheets=[css], font_config=font_config)
# ํŒŒ์ผ ์ €์žฅ
now = datetime.now(ZoneInfo("Asia/Seoul"))
filename = f"{now.strftime('%y%m%d_%H%M')}_{format_filename(user_topic)}.pdf"
with open(filename, 'wb') as f:
f.write(pdf_bytes)
return filename
except Exception as e:
print(f"PDF ์ƒ์„ฑ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: {str(e)}")
import traceback
traceback.print_exc()
return None
def save_content_to_pdf(blog_post):
pdf_filename = save_to_pdf(blog_post, "")
if pdf_filename:
return pdf_filename
else:
return None # ์˜ค๋ฅ˜ ๋ฐœ์ƒ ์‹œ None ๋ฐ˜ํ™˜
title = "์ผ๋ฐ˜"
with gr.Blocks() as demo:
gr.Markdown(f"# {title}")
gr.Markdown("### 1๋‹จ๊ณ„: ํฌ์ŠคํŒ… ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ ์ง€์ •ํ•ด์ฃผ์„ธ์š”", elem_id="step-title")
category = gr.Radio(choices=["์ผ๋ฐ˜", "์ƒํ™œ๊ฑด๊ฐ•"], label="ํฌ์ŠคํŒ… ์นดํ…Œ๊ณ ๋ฆฌ", value="์ผ๋ฐ˜")
gr.Markdown("---\n\n")
gr.Markdown("### 2๋‹จ๊ณ„: ํฌ์ŠคํŒ… ์Šคํƒ€์ผ์„ ์„ ํƒํ•ด์ฃผ์„ธ์š”", elem_id="step-title")
style = gr.Radio(choices=["์นœ๊ทผํ•œ", "์ผ๋ฐ˜", "์ „๋ฌธ์ ์ธ"], label="ํฌ์ŠคํŒ… ์Šคํƒ€์ผ", value="์นœ๊ทผํ•œ")
gr.Markdown("---\n\n")
gr.Markdown("### 3๋‹จ๊ณ„: ์ฐธ๊ณ  ๊ธ€์„ ์ž…๋ ฅํ•˜์„ธ์š”", elem_id="step-title")
references1 = gr.Textbox(label="์ฐธ๊ณ  ๊ธ€ 1", placeholder="์ฐธ๊ณ ํ•  ๊ธ€์„ ๋ณต์‚ฌํ•˜์—ฌ ๋ถ™์—ฌ๋„ฃ์œผ์„ธ์š”", lines=10)
references2 = gr.Textbox(label="์ฐธ๊ณ  ๊ธ€ 2", placeholder="์ฐธ๊ณ ํ•  ๊ธ€์„ ๋ณต์‚ฌํ•˜์—ฌ ๋ถ™์—ฌ๋„ฃ์œผ์„ธ์š”", lines=10)
references3 = gr.Textbox(label="์ฐธ๊ณ  ๊ธ€ 3", placeholder="์ฐธ๊ณ ํ•  ๊ธ€์„ ๋ณต์‚ฌํ•˜์—ฌ ๋ถ™์—ฌ๋„ฃ์œผ์„ธ์š”", lines=10)
gr.Markdown("---\n\n")
gr.Markdown("### 4๋‹จ๊ณ„: ์ œ๋ชฉ ์ถ”์ฒœํ•˜๊ธฐ", elem_id="step-title")
title_suggestions = gr.Textbox(label="์ œ๋ชฉ ์ถ”์ฒœ", lines=10)
# 10๊ฐœ์˜ ํ…์ŠคํŠธ ์ถœ๋ ฅ์ฐฝ ์ถ”๊ฐ€
title_outputs = [gr.Textbox(label=f"์ œ๋ชฉ {i+1}", lines=1) for i in range(10)]
title_btn = gr.Button("์ œ๋ชฉ ์ถ”์ฒœํ•˜๊ธฐ")
title_btn.click(
fn=suggest_title,
inputs=[category, style, references1, references2, references3],
outputs=[title_suggestions]
)
title_suggestions.change(
fn=split_titles,
inputs=[title_suggestions],
outputs=title_outputs
)
gr.Markdown("---\n\n")
gr.Markdown("### 5๋‹จ๊ณ„: ๋ธ”๋กœ๊ทธ ์ œ๋ชฉ์„ ์ž…๋ ฅํ•˜์„ธ์š”", elem_id="step-title")
blog_title = gr.Textbox(label="๋ธ”๋กœ๊ทธ ์ œ๋ชฉ", placeholder="๋ธ”๋กœ๊ทธ ์ œ๋ชฉ์„ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”")
gr.Markdown("---\n\n")
gr.Markdown("### 6๋‹จ๊ณ„: ์•„์›ƒ๋ผ์ธ์„ ์ž‘์„ฑํ•ด์ฃผ์„ธ์š”", elem_id="step-title")
gr.HTML("<span style='color: grey;'>[์•„์›ƒ๋ผ์ธ์—์„œ ๋‚˜์˜จ ๊ฒฐ๊ณผ๋ฅผ ์ˆ˜์ •ํ•ด์„œ ์‚ฌ์šฉํ•ด์ฃผ์„ธ์š”]</span>")
outline_generate_btn = gr.Button("์•„์›ƒ๋ผ์ธ ์ƒ์„ฑํ•˜๊ธฐ")
outline_result = gr.Textbox(label="์•„์›ƒ๋ผ์ธ ๊ฒฐ๊ณผ", lines=15)
outline_input = gr.Textbox(label="์ž‘์„ฑํ•  ์•„์›ƒ๋ผ์ธ์„ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”", placeholder="์ƒ์„ฑ๋œ ์•„์›ƒ๋ผ์ธ ๋ณต์‚ฌ, ์ˆ˜์ •ํ•ด์„œ ์‚ฌ์šฉํ•˜์„ธ์š”", lines=10)
outline_generate_btn.click(
fn=generate_outline,
inputs=[category, style, references1, references2, references3, blog_title],
outputs=[outline_result]
)
gr.Markdown("---\n\n")
gr.Markdown("### 7๋‹จ๊ณ„: ๊ธ€ ์ƒ์„ฑํ•˜๊ธฐ", elem_id="step-title")
gr.HTML("<span style='color: grey;'>[์•„์›ƒ๋ผ์ธ์„ ํ™•์ธํ•˜์„ธ์š”]</span>")
generate_btn = gr.Button("๋ธ”๋กœ๊ทธ ๊ธ€ ์ƒ์„ฑํ•˜๊ธฐ")
output = gr.HTML(label="์ƒ์„ฑ๋œ ๋ธ”๋กœ๊ทธ ๊ธ€")
generate_btn.click(
fn=generate_blog_post,
inputs=[category, style, references1, references2, references3, blog_title, outline_input],
outputs=[output],
show_progress=True
)
save_pdf_btn = gr.Button("PDF๋กœ ์ €์žฅํ•˜๊ธฐ")
pdf_output = gr.File(label="์ƒ์„ฑ๋œ PDF ํŒŒ์ผ")
save_pdf_btn.click(
fn=save_to_pdf,
inputs=[output, blog_title], # blog_title์„ user_topic์œผ๋กœ ์‚ฌ์šฉ
outputs=[pdf_output],
show_progress=True
)
demo.launch()
gr.HTML("""
<style>
#step-title {
font-size: 1.7em;
font-weight: bold;
}
</style>
""")