Spaces:
Sleeping
Sleeping
| import os | |
| import random | |
| import re | |
| import requests | |
| import logging | |
| import tempfile | |
| from bs4 import BeautifulSoup | |
| from datetime import datetime | |
| from zoneinfo import ZoneInfo | |
| import html | |
| from fpdf import FPDF | |
| from PIL import Image | |
| from urllib.request import urlopen | |
| import markdown2 | |
| import gradio as gr | |
| # ๋ก๊น ์ค์ (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 ๊ฐ | |
| # Pretendard ํฐํธ ํ์ผ ๊ฒฝ๋ก | |
| FONT_REGULAR_PATH = os.path.join("Pretendard-Regular.otf") | |
| FONT_BOLD_PATH = os.path.join("Pretendard-Bold.otf") | |
| # API ๊ด๋ จ ์ค์ | |
| API_BASE_URL = os.getenv("API_BASE_URL", "").rstrip('/') | |
| API_KEY = os.getenv("API_KEY") | |
| gemini_api_key = os.getenv("GEMINI_API_KEY") | |
| API_HEADERS = { | |
| "x-api-key": API_KEY, | |
| "content-type": "application/json" | |
| } | |
| # --- Google Gemini SDK ์ด๊ธฐํ --- | |
| from google import genai | |
| from google.genai import types | |
| client = genai.Client(api_key=gemini_api_key) | |
| # ------------------------------- | |
| # ๊ธฐ๋ณธ ๋์ฐ๋ฏธ ํจ์๋ค | |
| # ------------------------------- | |
| def fetch_references(topic): | |
| """API๋ฅผ ํตํด ์ฐธ๊ณ ๋ธ๋ก๊ทธ ๊ธ ๊ฐ์ ธ์ค๊ธฐ""" | |
| try: | |
| if not topic or not topic.strip(): | |
| return ["๊ฒ์ ํค์๋๋ฅผ ์ ๋ ฅํด์ฃผ์ธ์."] * 3 | |
| encoded_keyword = requests.utils.quote(topic.strip()) | |
| url = f"{API_BASE_URL}/search/{encoded_keyword}" | |
| logging.info(f"API ํธ์ถ URL: {url}") | |
| logging.info(f"API ํค๋: {API_HEADERS}") | |
| response = requests.get(url, headers=API_HEADERS) | |
| logging.info(f"API ์๋ต ์ํ: {response.status_code}") | |
| logging.info(f"API ์๋ต ๋ด์ฉ: {response.text}") | |
| if response.ok: | |
| result = response.json() | |
| return [ | |
| result.get("reference1", "์ฐธ๊ณ ๊ธ1์ ์ฐพ์ ์ ์์ต๋๋ค."), | |
| result.get("reference2", "์ฐธ๊ณ ๊ธ2์ ์ฐพ์ ์ ์์ต๋๋ค."), | |
| result.get("reference3", "์ฐธ๊ณ ๊ธ3์ ์ฐพ์ ์ ์์ต๋๋ค.") | |
| ] | |
| else: | |
| return [f"API ์ค๋ฅ: {response.text}"] * 3 | |
| except Exception as e: | |
| return [f"์ฐธ๊ณ ๊ธ ์์ง ์ค ์ค๋ฅ ๋ฐ์: {str(e)}"] * 3 | |
| 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 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. ๋๋ ์ต๊ณ ์ ์ฌํ ๋ธ๋ก๊ทธ ์๊ฐ์ด์ ์ฌํ ์ฝํ ์ธ ๊ตฌ์ฑ ์ ๋ฌธ๊ฐ์ด๋ค. | |
| 2. ์ฃผ์ด์ง ์ฐธ๊ณ ๊ธ์ ๊น์ด ๋ถ์ํ์ฌ ํด๋น ์ฌํ์ง์ ๋ํ ๊ฐ์ฅ ํจ๊ณผ์ ์ธ ์ฝํ ์ธ ๊ตฌ์กฐ๋ฅผ ๋ง๋ค์ด๋ผ. | |
| 3. ์ฌํ์์ ๊ด์ฌ์ ๋๊ณ ์ ์ฉํ ์ ๋ณด๋ฅผ ์ ๋ฌํ๋ ๋ฐ ์ด์ ์ ๋ง์ถฐ๋ผ. | |
| 4. ์ฌํ์ง์ ๋ํ ํต์ฐฐ๋ ฅ ์๋ ๋ถ์๊ณผ ์ค์ฉ์ ์ธ ์ ๋ณด๋ฅผ ์ ๊ณตํ๋ ๊ตฌ์กฐ๋ฅผ ์ค๊ณํ๋ผ. | |
| [์์๋ผ์ธ ์์ฑ ๊ท์น] | |
| 1. ๋ฐ๋์ ์ฐธ๊ณ ๊ธ์ ๊น์ด ๋ถ์ํ์ฌ ์ฌํ์ง์ ํต์ฌ ํน์ง๊ณผ ๊ฐ์น ์๋ ์ ๋ณด๋ฅผ ํ์ ํ๋ผ. | |
| 2. ์ฌํ์์ ๊ด์ฌ์ ๋๊ธฐ ์ํ ๋งค๋ ฅ์ ์ธ ์๊ฐ๋ก ์์ํ๋ผ. | |
| 3. ์ฌํ์ง์ ๋ํ ์ฌ์ธต์ ์ดํด๋ฅผ ์ ๊ณตํ๋ ๋ ผ๋ฆฌ์ ๊ตฌ์กฐ๋ฅผ ๋ง๋ค์ด๋ผ. | |
| 4. ๊ฐ ์์ฃผ์ ๋ 20์ ์ด๋ด์ ๋ช ํํ๊ณ ๋งค๋ ฅ์ ์ธ ์ ๋ชฉ์ผ๋ก ์์ฑํ๋ผ. | |
| 5. ์์ฃผ์ ๋ค์ ์ ์ฒด์ ์ผ๋ก ์ผ๊ด๋ ํ๋ฆ๊ณผ ์ฐ๊ฒฐ์ฑ์ ๊ฐ์ ธ์ผ ํ๋ค. | |
| 6. ์ฌํ์์๊ฒ ์ค์ง์ ์ธ ๊ฐ์น์ ํต์ฐฐ์ ์ ๊ณตํ๋ ์ ๋ณด ์ค์ฌ์ผ๋ก ๊ตฌ์ฑํ๋ผ. | |
| 7. ์ฐธ๊ณ ๊ธ์ ๋ด์ฉ๊ณผ ํน์ฑ์ ๋ฐ๋ผ ๊ฐ์ฅ ์ ํฉํ ์์ฃผ์ ๋ฅผ ์ ์ฐํ๊ฒ ๊ตฌ์ฑํ๋ผ. | |
| [์์๋ผ์ธ ๊ตฌ์ฑ] | |
| ๋ฐ๋์ ๋ค์ ๊ตฌ์กฐ๋ก ์์ฃผ์ ๋ฅผ ์์ฑํ๊ณ ๊ทธ๋๋ก ์ถ๋ ฅํ๋ผ: | |
| - ๋์ ๋ถ: [์ฌํ์ง ์๊ฐ ๋ฐ ํน์ง] | |
| - ๋ณธ๋ก 1~5: [์ฐธ๊ณ ๊ธ์์ ํ์ ๋ ์ฃผ์ ๋ด์ฉ์ ๋ฐ๋ผ ์ ์ฐํ๊ฒ ๊ตฌ์ฑ] | |
| - ๊ฒฐ๋ก : [์ฌํ์ง ์ต์ข ํ๊ฐ ๋ฐ ์ถ์ฒ] | |
| """, | |
| "์ฌํ ์ฝ์ค": """ | |
| [์ฌํ ์ฝ์ค ์์ฃผ์ (Outline) ์์ฑ ๊ท์น] | |
| 1. ๋๋ ์ต๊ณ ์ ์ฌํ ๋ธ๋ก๊ทธ ์๊ฐ์ด์ ์ฌํ ์ฝ์ค ๊ธฐํ ์ ๋ฌธ๊ฐ์ด๋ค. | |
| 2. ์ฃผ์ด์ง ์ฐธ๊ณ ๊ธ์ ๊น์ด ๋ถ์ํ์ฌ ์ต์ ์ ์ฌํ ์ฝ์ค ๊ตฌ์ฑ๊ณผ ์ฝํ ์ธ ๊ตฌ์กฐ๋ฅผ ๋ง๋ค์ด๋ผ. | |
| 3. ์ฌํ์์ ์๊ฐ๊ณผ ๊ฒฝํ์ ์ต์ ํํ ์ ์๋ ์ฝ์ค ๊ตฌ์ฑ์ ์ด์ ์ ๋ง์ถฐ๋ผ. | |
| 4. ์ค์ฉ์ ์ด๊ณ ํจ์จ์ ์ธ ์ฌํ ๊ณํ์ ์ ๊ณตํ๋ ๊ตฌ์กฐ๋ฅผ ์ค๊ณํ๋ผ. | |
| [์์๋ผ์ธ ์์ฑ ๊ท์น] | |
| 1. ์ฐธ๊ณ ๊ธ์ ์ฒ ์ ํ ๋ถ์ํ์ฌ ์ฌํ ์ฝ์ค์ ํต์ฌ ์์์ ํ๋ฆ์ ํ์ ํ๋ผ. | |
| 2. ์ฌํ ์ฝ์ค์ ๋งค๋ ฅ๊ณผ ํน์ง์ ๊ฐ์กฐํ๋ ์๊ฐ๋ก ์์ํ๋ผ. | |
| 3. ์ฌํ ์ผ์ ์ ๋ ผ๋ฆฌ์ ํ๋ฆ์ ๋ฐ์ํ ๊ตฌ์กฐ๋ฅผ ๋ง๋ค์ด๋ผ. | |
| 4. ๊ฐ ์์ฃผ์ ๋ 20์ ์ด๋ด์ ๋ช ํํ๊ณ ๋งค๋ ฅ์ ์ธ ์ ๋ชฉ์ผ๋ก ์์ฑํ๋ผ. | |
| 5. ์์ฃผ์ ๋ค์ด ์ ์ฒด ์ฌํ ํ๋ฆ์ ์์ฐ์ค๋ฝ๊ฒ ์ด๋์ด๊ฐ ์ ์๋๋ก ๊ตฌ์ฑํ๋ผ. | |
| 6. ์ฌํ์๊ฐ ์ค์ ๋ก ํ์ฉํ ์ ์๋ ๊ตฌ์ฒด์ ์ธ ์ ๋ณด ์ค์ฌ์ผ๋ก ๊ตฌ์ฑํ๋ผ. | |
| 7. ์ฐธ๊ณ ๊ธ์ ๋ด์ฉ๊ณผ ํน์ฑ์ ๋ฐ๋ผ ๊ฐ์ฅ ์ ํฉํ ์์ฃผ์ ๋ฅผ ์ ์ฐํ๊ฒ ๊ตฌ์ฑํ๋ผ. | |
| [์์๋ผ์ธ ๊ตฌ์ฑ] | |
| ๋ฐ๋์ ๋ค์ ๊ตฌ์กฐ๋ก ์์ฃผ์ ๋ฅผ ์์ฑํ๊ณ ๊ทธ๋๋ก ์ถ๋ ฅํ๋ผ: | |
| - ๋์ ๋ถ: [์ฌํ ์ฝ์ค ๊ฐ์ ๋ฐ ํน์ง] | |
| - ๋ณธ๋ก 1~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. ๊ฐ ์น์ ์ ์ต์ {MIN_SECTION_LENGTH}์ ์ด์์ ์ถฉ๋ถํ ๋ด์ฉ์ผ๋ก ์์ฑํ๋ผ. | |
| 7. ๊ธ ์ ์ฒด ๊ธธ์ด๋ ์ต์ {TARGET_CHAR_LENGTH}์๊ฐ ๋๋๋ก ์์ฑํ๋ผ. | |
| 8. ๊ธ ์ ์ฒด ๊ธธ์ด๋ {TARGET_CHAR_LENGTH}์์์ {TARGET_CHAR_LENGTH + 1000}์ ์ฌ์ด๊ฐ ๋๋๋ก ์์ฑํ๋ผ. | |
| [์ค์ ๊ท์น] | |
| 1. ๋งํฌ๋ค์ด ํ์(#, *, -, 1., 2. ๋ฑ)์ ์ฌ์ฉํ์ง ๋ง๊ณ ์ผ๋ฐ ํ ์คํธ๋ก ์์ฑํ๋ผ. | |
| 2. ์์ ๋ชฉ๊ณผ ๊ฒฐ๋ก ์ ๋ฒํธ ์์ด ์ผ๋ฐ ๋ฌธ์ฅ ํํ๋ก ์์ฑํ๋ผ. | |
| 3. ๋ชฉ๋ก์ ๋ถ๋ฆฟ์ด๋ ๋ฒํธ ๋์ ์์ฐ์ค๋ฌ์ด ๋ฌธ์ฅ์ผ๋ก ์์ ํ๋ผ. | |
| 4. "์ฐธ๊ณ ๊ธ", "์ฐธ๊ณ ๊ธ์ ๋ฐ๋ฅด๋ฉด" ๋ฑ์ ํํ์ ์ฌ์ฉํ์ง ๋ง๋ผ. | |
| 5. "์ฌ๋ฌ๋ถ", "๋ ์ ์ฌ๋ฌ๋ถ" ๋ฑ์ ์ง์ ์ ์ธ ํธ์นญ์ ์ง์ํ๋ผ. | |
| """ | |
| } | |
| return prompts.get(category, prompts["์ฌํ ๋จ์ผ"]) | |
| 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. ๊ธ์ ์ฒ์์ ์ ์ฒด ๊ธ์ ๋งค๋ ฅ์ ์ธ ์ ๋ชฉ์ ๋ฐ๋์ ์ถ๊ฐํ๋ผ. | |
| 16. ๋ฐ๋์ ๊ตฌ์ฒด์ ์ธ ์ฌํ ์ ๋ณด(์์น, ๊ตํต, ์๊ฐ, ๋น์ฉ, ์์ฝ๋ฐฉ๋ฒ, ํ ๋ฑ)๋ฅผ ํฌํจํ๋ผ. | |
| """ | |
| # 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) | |
| soup = BeautifulSoup(temp_html, 'html.parser') | |
| char_count = len(soup.get_text()) | |
| 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) | |
| soup = BeautifulSoup(temp_html, 'html.parser') | |
| char_count = len(soup.get_text()) | |
| 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) | |
| # ์ต์ข ๊ธ์ ์ ๊ณ์ฐ | |
| soup = BeautifulSoup(final_html, 'html.parser') | |
| final_char_count = len(soup.get_text()) | |
| 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 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'์ข์'), | |
| (r'์ต์ ์', r'์ข์'), | |
| (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) | |
| # ์ฌํ ๊ด๋ จ ํํ ์ ๋ฆฌ | |
| travel_specific_adjustments = [ | |
| (r'๋ฐฉ๋ฌธํด๋ณด์ธ์', r'๋ฐฉ๋ฌธํด ๋ณด์ธ์'), | |
| (r'๊ฒฝํํด๋ณด์ธ์', r'๊ฒฝํํด ๋ณด์ธ์'), | |
| (r'๋จน์ด๋ณด์ธ์', r'๋จน์ด ๋ณด์ธ์'), | |
| (r'ํ๋ณด์ธ์', r'ํ ๋ณด์ธ์'), | |
| (r'ํด๋ณด์ธ์', r'ํด ๋ณด์ธ์'), | |
| (r'์ฌํ๊ฐ๋ค์๊ฒ (.*?)์ ๊ฐ๋ ฅ ์ถ์ฒํฉ๋๋ค', r'์ฌํ๊ฐ๋ค์๊ฒ \1์ ์ถ์ฒํด์'), | |
| (r'์ฌํ๊ฐ๋ค์๊ฒ (.*?)๋ฅผ ๊ฐ๋ ฅ ์ถ์ฒํฉ๋๋ค', r'์ฌํ๊ฐ๋ค์๊ฒ \1๋ฅผ ์ถ์ฒํด์'), | |
| (r'์ฌํ๊ฐ๋ค์๊ฒ (.*?)์ ์ถ์ฒํฉ๋๋ค', r'์ฌํ๊ฐ๋ค์๊ฒ \1์ ์ถ์ฒํด์'), | |
| (r'์ฌํ๊ฐ๋ค์๊ฒ (.*?)๋ฅผ ์ถ์ฒํฉ๋๋ค', r'์ฌํ๊ฐ๋ค์๊ฒ \1๋ฅผ ์ถ์ฒํด์'), | |
| (r'์ฌํ๊ฐ์๊ฒ (.*?)์ ๊ฐ๋ ฅ ์ถ์ฒํฉ๋๋ค', r'์ฌํ๊ฐ์๊ฒ \1์ ์ถ์ฒํด์'), | |
| (r'์ฌํ๊ฐ์๊ฒ (.*?)๋ฅผ ๊ฐ๋ ฅ ์ถ์ฒํฉ๋๋ค', r'์ฌํ๊ฐ์๊ฒ \1๋ฅผ ์ถ์ฒํด์') | |
| ] | |
| for pattern, replacement in travel_specific_adjustments: | |
| blog_content = re.sub(pattern, replacement, blog_content) | |
| return blog_content | |
| except Exception as e: | |
| logging.error(f"๋ธ๋ก๊ทธ ๊ธ ํ์ฒ๋ฆฌ ์ค ์ค๋ฅ ๋ฐ์: {str(e)}") | |
| return blog_content | |
| 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 call_gemini_api(prompt, temperature=TEMPERATURE, top_p=TOP_P): | |
| """Gemini API ํธ์ถ ํจ์""" | |
| try: | |
| logging.info("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 | |
| ) | |
| ) | |
| logging.info("Gemini API ํธ์ถ ์๋ฃ") | |
| return response.text.strip() | |
| except Exception as e: | |
| logging.error(f"Gemini API ํธ์ถ ์ค ์ค๋ฅ ๋ฐ์: {str(e)}") | |
| return f"API ํธ์ถ ์ค ์ค๋ฅ ๋ฐ์: {str(e)}" | |
| 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. ์ฝ์ค ๊ฐ์์ ์ฌํ ๊ธฐ๊ฐ๋ณ ์ถ์ฒ ์ผ์ | |
| 4. ์ผ์ฐจ๋ณ ๋๋ ํ ๋ง๋ณ ์ธ๋ถ ์ฝ์ค ๊ตฌ์ฑ | |
| 5. ํจ์จ์ ์ธ ์ด๋ ๋ฐฉ๋ฒ๊ณผ ๊ตํต ์ ๋ณด | |
| 6. ์์ ๋ฐ ์๋น ์ถ์ฒ๊ณผ ์์ฝ ํ | |
| 7. ์ฌํ ์์ฐ๊ณผ ๋น์ฉ ์ ์ฝ ๋ฐฉ๋ฒ | |
| 8. (์ ํญ๋ชฉ๋ค์ ์์์ผ ๋ฟ, ์ฐธ๊ณ ์๋ฃ ๋ถ์์ ํตํด ์์ ๋กญ๊ฒ ๊ฒฐ์ ) | |
| 9. ๊ฒฐ๋ก (1๊ฐ) - ์ ์ฒด ์ฝ์ค์ ํน์ง์ ์์ฝํ๊ณ ์ฌํ ๊ณํ ์๋ฆฝ์ ๋์์ ์ฃผ๋ ์ ๋ชฉ | |
| [ํต์ฌ ์ง์นจ] | |
| 1. ์์ ํ ํ๊ตญ์ด๋ก๋ง ์์ฑํ ๊ฒ | |
| 2. ์์ ๋ชฉ์ ์ต๋ 30์ ์ด๋ด๋ก ๊ฐ๊ฒฐํ๊ฒ ์์ฑ | |
| 3. ๋ ์์ ์ฌํ ๊ณํ ์๋ฆฝ์ ๋๋ ์ค์ฉ์ ์ธ ํํ ์ฌ์ฉ (์: "์๋ฒฝํ 3๋ฐ 4์ผ ์ฝ์ค", "ํจ์จ์ ์ธ ๋์ ์ค๊ณ", "ํ์ง์ธ์ด ์๋ ค์ฃผ๋ ๊ฟ์ฝ์ค") | |
| 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 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)}" | |
| # PDF ํด๋์ค ์ ์ | |
| class PDF(FPDF): | |
| def __init__(self): | |
| super().__init__() | |
| self.add_font("Pretendard", "", FONT_REGULAR_PATH, uni=True) | |
| self.add_font("Pretendard", "B", FONT_BOLD_PATH, uni=True) | |
| def header(self): | |
| self.set_font("Pretendard", "", 10) | |
| def footer(self): | |
| self.set_y(-15) | |
| self.set_font("Pretendard", "", 8) | |
| self.cell(0, 10, f'Page {self.page_no()}', align='C') | |
| def save_to_pdf(blog_post, user_topic=""): | |
| try: | |
| logging.info("PDF ์์ฑ ์์") | |
| pdf = PDF() | |
| pdf.add_page() | |
| soup = BeautifulSoup(blog_post, 'html.parser') | |
| title = soup.h1.text.strip() if soup.h1 else user_topic or "๋ธ๋ก๊ทธ ๊ธ" | |
| logging.info(f"PDF ์ ๋ชฉ ์ค์ : {title}") | |
| page_width = pdf.w - 2 * pdf.l_margin | |
| image_width = page_width | |
| image_url1 = "https://finalendai.com/wp-content/uploads/2024/10/pdf-banner-top.png" | |
| image_url2 = "https://finalendai.com/wp-content/uploads/2024/10/pdf-banner-bottom.png" | |
| logging.info("์๋จ ์ด๋ฏธ์ง ์ฝ์ ์๋") | |
| try: | |
| with urlopen(image_url1) as response: | |
| with tempfile.NamedTemporaryFile(delete=False, suffix=".png") as tmp_file: | |
| tmp_file.write(response.read()) | |
| tmp_file_path = tmp_file.name | |
| img_width, img_height = Image.open(tmp_file_path).size | |
| ratio = img_height / img_width | |
| image_height = image_width * ratio | |
| x = (pdf.w - image_width) / 2 | |
| y = pdf.get_y() | |
| pdf.link(x, y, image_width, image_height, "https://finalendai.com") | |
| pdf.image(tmp_file_path, x=x, y=y, w=image_width) | |
| pdf.ln(image_height + 10) | |
| os.unlink(tmp_file_path) | |
| logging.info("์๋จ ์ด๋ฏธ์ง ์ฝ์ ์๋ฃ") | |
| except Exception as e: | |
| logging.error(f"์๋จ ์ด๋ฏธ์ง ์ฝ์ ์ค ์ค๋ฅ: {str(e)}") | |
| pdf.set_font("Pretendard", "B", 16) | |
| pdf.multi_cell(0, 10, title, align='C') | |
| pdf.ln(10) | |
| logging.info("PDF ๋ณธ๋ฌธ ๋ด์ฉ ์ถ๊ฐ ์์") | |
| pdf.set_font("Pretendard", "", 12) | |
| for tag in soup.find_all(["h2", "h3", "p", "ul", "li"]): | |
| tag_text = tag.get_text().strip() | |
| logging.info(f"์ถ๊ฐ ์ค์ธ ๋ณธ๋ฌธ ๋ด์ฉ [{tag.name}]: {tag_text}") | |
| if tag.name == "h2": | |
| pdf.set_font("Pretendard", "B", 14) | |
| pdf.multi_cell(0, 8, tag_text) | |
| pdf.ln(4) | |
| elif tag.name == "h3": | |
| pdf.set_font("Pretendard", "B", 12) | |
| pdf.multi_cell(0, 6, tag_text) | |
| pdf.ln(3) | |
| elif tag.name == "p": | |
| pdf.set_font("Pretendard", "", 12) | |
| pdf.multi_cell(0, 8, tag_text) | |
| pdf.ln(4) | |
| elif tag.name in ["ul", "li"]: | |
| pdf.set_font("Pretendard", "", 12) | |
| pdf.multi_cell(0, 8, f"โข {tag_text}") | |
| pdf.ln(4) | |
| logging.info("PDF ๋ณธ๋ฌธ ๋ด์ฉ ์ถ๊ฐ ์๋ฃ") | |
| logging.info("ํ๋จ ์ด๋ฏธ์ง ์ฝ์ ์๋") | |
| try: | |
| with urlopen(image_url2) as response: | |
| with tempfile.NamedTemporaryFile(delete=False, suffix=".png") as tmp_file: | |
| tmp_file.write(response.read()) | |
| tmp_file_path = tmp_file.name | |
| if pdf.get_y() + image_height > pdf.page_break_trigger: | |
| pdf.add_page() | |
| x = (pdf.w - image_width) / 2 | |
| y = pdf.get_y() | |
| pdf.link(x, y, image_width, image_height, "https://finalendai.com/story/") | |
| pdf.image(tmp_file_path, x=x, y=y, w=image_width) | |
| os.unlink(tmp_file_path) | |
| logging.info("ํ๋จ ์ด๋ฏธ์ง ์ฝ์ ์๋ฃ") | |
| except Exception as e: | |
| logging.error(f"ํ๋จ ์ด๋ฏธ์ง ์ฝ์ ์ค ์ค๋ฅ: {str(e)}") | |
| now = datetime.now(ZoneInfo("Asia/Seoul")) | |
| filename = f"{now.strftime('%y%m%d_%H%M')}_{format_filename(title)}.pdf" | |
| pdf.output(filename) | |
| logging.info(f"PDF ํ์ผ ์ ์ฅ ์๋ฃ: {filename}") | |
| return filename | |
| except Exception as e: | |
| logging.error(f"PDF ์์ฑ ์ค ์ค๋ฅ ๋ฐ์: {str(e)}") | |
| return None | |
| def format_filename(text): | |
| text = re.sub(r'[^\w\s-]', '', text) | |
| return text[:50].strip() | |
| def save_content_to_pdf(blog_post, user_topic=""): | |
| return save_to_pdf(blog_post, user_topic) | |
| # ------------------------------- | |
| # Gradio ์ธํฐํ์ด์ค ๊ตฌ์ฑ | |
| # ------------------------------- | |
| with gr.Blocks() as demo: | |
| gr.Markdown("# ์ฌํ ๋ธ๋ก๊ทธ ํฌ์คํ ์์ฑ๊ธฐ") | |
| 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") | |
| 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], | |
| outputs=[outline_result] | |
| ) | |
| gr.Markdown("---\n\n") | |
| gr.Markdown("### 5๋จ๊ณ: ๊ธ ์์ฑํ๊ธฐ", elem_id="step-title") | |
| gr.HTML("<span style='color: grey;'>[์์๋ผ์ธ์ ํ์ธํ๊ณ ํ์ํ ๊ฒฝ์ฐ ์์ ํ ํ ๊ธ์ ์์ฑํ์ธ์]</span>") | |
| generate_btn = gr.Button("๋ธ๋ก๊ทธ ๊ธ ์์ฑํ๊ธฐ") | |
| output = gr.HTML(label="์์ฑ๋ ๋ธ๋ก๊ทธ ๊ธ") | |
| char_count = gr.Number(label="๊ธ์ ์", precision=0) | |
| generate_btn.click( | |
| fn=generate_blog_post, | |
| inputs=[category, style, outline_input, references1, references2, references3], | |
| outputs=[output, char_count], | |
| show_progress=True | |
| ) | |
| save_pdf_btn = gr.Button("PDF๋ก ์ ์ฅํ๊ธฐ") | |
| pdf_output = gr.File(label="์์ฑ๋ PDF ํ์ผ") | |
| save_pdf_btn.click( | |
| fn=save_content_to_pdf, | |
| inputs=[output, category], | |
| outputs=[pdf_output], | |
| show_progress=True | |
| ) | |
| gr.HTML(""" | |
| <style> | |
| #step-title { | |
| font-size: 1.7em; | |
| font-weight: bold; | |
| } | |
| </style> | |
| """) | |
| if __name__ == "__main__": | |
| demo.launch() |