cylnx commited on
Commit
b05e429
·
verified ·
1 Parent(s): 6d6647d

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +21 -485
app.py CHANGED
@@ -1,496 +1,32 @@
1
  import os
2
- import json
3
- import requests
4
  import gradio as gr
5
- from typing import Generator
6
 
7
- # Configuration
8
- API_URL = "https://integrate.api.nvidia.com/v1/chat/completions"
9
- MODEL = "stepfun-ai/step-3.5-flash"
10
 
11
- def get_api_key() -> str:
12
- """Get API key from environment"""
13
- key = os.getenv("NVIDIA_API_KEY")
14
- if not key:
15
- raise ValueError("NVIDIA_API_KEY environment variable not set")
16
- return key
17
 
18
- def respond(message: str, history: list) -> Generator[str, None, None]:
19
- """Generate streaming response using direct HTTP requests"""
20
-
21
- # Build messages from history
22
- messages = []
23
- for msg in history:
24
- if isinstance(msg, dict):
25
- messages.append({"role": msg.get("role", "user"), "content": msg.get("content", "")})
26
- elif isinstance(msg, (list, tuple)) and len(msg) == 2:
27
- messages.append({"role": "user", "content": msg[0]})
28
- if msg[1]:
29
- messages.append({"role": "assistant", "content": msg[1]})
30
-
31
- messages.append({"role": "user", "content": message})
32
-
33
- headers = {
34
- "Authorization": f"Bearer {get_api_key()}",
35
- "Content-Type": "application/json",
36
- "Accept": "text/event-stream",
37
- }
38
-
39
- payload = {
40
- "model": MODEL,
41
- "messages": messages,
42
- "temperature": 0.9,
43
- "max_tokens": 16096,
44
- "stream": True,
45
- }
46
 
47
  try:
48
- # Use requests with stream=True for SSE
49
- with requests.post(
50
- API_URL,
51
- headers=headers,
52
- json=payload,
53
- stream=True,
54
- timeout=120,
55
- ) as response:
56
- response.raise_for_status()
57
-
58
- full_response = ""
59
- # Parse SSE stream
60
- for line in response.iter_lines(decode_unicode=True):
61
- if not line:
62
- continue
63
-
64
- if line.startswith("data: "):
65
- data = line[6:]
66
- if data == "[DONE]":
67
- break
68
-
69
- try:
70
- chunk = json.loads(data)
71
- if chunk.get("choices"):
72
- delta = chunk["choices"][0].get("delta", {})
73
- content = delta.get("content", "")
74
- if content:
75
- full_response += content
76
- yield full_response
77
- except json.JSONDecodeError:
78
- continue
79
-
80
- if not full_response:
81
- yield "No response received from the model."
82
-
83
- except requests.exceptions.Timeout:
84
- yield "⏱️ Request timed out. Please try again."
85
- except requests.exceptions.HTTPError as e:
86
- yield f"❌ HTTP Error {e.response.status_code}"
87
- except requests.exceptions.RequestException as e:
88
- yield f"❌ Connection error: {str(e)}"
89
- except Exception as e:
90
- yield f"❌ Unexpected error: {str(e)}"
91
-
92
- # Beautiful custom theme
93
- custom_theme = gr.themes.Soft(
94
- primary_hue="violet",
95
- secondary_hue="purple",
96
- neutral_hue="slate",
97
- font=gr.themes.GoogleFont("Plus Jakarta Sans"),
98
- text_size="lg",
99
- spacing_size="lg",
100
- radius_size="lg"
101
- ).set(
102
- button_primary_background_fill="linear-gradient(135deg, #8b5cf6 0%, #a855f7 100%)",
103
- button_primary_background_fill_hover="linear-gradient(135deg, #7c3aed 0%, #9333ea 100%)",
104
- button_primary_text_color="white",
105
- button_secondary_background_fill="*neutral_100",
106
- button_secondary_background_fill_hover="*neutral_200",
107
- block_title_text_weight="700",
108
- block_title_text_size="*text_lg",
109
- border_color_primary="rgba(139, 92, 246, 0.3)",
110
- color_accent="*primary_500",
111
- shadow_drop="0 10px 40px rgba(0, 0, 0, 0.15)",
112
- shadow_drop_lg="0 20px 60px rgba(0, 0, 0, 0.2)",
113
- block_border_width="0px",
114
- block_shadow="*shadow_drop",
115
- )
116
-
117
- # Modern CSS styling
118
- custom_css = """
119
- /* Main container */
120
- .gradio-container {
121
- max-width: 100% !important;
122
- padding: 0 !important;
123
- min-height: 100vh;
124
- }
125
-
126
- /* Header styling */
127
- .app-header {
128
- background: linear-gradient(135deg, rgba(139, 92, 246, 0.15) 0%, rgba(168, 85, 247, 0.1) 100%);
129
- backdrop-filter: blur(20px);
130
- border-bottom: 1px solid rgba(139, 92, 246, 0.2);
131
- padding: 24px 32px;
132
- margin: -12px -12px 0 -12px;
133
- position: sticky;
134
- top: 0;
135
- z-index: 100;
136
- }
137
-
138
- .app-title {
139
- font-size: 2rem !important;
140
- font-weight: 800 !important;
141
- background: linear-gradient(135deg, #8b5cf6 0%, #a855f7 50%, #c084fc 100%);
142
- -webkit-background-clip: text;
143
- -webkit-text-fill-color: transparent;
144
- background-clip: text;
145
- margin: 0 !important;
146
- letter-spacing: -0.02em;
147
- }
148
-
149
- .app-subtitle {
150
- font-size: 1rem !important;
151
- color: #64748b !important;
152
- margin-top: 4px !important;
153
- font-weight: 500;
154
- }
155
-
156
- /* Chat container */
157
- .chat-container {
158
- background: rgba(255, 255, 255, 0.98);
159
- border-radius: 24px !important;
160
- box-shadow: 0 20px 60px rgba(0, 0, 0, 0.1), 0 0 0 1px rgba(139, 92, 246, 0.1);
161
- overflow: hidden;
162
- margin-top: 16px;
163
- }
164
-
165
- /* Chatbot styling */
166
- .chatbot {
167
- background: transparent !important;
168
- border: none !important;
169
- box-shadow: none !important;
170
- }
171
-
172
- .chatbot .message-wrap {
173
- padding: 8px 0;
174
- }
175
-
176
- /* User message styling */
177
- .chatbot .message.user {
178
- background: linear-gradient(135deg, #8b5cf6 0%, #a855f7 100%) !important;
179
- color: white !important;
180
- border-radius: 20px 20px 4px 20px !important;
181
- padding: 14px 20px !important;
182
- margin-left: auto;
183
- max-width: 75%;
184
- box-shadow: 0 4px 15px rgba(139, 92, 246, 0.3);
185
- font-weight: 500;
186
- }
187
-
188
- /* Assistant message styling */
189
- .chatbot .message.assistant {
190
- background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%) !important;
191
- color: #1e293b !important;
192
- border-radius: 20px 20px 20px 4px !important;
193
- padding: 14px 20px !important;
194
- margin-right: auto;
195
- max-width: 75%;
196
- border: 1px solid rgba(139, 92, 246, 0.1) !important;
197
- box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05);
198
- }
199
-
200
- /* Input area */
201
- .input-container {
202
- background: white;
203
- border-top: 1px solid rgba(139, 92, 246, 0.1);
204
- padding: 20px 24px;
205
- margin: 0 -12px -12px -12px;
206
- }
207
-
208
- .textbox {
209
- border: 2px solid #e2e8f0 !important;
210
- border-radius: 16px !important;
211
- transition: all 0.3s ease !important;
212
- background: #f8fafc !important;
213
- }
214
-
215
- .textbox:focus-within {
216
- border-color: #8b5cf6 !important;
217
- box-shadow: 0 0 0 4px rgba(139, 92, 246, 0.1) !important;
218
- background: white !important;
219
- }
220
-
221
- .textbox textarea {
222
- font-size: 1rem !important;
223
- padding: 14px 18px !important;
224
- }
225
-
226
- /* Buttons */
227
- .primary-btn {
228
- background: linear-gradient(135deg, #8b5cf6 0%, #a855f7 100%) !important;
229
- border: none !important;
230
- border-radius: 12px !important;
231
- padding: 12px 24px !important;
232
- font-weight: 600 !important;
233
- transition: all 0.3s ease !important;
234
- box-shadow: 0 4px 15px rgba(139, 92, 246, 0.3) !important;
235
- }
236
-
237
- .primary-btn:hover {
238
- transform: translateY(-2px) !important;
239
- box-shadow: 0 8px 25px rgba(139, 92, 246, 0.4) !important;
240
- }
241
-
242
- .secondary-btn {
243
- background: #f1f5f9 !important;
244
- border: none !important;
245
- border-radius: 12px !important;
246
- padding: 12px 24px !important;
247
- font-weight: 600 !important;
248
- color: #475569 !important;
249
- transition: all 0.3s ease !important;
250
- }
251
-
252
- .secondary-btn:hover {
253
- background: #e2e8f0 !important;
254
- }
255
-
256
- /* Animations */
257
- @keyframes fadeInUp {
258
- from {
259
- opacity: 0;
260
- transform: translateY(10px);
261
- }
262
- to {
263
- opacity: 1;
264
- transform: translateY(0);
265
- }
266
- }
267
-
268
- @keyframes pulse {
269
- 0%, 100% {
270
- opacity: 1;
271
- }
272
- 50% {
273
- opacity: 0.7;
274
- }
275
- }
276
-
277
- .chatbot .message {
278
- animation: fadeInUp 0.3s ease-out !important;
279
- }
280
-
281
- /* Typing indicator */
282
- .typing-indicator {
283
- display: flex;
284
- gap: 4px;
285
- padding: 8px 12px;
286
- }
287
-
288
- .typing-indicator span {
289
- width: 8px;
290
- height: 8px;
291
- background: #8b5cf6;
292
- border-radius: 50%;
293
- animation: pulse 1.4s infinite ease-in-out;
294
- }
295
-
296
- .typing-indicator span:nth-child(1) { animation-delay: 0s; }
297
- .typing-indicator span:nth-child(2) { animation-delay: 0.2s; }
298
- .typing-indicator span:nth-child(3) { animation-delay: 0.4s; }
299
-
300
- /* Footer */
301
- .app-footer {
302
- text-align: center;
303
- padding: 16px;
304
- margin-top: 16px;
305
- opacity: 0.7;
306
- transition: opacity 0.3s ease;
307
- }
308
-
309
- .app-footer:hover {
310
- opacity: 1;
311
- }
312
-
313
- .app-footer a {
314
- color: #8b5cf6;
315
- text-decoration: none;
316
- font-weight: 500;
317
- font-size: 0.875rem;
318
- }
319
-
320
- /* Status indicator */
321
- .status-dot {
322
- display: inline-block;
323
- width: 8px;
324
- height: 8px;
325
- background: #10b981;
326
- border-radius: 50%;
327
- margin-right: 8px;
328
- animation: pulse 2s infinite;
329
- }
330
-
331
- /* Mobile responsive */
332
- @media (max-width: 768px) {
333
- .app-header {
334
- padding: 16px 20px;
335
- }
336
-
337
- .app-title {
338
- font-size: 1.5rem !important;
339
- }
340
-
341
- .chatbot .message.user,
342
- .chatbot .message.assistant {
343
- max-width: 85%;
344
- }
345
-
346
- .input-container {
347
- padding: 16px;
348
- }
349
- }
350
-
351
- /* Scrollbar styling */
352
- ::-webkit-scrollbar {
353
- width: 8px;
354
- height: 8px;
355
- }
356
-
357
- ::-webkit-scrollbar-track {
358
- background: transparent;
359
- }
360
-
361
- ::-webkit-scrollbar-thumb {
362
- background: rgba(139, 92, 246, 0.3);
363
- border-radius: 4px;
364
- }
365
-
366
- ::-webkit-scrollbar-thumb:hover {
367
- background: rgba(139, 92, 246, 0.5);
368
- }
369
-
370
- /* Code blocks in messages */
371
- .chatbot .message pre {
372
- background: #1e293b !important;
373
- border-radius: 12px !important;
374
- padding: 16px !important;
375
- overflow-x: auto;
376
- margin: 12px 0 !important;
377
- }
378
-
379
- .chatbot .message code {
380
- font-family: 'JetBrains Mono', monospace !important;
381
- font-size: 0.9rem !important;
382
- }
383
-
384
- /* Links in messages */
385
- .chatbot .message a {
386
- color: #8b5cf6;
387
- text-decoration: underline;
388
- text-underline-offset: 2px;
389
- }
390
-
391
- /* Loading state */
392
- .loading {
393
- position: relative;
394
- }
395
-
396
- .loading::after {
397
- content: '';
398
- position: absolute;
399
- bottom: 0;
400
- left: 0;
401
- width: 100%;
402
- height: 2px;
403
- background: linear-gradient(90deg, transparent, #8b5cf6, transparent);
404
- animation: loading 1.5s infinite;
405
- }
406
-
407
- @keyframes loading {
408
- 0% { transform: translateX(-100%); }
409
- 100% { transform: translateX(100%); }
410
- }
411
-
412
- /* Feature badges */
413
- .feature-badge {
414
- display: inline-flex;
415
- align-items: center;
416
- gap: 6px;
417
- background: rgba(139, 92, 246, 0.1);
418
- color: #7c3aed;
419
- padding: 6px 12px;
420
- border-radius: 20px;
421
- font-size: 0.8rem;
422
- font-weight: 600;
423
- margin-right: 8px;
424
- }
425
- """
426
-
427
- # Create the Gradio app
428
- with gr.Blocks() as demo:
429
- # Header
430
- gr.HTML("""
431
- <div class="app-header">
432
- <div style="display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 16px;">
433
- <div>
434
- <h1 class="app-title">✨ Step 3.5 Flash</h1>
435
- <p class="app-subtitle">Advanced AI Assistant powered by NVIDIA</p>
436
- </div>
437
- <div style="display: flex; align-items: center; gap: 12px;">
438
- <span class="feature-badge">🚀 Fast</span>
439
- <span class="feature-badge">🧠 Smart</span>
440
- <span class="feature-badge">💬 Streaming</span>
441
- </div>
442
- </div>
443
- </div>
444
- """)
445
-
446
- # Chat interface
447
- with gr.Group(elem_classes=["chat-container"]):
448
- chatbot = gr.Chatbot(
449
- show_label=False,
450
- container=True,
451
- height=550,
452
- layout="bubble",
453
- render_markdown=True,
454
- buttons=["copy"],
455
- placeholder="<div style='text-align: center; padding: 40px; color: #94a3b8;'><div style='font-size: 3rem; margin-bottom: 16px;'>💬</div><div style='font-size: 1.1rem; font-weight: 600;'>Start a conversation</div><div style='font-size: 0.9rem; margin-top: 8px;'>Ask me anything, I'm here to help!</div></div>",
456
  )
457
 
458
- with gr.Row(elem_classes=["input-container"]):
459
- msg = gr.Textbox(
460
- placeholder="Type your message here...",
461
- show_label=False,
462
- container=True,
463
- scale=9,
464
- lines=1,
465
- max_lines=5,
466
- elem_classes=["textbox"],
467
- )
468
- submit_btn = gr.Button("Send", variant="primary", scale=1, elem_classes=["primary-btn"])
469
- clear_btn = gr.Button("Clear", variant="secondary", scale=1, elem_classes=["secondary-btn"])
470
-
471
- # Footer
472
- gr.HTML("""
473
- <div class="app-footer">
474
- <a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank">
475
- Built with anycoder
476
- </a>
477
- </div>
478
- """)
479
-
480
- # Event handlers
481
- msg.submit(respond, [msg, chatbot], [chatbot], queue=True).then(
482
- lambda: "", None, msg, queue=False
483
- )
484
- submit_btn.click(respond, [msg, chatbot], [chatbot], queue=True).then(
485
- lambda: "", None, msg, queue=False
486
- )
487
- clear_btn.click(lambda: ([], ""), None, [chatbot, msg], queue=False)
488
 
489
  if __name__ == "__main__":
490
- demo.launch(
491
- theme=custom_theme,
492
- css=custom_css,
493
- server_name="0.0.0.0",
494
- server_port=7860,
495
- footer_links=[{"label": "Built with anycoder", "url": "https://huggingface.co/spaces/akhaliq/anycoder"}],
496
- )
 
1
  import os
 
 
2
  import gradio as gr
3
+ from openai import OpenAI
4
 
5
+ if not (key := os.getenv("NVIDIA_API_KEY")):
6
+ raise ValueError("NVIDIA_API_KEY не найден")
 
7
 
8
+ client = OpenAI(base_url="https://integrate.api.nvidia.com/v1", api_key=key)
 
 
 
 
 
9
 
10
+ def respond(message, history):
11
+ # В Gradio 4.x история уже в формате OpenAI (список словарей)
12
+ messages = history + [{"role": "user", "content": message}]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13
 
14
  try:
15
+ stream = client.chat.completions.create(
16
+ model="stepfun-ai/step-3.5-flash",
17
+ messages=messages,
18
+ temperature=0.9,
19
+ max_tokens=16096,
20
+ stream=True
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21
  )
22
 
23
+ response = ""
24
+ for chunk in stream:
25
+ if chunk.choices and (text := chunk.choices[0].delta.content):
26
+ response += text
27
+ yield response
28
+ except Exception as e:
29
+ yield f"Ошибка: {e}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
30
 
31
  if __name__ == "__main__":
32
+ gr.ChatInterface(respond, title="Step 3.5 Flash").launch()