seawolf2357 commited on
Commit
12bdf8b
ยท
verified ยท
1 Parent(s): 8849b1c

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +487 -4
app.py CHANGED
@@ -1,6 +1,489 @@
1
  import gradio as gr
 
 
 
2
 
3
- gr.load(
4
- "models/MiniMaxAI/MiniMax-M2.1",
5
- provider="novita",
6
- ).launch()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  import gradio as gr
2
+ from huggingface_hub import InferenceClient
3
+ from openai import OpenAI
4
+ import os
5
 
6
+ # ============================================
7
+ # MiniMax-M2.1 Streaming Chat
8
+ # Dual Provider: Novita (HF) + MiniMax Official API
9
+ # Comic Classic Theme
10
+ # ============================================
11
+
12
+ # Provider ์ƒํƒœ ๊ด€๋ฆฌ
13
+ class ProviderManager:
14
+ def __init__(self):
15
+ self.current_provider = "novita" # ๊ธฐ๋ณธ๊ฐ’: Novita
16
+ self.novita_available = True
17
+
18
+ # Novita Client (via HuggingFace)
19
+ self.novita_client = InferenceClient(
20
+ provider="novita",
21
+ api_key=os.environ.get("HF_TOKEN"),
22
+ )
23
+
24
+ # MiniMax Official API Client
25
+ self.minimax_client = OpenAI(
26
+ api_key=os.environ.get("MINIMAX_API_KEY", ""),
27
+ base_url="https://api.minimax.chat/v1"
28
+ )
29
+
30
+ def get_status(self):
31
+ if self.current_provider == "novita":
32
+ return "๐ŸŸข Novita (HuggingFace)"
33
+ else:
34
+ return "๐ŸŸก MiniMax Official API"
35
+
36
+ def switch_to_minimax(self):
37
+ self.current_provider = "minimax"
38
+ self.novita_available = False
39
+ print("โš ๏ธ Switched to MiniMax Official API")
40
+
41
+ def reset_to_novita(self):
42
+ self.current_provider = "novita"
43
+ self.novita_available = True
44
+ print("โœ… Reset to Novita provider")
45
+
46
+ # Global provider manager
47
+ provider = ProviderManager()
48
+
49
+ def chat_with_novita(messages):
50
+ """Novita provider๋ฅผ ํ†ตํ•œ ์ŠคํŠธ๋ฆฌ๋ฐ"""
51
+ stream = provider.novita_client.chat.completions.create(
52
+ model="MiniMaxAI/MiniMax-M2.1",
53
+ messages=messages,
54
+ max_tokens=4096,
55
+ temperature=1.0,
56
+ top_p=0.95,
57
+ stream=True
58
+ )
59
+
60
+ for chunk in stream:
61
+ if chunk.choices[0].delta.content:
62
+ yield chunk.choices[0].delta.content
63
+
64
+ def chat_with_minimax(messages):
65
+ """MiniMax ๊ณต์‹ API๋ฅผ ํ†ตํ•œ ์ŠคํŠธ๋ฆฌ๋ฐ"""
66
+ stream = provider.minimax_client.chat.completions.create(
67
+ model="MiniMax-M2.1",
68
+ messages=messages,
69
+ max_tokens=4096,
70
+ temperature=1.0,
71
+ top_p=0.95,
72
+ stream=True
73
+ )
74
+
75
+ for chunk in stream:
76
+ if chunk.choices and chunk.choices[0].delta.content:
77
+ yield chunk.choices[0].delta.content
78
+
79
+ def chat_stream(message, history):
80
+ """
81
+ Streaming chat with automatic fallback
82
+ 1์ฐจ: Novita (HuggingFace)
83
+ 2์ฐจ: MiniMax Official API (fallback)
84
+ """
85
+ if not message.strip():
86
+ yield "", provider.get_status()
87
+ return
88
+
89
+ # Build messages
90
+ messages = [{
91
+ "role": "system",
92
+ "content": "You are MiniMax-M2.1, a helpful AI assistant built by MiniMax. You excel at coding, tool use, and complex reasoning tasks. Respond in the same language as the user."
93
+ }]
94
+
95
+ for user_msg, assistant_msg in history:
96
+ if user_msg:
97
+ messages.append({"role": "user", "content": user_msg})
98
+ if assistant_msg:
99
+ messages.append({"role": "assistant", "content": assistant_msg})
100
+
101
+ messages.append({"role": "user", "content": message})
102
+
103
+ response_text = ""
104
+
105
+ # 1์ฐจ ์‹œ๋„: Novita (if available)
106
+ if provider.novita_available and provider.current_provider == "novita":
107
+ try:
108
+ for chunk in chat_with_novita(messages):
109
+ response_text += chunk
110
+ yield response_text, "๐ŸŸข Novita (HuggingFace)"
111
+ return
112
+ except Exception as e:
113
+ error_msg = str(e).lower()
114
+ # ํฌ๋ ˆ๋”ง ์†Œ์ง„ ๋˜๋Š” rate limit ๊ด€๋ จ ์—๋Ÿฌ ๊ฐ์ง€
115
+ if any(keyword in error_msg for keyword in [
116
+ "rate limit", "quota", "exceeded", "insufficient",
117
+ "credit", "balance", "limit", "429", "402", "payment"
118
+ ]):
119
+ print(f"โš ๏ธ Novita error (switching to MiniMax): {e}")
120
+ provider.switch_to_minimax()
121
+ else:
122
+ # ๋‹ค๋ฅธ ์—๋Ÿฌ๋Š” ์ผ์‹œ์ ์ผ ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ํ•œ ๋ฒˆ๋งŒ ์‹œ๋„
123
+ print(f"โš ๏ธ Novita temporary error: {e}")
124
+
125
+ # 2์ฐจ ์‹œ๋„: MiniMax Official API
126
+ try:
127
+ # MiniMax API ํ‚ค ํ™•์ธ
128
+ if not os.environ.get("MINIMAX_API_KEY"):
129
+ yield "โŒ Error: MINIMAX_API_KEY not configured. Please add it to Secrets.", "๐Ÿ”ด No Provider"
130
+ return
131
+
132
+ for chunk in chat_with_minimax(messages):
133
+ response_text += chunk
134
+ yield response_text, "๐ŸŸก MiniMax Official API"
135
+ return
136
+
137
+ except Exception as e:
138
+ error_msg = str(e)
139
+
140
+ # MiniMax๋„ ์‹คํŒจํ•˜๋ฉด Novita ๋‹ค์‹œ ์‹œ๋„ ๊ฐ€๋Šฅํ•˜๋„๋ก
141
+ if "rate limit" not in error_msg.lower():
142
+ provider.reset_to_novita()
143
+
144
+ yield f"โŒ Error: {error_msg}", "๐Ÿ”ด Error"
145
+
146
+ def reset_provider():
147
+ """์ˆ˜๋™์œผ๋กœ Novita๋กœ ๋ฆฌ์…‹"""
148
+ provider.reset_to_novita()
149
+ return "โœ… Provider reset to Novita. Next message will try Novita first."
150
+
151
+ # ============================================
152
+ # ๐ŸŽจ Comic Classic Theme CSS
153
+ # ============================================
154
+ css = """
155
+ /* ===== ๐ŸŽจ Google Fonts Import ===== */
156
+ @import url('https://fonts.googleapis.com/css2?family=Bangers&family=Comic+Neue:wght@400;700&display=swap');
157
+
158
+ /* ===== ๐ŸŽจ Comic Classic ๋ฐฐ๊ฒฝ ===== */
159
+ .gradio-container {
160
+ background-color: #FEF9C3 !important;
161
+ background-image: radial-gradient(#1F2937 1px, transparent 1px) !important;
162
+ background-size: 20px 20px !important;
163
+ min-height: 100vh !important;
164
+ font-family: 'Comic Neue', cursive, sans-serif !important;
165
+ }
166
+
167
+ /* ===== ํ—ˆ๊น…ํŽ˜์ด์Šค ํ—ค๋” ์ˆจ๊น€ ===== */
168
+ .huggingface-space-header,
169
+ #space-header,
170
+ .space-header,
171
+ [class*="space-header"] {
172
+ display: none !important;
173
+ }
174
+
175
+ /* ===== Footer ์ˆจ๊น€ ===== */
176
+ footer, .footer, .gradio-footer, .built-with-gradio {
177
+ display: none !important;
178
+ }
179
+
180
+ /* ===== ๐ŸŽจ ํ—ค๋” ํƒ€์ดํ‹€ ===== */
181
+ .header-text h1 {
182
+ font-family: 'Bangers', cursive !important;
183
+ color: #1F2937 !important;
184
+ font-size: 3.5rem !important;
185
+ text-align: center !important;
186
+ margin-bottom: 0.5rem !important;
187
+ text-shadow:
188
+ 4px 4px 0px #FACC15,
189
+ 6px 6px 0px #1F2937 !important;
190
+ letter-spacing: 3px !important;
191
+ -webkit-text-stroke: 2px #1F2937 !important;
192
+ }
193
+
194
+ /* ===== ๐ŸŽจ ์„œ๋ธŒํƒ€์ดํ‹€ ===== */
195
+ .subtitle {
196
+ text-align: center !important;
197
+ font-family: 'Comic Neue', cursive !important;
198
+ font-size: 1.2rem !important;
199
+ color: #1F2937 !important;
200
+ margin-bottom: 1.5rem !important;
201
+ font-weight: 700 !important;
202
+ }
203
+
204
+ /* ===== ๐ŸŽจ ์ฑ„ํŒ… ์ปจํ…Œ์ด๋„ˆ ===== */
205
+ .chatbot {
206
+ background: #FFFFFF !important;
207
+ border: 3px solid #1F2937 !important;
208
+ border-radius: 12px !important;
209
+ box-shadow: 6px 6px 0px #1F2937 !important;
210
+ }
211
+
212
+ /* ===== ๐ŸŽจ ์ž…๋ ฅ ํ•„๋“œ ===== */
213
+ textarea, input[type="text"] {
214
+ background: #FFFFFF !important;
215
+ border: 3px solid #1F2937 !important;
216
+ border-radius: 8px !important;
217
+ color: #1F2937 !important;
218
+ font-family: 'Comic Neue', cursive !important;
219
+ font-size: 1rem !important;
220
+ font-weight: 700 !important;
221
+ }
222
+
223
+ textarea:focus, input[type="text"]:focus {
224
+ border-color: #3B82F6 !important;
225
+ box-shadow: 4px 4px 0px #3B82F6 !important;
226
+ outline: none !important;
227
+ }
228
+
229
+ /* ===== ๐ŸŽจ Primary ๋ฒ„ํŠผ ===== */
230
+ .gr-button-primary, button.primary {
231
+ background: #3B82F6 !important;
232
+ border: 3px solid #1F2937 !important;
233
+ border-radius: 8px !important;
234
+ color: #FFFFFF !important;
235
+ font-family: 'Bangers', cursive !important;
236
+ font-size: 1.3rem !important;
237
+ letter-spacing: 2px !important;
238
+ padding: 14px 28px !important;
239
+ box-shadow: 5px 5px 0px #1F2937 !important;
240
+ text-shadow: 1px 1px 0px #1F2937 !important;
241
+ }
242
+
243
+ .gr-button-primary:hover, button.primary:hover {
244
+ background: #2563EB !important;
245
+ transform: translate(-2px, -2px) !important;
246
+ box-shadow: 7px 7px 0px #1F2937 !important;
247
+ }
248
+
249
+ .gr-button-primary:active, button.primary:active {
250
+ transform: translate(3px, 3px) !important;
251
+ box-shadow: 2px 2px 0px #1F2937 !important;
252
+ }
253
+
254
+ /* ===== ๐ŸŽจ Secondary ๋ฒ„ํŠผ ===== */
255
+ .gr-button-secondary, button.secondary {
256
+ background: #EF4444 !important;
257
+ border: 3px solid #1F2937 !important;
258
+ border-radius: 8px !important;
259
+ color: #FFFFFF !important;
260
+ font-family: 'Bangers', cursive !important;
261
+ font-size: 1.1rem !important;
262
+ box-shadow: 4px 4px 0px #1F2937 !important;
263
+ text-shadow: 1px 1px 0px #1F2937 !important;
264
+ }
265
+
266
+ .gr-button-secondary:hover, button.secondary:hover {
267
+ background: #DC2626 !important;
268
+ transform: translate(-2px, -2px) !important;
269
+ }
270
+
271
+ /* ===== ๐ŸŽจ ์นด๋“œ/ํŒจ๋„ ===== */
272
+ .gr-panel, .gr-box, .block, .gr-group {
273
+ background: #FFFFFF !important;
274
+ border: 3px solid #1F2937 !important;
275
+ border-radius: 8px !important;
276
+ box-shadow: 6px 6px 0px #1F2937 !important;
277
+ }
278
+
279
+ /* ===== ๐ŸŽจ ์•„์ฝ”๋””์–ธ ===== */
280
+ .gr-accordion {
281
+ background: #FACC15 !important;
282
+ border: 3px solid #1F2937 !important;
283
+ border-radius: 8px !important;
284
+ box-shadow: 4px 4px 0px #1F2937 !important;
285
+ }
286
+
287
+ /* ===== ๐ŸŽจ ๋ชจ๋ธ ์ •๋ณด ๋ฐ•์Šค ===== */
288
+ .model-info {
289
+ background: linear-gradient(135deg, #3B82F6 0%, #8B5CF6 100%) !important;
290
+ border: 3px solid #1F2937 !important;
291
+ border-radius: 12px !important;
292
+ padding: 15px !important;
293
+ color: white !important;
294
+ box-shadow: 5px 5px 0px #1F2937 !important;
295
+ margin-bottom: 20px !important;
296
+ }
297
+
298
+ /* ===== ๐ŸŽจ Provider ์ƒํƒœ ๋ฐ•์Šค ===== */
299
+ .provider-status {
300
+ background: #1F2937 !important;
301
+ border: 3px solid #10B981 !important;
302
+ border-radius: 8px !important;
303
+ padding: 10px 15px !important;
304
+ color: #10B981 !important;
305
+ font-family: 'Courier New', monospace !important;
306
+ font-weight: bold !important;
307
+ text-align: center !important;
308
+ box-shadow: 4px 4px 0px #10B981 !important;
309
+ }
310
+
311
+ /* ===== ๐ŸŽจ ์ฝ”๋“œ ๋ธ”๋ก ===== */
312
+ pre, code {
313
+ background: #1F2937 !important;
314
+ color: #10B981 !important;
315
+ border: 2px solid #10B981 !important;
316
+ border-radius: 6px !important;
317
+ font-family: 'Courier New', monospace !important;
318
+ }
319
+
320
+ /* ===== ๐ŸŽจ ์Šคํฌ๋กค๋ฐ” ===== */
321
+ ::-webkit-scrollbar {
322
+ width: 12px;
323
+ }
324
+
325
+ ::-webkit-scrollbar-track {
326
+ background: #FEF9C3;
327
+ border: 2px solid #1F2937;
328
+ }
329
+
330
+ ::-webkit-scrollbar-thumb {
331
+ background: #3B82F6;
332
+ border: 2px solid #1F2937;
333
+ }
334
+
335
+ ::-webkit-scrollbar-thumb:hover {
336
+ background: #EF4444;
337
+ }
338
+
339
+ /* ===== ๋ฐ˜์‘ํ˜• ===== */
340
+ @media (max-width: 768px) {
341
+ .header-text h1 {
342
+ font-size: 2.2rem !important;
343
+ }
344
+ }
345
+ """
346
+
347
+ # ============================================
348
+ # Gradio Interface
349
+ # ============================================
350
+ with gr.Blocks(fill_height=True, css=css, title="MiniMax-M2.1 Chat") as demo:
351
+
352
+ # HOME Badge
353
+ gr.HTML("""
354
+ <div style="text-align: center; margin: 20px 0 10px 0;">
355
+ <a href="https://www.humangen.ai" target="_blank" style="text-decoration: none;">
356
+ <img src="https://img.shields.io/static/v1?label=๐Ÿ  HOME&message=HUMANGEN.AI&color=0000ff&labelColor=ffcc00&style=for-the-badge" alt="HOME">
357
+ </a>
358
+ <a href="https://huggingface.co/MiniMaxAI/MiniMax-M2.1" target="_blank" style="text-decoration: none; margin-left: 10px;">
359
+ <img src="https://img.shields.io/static/v1?label=๐Ÿค—&message=MiniMax-M2.1&color=ff6f00&labelColor=1F2937&style=for-the-badge" alt="Model">
360
+ </a>
361
+ </div>
362
+ """)
363
+
364
+ # Header Title
365
+ gr.Markdown(
366
+ """# ๐Ÿค– MINIMAX-M2.1 CHAT ๐Ÿ’ฌ""",
367
+ elem_classes="header-text"
368
+ )
369
+
370
+ gr.Markdown(
371
+ """<p class="subtitle">โšก Claude Sonnet 4.5 ์ˆ˜์ค€์˜ ์ฝ”๋”ฉ & ์—์ด์ „ํŠธ ์„ฑ๋Šฅ! 230B ํŒŒ๋ผ๋ฏธํ„ฐ ์˜คํ”ˆ์†Œ์Šค ๋ชจ๋ธ ๐Ÿš€</p>""",
372
+ )
373
+
374
+ # Model Info Box
375
+ gr.HTML("""
376
+ <div class="model-info">
377
+ <div style="display: flex; justify-content: space-around; flex-wrap: wrap; text-align: center;">
378
+ <div><strong style="font-size: 1.5rem;">230B</strong><br><span style="font-size: 0.9rem;">Total Params</span></div>
379
+ <div><strong style="font-size: 1.5rem;">10B</strong><br><span style="font-size: 0.9rem;">Active Params</span></div>
380
+ <div><strong style="font-size: 1.5rem;">88.6</strong><br><span style="font-size: 0.9rem;">VIBE Score</span></div>
381
+ <div><strong style="font-size: 1.5rem;">#1</strong><br><span style="font-size: 0.9rem;">Open Source</span></div>
382
+ </div>
383
+ </div>
384
+ """)
385
+
386
+ # Provider Status
387
+ with gr.Row():
388
+ provider_status = gr.Textbox(
389
+ value="๐ŸŸข Novita (HuggingFace)",
390
+ label="๐Ÿ”Œ Current Provider",
391
+ interactive=False,
392
+ elem_classes="provider-status"
393
+ )
394
+ reset_btn = gr.Button("๐Ÿ”„ Reset to Novita", variant="secondary", scale=0)
395
+
396
+ # Chat Interface
397
+ chatbot = gr.Chatbot(
398
+ label="๐Ÿ’ฌ Chat",
399
+ height=450,
400
+ show_label=False,
401
+ elem_classes="chatbot"
402
+ )
403
+
404
+ with gr.Row():
405
+ msg = gr.Textbox(
406
+ label="",
407
+ placeholder="๋ฉ”์‹œ์ง€๋ฅผ ์ž…๋ ฅํ•˜์„ธ์š”... (์ฝ”๋”ฉ, ๋ถ„์„, ์ฐฝ์ž‘ ๋“ฑ ๋ฌด์—‡์ด๋“ !)",
408
+ scale=9,
409
+ container=False
410
+ )
411
+ submit_btn = gr.Button("๐Ÿ“ค SEND", variant="primary", scale=1)
412
+
413
+ with gr.Row():
414
+ clear_btn = gr.Button("๐Ÿ—‘๏ธ CLEAR CHAT", variant="secondary")
415
+
416
+ # Examples
417
+ with gr.Accordion("๐Ÿ’ก Example Prompts", open=False):
418
+ gr.Examples(
419
+ examples=[
420
+ "Python์œผ๋กœ ํ€ต์†ŒํŠธ ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ๊ตฌํ˜„ํ•ด์ค˜",
421
+ "React๋กœ Todo ์•ฑ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋งŒ๋“ค์–ด์ค˜",
422
+ "Docker์™€ Kubernetes์˜ ์ฐจ์ด์ ์„ ์„ค๋ช…ํ•ด์ค˜",
423
+ "REST API ์„ค๊ณ„ ๋ฒ ์ŠคํŠธ ํ”„๋ž™ํ‹ฐ์Šค๋ฅผ ์•Œ๋ ค์ค˜",
424
+ "FastAPI๋กœ JWT ์ธ์ฆ ๊ตฌํ˜„ํ•ด์ค˜",
425
+ ],
426
+ inputs=msg
427
+ )
428
+
429
+ # Provider Info
430
+ with gr.Accordion("๐Ÿ”Œ Provider Information", open=False):
431
+ gr.Markdown("""
432
+ ### ๋“€์–ผ ํ”„๋กœ๋ฐ”์ด๋” ์‹œ์Šคํ…œ
433
+
434
+ ์ด ์•ฑ์€ **์ž๋™ ํด๋ฐฑ** ๊ธฐ๋Šฅ์ด ์žˆ์Šต๋‹ˆ๋‹ค:
435
+
436
+ **1์ฐจ: Novita (HuggingFace)**
437
+ - HuggingFace PRO ํฌ๋ ˆ๋”ง ์‚ฌ์šฉ
438
+ - ๋น ๋ฅธ ์‘๋‹ต ์†๋„
439
+
440
+ **2์ฐจ: MiniMax Official API** (ํด๋ฐฑ)
441
+ - Novita ํฌ๋ ˆ๋”ง ์†Œ์ง„ ์‹œ ์ž๋™ ์ „ํ™˜
442
+ - MiniMax ๊ณต์‹ API (ํ˜„์žฌ ํ•œ์‹œ์  ๋ฌด๋ฃŒ)
443
+
444
+ ### ํ•„์š”ํ•œ Secrets
445
+ ```
446
+ HF_TOKEN: HuggingFace ํ† ํฐ (PRO ๊ณ„์ • ๊ถŒ์žฅ)
447
+ MINIMAX_API_KEY: MiniMax ๊ณต์‹ API ํ‚ค (ํด๋ฐฑ์šฉ)
448
+ ```
449
+
450
+ **MiniMax API ํ‚ค ๋ฐœ๊ธ‰:** [platform.minimax.io](https://platform.minimax.io)
451
+ """)
452
+
453
+ # Model capabilities
454
+ with gr.Accordion("๐ŸŽฏ Model Capabilities", open=False):
455
+ gr.Markdown("""
456
+ ### MiniMax-M2.1 ํŠน์ง•
457
+
458
+ - **๐Ÿ† SOTA ์ฝ”๋”ฉ ์„ฑ๋Šฅ** โ€” SWE-bench์—์„œ Claude Sonnet 4.5 ๋Šฅ๊ฐ€
459
+ - **๐ŸŒ ๋‹ค๊ตญ์–ด ํ”„๋กœ๊ทธ๋ž˜๋ฐ** โ€” Python, Rust, Java, Go, C++, TypeScript ๋“ฑ
460
+ - **๐Ÿค– ์—์ด์ „ํŠธ ๋Šฅ๋ ฅ** โ€” ๋ณต์žกํ•œ ๋ฉ€ํ‹ฐ์Šคํ… ํƒœ์Šคํฌ ์ˆ˜ํ–‰
461
+ - **๐Ÿ’ก ์ถ”๋ก  ๋Šฅ๋ ฅ** โ€” Interleaved Thinking์œผ๋กœ ์ฒด๊ณ„์  ๋ฌธ์ œ ํ•ด๊ฒฐ
462
+ - **๐Ÿ”ง ๋„๊ตฌ ์‚ฌ์šฉ** โ€” ํ•จ์ˆ˜ ํ˜ธ์ถœ ๋ฐ API ์—ฐ๋™
463
+ """)
464
+
465
+ # Event handlers
466
+ def respond(message, history):
467
+ history = history or []
468
+ bot_response = ""
469
+ current_status = ""
470
+
471
+ for response, status in chat_stream(message, history):
472
+ bot_response = response
473
+ current_status = status
474
+ yield history + [(message, bot_response)], "", current_status
475
+
476
+ def clear_chat():
477
+ return [], "", provider.get_status()
478
+
479
+ def do_reset():
480
+ return reset_provider()
481
+
482
+ # Connect events
483
+ msg.submit(respond, [msg, chatbot], [chatbot, msg, provider_status])
484
+ submit_btn.click(respond, [msg, chatbot], [chatbot, msg, provider_status])
485
+ clear_btn.click(clear_chat, outputs=[chatbot, msg, provider_status])
486
+ reset_btn.click(do_reset, outputs=[provider_status])
487
+
488
+ if __name__ == "__main__":
489
+ demo.launch()