chatbot_test / app.py
jonghhhh's picture
Initial deploy: Gemini chatbot with Google Search grounding
e4b106f
"""
Gemini ์ฑ—๋ด‡ - Gradio ๋ฒ„์ „
Google Search๋กœ ์ตœ์‹  ์ •๋ณด๋ฅผ ๊ฒ€์ƒ‰ํ•˜๋Š” AI ์ฑ—๋ด‡
"""
import os
import json
import datetime
from google import genai
from google.genai import types
import gradio as gr
# ============================================================
# 1. Gemini์—๊ฒŒ ๋ฉ”์‹œ์ง€ ๋ณด๋‚ด๊ธฐ
# ============================================================
def send_message(user_message, chat_history, api_key, system_prompt, use_search):
"""์‚ฌ์šฉ์ž ๋ฉ”์‹œ์ง€๋ฅผ Gemini์—๊ฒŒ ๋ณด๋‚ด๊ณ  ์‘๋‹ต์„ ๋ฐ›์Šต๋‹ˆ๋‹ค."""
# API Key ํ™•์ธ
if not api_key or not api_key.strip():
chat_history.append({"role": "user", "content": user_message})
chat_history.append({"role": "assistant", "content": "โš ๏ธ API Key๋ฅผ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”."})
return "", chat_history
# ๋นˆ ๋ฉ”์‹œ์ง€ ํ™•์ธ
if not user_message or not user_message.strip():
return "", chat_history
# ํด๋ผ์ด์–ธํŠธ ์ƒ์„ฑ
client = genai.Client(api_key=api_key.strip())
# ํ˜„์žฌ ๋‚ ์งœ๋ฅผ ์‹œ์Šคํ…œ ํ”„๋กฌํ”„ํŠธ์— ์ถ”๊ฐ€
today = datetime.date.today().strftime("%Y-%m-%d")
base_instruction = f"์˜ค๋Š˜ ๋‚ ์งœ๋Š” {today}์ž…๋‹ˆ๋‹ค. ์ตœ์‹  ์ •๋ณด๋ฅผ ๊ธฐ์ค€์œผ๋กœ ๋‹ต๋ณ€ํ•˜์„ธ์š”."
if system_prompt and system_prompt.strip():
full_instruction = f"{base_instruction}\n{system_prompt.strip()}"
else:
full_instruction = base_instruction
# ๋„๊ตฌ ์„ค์ • (Google Search)
tools = []
if use_search:
tools = [types.Tool(google_search=types.GoogleSearch())]
# ์„ค์ •
config = types.GenerateContentConfig(
system_instruction=full_instruction,
tools=tools if tools else None,
)
# ๋Œ€ํ™” ๊ธฐ๋ก์„ Gemini ํ˜•์‹์œผ๋กœ ๋ณ€ํ™˜
contents = []
for msg in chat_history:
# Gradio 6์—์„œ content๊ฐ€ ๋ฆฌ์ŠคํŠธ๋กœ ์˜ฌ ์ˆ˜ ์žˆ์Œ
content = msg["content"]
if isinstance(content, list):
content = "".join(part["text"] for part in content if "text" in part)
role = "user" if msg["role"] == "user" else "model"
contents.append(types.Content(role=role, parts=[types.Part(text=content)]))
contents.append(types.Content(role="user", parts=[types.Part(text=user_message)]))
# ๋ฉ”์‹œ์ง€ ์ „์†ก
try:
response = client.models.generate_content(
model="gemini-2.5-flash-lite",
contents=contents,
config=config,
)
reply = response.text
except Exception as e:
reply = f"โŒ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: {str(e)}"
# ๋Œ€ํ™” ๊ธฐ๋ก์— ์ถ”๊ฐ€
chat_history.append({"role": "user", "content": user_message})
chat_history.append({"role": "assistant", "content": reply})
return "", chat_history
# ============================================================
# 2. ๋Œ€ํ™” ๊ธฐ๋ก ์ €์žฅ
# ============================================================
def save_chat(chat_history):
"""๋Œ€ํ™” ๊ธฐ๋ก์„ JSON ํŒŒ์ผ๋กœ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค."""
if not chat_history:
return gr.update(value=None)
now = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
filename = f"chat_{now}.json"
filepath = os.path.join("saved_chats", filename)
os.makedirs("saved_chats", exist_ok=True)
with open(filepath, "w", encoding="utf-8") as f:
json.dump(chat_history, f, ensure_ascii=False, indent=2)
return gr.update(value=filepath)
def clear_chat():
"""๋Œ€ํ™” ๊ธฐ๋ก์„ ์ดˆ๊ธฐํ™”ํ•ฉ๋‹ˆ๋‹ค."""
return []
# ============================================================
# 3. Gradio UI ๋งŒ๋“ค๊ธฐ
# ============================================================
with gr.Blocks(
title="Gemini ์ฑ—๋ด‡",
) as app:
gr.Markdown("# Gemini ์ฑ—๋ด‡")
gr.Markdown("Google Gemini API๋ฅผ ์‚ฌ์šฉํ•˜๋Š” AI ์ฑ—๋ด‡์ž…๋‹ˆ๋‹ค.")
with gr.Row():
# --- ์™ผ์ชฝ: ์„ค์ • ํŒจ๋„ ---
with gr.Column(scale=1):
gr.Markdown("## ์„ค์ •")
api_key = gr.Textbox(
label="Gemini API Key",
placeholder="API Key๋ฅผ ์ž…๋ ฅํ•˜์„ธ์š”",
type="password",
)
system_prompt = gr.Textbox(
label="์‹œ์Šคํ…œ ํ”„๋กฌํ”„ํŠธ",
placeholder="์˜ˆ: ๋‹น์‹ ์€ ์นœ์ ˆํ•œ ํ•œ๊ตญ์–ด AI ๋น„์„œ์ž…๋‹ˆ๋‹ค.",
lines=3,
)
use_search = gr.Checkbox(
label="Google Search ์‚ฌ์šฉ",
value=True,
)
gr.Markdown("---")
gr.Markdown("## ๋Œ€ํ™” ๊ด€๋ฆฌ")
save_btn = gr.Button("๋Œ€ํ™” ์ €์žฅ", variant="secondary")
save_output = gr.File(label="์ €์žฅ๋œ ํŒŒ์ผ")
# --- ์˜ค๋ฅธ์ชฝ: ์ฑ„ํŒ… ์˜์—ญ ---
with gr.Column(scale=3):
chatbot = gr.Chatbot(
label="๋Œ€ํ™”",
height=500,
)
with gr.Row():
msg = gr.Textbox(
label="๋ฉ”์‹œ์ง€ ์ž…๋ ฅ",
placeholder="๋ฉ”์‹œ์ง€๋ฅผ ์ž…๋ ฅํ•˜์„ธ์š”...",
scale=4,
show_label=False,
)
send_btn = gr.Button("์ „์†ก", variant="primary", scale=1)
clear_btn = gr.Button("๋Œ€ํ™” ์ดˆ๊ธฐํ™”")
# --- ์ด๋ฒคํŠธ ์—ฐ๊ฒฐ ---
send_btn.click(
fn=send_message,
inputs=[msg, chatbot, api_key, system_prompt, use_search],
outputs=[msg, chatbot],
)
msg.submit(
fn=send_message,
inputs=[msg, chatbot, api_key, system_prompt, use_search],
outputs=[msg, chatbot],
)
clear_btn.click(fn=clear_chat, outputs=[chatbot])
save_btn.click(fn=save_chat, inputs=[chatbot], outputs=[save_output])
# ============================================================
# 4. ์•ฑ ์‹คํ–‰
# ============================================================
if __name__ == "__main__":
app.launch(server_name="0.0.0.0", server_port=7860, theme=gr.themes.Soft())