druvx13 commited on
Commit
820275c
·
verified ·
1 Parent(s): 3c34738

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +480 -1
app.py CHANGED
@@ -1,6 +1,7 @@
1
  import uvicorn
2
- from fastapi import FastAPI, HTTPException
3
  from fastapi.middleware.cors import CORSMiddleware
 
4
  from huggingface_hub import InferenceClient
5
  from pydantic import BaseModel
6
 
@@ -59,5 +60,483 @@ async def chat_stream(request: ChatRequest):
59
  except Exception as e:
60
  raise HTTPException(status_code=500, detail=str(e))
61
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
62
  if __name__ == "__main__":
63
  uvicorn.run(app, host="0.0.0.0", port=7860)
 
1
  import uvicorn
2
+ from fastapi import FastAPI, HTTPException, Request
3
  from fastapi.middleware.cors import CORSMiddleware
4
+ from fastapi.responses import HTMLResponse, StreamingResponse
5
  from huggingface_hub import InferenceClient
6
  from pydantic import BaseModel
7
 
 
60
  except Exception as e:
61
  raise HTTPException(status_code=500, detail=str(e))
62
 
63
+ @app.get("/", response_class=HTMLResponse)
64
+ async def read_root():
65
+ # Serve the HTML content directly
66
+ html_content = """
67
+ <!DOCTYPE html>
68
+ <html lang="en">
69
+ <head>
70
+ <meta charset="UTF-8">
71
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
72
+ <title>Qwen2.5 Coder - AI Assistant</title>
73
+ <script src="https://cdn.tailwindcss.com"></script>
74
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
75
+ <style>
76
+ :root {
77
+ --primary: #2563eb;
78
+ --primary-dark: #1d4ed8;
79
+ --dark: #1e293b;
80
+ --light: #f8fafc;
81
+ --gray: #94a3b8;
82
+ --success: #10b981;
83
+ }
84
+ .chat-container {
85
+ height: calc(100vh - 120px);
86
+ }
87
+ .message-user {
88
+ background-color: white;
89
+ border-left: 4px solid var(--primary);
90
+ }
91
+ .message-assistant {
92
+ background-color: white;
93
+ border-left: 4px solid var(--success);
94
+ }
95
+ .typing-indicator span {
96
+ display: inline-block;
97
+ width: 8px;
98
+ height: 8px;
99
+ background-color: var(--gray);
100
+ border-radius: 50%;
101
+ margin-right: 4px;
102
+ animation: bounce 1.4s infinite ease-in-out;
103
+ }
104
+ .typing-indicator span:nth-child(2) {
105
+ animation-delay: 0.2s;
106
+ }
107
+ .typing-indicator span:nth-child(3) {
108
+ animation-delay: 0.4s;
109
+ }
110
+ @keyframes bounce {
111
+ 0%, 60%, 100% { transform: translateY(0); }
112
+ 30% { transform: translateY(-5px); }
113
+ }
114
+ .code-block {
115
+ background-color: #0f172a;
116
+ color: #e2e8f0;
117
+ font-family: 'Fira Code', monospace;
118
+ }
119
+ .sidebar {
120
+ transition: transform 0.3s ease;
121
+ }
122
+ @media (max-width: 768px) {
123
+ .sidebar {
124
+ transform: translateX(-100%);
125
+ position: fixed;
126
+ z-index: 50;
127
+ height: 100vh;
128
+ }
129
+ .sidebar-open {
130
+ transform: translateX(0);
131
+ }
132
+ }
133
+ </style>
134
+ </head>
135
+ <body>
136
+ <div class="flex h-screen overflow-hidden">
137
+ <!-- Sidebar -->
138
+ <div class="sidebar bg-white w-64 border-r border-gray-200 flex flex-col md:relative absolute">
139
+ <div class="p-4 border-b border-gray-200 flex items-center">
140
+ <div class="w-10 h-10 rounded-full bg-blue-500 flex items-center justify-center text-white font-bold">Q</div>
141
+ <div class="ml-3">
142
+ <h2 class="font-semibold">Qwen2.5 Coder</h2>
143
+ <p class="text-xs text-gray-500">32B Instruct</p>
144
+ </div>
145
+ <button id="close-sidebar" class="ml-auto md:hidden text-gray-500">
146
+ <i class="fas fa-times"></i>
147
+ </button>
148
+ </div>
149
+ <div class="p-4 border-b border-gray-200">
150
+ <button id="new-chat" class="w-full bg-blue-500 hover:bg-blue-600 text-white py-2 px-4 rounded-md flex items-center justify-center">
151
+ <i class="fas fa-plus mr-2"></i> New Chat
152
+ </button>
153
+ </div>
154
+ <div class="flex-1 overflow-y-auto p-2">
155
+ <div class="p-2 text-sm font-medium text-gray-500">Recent Chats</div>
156
+ <div id="chat-history" class="space-y-1">
157
+ <!-- Chat history will be populated here -->
158
+ </div>
159
+ </div>
160
+ <div class="p-4 border-t border-gray-200">
161
+ <div class="flex items-center">
162
+ <div class="w-8 h-8 rounded-full bg-gray-300 flex items-center justify-center">
163
+ <i class="fas fa-user text-gray-600"></i>
164
+ </div>
165
+ <div class="ml-2">
166
+ <p class="text-sm font-medium">User Account</p>
167
+ </div>
168
+ </div>
169
+ </div>
170
+ </div>
171
+ <!-- Main Content -->
172
+ <div class="flex-1 flex flex-col overflow-hidden">
173
+ <!-- Header -->
174
+ <header class="bg-white border-b border-gray-200 p-4 flex items-center">
175
+ <button id="menu-button" class="mr-4 text-gray-500 md:hidden">
176
+ <i class="fas fa-bars"></i>
177
+ </button>
178
+ <h1 class="text-xl font-semibold">Chat with Qwen2.5 Coder</h1>
179
+ <div class="ml-auto flex space-x-2">
180
+ <button class="p-2 rounded-full hover:bg-gray-100">
181
+ <i class="fas fa-cog text-gray-500"></i>
182
+ </button>
183
+ <button class="p-2 rounded-full hover:bg-gray-100">
184
+ <i class="fas fa-question-circle text-gray-500"></i>
185
+ </button>
186
+ </div>
187
+ </header>
188
+ <!-- Chat Area -->
189
+ <div id="chat-area" class="chat-container flex-1 overflow-y-auto p-4 space-y-4">
190
+ <div class="message-assistant p-4 rounded-lg shadow-sm">
191
+ <div class="flex items-start">
192
+ <div class="w-8 h-8 rounded-full bg-green-500 flex items-center justify-center text-white mr-3">
193
+ <i class="fas fa-robot"></i>
194
+ </div>
195
+ <div class="flex-1">
196
+ <p class="font-medium text-gray-700">Qwen2.5 Coder</p>
197
+ <p class="mt-1 text-gray-800">Hello! I'm Qwen2.5 Coder, a 32B parameter AI assistant specialized in coding and technical questions. How can I help you today?</p>
198
+ </div>
199
+ </div>
200
+ </div>
201
+ </div>
202
+ <!-- Input Area -->
203
+ <div class="border-t border-gray-200 p-4 bg-white">
204
+ <div class="flex items-center mb-2">
205
+ <button class="p-2 rounded-full hover:bg-gray-100 text-gray-500 mr-1">
206
+ <i class="fas fa-paperclip"></i>
207
+ </button>
208
+ <button class="p-2 rounded-full hover:bg-gray-100 text-gray-500 mr-1">
209
+ <i class="fas fa-code"></i>
210
+ </button>
211
+ <button id="settings-button" class="p-2 rounded-full hover:bg-gray-100 text-gray-500">
212
+ <i class="fas fa-sliders-h"></i>
213
+ </button>
214
+ </div>
215
+ <!-- Settings Panel -->
216
+ <div id="settings-panel" class="hidden bg-gray-50 p-4 rounded-lg mb-4">
217
+ <div class="grid grid-cols-1 md:grid-cols-2 gap-4">
218
+ <div>
219
+ <label class="block text-sm font-medium text-gray-700 mb-1">System Message</label>
220
+ <textarea id="system-message" class="w-full p-2 border border-gray-300 rounded-md text-sm" rows="2">You are a helpful AI assistant that specializes in coding and technical questions.</textarea>
221
+ </div>
222
+ <div>
223
+ <label class="block text-sm font-medium text-gray-700 mb-1">Max Tokens</label>
224
+ <input id="max-tokens" type="range" min="1" max="200000" value="512" class="w-full">
225
+ <div class="flex justify-between text-xs text-gray-500">
226
+ <span>1</span>
227
+ <span>512</span>
228
+ <span>200k</span>
229
+ </div>
230
+ </div>
231
+ <div>
232
+ <label class="block text-sm font-medium text-gray-700 mb-1">Temperature</label>
233
+ <input id="temperature" type="range" min="0.1" max="4.0" step="0.1" value="0.7" class="w-full">
234
+ <div class="flex justify-between text-xs text-gray-500">
235
+ <span>0.1</span>
236
+ <span>0.7</span>
237
+ <span>4.0</span>
238
+ </div>
239
+ </div>
240
+ <div>
241
+ <label class="block text-sm font-medium text-gray-700 mb-1">Top-p</label>
242
+ <input id="top-p" type="range" min="0.1" max="1.0" step="0.05" value="0.95" class="w-full">
243
+ <div class="flex justify-between text-xs text-gray-500">
244
+ <span>0.1</span>
245
+ <span>0.95</span>
246
+ <span>1.0</span>
247
+ </div>
248
+ </div>
249
+ </div>
250
+ </div>
251
+ <div class="flex items-center">
252
+ <textarea id="message-input" class="flex-1 p-3 border border-gray-300 rounded-l-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent" placeholder="Type your message here..." rows="1"></textarea>
253
+ <button id="send-button" class="bg-blue-500 hover:bg-blue-600 text-white p-3 rounded-r-md">
254
+ <i class="fas fa-paper-plane"></i>
255
+ </button>
256
+ </div>
257
+ <p class="text-xs text-gray-500 mt-2">Qwen2.5 Coder may produce inaccurate information about people, places, or facts.</p>
258
+ </div>
259
+ </div>
260
+ </div>
261
+ <script>
262
+ // State management
263
+ const state = {
264
+ currentChatId: generateId(),
265
+ chatHistory: {},
266
+ settings: {
267
+ systemMessage: "You are a helpful AI assistant that specializes in coding and technical questions.",
268
+ maxTokens: 512,
269
+ temperature: 0.7,
270
+ topP: 0.95
271
+ }
272
+ };
273
+ // Initialize the app
274
+ document.addEventListener('DOMContentLoaded', function() {
275
+ // Load chat history from localStorage if available
276
+ const savedHistory = localStorage.getItem('chatHistory');
277
+ if (savedHistory) {
278
+ state.chatHistory = JSON.parse(savedHistory);
279
+ renderChatHistory();
280
+ }
281
+ // Create initial chat
282
+ if (!state.chatHistory[state.currentChatId]) {
283
+ state.chatHistory[state.currentChatId] = {
284
+ id: state.currentChatId,
285
+ title: "New Chat",
286
+ messages: [
287
+ {
288
+ role: "assistant",
289
+ content: "Hello! I'm Qwen2.5 Coder, a 32B parameter AI assistant specialized in coding and technical questions. How can I help you today?"
290
+ }
291
+ ],
292
+ createdAt: new Date().toISOString()
293
+ };
294
+ saveChatHistory();
295
+ }
296
+ // UI event listeners
297
+ setupEventListeners();
298
+ });
299
+ // Helper functions
300
+ function generateId() {
301
+ return Date.now().toString(36) + Math.random().toString(36).substring(2);
302
+ }
303
+ function saveChatHistory() {
304
+ localStorage.setItem('chatHistory', JSON.stringify(state.chatHistory));
305
+ }
306
+ function renderChatHistory() {
307
+ const chatHistoryContainer = document.getElementById('chat-history');
308
+ chatHistoryContainer.innerHTML = '';
309
+ // Sort chats by creation date (newest first)
310
+ const sortedChats = Object.values(state.chatHistory).sort((a, b) =>
311
+ new Date(b.createdAt) - new Date(a.createdAt)
312
+ );
313
+ sortedChats.forEach(chat => {
314
+ const chatElement = document.createElement('div');
315
+ chatElement.className = `p-2 hover:bg-gray-100 rounded-md cursor-pointer flex items-center ${chat.id === state.currentChatId ? 'bg-gray-100' : ''}`;
316
+ chatElement.innerHTML = `
317
+ <i class="fas fa-comment mr-2 text-gray-500"></i>
318
+ <span class="truncate">${chat.title}</span>
319
+ `;
320
+ chatElement.addEventListener('click', () => loadChat(chat.id));
321
+ chatHistoryContainer.appendChild(chatElement);
322
+ });
323
+ }
324
+ function loadChat(chatId) {
325
+ state.currentChatId = chatId;
326
+ renderChatHistory();
327
+ renderChatMessages();
328
+ }
329
+ function renderChatMessages() {
330
+ const chatArea = document.getElementById('chat-area');
331
+ chatArea.innerHTML = '';
332
+ const currentChat = state.chatHistory[state.currentChatId];
333
+ if (!currentChat) return;
334
+ currentChat.messages.forEach(message => {
335
+ const messageDiv = document.createElement('div');
336
+ messageDiv.className = message.role === 'user' ?
337
+ 'message-user p-4 rounded-lg shadow-sm' :
338
+ 'message-assistant p-4 rounded-lg shadow-sm';
339
+ messageDiv.innerHTML = `
340
+ <div class="flex items-start">
341
+ <div class="w-8 h-8 rounded-full ${message.role === 'user' ? 'bg-blue-500' : 'bg-green-500'} flex items-center justify-center text-white mr-3">
342
+ <i class="fas ${message.role === 'user' ? 'fa-user' : 'fa-robot'}"></i>
343
+ </div>
344
+ <div class="flex-1">
345
+ <p class="font-medium text-gray-700">${message.role === 'user' ? 'You' : 'Qwen2.5 Coder'}</p>
346
+ <div class="mt-1 text-gray-800">${formatMessageContent(message.content)}</div>
347
+ </div>
348
+ </div>
349
+ `;
350
+ chatArea.appendChild(messageDiv);
351
+ });
352
+ chatArea.scrollTop = chatArea.scrollHeight;
353
+ }
354
+ function formatMessageContent(content) {
355
+ // Simple formatting for code blocks (replace with proper markdown parsing if needed)
356
+ return content.replace(/```([\s\S]*?)```/g, '<div class="code-block mt-2 p-3 rounded-md text-sm overflow-x-auto"><pre><code>$1</code></pre></div>');
357
+ }
358
+ function setupEventListeners() {
359
+ // Toggle sidebar on mobile
360
+ document.getElementById('menu-button').addEventListener('click', function() {
361
+ document.querySelector('.sidebar').classList.add('sidebar-open');
362
+ });
363
+ document.getElementById('close-sidebar').addEventListener('click', function() {
364
+ document.querySelector('.sidebar').classList.remove('sidebar-open');
365
+ });
366
+ // Toggle settings panel
367
+ document.getElementById('settings-button').addEventListener('click', function() {
368
+ document.getElementById('settings-panel').classList.toggle('hidden');
369
+ });
370
+ // Auto-resize textarea
371
+ const textarea = document.getElementById('message-input');
372
+ textarea.addEventListener('input', function() {
373
+ this.style.height = 'auto';
374
+ this.style.height = (this.scrollHeight) + 'px';
375
+ });
376
+ // New chat button
377
+ document.getElementById('new-chat').addEventListener('click', function() {
378
+ const newChatId = generateId();
379
+ state.currentChatId = newChatId;
380
+ state.chatHistory[newChatId] = {
381
+ id: newChatId,
382
+ title: "New Chat",
383
+ messages: [
384
+ {
385
+ role: "assistant",
386
+ content: "Hello! I'm Qwen2.5 Coder, a 32B parameter AI assistant specialized in coding and technical questions. How can I help you today?"
387
+ }
388
+ ],
389
+ createdAt: new Date().toISOString()
390
+ };
391
+ saveChatHistory();
392
+ renderChatHistory();
393
+ renderChatMessages();
394
+ document.querySelector('.sidebar').classList.remove('sidebar-open');
395
+ });
396
+ // Send message
397
+ document.getElementById('send-button').addEventListener('click', sendMessage);
398
+ // Allow pressing Enter to send message (Shift+Enter for new line)
399
+ textarea.addEventListener('keydown', function(e) {
400
+ if (e.key === 'Enter' && !e.shiftKey) {
401
+ e.preventDefault();
402
+ sendMessage();
403
+ }
404
+ });
405
+ // Settings change listeners
406
+ document.getElementById('system-message').addEventListener('change', function() {
407
+ state.settings.systemMessage = this.value;
408
+ });
409
+ document.getElementById('max-tokens').addEventListener('input', function() {
410
+ state.settings.maxTokens = parseInt(this.value);
411
+ // Update the displayed value
412
+ this.parentNode.querySelector('span:nth-child(2)').textContent = this.value;
413
+ });
414
+ document.getElementById('temperature').addEventListener('input', function() {
415
+ state.settings.temperature = parseFloat(this.value);
416
+ this.parentNode.querySelector('span:nth-child(2)').textContent = this.value;
417
+ });
418
+ document.getElementById('top-p').addEventListener('input', function() {
419
+ state.settings.topP = parseFloat(this.value);
420
+ this.parentNode.querySelector('span:nth-child(2)').textContent = this.value;
421
+ });
422
+ }
423
+ async function sendMessage() {
424
+ const textarea = document.getElementById('message-input');
425
+ const message = textarea.value.trim();
426
+ if (message) {
427
+ // Clear input and adjust height
428
+ textarea.value = '';
429
+ textarea.style.height = 'auto';
430
+ // Add user message to chat
431
+ addMessageToChat('user', message);
432
+ // Show typing indicator
433
+ showTypingIndicator();
434
+ try {
435
+ // Prepare the request data
436
+ const requestData = {
437
+ message: message,
438
+ history: getMessageHistory(),
439
+ system_message: state.settings.systemMessage,
440
+ max_tokens: state.settings.maxTokens,
441
+ temperature: state.settings.temperature,
442
+ top_p: state.settings.topP
443
+ };
444
+ // Call the API
445
+ const response = await fetch('/api/chat', {
446
+ method: 'POST',
447
+ headers: {
448
+ 'Content-Type': 'application/json',
449
+ },
450
+ body: JSON.stringify(requestData)
451
+ });
452
+ // Handle streaming response
453
+ const reader = response.body.getReader();
454
+ const decoder = new TextDecoder();
455
+ let assistantResponse = '';
456
+ let responseId = generateId();
457
+ while(true) {
458
+ const { done, value } = await reader.read();
459
+ if(done) break;
460
+ const chunk = decoder.decode(value);
461
+ assistantResponse += chunk;
462
+ // Update the assistant message in real-time
463
+ updateAssistantMessage(responseId, assistantResponse);
464
+ }
465
+ // Finalize the message
466
+ finalizeMessage(responseId, assistantResponse);
467
+ updateChatTitle(message);
468
+ } catch (error) {
469
+ console.error('Error:', error);
470
+ addMessageToChat('assistant', "Sorry, I encountered an error. Please try again.");
471
+ } finally {
472
+ hideTypingIndicator();
473
+ }
474
+ }
475
+ }
476
+ function addMessageToChat(role, content, id) {
477
+ const messageId = id || generateId();
478
+ const currentChat = state.chatHistory[state.currentChatId];
479
+ currentChat.messages.push({
480
+ id: messageId,
481
+ role: role,
482
+ content: content
483
+ });
484
+ saveChatHistory();
485
+ renderChatMessages();
486
+ return messageId;
487
+ }
488
+ function updateAssistantMessage(id, content) {
489
+ const messageElement = document.querySelector(`[data-message-id="${id}"]`);
490
+ if(messageElement) {
491
+ messageElement.querySelector('.message-content').innerHTML = formatMessageContent(content);
492
+ messageElement.scrollIntoView({ behavior: 'smooth' });
493
+ }
494
+ }
495
+ function finalizeMessage(id, content) {
496
+ const currentChat = state.chatHistory[state.currentChatId];
497
+ const message = currentChat.messages.find(m => m.id === id);
498
+ if(message) {
499
+ message.content = content;
500
+ saveChatHistory();
501
+ }
502
+ }
503
+ function showTypingIndicator() {
504
+ const typingIndicator = document.createElement('div');
505
+ typingIndicator.className = 'message-assistant p-4 rounded-lg shadow-sm';
506
+ typingIndicator.innerHTML = `
507
+ <div class="flex items-start">
508
+ <div class="w-8 h-8 rounded-full bg-green-500 flex items-center justify-center text-white mr-3">
509
+ <i class="fas fa-robot"></i>
510
+ </div>
511
+ <div class="flex-1">
512
+ <p class="font-medium text-gray-700">Qwen2.5 Coder</p>
513
+ <div class="typing-indicator mt-1">
514
+ <span></span>
515
+ <span></span>
516
+ <span></span>
517
+ </div>
518
+ </div>
519
+ </div>
520
+ `;
521
+ document.getElementById('chat-area').appendChild(typingIndicator);
522
+ }
523
+ function hideTypingIndicator() {
524
+ const typingIndicators = document.getElementsByClassName('typing-indicator');
525
+ while(typingIndicators.length > 0) {
526
+ typingIndicators[0].parentNode.parentNode.parentNode.remove();
527
+ }
528
+ }
529
+ function getMessageHistory() {
530
+ const currentChat = state.chatHistory[state.currentChatId];
531
+ return currentChat.messages
532
+ .filter(msg => msg.role !== 'system')
533
+ .map(msg => [msg.role === 'user' ? msg.content : '', msg.role === 'assistant' ? msg.content : '']);
534
+ }
535
+ </script>
536
+ </body>
537
+ </html>
538
+ """
539
+ return HTMLResponse(content=html_content)
540
+
541
  if __name__ == "__main__":
542
  uvicorn.run(app, host="0.0.0.0", port=7860)