gradio-example / app.py
JUNGU's picture
Update app.py
7af9de2 verified
raw
history blame
9 kB
# ํ•„์š”ํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.
import gradio as gr
import google.generativeai as genai
import os
import logging
# ๋กœ๊น… ์„ค์ •
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
# ์‹œ์ž‘ ์‹œ ํ™˜๊ฒฝ๋ณ€์ˆ˜ ํ™•์ธ
GEMINI_API_KEY = os.environ.get("GEMINI_API_KEY")
if GEMINI_API_KEY:
logger.info("API ํ‚ค๊ฐ€ ํ™˜๊ฒฝ๋ณ€์ˆ˜์—์„œ ๊ฐ์ง€๋˜์—ˆ์Šต๋‹ˆ๋‹ค.")
logger.info(f"API ํ‚ค ๋ฏธ๋ฆฌ๋ณด๊ธฐ: {GEMINI_API_KEY[:8]}...")
else:
logger.warning("GEMINI_API_KEY๊ฐ€ ํ™˜๊ฒฝ๋ณ€์ˆ˜์—์„œ ๊ฐ์ง€๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.")
# --- UI ๋ฐ ์ฑ—๋ด‡ ์„ค๋ช… ---
# Gradio Blocks๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ข€ ๋” ์œ ์—ฐํ•œ UI๋ฅผ ๊ตฌ์„ฑํ•ฉ๋‹ˆ๋‹ค.
with gr.Blocks(theme=gr.themes.Default(primary_hue="blue")) as demo:
gr.Markdown(
"""
# โ™Š๏ธ Gemini API ์ฑ—๋ด‡
Google Gemini API๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ฑ—๋ด‡์ž…๋‹ˆ๋‹ค.
**์ค‘์š”**: Hugging Face Spaces์˜ **Settings โ†’ Repository secrets**์— `GEMINI_API_KEY`๊ฐ€ ์„ค์ •๋˜์–ด ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
[API ํ‚ค ๋ฐœ๊ธ‰๋ฐ›๊ธฐ](https://aistudio.google.com/app/apikey)
"""
)
# ํ™˜๊ฒฝ๋ณ€์ˆ˜ ์ƒํƒœ ํ‘œ์‹œ
with gr.Row():
env_status = gr.Textbox(
label="ํ™˜๊ฒฝ๋ณ€์ˆ˜ ์ƒํƒœ",
value=f"GEMINI_API_KEY: {'โœ… ์„ค์ •๋จ' if GEMINI_API_KEY else 'โŒ ์„ค์ •๋˜์ง€ ์•Š์Œ'}",
interactive=False
)
# Gradio ์ฑ—๋ด‡ UI ์ปดํฌ๋„ŒํŠธ - type ํŒŒ๋ผ๋ฏธํ„ฐ ์ถ”๊ฐ€
chatbot = gr.Chatbot(
label="Gemini ์ฑ—๋ด‡",
height=600,
type="messages" # ์ด ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ ๊ฒฝ๊ณ  ํ•ด๊ฒฐ
)
with gr.Row():
# ์‚ฌ์šฉ์ž ๋ฉ”์‹œ์ง€ ์ž…๋ ฅ๋ž€
msg = gr.Textbox(
label="๋ฉ”์‹œ์ง€ ์ž…๋ ฅ",
placeholder="๋ฌด์—‡์ด๋“  ๋ฌผ์–ด๋ณด์„ธ์š”...",
scale=7,
lines=1
)
# ์ „์†ก ๋ฒ„ํŠผ
submit_button = gr.Button("์ „์†ก", variant="primary", scale=1)
with gr.Accordion("๊ณ ๊ธ‰ ์„ค์ •", open=False):
# LLM์˜ ์—ญํ• ์„ ์ •์˜ํ•˜๋Š” ์‹œ์Šคํ…œ ๋ฉ”์‹œ์ง€
system_message = gr.Textbox(
value="You are a helpful and friendly chatbot.",
label="์‹œ์Šคํ…œ ๋ฉ”์‹œ์ง€",
lines=2
)
# ๋ชจ๋ธ์˜ ์ฐฝ์˜์„ฑ์„ ์กฐ์ ˆํ•˜๋Š” ์Šฌ๋ผ์ด๋”
temperature = gr.Slider(
minimum=0.0,
maximum=1.0,
value=0.7,
step=0.1,
label="Temperature"
)
# ์ƒ์„ฑํ•  ์ตœ๋Œ€ ํ† ํฐ ์ˆ˜๋ฅผ ์กฐ์ ˆํ•˜๋Š” ์Šฌ๋ผ์ด๋”
max_tokens = gr.Slider(
minimum=1,
maximum=4096,
value=1024,
step=1,
label="Max new tokens"
)
# ํ™˜๊ฒฝ๋ณ€์ˆ˜ ์ƒˆ๋กœ๊ณ ์นจ ๋ฒ„ํŠผ
refresh_button = gr.Button("๐Ÿ”„ ํ™˜๊ฒฝ๋ณ€์ˆ˜ ์ƒˆ๋กœ๊ณ ์นจ", size="sm")
def refresh_env_status():
"""ํ™˜๊ฒฝ๋ณ€์ˆ˜ ์ƒํƒœ๋ฅผ ์ƒˆ๋กœ๊ณ ์นจํ•ฉ๋‹ˆ๋‹ค."""
global GEMINI_API_KEY
GEMINI_API_KEY = os.environ.get("GEMINI_API_KEY")
status = f"GEMINI_API_KEY: {'โœ… ์„ค์ •๋จ' if GEMINI_API_KEY else 'โŒ ์„ค์ •๋˜์ง€ ์•Š์Œ'}"
if GEMINI_API_KEY:
status += f" (๋ฏธ๋ฆฌ๋ณด๊ธฐ: {GEMINI_API_KEY[:8]}...)"
return status
refresh_button.click(refresh_env_status, outputs=[env_status])
# --- Gemini API ํ˜ธ์ถœ ํ•จ์ˆ˜ ---
def respond(message, chat_history, system_prompt, temp, max_output_tokens):
# ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœ๋  ๋•Œ๋งˆ๋‹ค ํ™˜๊ฒฝ๋ณ€์ˆ˜์—์„œ API ํ‚ค๋ฅผ ๋‹ค์‹œ ํ™•์ธ
api_key = os.environ.get("GEMINI_API_KEY")
# ๋””๋ฒ„๊น…์„ ์œ„ํ•œ ์ถ”๊ฐ€ ์ •๋ณด
logger.info(f"API ํ‚ค ํ™•์ธ: {'์žˆ์Œ' if api_key else '์—†์Œ'}")
# ํ™˜๊ฒฝ๋ณ€์ˆ˜์—์„œ ๊ฐ€์ ธ์˜จ API ํ‚ค๊ฐ€ ์—†์œผ๋ฉด ์•ˆ๋‚ด ๋ฉ”์‹œ์ง€๋ฅผ ๋„์›๋‹ˆ๋‹ค.
if not api_key:
error_msg = """โš ๏ธ **์˜ค๋ฅ˜**: `GEMINI_API_KEY`๊ฐ€ ์„ค์ •๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.
**ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•**:
1. Hugging Face Spaces์˜ **Settings** ํƒญ์œผ๋กœ ์ด๋™
2. **Repository secrets** ์„น์…˜ ์ฐพ๊ธฐ
3. **New secret** ๋ฒ„ํŠผ ํด๋ฆญ
4. Name: `GEMINI_API_KEY`, Value: ์‹ค์ œ API ํ‚ค ์ž…๋ ฅ
5. **Save** ํด๋ฆญ
6. Space๋ฅผ **์žฌ์‹œ์ž‘** (Settings โ†’ Factory reboot)
**์ฐธ๊ณ **: Private space๊ฐ€ ์•„๋‹Œ ๊ฒฝ์šฐ์—๋„ secrets๋Š” ์•ˆ์ „ํ•˜๊ฒŒ ๋ณดํ˜ธ๋ฉ๋‹ˆ๋‹ค."""
yield error_msg
return
try:
# API ํ‚ค๋ฅผ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.
genai.configure(api_key=api_key)
logger.info("API ํ‚ค ์„ค์ • ์„ฑ๊ณต")
except Exception as e:
yield f"API ํ‚ค ์„ค์ •์— ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค: {str(e)}"
return
# ์‚ฌ์šฉํ•  ๋ชจ๋ธ๊ณผ ์‹œ์Šคํ…œ ํ”„๋กฌํ”„ํŠธ๋ฅผ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.
try:
# ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ๋ชจ๋ธ๋กœ ๋ณ€๊ฒฝ
model = genai.GenerativeModel(
model_name='gemini-2.0-flash', # ์•ˆ์ •์ ์ธ ๋ชจ๋ธ ์‚ฌ์šฉ
system_instruction=system_prompt
)
except Exception as e:
yield f"๋ชจ๋ธ ์ดˆ๊ธฐํ™” ์˜ค๋ฅ˜: {str(e)}\n์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ๋ชจ๋ธ: gemini-1.5-flash, gemini-1.5-pro"
return
# Gradio์˜ ๋Œ€ํ™” ๊ธฐ๋ก์„ Gemini API๊ฐ€ ์ดํ•ดํ•  ์ˆ˜ ์žˆ๋Š” ํ˜•์‹์œผ๋กœ ๋ณ€ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
gemini_history = []
# type="messages" ํ˜•์‹์— ๋งž๊ฒŒ ์ฒ˜๋ฆฌ
if isinstance(chat_history, list) and len(chat_history) > 0:
# ์ƒˆ๋กœ์šด ๋ฉ”์‹œ์ง€ ํ˜•์‹ ์ฒ˜๋ฆฌ
if isinstance(chat_history[0], dict):
for msg in chat_history:
if msg.get("role") == "user":
gemini_history.append({"role": "user", "parts": [msg.get("content", "")]})
elif msg.get("role") == "assistant":
gemini_history.append({"role": "model", "parts": [msg.get("content", "")]})
# ์ด์ „ ํŠœํ”Œ ํ˜•์‹๋„ ์ง€์›
else:
for user_msg, model_msg in chat_history:
if user_msg:
gemini_history.append({"role": "user", "parts": [user_msg]})
if model_msg:
gemini_history.append({"role": "model", "parts": [model_msg]})
# ์ด์ „ ๋Œ€ํ™” ๊ธฐ๋ก์„ ๋ฐ”ํƒ•์œผ๋กœ ์ฑ„ํŒ… ์„ธ์…˜์„ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค.
chat = model.start_chat(history=gemini_history)
# ๋ชจ๋ธ ์ƒ์„ฑ ๊ด€๋ จ ์„ค์ •์„ ๊ตฌ์„ฑํ•ฉ๋‹ˆ๋‹ค.
generation_config = genai.types.GenerationConfig(
temperature=temp,
max_output_tokens=int(max_output_tokens),
)
try:
# ์ŠคํŠธ๋ฆฌ๋ฐ ๋ฐฉ์‹์œผ๋กœ ๋ฉ”์‹œ์ง€๋ฅผ ๋ณด๋‚ด๊ณ  ์‘๋‹ต์„ ๋ฐ›์Šต๋‹ˆ๋‹ค.
response = chat.send_message(
message,
stream=True,
generation_config=generation_config
)
# ์ŠคํŠธ๋ฆฌ๋ฐ ์‘๋‹ต์„ ์‹ค์‹œ๊ฐ„์œผ๋กœ UI์— ํ‘œ์‹œํ•ฉ๋‹ˆ๋‹ค.
full_response = ""
for chunk in response:
if hasattr(chunk, 'text'):
full_response += chunk.text
yield full_response
except Exception as e:
# API ํ˜ธ์ถœ ์ค‘ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด UI์— ํ‘œ์‹œํ•ฉ๋‹ˆ๋‹ค.
error_detail = str(e)
if "API_KEY_INVALID" in error_detail:
yield "โŒ API ํ‚ค๊ฐ€ ์œ ํšจํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์˜ฌ๋ฐ”๋ฅธ API ํ‚ค์ธ์ง€ ํ™•์ธํ•ด์ฃผ์„ธ์š”."
elif "QUOTA_EXCEEDED" in error_detail:
yield "โŒ API ์‚ฌ์šฉ๋Ÿ‰ ํ•œ๋„๋ฅผ ์ดˆ๊ณผํ–ˆ์Šต๋‹ˆ๋‹ค."
else:
yield f"์‘๋‹ต ์ƒ์„ฑ ์ค‘ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค: {error_detail}"
# --- Gradio ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ ---
def on_submit(message, chat_history, system_prompt, temp, max_output_tokens):
if not message.strip():
return "", chat_history
# ์ƒˆ๋กœ์šด ๋ฉ”์‹œ์ง€ ํ˜•์‹ ์‚ฌ์šฉ
chat_history = chat_history or []
# ์‚ฌ์šฉ์ž ๋ฉ”์‹œ์ง€ ์ถ”๊ฐ€
chat_history.append({"role": "user", "content": message})
# ๋ด‡ ์‘๋‹ต ์ŠคํŠธ๋ฆฌ๋ฐ
bot_response_stream = respond(message, chat_history[:-1], system_prompt, temp, max_output_tokens)
for partial_response in bot_response_stream:
# ๋งˆ์ง€๋ง‰ ๋ฉ”์‹œ์ง€๊ฐ€ ์‚ฌ์šฉ์ž ๋ฉ”์‹œ์ง€์ธ ๊ฒฝ์šฐ์—๋งŒ ๋ด‡ ์‘๋‹ต ์ถ”๊ฐ€
if chat_history and chat_history[-1]["role"] == "user":
chat_history.append({"role": "assistant", "content": partial_response})
else:
# ๋ด‡ ์‘๋‹ต ์—…๋ฐ์ดํŠธ
chat_history[-1]["content"] = partial_response
yield "", chat_history
# ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ ์—ฐ๊ฒฐ
msg.submit(
on_submit,
[msg, chatbot, system_message, temperature, max_tokens],
[msg, chatbot]
)
submit_button.click(
on_submit,
[msg, chatbot, system_message, temperature, max_tokens],
[msg, chatbot]
)
# ๋ฉ”์ธ ์‹คํ–‰ ๋ถ€๋ถ„
if __name__ == "__main__":
# ๋””๋ฒ„๊น… ๋ชจ๋“œ๋กœ ์‹คํ–‰
demo.launch(debug=True)