jonghhhh Claude Opus 4.6 commited on
Commit
e4b106f
ยท
1 Parent(s): 4180839

Initial deploy: Gemini chatbot with Google Search grounding

Browse files

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

Files changed (5) hide show
  1. .gitignore +6 -0
  2. Dockerfile +12 -0
  3. README.md +13 -7
  4. app.py +188 -0
  5. requirements.txt +2 -0
.gitignore ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ .venv/
2
+ __pycache__/
3
+ .env
4
+ *.pyc
5
+ saved_chats/
6
+ .ipynb_checkpoints/
Dockerfile ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.11-slim
2
+
3
+ WORKDIR /app
4
+
5
+ COPY requirements.txt .
6
+ RUN pip install --no-cache-dir -r requirements.txt
7
+
8
+ COPY . .
9
+
10
+ EXPOSE 7860
11
+
12
+ CMD ["python", "app.py"]
README.md CHANGED
@@ -1,12 +1,18 @@
1
  ---
2
- title: Chatbot Test
3
- emoji: ๐Ÿฆ€
4
  colorFrom: blue
5
- colorTo: yellow
6
- sdk: gradio
7
- sdk_version: 6.5.1
8
- app_file: app.py
9
  pinned: false
10
  ---
11
 
12
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
1
  ---
2
+ title: My Chatbot
3
+ emoji: ๐Ÿค–
4
  colorFrom: blue
5
+ colorTo: purple
6
+ sdk: docker
 
 
7
  pinned: false
8
  ---
9
 
10
+ # ๐Ÿค– Gemini ์ฑ—๋ด‡
11
+
12
+ Google Gemini API๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฐ„๋‹จํ•œ AI ์ฑ—๋ด‡์ž…๋‹ˆ๋‹ค.
13
+
14
+ ## ๊ธฐ๋Šฅ
15
+ - Gemini 2.5 Flash Lite ๋ชจ๋ธ ๋Œ€ํ™”
16
+ - Google Search ์—ฐ๋™
17
+ - ๋Œ€ํ™” ๊ธฐ๋ก ์ €์žฅ/๋ถˆ๋Ÿฌ์˜ค๊ธฐ
18
+ - ์‹œ์Šคํ…œ ํ”„๋กฌํ”„ํŠธ ์„ค์ •
app.py ADDED
@@ -0,0 +1,188 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Gemini ์ฑ—๋ด‡ - Gradio ๋ฒ„์ „
3
+ Google Search๋กœ ์ตœ์‹  ์ •๋ณด๋ฅผ ๊ฒ€์ƒ‰ํ•˜๋Š” AI ์ฑ—๋ด‡
4
+ """
5
+
6
+ import os
7
+ import json
8
+ import datetime
9
+ from google import genai
10
+ from google.genai import types
11
+ import gradio as gr
12
+
13
+ # ============================================================
14
+ # 1. Gemini์—๊ฒŒ ๋ฉ”์‹œ์ง€ ๋ณด๋‚ด๊ธฐ
15
+ # ============================================================
16
+
17
+ def send_message(user_message, chat_history, api_key, system_prompt, use_search):
18
+ """์‚ฌ์šฉ์ž ๋ฉ”์‹œ์ง€๋ฅผ Gemini์—๊ฒŒ ๋ณด๋‚ด๊ณ  ์‘๋‹ต์„ ๋ฐ›์Šต๋‹ˆ๋‹ค."""
19
+ # API Key ํ™•์ธ
20
+ if not api_key or not api_key.strip():
21
+ chat_history.append({"role": "user", "content": user_message})
22
+ chat_history.append({"role": "assistant", "content": "โš ๏ธ API Key๋ฅผ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”."})
23
+ return "", chat_history
24
+
25
+ # ๋นˆ ๋ฉ”์‹œ์ง€ ํ™•์ธ
26
+ if not user_message or not user_message.strip():
27
+ return "", chat_history
28
+
29
+ # ํด๋ผ์ด์–ธํŠธ ์ƒ์„ฑ
30
+ client = genai.Client(api_key=api_key.strip())
31
+
32
+ # ํ˜„์žฌ ๋‚ ์งœ๋ฅผ ์‹œ์Šคํ…œ ํ”„๋กฌํ”„ํŠธ์— ์ถ”๊ฐ€
33
+ today = datetime.date.today().strftime("%Y-%m-%d")
34
+ base_instruction = f"์˜ค๋Š˜ ๋‚ ์งœ๋Š” {today}์ž…๋‹ˆ๋‹ค. ์ตœ์‹  ์ •๋ณด๋ฅผ ๊ธฐ์ค€์œผ๋กœ ๋‹ต๋ณ€ํ•˜์„ธ์š”."
35
+ if system_prompt and system_prompt.strip():
36
+ full_instruction = f"{base_instruction}\n{system_prompt.strip()}"
37
+ else:
38
+ full_instruction = base_instruction
39
+
40
+ # ๋„๊ตฌ ์„ค์ • (Google Search)
41
+ tools = []
42
+ if use_search:
43
+ tools = [types.Tool(google_search=types.GoogleSearch())]
44
+
45
+ # ์„ค์ •
46
+ config = types.GenerateContentConfig(
47
+ system_instruction=full_instruction,
48
+ tools=tools if tools else None,
49
+ )
50
+
51
+ # ๋Œ€ํ™” ๊ธฐ๋ก์„ Gemini ํ˜•์‹์œผ๋กœ ๋ณ€ํ™˜
52
+ contents = []
53
+ for msg in chat_history:
54
+ # Gradio 6์—์„œ content๊ฐ€ ๋ฆฌ์ŠคํŠธ๋กœ ์˜ฌ ์ˆ˜ ์žˆ์Œ
55
+ content = msg["content"]
56
+ if isinstance(content, list):
57
+ content = "".join(part["text"] for part in content if "text" in part)
58
+ role = "user" if msg["role"] == "user" else "model"
59
+ contents.append(types.Content(role=role, parts=[types.Part(text=content)]))
60
+ contents.append(types.Content(role="user", parts=[types.Part(text=user_message)]))
61
+
62
+ # ๋ฉ”์‹œ์ง€ ์ „์†ก
63
+ try:
64
+ response = client.models.generate_content(
65
+ model="gemini-2.5-flash-lite",
66
+ contents=contents,
67
+ config=config,
68
+ )
69
+ reply = response.text
70
+
71
+ except Exception as e:
72
+ reply = f"โŒ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: {str(e)}"
73
+
74
+ # ๋Œ€ํ™” ๊ธฐ๋ก์— ์ถ”๊ฐ€
75
+ chat_history.append({"role": "user", "content": user_message})
76
+ chat_history.append({"role": "assistant", "content": reply})
77
+
78
+ return "", chat_history
79
+
80
+
81
+ # ============================================================
82
+ # 2. ๋Œ€ํ™” ๊ธฐ๋ก ์ €์žฅ
83
+ # ============================================================
84
+
85
+ def save_chat(chat_history):
86
+ """๋Œ€ํ™” ๊ธฐ๋ก์„ JSON ํŒŒ์ผ๋กœ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค."""
87
+ if not chat_history:
88
+ return gr.update(value=None)
89
+
90
+ now = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
91
+ filename = f"chat_{now}.json"
92
+ filepath = os.path.join("saved_chats", filename)
93
+
94
+ os.makedirs("saved_chats", exist_ok=True)
95
+
96
+ with open(filepath, "w", encoding="utf-8") as f:
97
+ json.dump(chat_history, f, ensure_ascii=False, indent=2)
98
+
99
+ return gr.update(value=filepath)
100
+
101
+
102
+ def clear_chat():
103
+ """๋Œ€ํ™” ๊ธฐ๋ก์„ ์ดˆ๊ธฐํ™”ํ•ฉ๋‹ˆ๋‹ค."""
104
+ return []
105
+
106
+
107
+ # ============================================================
108
+ # 3. Gradio UI ๋งŒ๋“ค๊ธฐ
109
+ # ============================================================
110
+
111
+ with gr.Blocks(
112
+ title="Gemini ์ฑ—๋ด‡",
113
+ ) as app:
114
+
115
+ gr.Markdown("# Gemini ์ฑ—๋ด‡")
116
+ gr.Markdown("Google Gemini API๋ฅผ ์‚ฌ์šฉํ•˜๋Š” AI ์ฑ—๋ด‡์ž…๋‹ˆ๋‹ค.")
117
+
118
+ with gr.Row():
119
+
120
+ # --- ์™ผ์ชฝ: ์„ค์ • ํŒจ๋„ ---
121
+ with gr.Column(scale=1):
122
+ gr.Markdown("## ์„ค์ •")
123
+
124
+ api_key = gr.Textbox(
125
+ label="Gemini API Key",
126
+ placeholder="API Key๋ฅผ ์ž…๋ ฅํ•˜์„ธ์š”",
127
+ type="password",
128
+ )
129
+
130
+ system_prompt = gr.Textbox(
131
+ label="์‹œ์Šคํ…œ ํ”„๋กฌํ”„ํŠธ",
132
+ placeholder="์˜ˆ: ๋‹น์‹ ์€ ์นœ์ ˆํ•œ ํ•œ๊ตญ์–ด AI ๋น„์„œ์ž…๋‹ˆ๋‹ค.",
133
+ lines=3,
134
+ )
135
+
136
+ use_search = gr.Checkbox(
137
+ label="Google Search ์‚ฌ์šฉ",
138
+ value=True,
139
+ )
140
+
141
+ gr.Markdown("---")
142
+ gr.Markdown("## ๋Œ€ํ™” ๊ด€๋ฆฌ")
143
+
144
+ save_btn = gr.Button("๋Œ€ํ™” ์ €์žฅ", variant="secondary")
145
+ save_output = gr.File(label="์ €์žฅ๋œ ํŒŒ์ผ")
146
+
147
+ # --- ์˜ค๋ฅธ์ชฝ: ์ฑ„ํŒ… ์˜์—ญ ---
148
+ with gr.Column(scale=3):
149
+ chatbot = gr.Chatbot(
150
+ label="๋Œ€ํ™”",
151
+ height=500,
152
+ )
153
+
154
+ with gr.Row():
155
+ msg = gr.Textbox(
156
+ label="๋ฉ”์‹œ์ง€ ์ž…๋ ฅ",
157
+ placeholder="๋ฉ”์‹œ์ง€๋ฅผ ์ž…๋ ฅํ•˜์„ธ์š”...",
158
+ scale=4,
159
+ show_label=False,
160
+ )
161
+ send_btn = gr.Button("์ „์†ก", variant="primary", scale=1)
162
+
163
+ clear_btn = gr.Button("๋Œ€ํ™” ์ดˆ๊ธฐํ™”")
164
+
165
+ # --- ์ด๋ฒคํŠธ ์—ฐ๊ฒฐ ---
166
+
167
+ send_btn.click(
168
+ fn=send_message,
169
+ inputs=[msg, chatbot, api_key, system_prompt, use_search],
170
+ outputs=[msg, chatbot],
171
+ )
172
+
173
+ msg.submit(
174
+ fn=send_message,
175
+ inputs=[msg, chatbot, api_key, system_prompt, use_search],
176
+ outputs=[msg, chatbot],
177
+ )
178
+
179
+ clear_btn.click(fn=clear_chat, outputs=[chatbot])
180
+ save_btn.click(fn=save_chat, inputs=[chatbot], outputs=[save_output])
181
+
182
+
183
+ # ============================================================
184
+ # 4. ์•ฑ ์‹คํ–‰
185
+ # ============================================================
186
+
187
+ if __name__ == "__main__":
188
+ app.launch(server_name="0.0.0.0", server_port=7860, theme=gr.themes.Soft())
requirements.txt ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ google-genai
2
+ gradio