E2T4TWEWEWE / app.py
ssboost's picture
Create app.py
d7f2ca8 verified
raw
history blame
16.7 kB
import os
import gradio as gr
from dotenv import load_dotenv
import logging
import time
import uuid
import google.generativeai as genai
# ๋กœ๊น… ์„ค์ • - INFO ๋ ˆ๋ฒจ๋กœ ๋ณ€๊ฒฝ
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
# ํ™˜๊ฒฝ ๋ณ€์ˆ˜ ๋กœ๋“œ
load_dotenv()
# API ํ‚ค ์„ค์ •
GOOGLE_API_KEY = os.getenv("GOOGLE_API_KEY")
logger.info("API ํ‚ค ์„ค์ • ์™„๋ฃŒ")
# Google Gemini ์ดˆ๊ธฐํ™”
genai.configure(api_key=GOOGLE_API_KEY)
# ๋ชจ๋ธ๋ณ„ ํ”„๋กฌํ”„ํŠธ ์ •์˜
GEMINI_PROMPTS = {
"๋งž์ถค๋ฒ• ๊ฒ€์‚ฌ๊ธฐ": """
# ๋ชฉ์ : ํ•œ๊ตญ์–ด ๋ฌธ๋ฒ• ๊ต์ • ๋ฐ ๊ฐœ์„ 
## ์ง€์นจ
1. ์ฃผ์–ด์ง„ ํ…์ŠคํŠธ์˜ ๋ฌธ๋ฒ•์„ ์ „๋ฌธ์ ์œผ๋กœ ๊ฒ€ํ† ํ•˜๊ณ  ๊ต์ •ํ•˜์„ธ์š”.
2. ์›๋ณธ ํ…์ŠคํŠธ์˜ ์˜๋ฏธ์™€ ์˜๋„๋ฅผ ์ฒ ์ €ํžˆ ์œ ์ง€ํ•˜๋ฉด์„œ ๋ฌธ๋ฒ•์ ์ธ ๋ถ€๋ถ„๋งŒ ์ˆ˜์ •ํ•˜์„ธ์š”.
3. ๋‹ค์Œ ์š”์†Œ๋“ค์„ ํ•œ๊ตญ์–ด ๋ฌธ๋ฒ• ๊ทœ์น™์— ๋งž๊ฒŒ ์ •ํ™•ํ•˜๊ฒŒ ์ˆ˜์ •ํ•˜์„ธ์š”:
- ๋งž์ถค๋ฒ• ์˜ค๋ฅ˜
- ๋„์–ด์“ฐ๊ธฐ ์˜ค๋ฅ˜
- ๋ฌธ์žฅ ๋ถ€ํ˜ธ ์‚ฌ์šฉ
- ์กฐ์‚ฌ ์‚ฌ์šฉ์˜ ์ •ํ™•์„ฑ
- ์–ด๋ฏธ ํ™œ์šฉ์˜ ์ •ํ™•์„ฑ
- ๋ฌธ์žฅ ์„ฑ๋ถ„์˜ ํ˜ธ์‘ ๊ด€๊ณ„
4. ์ ˆ๋Œ€ ์›๋ณธ ํ…์ŠคํŠธ์— ์—†๋Š” ๋‚ด์šฉ์„ ์ถ”๊ฐ€ํ•˜๊ฑฐ๋‚˜ ์˜๋ฏธ๋ฅผ ๋ณ€๊ฒฝํ•˜์ง€ ๋งˆ์„ธ์š”.
5. ๋ถ€๊ฐ€ ์„ค๋ช…์ด๋‚˜ ๋ฉ”ํƒ€ ์ •๋ณด(์˜ˆ: "์ˆ˜์ •๋œ ํ…์ŠคํŠธ:", "๊ฐœ์„ ๋œ ํ…์ŠคํŠธ:" ๋“ฑ)๋Š” ์ถœ๋ ฅํ•˜์ง€ ๋งˆ์„ธ์š”.
6. ์˜ค์ง ๊ต์ •๋œ ํ…์ŠคํŠธ๋งŒ ์ถœ๋ ฅํ•˜์„ธ์š”.
""",
"๊ธ€ ๋‹ค๋“ฌ๊ธฐ": """
# ๋ชฉ์ : ๋ฌธ์žฅ ๊ตฌ์กฐ์™€ ํ‘œํ˜„ ๊ฐœ์„ 
## ์ง€์นจ
1. ๋ฌธ์žฅ ๊ตฌ์กฐ ์ตœ์ ํ™”
- ๋ถˆํ•„์š”ํ•œ ๋ฌธ๊ตฌ์™€ ์ค‘๋ณต ํ‘œํ˜„์„ ์ œ๊ฑฐํ•˜์—ฌ ๊ฐ„๊ฒฐ์„ฑ ํ™•๋ณด
- ์ฃผ์–ด-์„œ์ˆ ์–ด ๊ด€๊ณ„๋ฅผ ๋ช…ํ™•ํžˆ ํ•˜์—ฌ ์˜๋ฏธ ์ „๋‹ฌ๋ ฅ ๊ฐ•ํ™”
- ๊ณผ๋„ํ•˜๊ฒŒ ๊ธด ๋ฌธ์žฅ์€ ์ ์ ˆํžˆ ๋ถ„๋ฆฌํ•˜์—ฌ ๊ฐ€๋…์„ฑ ํ–ฅ์ƒ
- ๋ฌธ์žฅ ๊ฐ„์˜ ๋…ผ๋ฆฌ์  ์—ฐ๊ฒฐ์„ฑ ํ™•๋ณด
2. ๋‹จ๋ฝ ๊ตฌ์„ฑ ์ตœ์ ํ™”
- ๊ฐ ๋‹จ๋ฝ์ด ๋ช…ํ™•ํ•œ ํ•ต์‹ฌ ์ฃผ์ œ๋ฅผ ๊ฐ€์ง€๋„๋ก ์กฐ์ •
- ๋‹จ๋ฝ ๊ฐ„ ์ž์—ฐ์Šค๋Ÿฌ์šด ํ๋ฆ„์„ ์œ„ํ•œ ์—ฐ๊ฒฐ์–ด ์‚ฌ์šฉ
- ๋‹จ๋ฝ ๊ธธ์ด์˜ ๊ท ํ˜• ์œ ์ง€
3. ์–ดํœ˜ ๋ฐ ํ‘œํ˜„ ๊ฐœ์„ 
- ๋ถˆํ•„์š”ํ•œ ์™ธ๋ž˜์–ด๋Š” ์ ์ ˆํ•œ ํ•œ๊ตญ์–ด๋กœ ๋Œ€์ฒด
- ์ถ”์ƒ์ ์ด๊ฑฐ๋‚˜ ๋ชจํ˜ธํ•œ ํ‘œํ˜„์€ ๊ตฌ์ฒด์ ์ด๊ณ  ๋ช…ํ™•ํ•œ ์šฉ์–ด๋กœ ๋Œ€์ฒด
- ์ค‘๋ณต๋˜๋Š” ํ‘œํ˜„ ์ œ๊ฑฐ๋กœ ๋ฌธ์žฅ ํšจ์œจ์„ฑ ์ฆ๋Œ€
- ๊ด€์šฉ์  ํ‘œํ˜„๊ณผ ์ ์ ˆํ•œ ๋น„์œ ๋ฅผ ํ™œ์šฉํ•˜์—ฌ ํ‘œํ˜„๋ ฅ ๊ฐ•ํ™”
4. ์ „๋‹ฌ๋ ฅ ๊ฐ•ํ™”
- ํ•ต์‹ฌ ๋ฉ”์‹œ์ง€๊ฐ€ ๋‹๋ณด์ด๋„๋ก ๋ฌธ์žฅ ๊ตฌ์กฐ ์žฌ๋ฐฐ์น˜
- ๋…ผ๋ฆฌ์  ํ๋ฆ„๊ณผ ์ผ๊ด€์„ฑ ํ™•๋ณด
- ๋…์ž์˜ ์ดํ•ด๋„๋ฅผ ๊ณ ๋ คํ•œ ํ‘œํ˜„ ์„ ํƒ
5. ์ผ๊ด€์„ฑ ์œ ์ง€
- ๋ฌธ์ฒด์™€ ํ†ค์˜ ์ผ๊ด€์„ฑ ์œ ์ง€
- ์ „๋ฌธ ์šฉ์–ด์™€ ํ‘œํ˜„์˜ ํ†ต์ผ์„ฑ ํ™•๋ณด
- ์‹œ์ œ์˜ ์ผ๊ด€๋œ ์‚ฌ์šฉ
## ์ถœ๋ ฅ ํ˜•์‹
- ์›๋ณธ ํ…์ŠคํŠธ์™€ ๋™์ผํ•œ ๋งํˆฌ์™€ ์–ด์กฐ๋ฅผ ์œ ์ง€ํ•˜๋˜, ์œ„ ๊ธฐ์ค€์— ๋”ฐ๋ผ ๊ฐœ์„ ๋œ ํ…์ŠคํŠธ๋งŒ ์ถœ๋ ฅ
- ๋ถ€๊ฐ€ ์„ค๋ช…์ด๋‚˜ ๋ฉ”ํƒ€ ์ •๋ณด๋Š” ํฌํ•จํ•˜์ง€ ์•Š์Œ
""",
"๋ช…์–ธ ์ธ์šฉํ•˜๊ธฐ": """
# ๋ชฉ์ : ๋ช…์–ธ์„ ํ™œ์šฉํ•œ ์„ค๋“๋ ฅ ์žˆ๋Š” ํ…์ŠคํŠธ ๊ฐœ์„ 
## ์ง€์นจ
1. ๋ฌธ๋งฅ ๋ถ„์„
- ํ…์ŠคํŠธ์˜ ํ•ต์‹ฌ ์ฃผ์ œ์™€ ์˜๋„ ํŒŒ์•…
- ํ…์ŠคํŠธ์˜ ๋ถ„์œ„๊ธฐ์™€ ํ†ค ๋ถ„์„
- ๋…์ž์ธต๊ณผ ๋ชฉ์  ๊ณ ๋ ค
2. ์ ์ ˆํ•œ ๋ช…์–ธ ์„ ํƒ
- ํ…์ŠคํŠธ์˜ ์ฃผ์ œ์™€ ์ง์ ‘์ ์œผ๋กœ ์—ฐ๊ด€๋œ ๋ช…์–ธ ์„ ํƒ
- ๋‹ค์–‘ํ•œ ๋ถ„์•ผ(์ฒ ํ•™, ๋ฌธํ•™, ์—ญ์‚ฌ, ๊ณผํ•™ ๋“ฑ)์˜ ๋ช…์–ธ ๊ณ ๋ ค
- ๊ณ ์ „์ ์ธ ๋ช…์–ธ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ํ˜„๋Œ€ ์œ ๋ช…์ธ(์—ฐ์˜ˆ์ธ, ๊ธฐ์—…์ธ, ์šด๋™์„ ์ˆ˜, ์ •์น˜์ธ ๋“ฑ)์˜ ์ธ์ƒ์ ์ธ ๋ง๋„ ์ ๊ทน ํ™œ์šฉ
- ํ•œ๊ตญ ๋ฐ ์„ธ๊ณ„์˜ ์ €๋ช…ํ•œ ์ธ๋ฌผ์˜ ๋ช…์–ธ ํ™œ์šฉ
- ํ…์ŠคํŠธ์˜ ํ†ค๊ณผ ๋ถ„์œ„๊ธฐ์— ์–ด์šธ๋ฆฌ๋Š” ๋ช…์–ธ ์„ ํƒ
- ๊ฐ€๋Šฅํ•˜๋ฉด ์‹œ์˜์ ์ ˆํ•˜๊ณ  ์ตœ์‹  ํŠธ๋ Œ๋“œ๋ฅผ ๋ฐ˜์˜ํ•œ ํ˜„๋Œ€์  ๋ช…์–ธ ์šฐ์„  ๊ณ ๋ ค
3. ๋ช…์–ธ ํ†ตํ•ฉ
- ํ…์ŠคํŠธ ๋‚ด ๊ฐ€์žฅ ํšจ๊ณผ์ ์ธ ์œ„์น˜์— ๋ช…์–ธ ๋ฐฐ์น˜ (์‹œ์ž‘, ์ค‘๊ฐ„, ๋˜๋Š” ๊ฒฐ๋ก )
- ๋ช…์–ธ์„ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ๋„์ž…ํ•˜์—ฌ ๊ธฐ์กด ํ…์ŠคํŠธ์™€ ์กฐํ™”๋กญ๊ฒŒ ํ†ตํ•ฉ
- ํ•„์š”์‹œ ๋ช…์–ธ์˜ ์ถœ์ฒ˜(์ธ๋ฌผ ์ด๋ฆ„) ํฌํ•จ
- ๋”ฑ ํ•œ ๋ฒˆ๋งŒ ๋ช…์–ธ ์ธ์šฉํ•˜๊ธฐ
- ํ˜„๋Œ€ ์œ ๋ช…์ธ์˜ ๋ช…์–ธ ์‚ฌ์šฉ ์‹œ ๊ฐ„๋‹จํ•œ ๋งฅ๋ฝ ์„ค๋ช… ๊ณ ๋ ค(ํ•„์š”ํ•œ ๊ฒฝ์šฐ)
4. ์ „์ฒด ํ…์ŠคํŠธ ์กฐ์ •
- ๋ช…์–ธ ๋„์ž… ํ›„ ํ•„์š”์‹œ ์ „ํ›„ ๋ฌธ์žฅ ์กฐ์ •ํ•˜์—ฌ ์ž์—ฐ์Šค๋Ÿฌ์šด ํ๋ฆ„ ์œ ์ง€
- ์›๋ณธ ํ…์ŠคํŠธ์˜ ํ•ต์‹ฌ ๋ฉ”์‹œ์ง€์™€ ์˜๋„ ๋ณด์กด
- ์ „์ฒด์ ์ธ ์ผ๊ด€์„ฑ๊ณผ ์‘์ง‘๋ ฅ ์œ ์ง€
- ๋ช…์–ธ์ด ํ…์ŠคํŠธ์— ์‹ ์„ ํ•จ๊ณผ ๊ถŒ์œ„๋ฅผ ๋ถ€์—ฌํ•˜๋Š”์ง€ ํ™•์ธ
## ์ถœ๋ ฅ ํ˜•์‹
- ๋ช…์–ธ์ด ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ํ†ตํ•ฉ๋œ ๊ฐœ์„ ๋œ ํ…์ŠคํŠธ๋งŒ ์ถœ๋ ฅ
- ๋ถ€๊ฐ€ ์„ค๋ช…์ด๋‚˜ ๋ฉ”ํƒ€ ์ •๋ณด ์—†์ด ์ˆœ์ˆ˜ํ•˜๊ฒŒ ๊ฐœ์„ ๋œ ํ…์ŠคํŠธ๋งŒ ์ œ๊ณต
""",
"๋งž์ถคํ˜• ๋ณ€ํ™˜": """
# ๋ชฉ์ : ์‚ฌ์šฉ์ž ์ •์˜ ํŽ˜๋ฅด์†Œ๋‚˜์™€ ๋ชฉ์ ์— ๋งž๋Š” ํ…์ŠคํŠธ ๋ณ€ํ™˜
## ์ง€์นจ
1. ํŽ˜๋ฅด์†Œ๋‚˜ ๋ถ„์„ ๋ฐ ์ ์šฉ
- ์‚ฌ์šฉ์ž๊ฐ€ ์ œ๊ณตํ•œ ํŽ˜๋ฅด์†Œ๋‚˜์˜ ํŠน์„ฑ ๋ถ„์„ (๋งํˆฌ, ์–ดํœ˜ ์„ ํƒ, ๋ฌธ์žฅ ๊ตฌ์กฐ ๋“ฑ)
- ํ•ด๋‹น ํŽ˜๋ฅด์†Œ๋‚˜๊ฐ€ ์‹ค์ œ๋กœ ์ž‘์„ฑํ–ˆ์„ ๋ฒ•ํ•œ ์Šคํƒ€์ผ๋กœ ํ…์ŠคํŠธ ์žฌ๊ตฌ์„ฑ
- ํŽ˜๋ฅด์†Œ๋‚˜์˜ ๊ณ ์œ ํ•œ ํ‘œํ˜„ ๋ฐฉ์‹๊ณผ ๊ด€์  ๋ฐ˜์˜
2. ๋ชฉ์  ๋ถ„์„ ๋ฐ ์ ์šฉ
- ์‚ฌ์šฉ์ž๊ฐ€ ๋ช…์‹œํ•œ ๋ชฉ์ ์— ๋งž๊ฒŒ ํ…์ŠคํŠธ์˜ ์ „๋ฐ˜์ ์ธ ๋ฐฉํ–ฅ์„ฑ ์กฐ์ •
- ๋ชฉ์ ์— ๋งž๋Š” ๊ตฌ์กฐ, ๋…ผ์กฐ, ๊ฐ•์กฐ์  ์„ค์ •
- ๋ชฉ์  ๋‹ฌ์„ฑ์— ํ•„์š”ํ•œ ์š”์†Œ ๊ฐ•ํ™” ๋ฐ ๋ถˆํ•„์š”ํ•œ ์š”์†Œ ์ œ๊ฑฐ
3. ํ…์ŠคํŠธ ๋งž์ถค ๋ณ€ํ™˜
- ํŽ˜๋ฅด์†Œ๋‚˜์™€ ๋ชฉ์ ์„ ์ข…ํ•ฉ์ ์œผ๋กœ ๊ณ ๋ คํ•œ ํ…์ŠคํŠธ ๋ณ€ํ™˜
- ์›๋ณธ ํ…์ŠคํŠธ์˜ ํ•ต์‹ฌ ์ •๋ณด์™€ ์ฃผ์š” ๋…ผ์  ์œ ์ง€
- ์–ดํœ˜, ๋ฌธ์žฅ ๊ตฌ์กฐ, ๋น„์œ , ์˜ˆ์‹œ ๋“ฑ์„ ํŽ˜๋ฅด์†Œ๋‚˜์™€ ๋ชฉ์ ์— ๋งž๊ฒŒ ์กฐ์ •
- ์ „์ฒด์ ์ธ ์ผ๊ด€์„ฑ๊ณผ ์ง„์ •์„ฑ ์œ ์ง€
4. ํ’ˆ์งˆ ๋ฐ ํšจ๊ณผ ์ตœ์ ํ™”
- ๋ช…ํ™•์„ฑ๊ณผ ์ดํ•ด๋„ ํ–ฅ์ƒ
- ์„ค๋“๋ ฅ๊ณผ ํ˜ธ์†Œ๋ ฅ ๊ฐ•ํ™”
- ๋…์ฐฝ์„ฑ๊ณผ ์ฐธ์‹ ํ•จ ์ถ”๊ตฌ
- ๋ชฉํ‘œ ๋…์ž์—๊ฒŒ ํšจ๊ณผ์ ์œผ๋กœ ์ „๋‹ฌ๋  ์ˆ˜ ์žˆ๋Š” ํ˜•ํƒœ๋กœ ์ตœ์ ํ™”
## ์ถœ๋ ฅ ํ˜•์‹
- ํŽ˜๋ฅด์†Œ๋‚˜์™€ ๋ชฉ์ ์— ๋งž๊ฒŒ ๋ณ€ํ˜•๋œ ํ…์ŠคํŠธ๋งŒ ์ถœ๋ ฅ
- ๋ถ€๊ฐ€ ์„ค๋ช…์ด๋‚˜ ๋ฉ”ํƒ€ ์ •๋ณด ์—†์ด ์ˆœ์ˆ˜ํ•˜๊ฒŒ ๋ณ€ํ™˜๋œ ํ…์ŠคํŠธ๋งŒ ์ œ๊ณต
- ์‚ฌ์šฉ์ž๊ฐ€ ๋ช…์‹œํ•œ ๋ชฉ์ ๊ณผ ํŽ˜๋ฅด์†Œ๋‚˜์˜ ํŠน์„ฑ์ด ๋ช…ํ™•ํžˆ ๋“œ๋Ÿฌ๋‚˜๋Š” ๊ฒฐ๊ณผ๋ฌผ ์ œ๊ณต
""",
}
def process_text(input_text, improvement_type, custom_purpose, persona, temperature, top_p):
"""Gemini ๋ชจ๋ธ์šฉ ํ…์ŠคํŠธ ์ฒ˜๋ฆฌ ํ•จ์ˆ˜"""
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 = GEMINI_PROMPTS[improvement_type]
model = genai.GenerativeModel(
model_name="gemini-2.0-flash",
generation_config={
"temperature": temperature,
"top_p": top_p,
"max_output_tokens": 2000,
}
)
# ์‹œ์Šคํ…œ ์ง€์‹œ์‚ฌํ•ญ์„ ์ฒซ ๋ฒˆ์งธ ์‚ฌ์šฉ์ž ๋ฉ”์‹œ์ง€์— ํฌํ•จ
prompt = f"REQ-{request_id}-{timestamp_micro}\n\n๋‹ค์Œ ํ…์ŠคํŠธ๋ฅผ ๋ชฉ์ ์— ๋งž๊ฒŒ ๋‹ค๋“ฌ์–ด์ฃผ์„ธ์š”.\n\nํ…์ŠคํŠธ: {input_text}\n\n๋ชฉ์ : {purpose}"
response = model.generate_content(prompt)
print("ํ…์ŠคํŠธ ์ฒ˜๋ฆฌ ์™„๋ฃŒ")
return response.text
except Exception as e:
print("ํ…์ŠคํŠธ ์ฒ˜๋ฆฌ ์‹คํŒจ")
logger.error(f"์ฒ˜๋ฆฌ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: {str(e)}")
return f"์˜ค๋ฅ˜ ๋ฐœ์ƒ: {str(e)}"
def create_interface():
# FontAwesome ์•„์ด์ฝ˜ ํฌํ•จ
fontawesome = """
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" crossorigin="anonymous" referrerpolicy="no-referrer" />
"""
# ์ปค์Šคํ…€ CSS ์Šคํƒ€์ผ
css = """
:root {
--primary-color: #FF7F00;
--secondary-color: #ff9a8b;
--accent-color: #FF6B6B;
--background-color: #FFF8F0;
--card-bg: #ffffff;
--text-color: #334155;
--border-radius: 18px;
--shadow: 0 8px 30px rgba(251, 127, 13, 0.08);
}
body {
font-family: 'Pretendard', 'Noto Sans KR', -apple-system, BlinkMacSystemFont, sans-serif;
background-color: var(--background-color);
color: var(--text-color);
line-height: 1.6;
}
footer {
visibility: hidden;
}
.container {
max-width: 1200px;
margin: 0 auto;
}
.header {
background: linear-gradient(135deg, #FF7F00, #FF9A5B);
padding: 2rem;
border-radius: 15px;
margin-bottom: 20px;
box-shadow: var(--shadow);
text-align: center;
color: white;
}
.header h1 {
margin: 0;
font-size: 2.5rem;
font-weight: 700;
}
.header p {
margin: 10px 0 0;
font-size: 1.2rem;
opacity: 0.9;
}
.card {
background-color: var(--card-bg);
border-radius: var(--border-radius);
padding: 20px;
margin: 10px 0;
box-shadow: var(--shadow);
border: 1px solid rgba(0, 0, 0, 0.04);
}
.button-primary {
border-radius: 30px !important;
background: linear-gradient(135deg, var(--primary-color), var(--secondary-color)) !important;
color: white !important;
font-size: 18px !important;
padding: 10px 20px !important;
border: none;
box-shadow: 0 4px 8px rgba(251, 127, 13, 0.25);
transition: transform 0.3s ease;
text-align: center;
font-weight: 600;
}
.button-primary:hover {
transform: translateY(-2px);
box-shadow: 0 6px 12px rgba(251, 127, 13, 0.3);
}
.section-title {
display: flex;
align-items: center;
font-size: 20px;
font-weight: 700;
color: #333333;
margin-bottom: 15px;
padding-bottom: 8px;
border-bottom: 2px solid #FF7F00;
}
.section-title i {
margin-right: 10px;
color: #FF7F00;
}
.guide-container {
background-color: #FFF0E2;
border-radius: var(--border-radius);
padding: 1.5rem;
margin-bottom: 1.5rem;
border: 1px solid rgba(255, 127, 0, 0.1);
}
.guide-title {
font-size: 1.3rem;
font-weight: 700;
color: var(--primary-color);
margin-bottom: 1rem;
display: flex;
align-items: center;
}
.guide-title i {
margin-right: 0.8rem;
font-size: 1.3rem;
}
.guide-item {
display: flex;
margin-bottom: 0.8rem;
align-items: flex-start;
}
.guide-number {
background-color: var(--primary-color);
color: white;
width: 24px;
height: 24px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-weight: bold;
margin-right: 10px;
flex-shrink: 0;
font-size: 14px;
}
.guide-text {
flex: 1;
line-height: 1.6;
}
.feature-tag {
display: inline-block;
background-color: rgba(255, 127, 0, 0.1);
color: #FF7F00;
padding: 3px 10px;
border-radius: 12px;
font-size: 14px;
font-weight: 600;
margin-right: 8px;
margin-bottom: 8px;
}
.input-label {
font-weight: 600;
margin-bottom: 8px;
color: #444;
}
/* ๊ทธ๋ผ๋””์˜ค ์š”์†Œ ์Šคํƒ€์ผ ์ปค์Šคํ„ฐ๋งˆ์ด์ง• */
.gr-input, .gr-text-input, .gr-sample-inputs {
border-radius: var(--border-radius) !important;
border: 1px solid #e5e7eb !important;
padding: 12px !important;
transition: all 0.3s ease !important;
}
.gr-input:focus, .gr-text-input:focus {
border-color: var(--primary-color) !important;
outline: none !important;
box-shadow: 0 0 0 2px rgba(251, 127, 13, 0.2) !important;
}
/* ์Šคํฌ๋กค๋ฐ” ์Šคํƒ€์ผ๋ง */
::-webkit-scrollbar {
width: 8px;
height: 8px;
}
::-webkit-scrollbar-track {
background: rgba(0, 0, 0, 0.05);
border-radius: 10px;
}
::-webkit-scrollbar-thumb {
background: var(--primary-color);
border-radius: 10px;
}
"""
with gr.Blocks(css=css, 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")
)) as demo:
gr.HTML(fontawesome)
with gr.Row():
with gr.Column(scale=1):
# ์™ผ์ชฝ ์ž…๋ ฅ ์˜์—ญ
with gr.Column(elem_classes="card"):
gr.HTML('<div class="section-title"><i class="fas fa-edit"></i> ์›๋ณธ ํ…์ŠคํŠธ</div>')
input_text = gr.Textbox(
label="",
placeholder="์—ฌ๊ธฐ์— ๊ฐœ์„ ํ•˜๊ณ  ์‹ถ์€ ํ…์ŠคํŠธ๋ฅผ ์ž…๋ ฅํ•˜์„ธ์š”...",
lines=15
)
with gr.Column(elem_classes="card"):
gr.HTML('<div class="section-title"><i class="fas fa-sliders"></i> ๋ณ€ํ™˜ ์„ค์ •</div>')
improvement_type = gr.Radio(
choices=["๋งž์ถค๋ฒ• ๊ฒ€์‚ฌ๊ธฐ", "๊ธ€ ๋‹ค๋“ฌ๊ธฐ", "๋ช…์–ธ ์ธ์šฉํ•˜๊ธฐ", "๋งž์ถคํ˜• ๋ณ€ํ™˜"],
label="๋ณ€ํ™˜ ์œ ํ˜• ์„ ํƒ",
value="๋งž์ถค๋ฒ• ๊ฒ€์‚ฌ๊ธฐ"
)
# ๋งž์ถคํ˜• ๋ณ€ํ™˜ ์˜ต์…˜๋“ค
custom_purpose = gr.Textbox(
label="๋ณ€ํ™˜ ๋ชฉ์ ",
placeholder="ํ…์ŠคํŠธ๋ฅผ ์–ด๋–ค ๋ฐฉํ–ฅ์œผ๋กœ ๋ณ€ํ™˜ํ•˜๊ณ  ์‹ถ์œผ์‹ ์ง€ ์„ค๋ช…ํ•ด์ฃผ์„ธ์š”...",
lines=2,
visible=False
)
persona = gr.Textbox(
label="ํŽ˜๋ฅด์†Œ๋‚˜ ์„ค์ •",
placeholder="์–ด๋–ค ์—ญํ• ์ด๋‚˜ ์„ฑ๊ฒฉ์„ ๊ฐ€์ง„ ๊ธ€์“ฐ๊ธฐ ์Šคํƒ€์ผ์„ ์›ํ•˜์‹œ๋‚˜์š”? (์˜ˆ: ์œ ๋จธ๋Ÿฌ์Šคํ•œ ๊ฐœ๊ทธ๋งจ, ์ „๋ฌธ์ ์ธ ๋ถ„์„๊ฐ€)",
lines=2,
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="์ฐฝ์˜์„ฑ ์ˆ˜์ค€",
info="๋†’์„์ˆ˜๋ก ๋” ์ฐฝ์˜์ ์ธ ๊ฒฐ๊ณผ๊ฐ€ ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค"
)
top_p = gr.Slider(
minimum=0.0,
maximum=1.0,
value=0.9,
step=0.1,
label="๋‹ค์–‘์„ฑ ์ˆ˜์ค€",
info="๋†’์„์ˆ˜๋ก ๋” ๋‹ค์–‘ํ•œ ํ‘œํ˜„์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค"
)
submit_btn = gr.Button(
"โœจ ํ…์ŠคํŠธ ๋ณ€ํ™˜ํ•˜๊ธฐ",
elem_classes="button-primary"
)
with gr.Column(scale=1):
# ์˜ค๋ฅธ์ชฝ ์ถœ๋ ฅ ์˜์—ญ
with gr.Column(elem_classes="card"):
gr.HTML('<div class="section-title"><i class="fas fa-wand-magic-sparkles"></i> ๋ณ€ํ™˜๋œ ํ…์ŠคํŠธ</div>')
output_text = gr.Textbox(
label="",
lines=22,
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()