akhaliq HF Staff commited on
Commit
826ae84
·
1 Parent(s): cfbcf09

feat: initialize DeepSeek V4 Pro project with a Gradio-backed web chat interface

Browse files
Files changed (3) hide show
  1. app.py +40 -0
  2. index.html +470 -0
  3. requirements.txt +3 -0
app.py ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ from openai import OpenAI
3
+ from gradio import Server
4
+ from fastapi.responses import HTMLResponse
5
+
6
+ app = Server()
7
+
8
+ client = OpenAI(
9
+ base_url="https://router.huggingface.co/v1",
10
+ api_key=os.environ.get("HF_TOKEN", ""),
11
+ default_headers={
12
+ "X-HF-Bill-To": "huggingface"
13
+ }
14
+ )
15
+
16
+ @app.api("/chat")
17
+ def chat(message: str, history_json: list):
18
+ # history_json should be a list of dictionaries like [{"role": "user", "content": "..."}, {"role": "assistant", "content": "..."}]
19
+ messages = history_json + [{"role": "user", "content": message}]
20
+
21
+ completion = client.chat.completions.create(
22
+ model="deepseek-ai/DeepSeek-V4-Pro:together",
23
+ messages=messages,
24
+ stream=True
25
+ )
26
+
27
+ full_response = ""
28
+ for chunk in completion:
29
+ if chunk.choices and chunk.choices[0].delta.content:
30
+ full_response += chunk.choices[0].delta.content
31
+ yield full_response
32
+
33
+ @app.get("/")
34
+ async def homepage():
35
+ html_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "index.html")
36
+ with open(html_path, "r", encoding="utf-8") as f:
37
+ return HTMLResponse(content=f.read())
38
+
39
+ if __name__ == "__main__":
40
+ app.launch(show_error=True)
index.html ADDED
@@ -0,0 +1,470 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>DeepSeek V4 Pro</title>
7
+ <!-- Fonts -->
8
+ <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap" rel="stylesheet">
9
+ <link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">
10
+ <!-- Marked.js for Markdown parsing -->
11
+ <script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
12
+ <!-- Gradio Client -->
13
+ <script type="module">
14
+ import { Client } from "https://cdn.jsdelivr.net/npm/@gradio/client/dist/index.min.js";
15
+ window.GradioClient = Client;
16
+ </script>
17
+ <style>
18
+ :root {
19
+ --bg-color: #0b0f19;
20
+ --chat-bg: #151a2a;
21
+ --user-msg: #3b82f6;
22
+ --bot-msg: #1e293b;
23
+ --text-color: #e2e8f0;
24
+ --text-muted: #94a3b8;
25
+ --border-color: #334155;
26
+ --input-bg: #0f172a;
27
+ --glow: 0 0 20px rgba(59, 130, 246, 0.15);
28
+ --gradient: linear-gradient(135deg, #3b82f6 0%, #8b5cf6 100%);
29
+ }
30
+
31
+ * {
32
+ box-sizing: border-box;
33
+ margin: 0;
34
+ padding: 0;
35
+ }
36
+
37
+ body {
38
+ font-family: 'Inter', sans-serif;
39
+ background-color: var(--bg-color);
40
+ color: var(--text-color);
41
+ display: flex;
42
+ justify-content: center;
43
+ height: 100vh;
44
+ overflow: hidden;
45
+ }
46
+
47
+ #app {
48
+ width: 100%;
49
+ max-width: 1000px;
50
+ display: flex;
51
+ flex-direction: column;
52
+ height: 100vh;
53
+ position: relative;
54
+ }
55
+
56
+ /* Glassmorphism Header */
57
+ header {
58
+ padding: 20px 30px;
59
+ background: rgba(15, 23, 42, 0.7);
60
+ backdrop-filter: blur(12px);
61
+ border-bottom: 1px solid var(--border-color);
62
+ display: flex;
63
+ align-items: center;
64
+ z-index: 10;
65
+ }
66
+
67
+ .title {
68
+ font-size: 1.25rem;
69
+ font-weight: 600;
70
+ background: var(--gradient);
71
+ -webkit-background-clip: text;
72
+ -webkit-text-fill-color: transparent;
73
+ letter-spacing: -0.02em;
74
+ }
75
+
76
+ /* Chat Container */
77
+ #chat-container {
78
+ flex: 1;
79
+ overflow-y: auto;
80
+ padding: 30px;
81
+ display: flex;
82
+ flex-direction: column;
83
+ gap: 24px;
84
+ scroll-behavior: smooth;
85
+ }
86
+
87
+ /* Scrollbar */
88
+ #chat-container::-webkit-scrollbar {
89
+ width: 8px;
90
+ }
91
+ #chat-container::-webkit-scrollbar-track {
92
+ background: transparent;
93
+ }
94
+ #chat-container::-webkit-scrollbar-thumb {
95
+ background: var(--border-color);
96
+ border-radius: 4px;
97
+ }
98
+
99
+ /* Messages */
100
+ .message {
101
+ display: flex;
102
+ flex-direction: column;
103
+ max-width: 85%;
104
+ animation: fadeIn 0.3s ease-out forwards;
105
+ }
106
+
107
+ @keyframes fadeIn {
108
+ from { opacity: 0; transform: translateY(10px); }
109
+ to { opacity: 1; transform: translateY(0); }
110
+ }
111
+
112
+ .message.user {
113
+ align-self: flex-end;
114
+ }
115
+
116
+ .message.bot {
117
+ align-self: flex-start;
118
+ }
119
+
120
+ .message-content {
121
+ padding: 16px 20px;
122
+ border-radius: 20px;
123
+ font-size: 0.95rem;
124
+ line-height: 1.6;
125
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
126
+ }
127
+
128
+ .message.user .message-content {
129
+ background: var(--user-msg);
130
+ color: white;
131
+ border-bottom-right-radius: 4px;
132
+ }
133
+
134
+ .message.bot .message-content {
135
+ background: var(--bot-msg);
136
+ border: 1px solid var(--border-color);
137
+ border-bottom-left-radius: 4px;
138
+ overflow-x: auto;
139
+ }
140
+
141
+ /* Markdown Styles in Bot Message */
142
+ .message.bot .message-content p {
143
+ margin-bottom: 0.75em;
144
+ }
145
+ .message.bot .message-content p:last-child {
146
+ margin-bottom: 0;
147
+ }
148
+ .message.bot .message-content pre {
149
+ background: #0f172a;
150
+ padding: 12px;
151
+ border-radius: 8px;
152
+ overflow-x: auto;
153
+ margin: 10px 0;
154
+ border: 1px solid var(--border-color);
155
+ }
156
+ .message.bot .message-content code {
157
+ font-family: 'JetBrains Mono', monospace;
158
+ font-size: 0.85em;
159
+ background: rgba(0, 0, 0, 0.2);
160
+ padding: 2px 4px;
161
+ border-radius: 4px;
162
+ }
163
+ .message.bot .message-content pre code {
164
+ background: transparent;
165
+ padding: 0;
166
+ }
167
+
168
+ /* Input Area */
169
+ #input-container {
170
+ padding: 24px 30px;
171
+ background: var(--chat-bg);
172
+ border-top: 1px solid var(--border-color);
173
+ box-shadow: 0 -10px 40px rgba(0,0,0,0.2);
174
+ position: relative;
175
+ }
176
+
177
+ .input-wrapper {
178
+ display: flex;
179
+ align-items: flex-end;
180
+ background: var(--input-bg);
181
+ border: 1px solid var(--border-color);
182
+ border-radius: 24px;
183
+ padding: 8px 16px;
184
+ transition: border-color 0.2s, box-shadow 0.2s;
185
+ }
186
+
187
+ .input-wrapper:focus-within {
188
+ border-color: #3b82f6;
189
+ box-shadow: var(--glow);
190
+ }
191
+
192
+ #user-input {
193
+ flex: 1;
194
+ background: transparent;
195
+ border: none;
196
+ color: white;
197
+ font-size: 1rem;
198
+ font-family: 'Inter', sans-serif;
199
+ resize: none;
200
+ padding: 10px 0;
201
+ max-height: 150px;
202
+ min-height: 24px;
203
+ outline: none;
204
+ line-height: 1.5;
205
+ }
206
+
207
+ #user-input::placeholder {
208
+ color: var(--text-muted);
209
+ }
210
+
211
+ #send-btn {
212
+ background: var(--gradient);
213
+ border: none;
214
+ width: 40px;
215
+ height: 40px;
216
+ border-radius: 50%;
217
+ display: flex;
218
+ align-items: center;
219
+ justify-content: center;
220
+ cursor: pointer;
221
+ margin-bottom: 4px;
222
+ margin-left: 12px;
223
+ transition: transform 0.2s, box-shadow 0.2s;
224
+ color: white;
225
+ flex-shrink: 0;
226
+ }
227
+
228
+ #send-btn:hover {
229
+ transform: scale(1.05);
230
+ box-shadow: 0 0 15px rgba(139, 92, 246, 0.5);
231
+ }
232
+
233
+ #send-btn:disabled {
234
+ opacity: 0.5;
235
+ cursor: not-allowed;
236
+ transform: none;
237
+ box-shadow: none;
238
+ }
239
+
240
+ #send-btn svg {
241
+ width: 18px;
242
+ height: 18px;
243
+ fill: currentColor;
244
+ margin-left: 2px;
245
+ }
246
+
247
+ /* Loading Indicator */
248
+ .typing-indicator {
249
+ display: none;
250
+ align-items: center;
251
+ gap: 4px;
252
+ padding: 12px 16px;
253
+ background: var(--bot-msg);
254
+ border-radius: 16px;
255
+ border-bottom-left-radius: 4px;
256
+ width: fit-content;
257
+ border: 1px solid var(--border-color);
258
+ }
259
+
260
+ .dot {
261
+ width: 6px;
262
+ height: 6px;
263
+ background: var(--text-muted);
264
+ border-radius: 50%;
265
+ animation: bounce 1.4s infinite ease-in-out both;
266
+ }
267
+
268
+ .dot:nth-child(1) { animation-delay: -0.32s; }
269
+ .dot:nth-child(2) { animation-delay: -0.16s; }
270
+
271
+ @keyframes bounce {
272
+ 0%, 80%, 100% { transform: scale(0); }
273
+ 40% { transform: scale(1); }
274
+ }
275
+
276
+ .empty-state {
277
+ display: flex;
278
+ flex-direction: column;
279
+ align-items: center;
280
+ justify-content: center;
281
+ height: 100%;
282
+ color: var(--text-muted);
283
+ text-align: center;
284
+ }
285
+ .empty-state h2 {
286
+ font-size: 2rem;
287
+ margin-bottom: 12px;
288
+ background: var(--gradient);
289
+ -webkit-background-clip: text;
290
+ -webkit-text-fill-color: transparent;
291
+ }
292
+ .empty-state p {
293
+ max-width: 400px;
294
+ line-height: 1.6;
295
+ }
296
+ </style>
297
+ </head>
298
+ <body>
299
+
300
+ <div id="app">
301
+ <header>
302
+ <div class="title">DeepSeek-V4-Pro</div>
303
+ </header>
304
+
305
+ <div id="chat-container">
306
+ <div class="empty-state" id="empty-state">
307
+ <h2>What can I help you with?</h2>
308
+ <p>Experience the power of DeepSeek V4 Pro, ready to answer your questions and assist with complex tasks.</p>
309
+ </div>
310
+
311
+ <div class="message bot" style="display:none;" id="typing-indicator-wrapper">
312
+ <div class="typing-indicator" id="typing-indicator">
313
+ <div class="dot"></div>
314
+ <div class="dot"></div>
315
+ <div class="dot"></div>
316
+ </div>
317
+ </div>
318
+ </div>
319
+
320
+
321
+ <div id="input-container">
322
+ <div class="input-wrapper">
323
+ <textarea id="user-input" rows="1" placeholder="Type a message..."></textarea>
324
+ <button id="send-btn" disabled>
325
+ <svg viewBox="0 0 24 24">
326
+ <path d="M2.01 21L23 12 2.01 3 2 10l15 2-15 2z"></path>
327
+ </svg>
328
+ </button>
329
+ </div>
330
+ </div>
331
+ </div>
332
+
333
+ <script type="module">
334
+ let client;
335
+ let history = [];
336
+
337
+ const chatContainer = document.getElementById('chat-container');
338
+ const userInput = document.getElementById('user-input');
339
+ const sendBtn = document.getElementById('send-btn');
340
+ const emptyState = document.getElementById('empty-state');
341
+ const typingIndicatorWrapper = document.getElementById('typing-indicator-wrapper');
342
+ const typingIndicator = document.getElementById('typing-indicator');
343
+
344
+ // Initialize Gradio Client
345
+ async function initClient() {
346
+ try {
347
+ client = await window.GradioClient.connect(window.location.origin);
348
+ console.log("Connected to Gradio Server");
349
+ userInput.placeholder = "Message DeepSeek-V4-Pro...";
350
+ } catch (err) {
351
+ console.error("Failed to connect to Gradio Server:", err);
352
+ userInput.placeholder = "Failed to connect to server.";
353
+ }
354
+ }
355
+
356
+ // Auto-resize textarea
357
+ userInput.addEventListener('input', function() {
358
+ this.style.height = 'auto';
359
+ this.style.height = Math.min(this.scrollHeight, 150) + 'px';
360
+ sendBtn.disabled = this.value.trim().length === 0;
361
+ });
362
+
363
+ // Handle Enter key (Shift+Enter for newline)
364
+ userInput.addEventListener('keydown', function(e) {
365
+ if (e.key === 'Enter' && !e.shiftKey) {
366
+ e.preventDefault();
367
+ if (!sendBtn.disabled) {
368
+ sendMessage();
369
+ }
370
+ }
371
+ });
372
+
373
+ sendBtn.addEventListener('click', sendMessage);
374
+
375
+ function addMessage(role, content, isStreaming = false) {
376
+ if (emptyState && emptyState.style.display !== 'none') {
377
+ emptyState.style.display = 'none';
378
+ }
379
+
380
+ const messageDiv = document.createElement('div');
381
+ messageDiv.className = `message ${role}`;
382
+
383
+ const contentDiv = document.createElement('div');
384
+ contentDiv.className = 'message-content';
385
+
386
+ if (role === 'bot') {
387
+ contentDiv.innerHTML = marked.parse(content);
388
+ } else {
389
+ contentDiv.textContent = content;
390
+ }
391
+
392
+ messageDiv.appendChild(contentDiv);
393
+
394
+ // Insert before typing indicator wrapper if it's there
395
+ chatContainer.insertBefore(messageDiv, typingIndicatorWrapper);
396
+
397
+ scrollToBottom();
398
+
399
+ return contentDiv;
400
+ }
401
+
402
+ function scrollToBottom() {
403
+ chatContainer.scrollTop = chatContainer.scrollHeight;
404
+ }
405
+
406
+ async function sendMessage() {
407
+ const text = userInput.value.trim();
408
+ if (!text || !client) return;
409
+
410
+ // Reset input
411
+ userInput.value = '';
412
+ userInput.style.height = 'auto';
413
+ sendBtn.disabled = true;
414
+ userInput.disabled = true;
415
+
416
+ // Add user message to UI
417
+ addMessage('user', text);
418
+
419
+ // Show typing indicator
420
+ typingIndicatorWrapper.style.display = 'flex';
421
+ typingIndicator.style.display = 'flex';
422
+ scrollToBottom();
423
+
424
+ // Setup streaming bot message
425
+ const botContentDiv = addMessage('bot', '', true);
426
+ let fullResponse = "";
427
+
428
+ try {
429
+ const submission = client.submit("/chat", {
430
+ message: text,
431
+ history_json: history
432
+ });
433
+
434
+ for await (const event of submission) {
435
+ if (event.type === "data") {
436
+ if (typingIndicatorWrapper.style.display !== 'none') {
437
+ typingIndicatorWrapper.style.display = 'none';
438
+ typingIndicator.style.display = 'none';
439
+ }
440
+ fullResponse = event.data[0];
441
+ botContentDiv.innerHTML = marked.parse(fullResponse);
442
+ scrollToBottom();
443
+ }
444
+ if (event.type === "status") {
445
+ if (event.stage === "error") {
446
+ throw new Error(event.message);
447
+ }
448
+ }
449
+ }
450
+
451
+ // Update history
452
+ history.push({"role": "user", "content": text});
453
+ history.push({"role": "assistant", "content": fullResponse});
454
+
455
+ } catch (err) {
456
+ console.error("Error during generation:", err);
457
+ typingIndicatorWrapper.style.display = 'none';
458
+ typingIndicator.style.display = 'none';
459
+ botContentDiv.innerHTML = `<span style="color: #ef4444;">Error: ${err.message || 'Something went wrong.'}</span>`;
460
+ } finally {
461
+ userInput.disabled = false;
462
+ userInput.focus();
463
+ }
464
+ }
465
+
466
+ // Run init
467
+ initClient();
468
+ </script>
469
+ </body>
470
+ </html>
requirements.txt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ fastapi
2
+ gradio
3
+ openai