corr_writ-1-1 / app.py
ssboost's picture
Create app.py
79a8a6e verified
import os
import gradio as gr
from dotenv import load_dotenv
from openai import OpenAI
import logging
import time
import uuid
# ๋กœ๊น… ์„ค์ • - INFO ๋ ˆ๋ฒจ๋กœ ๋ณ€๊ฒฝ
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
# ํ™˜๊ฒฝ ๋ณ€์ˆ˜ ๋กœ๋“œ
load_dotenv()
# API ํ‚ค ์„ค์ •
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
logger.info("API ํ‚ค ์„ค์ • ์™„๋ฃŒ")
# OpenAI ํด๋ผ์ด์–ธํŠธ ์„ค์ •
openai_client = OpenAI(api_key=OPENAI_API_KEY)
# ๋ชจ๋ธ๋ณ„ ํ”„๋กฌํ”„ํŠธ ์ •์˜
GPT_PROMPTS = {
"๋ฌธ๋ฒ• ๊ต์ •": """
1. ์ฃผ์–ด์ง„ ํ…์ŠคํŠธ์˜ ๋ฌธ๋ฒ•์„ ๊ฒ€ํ† ํ•˜๊ณ  ๊ต์ •ํ•˜๋ผ
2. ๋ฐ˜๋“œ์‹œ ์›๋ณธ ํ…์ŠคํŠธ๋ฅผ ์œ ์ง€ํ•˜๋ฉด์„œ ๋ฌธ๋ฒ•์ ์ธ ๋ถ€๋ถ„์—์„œ๋งŒ ์ˆ˜์ •ํ•˜๋ผ
3. ๋งž์ถค๋ฒ•, ๋„์–ด์“ฐ๊ธฐ, ๋ฌธ์žฅ ๋ถ€ํ˜ธ ๋“ฑ์„ ํ•œ๊ตญ์–ด ๋ฌธ๋ฒ•์— ๋งž๊ฒŒ ์ •ํ™•ํ•˜๊ฒŒ ์ˆ˜์ •ํ•˜๋ผ
4. ์ ˆ๋Œ€ ์›๋ณธ ํ…์ŠคํŠธ ์ด์™ธ์˜ ๋‹ค๋ฅธ ๋ถ€๊ฐ€์ ์ธ ์„ค๋ช…์„ ์ถœ๋ ฅํ•˜์ง€ ๋ง ๊ฒƒ
- '์ˆ˜์ •๋œ ํ…์ŠคํŠธ', '๊ฐœ์„ ๋œ ํ…์ŠคํŠธ'๋“ฑ ์ถœ๋ ฅ๊ธˆ์ง€
""",
"๋ฌธ์žฅ ๋‹ค๋“ฌ๊ธฐ": """
## ๋ฌธ์žฅ ๊ตฌ์กฐ ๊ฒ€ํ† 
- **๋ถˆํ•„์š”ํ•œ ๋ฌธ๊ตฌ ์ œ๊ฑฐ:** ํ•„์ˆ˜์ ์ด์ง€ ์•Š์€ ํ‘œํ˜„์„ ์‚ญ์ œํ•˜์—ฌ ๋ฌธ์žฅ์„ ๊ฐ„๊ฒฐํ•˜๊ฒŒ ์œ ์ง€ํ•ฉ๋‹ˆ๋‹ค.
- **์ฃผ์–ด-์„œ์ˆ ์–ด ๋ช…ํ™•์„ฑ:** ๋ฌธ์žฅ์˜ ์ฃผ์–ด์™€ ์„œ์ˆ ์–ด๋ฅผ ๋ช…ํ™•ํžˆ ํ•˜์—ฌ ์˜๋ฏธ ์ „๋‹ฌ์ด ์‹ค์ˆ˜ ์—†์ด ์ด๋ฃจ์–ด์ง€๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.
- **๊ธด ๋ฌธ์žฅ ๋ถ„๋ฆฌ:** ์ง€๋‚˜์น˜๊ฒŒ ๊ธด ๋ฌธ์žฅ์€ ์ฝ๊ธฐ ์‰ฝ๊ฒŒ ์—ฌ๋Ÿฌ ๋ฌธ์žฅ์œผ๋กœ ๋‚˜๋ˆ•๋‹ˆ๋‹ค.
## ๋‹จ๋ฝ ๊ตฌ์„ฑ ์ ๊ฒ€
- **ํ•ต์‹ฌ ์ฃผ์ œ ํ™•์ธ:** ๊ฐ ๋‹จ๋ฝ์ด ๋ช…ํ™•ํ•œ ํ•ต์‹ฌ ์ฃผ์ œ๋‚˜ ์ค‘์‹ฌ ์ƒ๊ฐ์„ ๊ฐ€์ง€๊ณ  ์žˆ๋Š”์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.
- **์ž์—ฐ์Šค๋Ÿฌ์šด ์—ฐ๊ฒฐ:** ๋‹จ๋ฝ ๊ฐ„์˜ ํ๋ฆ„์ด ์ž์—ฐ์Šค๋Ÿฝ๋„๋ก ์—ฐ๊ฒฐ์–ด๋ฅผ ์ ์ ˆํžˆ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
- **๋‹จ๋ฝ ๊ธธ์ด ์กฐ์ ˆ:** ๋„ˆ๋ฌด ๊ธธ๊ฑฐ๋‚˜ ์งง์€ ๋‹จ๋ฝ์€ ์กฐ์ •ํ•˜์—ฌ ๊ท ํ˜•์„ ๋งž์ถฅ๋‹ˆ๋‹ค.
## ์–ดํœ˜ ๊ฐœ์„ 
- **์™ธ๋ž˜์–ด ์ˆœํ™”:** ๋ถˆํ•„์š”ํ•œ ์™ธ๋ž˜์–ด๋ฅผ ํ•œ๊ตญ์–ด๋กœ ๋Œ€์ฒดํ•ฉ๋‹ˆ๋‹ค.
- **๋‹จ์–ด ๊ตฌ์ฒดํ™”:** ๋ชจํ˜ธํ•œ ํ‘œํ˜„์€ ๋ณด๋‹ค ๋ช…ํ™•ํ•œ ์šฉ์–ด๋กœ ๋ฐ”๊ฟ‰๋‹ˆ๋‹ค.
- **์ค‘๋ณต ํ‘œํ˜„ ์‚ญ์ œ:** ์˜๋ฏธ๊ฐ€ ์ค‘๋ณต๋˜๋Š” ๋‹จ์–ด๋ฅผ ์ œ๊ฑฐํ•˜์—ฌ ๋ฌธ์žฅ์˜ ํšจ์œจ์„ฑ์„ ๋†’์ž…๋‹ˆ๋‹ค.
## ์ „๋‹ฌ๋ ฅ ๊ฐ•ํ™”
- **ํ•ต์‹ฌ ๋ฉ”์‹œ์ง€ ๋ถ€๊ฐ:** ๋ฌธ์žฅ์—์„œ ๊ฐ€์žฅ ์ค‘์š”ํ•œ ๋ฉ”์‹œ์ง€๊ฐ€ ์ž˜ ๋“œ๋Ÿฌ๋‚˜๋„๋ก ์กฐ์ •ํ•ฉ๋‹ˆ๋‹ค.
- **๋…ผ๋ฆฌ์  ํ๋ฆ„ ๊ฐœ์„ :** ์ „์ฒด ๋ฌธ๋‹จ์˜ ๋…ผ๋ฆฌ์ ์ธ ํ๋ฆ„์ด ์ž์—ฐ์Šค๋Ÿฝ๋„๋ก ๋งŒ๋“ญ๋‹ˆ๋‹ค.
- **๋…์ž ์ดํ•ด ๊ณ ๋ ค:** ๋…์ž๊ฐ€ ์‰ฝ๊ฒŒ ์ดํ•ดํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ๊ณ ๋ คํ•˜์—ฌ ํ‘œํ˜„ํ•ฉ๋‹ˆ๋‹ค.
## ์ผ๊ด€์„ฑ ํ™•๋ณด
- **๋ฌธ์ฒด ํ†ต์ผ:** ๋ฌธ์žฅ์˜ ํ†ค๊ณผ ์Šคํƒ€์ผ์ด ์ผ์ •ํ•œ์ง€ ์œ ์ง€ํ•ฉ๋‹ˆ๋‹ค.
- **์šฉ์–ด ํ†ต์ผ:** ๋™์ผํ•œ ์šฉ์–ด๋ฅผ ์ผ๊ด€์„ฑ ์žˆ๊ฒŒ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
- **์‹œ์ œ ์ผ๊ด€์„ฑ:** ์‹œ์ œ๊ฐ€ ์ผ์ •ํ•˜๊ฒŒ ์œ ์ง€๋˜๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.
# Output Format
- ์›๋ณธ๊ณผ ๋™์ผํ•œ ๋งํˆฌ์™€ ์–ด์กฐ๋ฅผ ์œ ์ง€ํ•˜์—ฌ, ํ•„์š”ํ•œ ๋ถ€๋ถ„๋งŒ์„ ๋‹ค๋“ฌ์€ ํ…์ŠคํŠธ๋กœ ์ถœ๋ ฅํ•ฉ๋‹ˆ๋‹ค.
- ๋ถ€๊ฐ€์ ์ธ ์„ค๋ช… ์—†์ด ๋‹จ์ˆœํžˆ ๊ฐœ์„ ๋œ ํ…์ŠคํŠธ๋งŒ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.
""",
"๋ช…์–ธ์ธ์šฉํ•˜์—ฌ ๋‹ค๋“ฌ๊ธฐ": """
1. ์ฃผ์–ด์ง„ ํ…์ŠคํŠธ์˜ ๋ฌธ์žฅ์— ์ ์ ˆํ•œ ๋ช…์–ธ์ด๋‚˜ ๊ฒฉ์–ธ์„ ๋”ฑํ•œ๋ฒˆ ์ธ์šฉํ•˜์—ฌ ๋” ์„ค๋“๋ ฅ ์žˆ๊ณ  ์ธ์ƒ์ ์ธ ๋‚ด์šฉ์œผ๋กœ ๋ฐœ์ „์‹œ์ผœ๋ผ
2. ์ธ์šฉ๊ตฌ๋ฅผ ๋ฌธ๋งฅ์— ๋งž๊ฒŒ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ๋…น์•„๋“ค๊ฒŒ ์ž‘์„ฑํ•˜๋ผ
3. ์›๋ณธ ํ…์ŠคํŠธ์˜ ๋‚ด์šฉ๊ณผ ๋ถ„์œ„๊ธฐ๋ฅผ ์ตœ๋Œ€ํ•œ ๋ฐ˜์˜ํ•˜๋ผ
4. ์ ˆ๋Œ€ ์›๋ณธ ํ…์ŠคํŠธ ์ด์™ธ์˜ ๋‹ค๋ฅธ ๋ถ€๊ฐ€์ ์ธ ์„ค๋ช…์„ ์ถœ๋ ฅํ•˜์ง€ ๋ง ๊ฒƒ
- '์ˆ˜์ •๋œ ํ…์ŠคํŠธ', '๊ฐœ์„ ๋œ ํ…์ŠคํŠธ'๋“ฑ ์ถœ๋ ฅ๊ธˆ์ง€
""",
"๋‚ด ๋งˆ์Œ๋Œ€๋กœ ๋‹ค๋“ฌ๊ธฐ": """
1. ์‚ฌ์šฉ์ž๊ฐ€ ์ œ๊ณตํ•œ ํŽ˜๋ฅด์†Œ๋‚˜์™€ ๋ชฉ์ ์— ๋งž๊ฒŒ ํ…์ŠคํŠธ๋ฅผ ๋‹ค๋“ฌ์–ด๋ผ
2. ํ…์ŠคํŠธ์˜ ์ „๋ฐ˜์ ์ธ ํ†ค๊ณผ ๋ถ„์œ„๊ธฐ๋ฅผ ์‚ฌ์šฉ์ž๊ฐ€ ์„ค์ •ํ•œ ๋ฐฉํ–ฅ์— ๋งž์ถ”์–ด ์ˆ˜์ •ํ•˜๋ผ
3. ๋ช…ํ™•์„ฑ, ์ผ๊ด€์„ฑ, ๋…์ฐฝ์„ฑ์„ ์œ ์ง€ํ•˜๋ฉฐ ๊ฐœ์„ ํ•˜๋ผ
4. ๋ฐ˜๋“œ์‹œ ์‚ฌ์šฉ์ž ์ง€์ • ์ง€์นจ์— ๋”ฐ๋ผ ์ˆ˜์ •ํ•˜๋ผ
5. ์ ˆ๋Œ€ ๋‹ค๋ฅธ ๋ถ€๊ฐ€์ ์ธ ์„ค๋ช…์„ ์ถœ๋ ฅํ•˜์ง€ ๋ง ๊ฒƒ
- '์ˆ˜์ •๋œ ํ…์ŠคํŠธ', '๊ฐœ์„ ๋œ ํ…์ŠคํŠธ'๋“ฑ ์ถœ๋ ฅ๊ธˆ์ง€
""",
}
def process_text(input_text, improvement_type, custom_purpose, persona, temperature, top_p):
"""GPT ๋ชจ๋ธ์šฉ ํ…์ŠคํŠธ ์ฒ˜๋ฆฌ ํ•จ์ˆ˜"""
try:
print("ํ…์ŠคํŠธ ์ฒ˜๋ฆฌ ์‹œ์ž‘")
request_id = str(uuid.uuid4())[:8]
timestamp_micro = int(time.time() * 1000000) % 1000
if improvement_type == "๋‚ด ๋งˆ์Œ๋Œ€๋กœ ๋‹ค๋“ฌ๊ธฐ":
purpose = f"๋‹ค์Œ ํŽ˜๋ฅด์†Œ๋‚˜๋ฅผ ๊ฐ€์ง€๊ณ  ํ…์ŠคํŠธ๋ฅผ ๋‹ค๋“ฌ์œผ์„ธ์š”: {persona}\n\n๋ชฉ์ : {custom_purpose}"
else:
purpose = GPT_PROMPTS[improvement_type]
response = openai_client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{
"role": "system",
"content": f"REQ-{request_id}-{timestamp_micro}"
},
{
"role": "user",
"content": f"๋‹ค์Œ ํ…์ŠคํŠธ๋ฅผ ๋ชฉ์ ์— ๋งž๊ฒŒ ๋‹ค๋“ฌ์–ด๋ผ.\n\nํ…์ŠคํŠธ: {input_text}\n\n๋ชฉ์ : {purpose}"
}
],
max_tokens=2000,
temperature=temperature,
top_p=top_p
)
print("ํ…์ŠคํŠธ ์ฒ˜๋ฆฌ ์™„๋ฃŒ")
return response.choices[0].message.content
except Exception as e:
print("ํ…์ŠคํŠธ ์ฒ˜๋ฆฌ ์‹คํŒจ")
logger.error(f"์ฒ˜๋ฆฌ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: {str(e)}")
return f"์˜ค๋ฅ˜ ๋ฐœ์ƒ: {str(e)}"
def create_interface():
css = """
footer {
visibility: hidden;
}
"""
with gr.Blocks(theme=gr.themes.Soft(
primary_hue=gr.themes.Color(
c50="#FFF7ED", # ๊ฐ€์žฅ ๋ฐ์€ ์ฃผํ™ฉ
c100="#FFEDD5",
c200="#FED7AA",
c300="#FDBA74",
c400="#FB923C",
c500="#F97316", # ๊ธฐ๋ณธ ์ฃผํ™ฉ
c600="#EA580C",
c700="#C2410C",
c800="#9A3412",
c900="#7C2D12", # ๊ฐ€์žฅ ์–ด๋‘์šด ์ฃผํ™ฉ
c950="#431407",
),
secondary_hue="zinc", # ๋ชจ๋˜ํ•œ ๋Š๋‚Œ์˜ ํšŒ์ƒ‰ ๊ณ„์—ด
neutral_hue="zinc",
font=("Pretendard", "sans-serif")
), css=css) as demo:
gr.Markdown(
"""
# โœจ ํ…์ŠคํŠธ ๊ฐœ์„  ๋„๊ตฌ
### ํ…์ŠคํŠธ๋ฅผ ๋ชฉ์ ์— ๋งž๊ฒŒ ๊ฐœ์„ ํ•ด๋ณด์„ธ์š”
""",
elem_classes="text-3xl"
)
with gr.Row():
with gr.Column(scale=1):
input_text = gr.Textbox(
label="์›๋ณธ ํ…์ŠคํŠธ",
placeholder="์—ฌ๊ธฐ์— ๊ฐœ์„ ํ•˜๊ณ  ์‹ถ์€ ํ…์ŠคํŠธ๋ฅผ ์ž…๋ ฅํ•˜์„ธ์š”...1,000์ž ์ด์ƒ์€ ๋ชจ๋ธ์— ๋”ฐ๋ผ ํ€„๋ฆฌํ‹ฐ๊ฐ€ ๋–จ์–ด์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค",
lines=6
)
improvement_type = gr.Radio(
choices=["๋ฌธ๋ฒ• ๊ต์ •", "๋ฌธ์žฅ ๋‹ค๋“ฌ๊ธฐ", "๋ช…์–ธ์ธ์šฉํ•˜์—ฌ ๋‹ค๋“ฌ๊ธฐ", "๋‚ด ๋งˆ์Œ๋Œ€๋กœ ๋‹ค๋“ฌ๊ธฐ"],
label="๊ฐœ์„  ๋ฐฉํ–ฅ",
value="๋ฌธ๋ฒ• ๊ต์ •"
)
custom_purpose = gr.Textbox(
label="๊ฐœ์„  ๋ชฉ์ /๋ฐฉํ–ฅ์„ฑ",
placeholder="ํ…์ŠคํŠธ๋ฅผ ์–ด๋–ค ๋ฐฉํ–ฅ์œผ๋กœ ๊ฐœ์„ ํ•˜๊ณ  ์‹ถ์œผ์‹ ์ง€ ์„ค๋ช…ํ•ด์ฃผ์„ธ์š”...",
lines=4,
visible=False
)
persona = gr.Textbox(
label="ํŽ˜๋ฅด์†Œ๋‚˜ ์ ์šฉํ•˜๊ธฐ",
placeholder="์–ด๋–ค ์—ญํ• , ์„ฑ๊ฒฉ์„ ๊ฐ€์ง€๊ณ  ํ…์ŠคํŠธ๋ฅผ ๋‹ค๋“ฌ๊ธธ ์›ํ•˜์‹œ๋‚˜์š”? (์˜ˆ: ์œ ๋จธ๋Ÿฌ์Šคํ•œ ๊ฐœ๊ทธ๋งจ, ์ง„์ง€ํ•œ ๊ต์ˆ˜ ๋“ฑ)",
lines=4,
visible=False
)
with gr.Row(visible=False) as generation_settings:
temperature = gr.Slider(
minimum=0.0,
maximum=1.0,
value=0.7,
step=0.1,
label="Temperature",
info="๋†’์„์ˆ˜๋ก ๋” ์ฐฝ์˜์ ์ธ ๊ฒฐ๊ณผ๊ฐ€ ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค"
)
top_p = gr.Slider(
minimum=0.0,
maximum=1.0,
value=0.9,
step=0.1,
label="Top P",
info="๋†’์„์ˆ˜๋ก ๋” ๋‹ค์–‘ํ•œ ๋‹จ์–ด๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค"
)
submit_btn = gr.Button(
"โœจ ํ…์ŠคํŠธ ๊ฐœ์„ ํ•˜๊ธฐ",
variant="primary",
size="lg"
)
gr.Markdown("""
### ๐Ÿ’ก ์‚ฌ์šฉ ๊ฐ€์ด๋“œ
1. ๊ฐœ์„ ํ•˜๊ณ  ์‹ถ์€ ํ…์ŠคํŠธ๋ฅผ ์ž…๋ ฅํ•˜์„ธ์š”
2. ๊ฐœ์„  ๋ฐฉํ–ฅ์„ ์„ ํƒํ•˜์„ธ์š”
3. '๋‚ด ๋งˆ์Œ๋Œ€๋กœ ๋‹ค๋“ฌ๊ธฐ' ์„ ํƒ ์‹œ:
- ๊ฐœ์„  ๋ชฉ์ /๋ฐฉํ–ฅ์„ฑ์„ ์ž…๋ ฅํ•˜์„ธ์š”
- ํŽ˜๋ฅด์†Œ๋‚˜๋ฅผ ์„ค์ •ํ•˜์„ธ์š”
- Temperature, Top-p๋ฅผ ์„ค์ •ํ•ด๋ณด์„ธ์š”
4. 'ํ…์ŠคํŠธ ๊ฐœ์„ ํ•˜๊ธฐ' ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜์„ธ์š”
""")
with gr.Column(scale=1):
output_text = gr.Textbox(
label="๊ฐœ์„ ๋œ ํ…์ŠคํŠธ",
lines=35,
show_copy_button=True
)
def update_custom_inputs_visibility(choice):
is_custom = choice == "๋‚ด ๋งˆ์Œ๋Œ€๋กœ ๋‹ค๋“ฌ๊ธฐ"
return {
custom_purpose: gr.update(visible=is_custom),
persona: gr.update(visible=is_custom),
generation_settings: gr.update(visible=is_custom)
}
improvement_type.change(
fn=update_custom_inputs_visibility,
inputs=[improvement_type],
outputs=[custom_purpose, persona, generation_settings]
)
submit_btn.click(
fn=process_text,
inputs=[input_text, improvement_type, custom_purpose, persona, temperature, top_p],
outputs=output_text,
api_name="improve_text"
)
return demo
if __name__ == "__main__":
logger.info("์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์‹œ์ž‘")
demo = create_interface()
demo.queue()
demo.launch()