seawolf2357 commited on
Commit
687cbda
Β·
verified Β·
1 Parent(s): 60690c5

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +86 -128
app.py CHANGED
@@ -6,13 +6,13 @@ import os
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)
@@ -79,39 +79,44 @@ def chat_with_minimax(messages):
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"
@@ -119,43 +124,53 @@ def chat_stream(message, history):
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;
@@ -164,34 +179,25 @@ css = """
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;
@@ -201,7 +207,6 @@ footer, .footer, .gradio-footer, .built-with-gradio {
201
  font-weight: 700 !important;
202
  }
203
 
204
- /* ===== 🎨 μ±„νŒ… μ»¨ν…Œμ΄λ„ˆ ===== */
205
  .chatbot {
206
  background: #FFFFFF !important;
207
  border: 3px solid #1F2937 !important;
@@ -209,7 +214,6 @@ footer, .footer, .gradio-footer, .built-with-gradio {
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;
@@ -226,7 +230,6 @@ textarea:focus, input[type="text"]:focus {
226
  outline: none !important;
227
  }
228
 
229
- /* ===== 🎨 Primary λ²„νŠΌ ===== */
230
  .gr-button-primary, button.primary {
231
  background: #3B82F6 !important;
232
  border: 3px solid #1F2937 !important;
@@ -251,7 +254,6 @@ textarea:focus, input[type="text"]:focus {
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;
@@ -268,7 +270,6 @@ textarea:focus, input[type="text"]:focus {
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;
@@ -276,7 +277,6 @@ textarea:focus, input[type="text"]:focus {
276
  box-shadow: 6px 6px 0px #1F2937 !important;
277
  }
278
 
279
- /* ===== 🎨 μ•„μ½”λ””μ–Έ ===== */
280
  .gr-accordion {
281
  background: #FACC15 !important;
282
  border: 3px solid #1F2937 !important;
@@ -284,7 +284,6 @@ textarea:focus, input[type="text"]:focus {
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;
@@ -295,7 +294,6 @@ textarea:focus, input[type="text"]:focus {
295
  margin-bottom: 20px !important;
296
  }
297
 
298
- /* ===== 🎨 Provider μƒνƒœ λ°•μŠ€ ===== */
299
  .provider-status {
300
  background: #1F2937 !important;
301
  border: 3px solid #10B981 !important;
@@ -308,7 +306,6 @@ textarea:focus, input[type="text"]:focus {
308
  box-shadow: 4px 4px 0px #10B981 !important;
309
  }
310
 
311
- /* ===== 🎨 μ½”λ“œ 블둝 ===== */
312
  pre, code {
313
  background: #1F2937 !important;
314
  color: #10B981 !important;
@@ -317,37 +314,23 @@ pre, code {
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("""
@@ -355,23 +338,15 @@ with gr.Blocks(fill_height=True, css=css, title="MiniMax-M2.1 Chat") as demo:
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;">
@@ -391,13 +366,14 @@ with gr.Blocks(fill_height=True, css=css, title="MiniMax-M2.1 Chat") as demo:
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
 
@@ -429,61 +405,43 @@ with gr.Blocks(fill_height=True, css=css, title="MiniMax-M2.1 Chat") as demo:
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()
 
6
  # ============================================
7
  # MiniMax-M2.1 Streaming Chat
8
  # Dual Provider: Novita (HF) + MiniMax Official API
9
+ # Gradio 6.0 Compatible
10
  # ============================================
11
 
12
  # Provider μƒνƒœ 관리
13
  class ProviderManager:
14
  def __init__(self):
15
+ self.current_provider = "novita"
16
  self.novita_available = True
17
 
18
  # Novita Client (via HuggingFace)
 
79
  def chat_stream(message, history):
80
  """
81
  Streaming chat with automatic fallback
82
+ Gradio 6.0 messages format compatible
 
83
  """
84
  if not message.strip():
85
+ yield [], provider.get_status()
86
  return
87
 
88
+ # Build API messages from Gradio history
89
+ api_messages = [{
90
  "role": "system",
91
  "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."
92
  }]
93
 
94
+ # Convert Gradio messages format to API format
95
+ for msg in history:
96
+ if isinstance(msg, dict):
97
+ api_messages.append({
98
+ "role": msg.get("role", "user"),
99
+ "content": msg.get("content", "")
100
+ })
101
 
102
+ api_messages.append({"role": "user", "content": message})
103
 
104
  response_text = ""
105
 
106
+ # 1μ°¨ μ‹œλ„: Novita
107
  if provider.novita_available and provider.current_provider == "novita":
108
  try:
109
+ for chunk in chat_with_novita(api_messages):
110
  response_text += chunk
111
+ # Gradio 6.0 messages format
112
+ new_history = history + [
113
+ {"role": "user", "content": message},
114
+ {"role": "assistant", "content": response_text}
115
+ ]
116
+ yield new_history, "🟒 Novita (HuggingFace)"
117
  return
118
  except Exception as e:
119
  error_msg = str(e).lower()
 
120
  if any(keyword in error_msg for keyword in [
121
  "rate limit", "quota", "exceeded", "insufficient",
122
  "credit", "balance", "limit", "429", "402", "payment"
 
124
  print(f"⚠️ Novita error (switching to MiniMax): {e}")
125
  provider.switch_to_minimax()
126
  else:
 
127
  print(f"⚠️ Novita temporary error: {e}")
128
 
129
  # 2μ°¨ μ‹œλ„: MiniMax Official API
130
  try:
 
131
  if not os.environ.get("MINIMAX_API_KEY"):
132
+ error_history = history + [
133
+ {"role": "user", "content": message},
134
+ {"role": "assistant", "content": "❌ Error: MINIMAX_API_KEY not configured. Please add it to Secrets."}
135
+ ]
136
+ yield error_history, "πŸ”΄ No Provider"
137
  return
138
 
139
+ for chunk in chat_with_minimax(api_messages):
140
  response_text += chunk
141
+ new_history = history + [
142
+ {"role": "user", "content": message},
143
+ {"role": "assistant", "content": response_text}
144
+ ]
145
+ yield new_history, "🟑 MiniMax Official API"
146
  return
147
 
148
  except Exception as e:
149
  error_msg = str(e)
 
 
150
  if "rate limit" not in error_msg.lower():
151
  provider.reset_to_novita()
152
 
153
+ error_history = history + [
154
+ {"role": "user", "content": message},
155
+ {"role": "assistant", "content": f"❌ Error: {error_msg}"}
156
+ ]
157
+ yield error_history, "πŸ”΄ Error"
158
 
159
  def reset_provider():
160
  """μˆ˜λ™μœΌλ‘œ Novita둜 리셋"""
161
  provider.reset_to_novita()
162
+ return "βœ… Reset to Novita!"
163
+
164
+ def clear_chat():
165
+ """μ±„νŒ… μ΄ˆκΈ°ν™”"""
166
+ return [], "", provider.get_status()
167
 
168
  # ============================================
169
  # 🎨 Comic Classic Theme CSS
170
  # ============================================
171
  css = """
 
172
  @import url('https://fonts.googleapis.com/css2?family=Bangers&family=Comic+Neue:wght@400;700&display=swap');
173
 
 
174
  .gradio-container {
175
  background-color: #FEF9C3 !important;
176
  background-image: radial-gradient(#1F2937 1px, transparent 1px) !important;
 
179
  font-family: 'Comic Neue', cursive, sans-serif !important;
180
  }
181
 
182
+ .huggingface-space-header, #space-header, .space-header, [class*="space-header"] {
 
 
 
 
183
  display: none !important;
184
  }
185
 
 
186
  footer, .footer, .gradio-footer, .built-with-gradio {
187
  display: none !important;
188
  }
189
 
 
190
  .header-text h1 {
191
  font-family: 'Bangers', cursive !important;
192
  color: #1F2937 !important;
193
  font-size: 3.5rem !important;
194
  text-align: center !important;
195
  margin-bottom: 0.5rem !important;
196
+ text-shadow: 4px 4px 0px #FACC15, 6px 6px 0px #1F2937 !important;
 
 
197
  letter-spacing: 3px !important;
198
  -webkit-text-stroke: 2px #1F2937 !important;
199
  }
200
 
 
201
  .subtitle {
202
  text-align: center !important;
203
  font-family: 'Comic Neue', cursive !important;
 
207
  font-weight: 700 !important;
208
  }
209
 
 
210
  .chatbot {
211
  background: #FFFFFF !important;
212
  border: 3px solid #1F2937 !important;
 
214
  box-shadow: 6px 6px 0px #1F2937 !important;
215
  }
216
 
 
217
  textarea, input[type="text"] {
218
  background: #FFFFFF !important;
219
  border: 3px solid #1F2937 !important;
 
230
  outline: none !important;
231
  }
232
 
 
233
  .gr-button-primary, button.primary {
234
  background: #3B82F6 !important;
235
  border: 3px solid #1F2937 !important;
 
254
  box-shadow: 2px 2px 0px #1F2937 !important;
255
  }
256
 
 
257
  .gr-button-secondary, button.secondary {
258
  background: #EF4444 !important;
259
  border: 3px solid #1F2937 !important;
 
270
  transform: translate(-2px, -2px) !important;
271
  }
272
 
 
273
  .gr-panel, .gr-box, .block, .gr-group {
274
  background: #FFFFFF !important;
275
  border: 3px solid #1F2937 !important;
 
277
  box-shadow: 6px 6px 0px #1F2937 !important;
278
  }
279
 
 
280
  .gr-accordion {
281
  background: #FACC15 !important;
282
  border: 3px solid #1F2937 !important;
 
284
  box-shadow: 4px 4px 0px #1F2937 !important;
285
  }
286
 
 
287
  .model-info {
288
  background: linear-gradient(135deg, #3B82F6 0%, #8B5CF6 100%) !important;
289
  border: 3px solid #1F2937 !important;
 
294
  margin-bottom: 20px !important;
295
  }
296
 
 
297
  .provider-status {
298
  background: #1F2937 !important;
299
  border: 3px solid #10B981 !important;
 
306
  box-shadow: 4px 4px 0px #10B981 !important;
307
  }
308
 
 
309
  pre, code {
310
  background: #1F2937 !important;
311
  color: #10B981 !important;
 
314
  font-family: 'Courier New', monospace !important;
315
  }
316
 
317
+ ::-webkit-scrollbar { width: 12px; }
318
+ ::-webkit-scrollbar-track { background: #FEF9C3; border: 2px solid #1F2937; }
319
+ ::-webkit-scrollbar-thumb { background: #3B82F6; border: 2px solid #1F2937; }
320
+ ::-webkit-scrollbar-thumb:hover { background: #EF4444; }
 
 
 
 
 
 
 
 
 
 
321
 
 
 
 
 
 
322
  @media (max-width: 768px) {
323
+ .header-text h1 { font-size: 2.2rem !important; }
 
 
324
  }
325
  """
326
 
327
  # ============================================
328
+ # Gradio Interface (6.0 Compatible)
329
  # ============================================
330
+ with gr.Blocks(title="MiniMax-M2.1 Chat") as demo:
331
+
332
+ # Inject CSS
333
+ gr.HTML(f"<style>{css}</style>")
334
 
335
  # HOME Badge
336
  gr.HTML("""
 
338
  <a href="https://www.humangen.ai" target="_blank" style="text-decoration: none;">
339
  <img src="https://img.shields.io/static/v1?label=🏠 HOME&message=HUMANGEN.AI&color=0000ff&labelColor=ffcc00&style=for-the-badge" alt="HOME">
340
  </a>
341
+
 
 
342
  </div>
343
  """)
344
 
345
+ # Header
346
+ gr.Markdown("""# πŸ€– MINIMAX-M2.1 CHAT πŸ’¬""", elem_classes="header-text")
347
+ gr.Markdown("""<p class="subtitle">⚑ Claude Sonnet 4.5 μˆ˜μ€€μ˜ μ½”λ”© & μ—μ΄μ „νŠΈ μ„±λŠ₯! 230B νŒŒλΌλ―Έν„° μ˜€ν”ˆμ†ŒμŠ€ λͺ¨λΈ πŸš€</p>""")
 
 
348
 
349
+ # Model Info
 
 
 
 
350
  gr.HTML("""
351
  <div class="model-info">
352
  <div style="display: flex; justify-content: space-around; flex-wrap: wrap; text-align: center;">
 
366
  interactive=False,
367
  elem_classes="provider-status"
368
  )
369
+ reset_btn = gr.Button("πŸ”„ Reset", variant="secondary", scale=0)
370
 
371
+ # Chat Interface - Gradio 6.0 messages format
372
  chatbot = gr.Chatbot(
373
  label="πŸ’¬ Chat",
374
  height=450,
375
  show_label=False,
376
+ type="messages", # Gradio 6.0 format
377
  elem_classes="chatbot"
378
  )
379
 
 
405
  # Provider Info
406
  with gr.Accordion("πŸ”Œ Provider Information", open=False):
407
  gr.Markdown("""
408
+ ### λ“€μ–Ό ν”„λ‘œλ°”μ΄λ” μ‹œμŠ€ν…œ
409
+
410
+ **1μ°¨: Novita (HuggingFace)** - HF PRO ν¬λ ˆλ”§ μ‚¬μš©
411
+
412
+ **2μ°¨: MiniMax Official API** - ν¬λ ˆλ”§ μ†Œμ§„ μ‹œ μžλ™ μ „ν™˜
413
+
414
+ ### ν•„μš”ν•œ Secrets
415
+ - `HF_TOKEN`: HuggingFace 토큰
416
+ - `MINIMAX_API_KEY`: MiniMax API ν‚€
417
+
418
+ **MiniMax API:** [platform.minimax.io](https://platform.minimax.io)
 
 
 
 
 
 
 
 
419
  """)
420
 
421
  # Model capabilities
422
  with gr.Accordion("🎯 Model Capabilities", open=False):
423
  gr.Markdown("""
424
+ - **πŸ† SOTA μ½”λ”©** β€” SWE-benchμ—μ„œ Claude Sonnet 4.5 λŠ₯κ°€
425
+ - **🌍 λ‹€κ΅­μ–΄** β€” Python, Rust, Java, Go, C++, TypeScript
426
+ - **πŸ€– μ—μ΄μ „νŠΈ** β€” λ³΅μž‘ν•œ λ©€ν‹°μŠ€ν… νƒœμŠ€ν¬
427
+ - **πŸ’‘ μΆ”λ‘ ** β€” Interleaved Thinking
428
+ - **πŸ”§ 도ꡬ** β€” ν•¨μˆ˜ 호좜 및 API 연동
 
 
429
  """)
430
 
431
  # Event handlers
432
  def respond(message, history):
433
+ if not message.strip():
434
+ yield history, "", provider.get_status()
435
+ return
436
 
437
+ for new_history, status in chat_stream(message, history):
438
+ yield new_history, "", status
 
 
 
 
 
 
 
 
439
 
440
  # Connect events
441
  msg.submit(respond, [msg, chatbot], [chatbot, msg, provider_status])
442
  submit_btn.click(respond, [msg, chatbot], [chatbot, msg, provider_status])
443
  clear_btn.click(clear_chat, outputs=[chatbot, msg, provider_status])
444
+ reset_btn.click(reset_provider, outputs=[provider_status])
445
 
446
  if __name__ == "__main__":
447
+ demo.launch(ssr_mode=False)