dexter2389 commited on
Commit
4f20237
·
1 Parent(s): ff69313

Update app and add frontend

Browse files
Files changed (3) hide show
  1. Dockerfile +1 -0
  2. app.py +4 -6
  3. frontend.html +463 -0
Dockerfile CHANGED
@@ -10,4 +10,5 @@ COPY --chown=user ./requirements.txt requirements.txt
10
  RUN pip install --no-cache-dir --upgrade -r requirements.txt
11
 
12
  COPY --chown=user ./app.py app.py
 
13
  CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "7860"]
 
10
  RUN pip install --no-cache-dir --upgrade -r requirements.txt
11
 
12
  COPY --chown=user ./app.py app.py
13
+ COPY --chown=user ./frontend.html frontend.html
14
  CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "7860"]
app.py CHANGED
@@ -16,12 +16,12 @@ from transformers import pipeline
16
 
17
  class SupportedModelPipes(Enum):
18
  Qwen25 = pipeline("text-generation", model="Qwen/Qwen2.5-1.5B-Instruct")
19
- Gemma3 = pipeline("text-generation", model="google/gemma-3-1b-it")
20
  SmolVLM = pipeline("image-text-to-text", model="HuggingFaceTB/SmolVLM-Instruct")
21
 
22
 
23
  class ChatRequest(BaseModel):
24
- model: SupportedModelPipes = SupportedModelPipes.Gemma3
25
  message: str
26
 
27
 
@@ -88,7 +88,5 @@ def chat(payload: ChatRequest, request: Request):
88
 
89
 
90
  @app.get("/")
91
- # async def read_index():
92
- # return FileResponse("test1.html")
93
- def greet_json():
94
- return {"hello": "world"}
 
16
 
17
  class SupportedModelPipes(Enum):
18
  Qwen25 = pipeline("text-generation", model="Qwen/Qwen2.5-1.5B-Instruct")
19
+ SmolLLM2 = pipeline("text-generation", model="HuggingFaceTB/SmolLM2-1.7B-Instruct")
20
  SmolVLM = pipeline("image-text-to-text", model="HuggingFaceTB/SmolVLM-Instruct")
21
 
22
 
23
  class ChatRequest(BaseModel):
24
+ model: SupportedModelPipes = SupportedModelPipes.SmolLLM2
25
  message: str
26
 
27
 
 
88
 
89
 
90
  @app.get("/")
91
+ def frontend():
92
+ return FileResponse("frontend.html")
 
 
frontend.html ADDED
@@ -0,0 +1,463 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+
4
+ <head>
5
+ <meta charset="UTF-8">
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
+ <title>AI Chat Interface</title>
8
+ <script src="https://cdn.tailwindcss.com"></script>
9
+ <script>
10
+ tailwind.config = {
11
+ theme: {
12
+ extend: {
13
+ colors: {
14
+ primary: {
15
+ DEFAULT: '#3b82f6',
16
+ foreground: '#ffffff',
17
+ },
18
+ secondary: {
19
+ DEFAULT: '#f3f4f6',
20
+ foreground: '#1f2937',
21
+ },
22
+ }
23
+ }
24
+ }
25
+ }
26
+ </script>
27
+ <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet">
28
+ </head>
29
+
30
+ <body class="bg-white text-gray-800 font-['Inter']">
31
+ <div class="flex flex-col h-screen">
32
+ <!-- Header -->
33
+ <header class="border-b border-gray-200 p-4">
34
+ <div class="max-w-screen-xl mx-auto flex items-center justify-between">
35
+ <div class="flex items-center">
36
+ <h1 class="text-xl font-medium">OpenGPT with <span class="font-semibold"
37
+ style="color: #067ff3;">Ar</span><span class="font-semibold"
38
+ style="color: #f7cd1b;">ca</span><span class="font-semibold"
39
+ style="color: #07b682;">na</span></h1>
40
+ </div>
41
+
42
+ <nav class="flex items-center space-x-6">
43
+ <a href="https://arcana.ad/" class="text-gray-600 hover:text-gray-900 font-medium">Home</a>
44
+ </nav>
45
+ </div>
46
+ </header>
47
+
48
+ <!-- Chat container -->
49
+ <div id="chat-container" class="flex-1 overflow-y-auto py-4 px-4 md:px-0">
50
+ <div class="max-w-screen-md mx-auto">
51
+ <!-- Initial welcome message -->
52
+ <div class="flex flex-col items-center justify-center mt-16 mb-8">
53
+ <div
54
+ class="w-16 h-16 rounded-full bg-gray-100 flex items-center justify-center text-2xl font-semibold mb-4">
55
+ AR
56
+ </div>
57
+ <h2 class="text-2xl font-semibold text-center">Hello, User</h2>
58
+ <p class="text-2xl text-center">How can I help you today?</p>
59
+ </div>
60
+
61
+ <!-- Messages will be added here -->
62
+ </div>
63
+ </div>
64
+
65
+ <!-- Loading indicator -->
66
+ <div id="loading" class="hidden">
67
+ <div class="max-w-screen-md mx-auto">
68
+ <div class="flex items-start mb-4">
69
+ <div class="w-8 h-8 rounded-full bg-gray-100 flex items-center justify-center mr-2">
70
+ <span class="font-semibold text-sm">AR</span>
71
+ </div>
72
+ <div class="bg-gray-100 p-3 rounded-lg">
73
+ <div class="typing-indicator">
74
+ <span class="dot"></span>
75
+ <span class="dot"></span>
76
+ <span class="dot"></span>
77
+ </div>
78
+ </div>
79
+ </div>
80
+ </div>
81
+ </div>
82
+
83
+ <!-- Suggestion buttons -->
84
+ <div class="max-w-screen-md mx-auto px-4 md:px-0 mb-6 grid grid-cols-1 md:grid-cols-2 gap-3">
85
+ <button class="text-left bg-gray-50 hover:bg-gray-100 p-4 rounded-xl transition-colors">
86
+ <div class="font-medium">Create a short 3 scene video script</div>
87
+ <div class="text-gray-500 text-sm">set in a cyberpunk world run by AI</div>
88
+ </button>
89
+ <button class="text-left bg-gray-50 hover:bg-gray-100 p-4 rounded-xl transition-colors">
90
+ <div class="font-medium">Write a python code</div>
91
+ <div class="text-gray-500 text-sm">for a simple, functional web app</div>
92
+ </button>
93
+ <button class="text-left bg-gray-50 hover:bg-gray-100 p-4 rounded-xl transition-colors">
94
+ <div class="font-medium">Help me study</div>
95
+ <div class="text-gray-500 text-sm">vocabulary for a college entrance exam</div>
96
+ </button>
97
+ <button class="text-left bg-gray-50 hover:bg-gray-100 p-4 rounded-xl transition-colors">
98
+ <div class="font-medium">Give me ideas</div>
99
+ <div class="text-gray-500 text-sm">for a LinkedIn post for my recent promotion</div>
100
+ </button>
101
+ </div>
102
+
103
+ <!-- Input area -->
104
+ <div class="border-t border-gray-200 p-4">
105
+ <div class="max-w-screen-md mx-auto">
106
+ <form id="chat-form" class="relative">
107
+ <div class="flex items-center bg-white border border-gray-300 rounded-full shadow-sm">
108
+ <button type="button" class="p-3 text-gray-400 hover:text-gray-600">
109
+ <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24"
110
+ fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
111
+ stroke-linejoin="round" class="lucide lucide-plus">
112
+ <path d="M5 12h14" />
113
+ <path d="M12 5v14" />
114
+ </svg>
115
+ </button>
116
+ <input type="text" id="user-input" class="flex-1 py-3 px-2 bg-transparent focus:outline-none"
117
+ placeholder="Send a Message" autocomplete="off">
118
+ <button type="button" class="p-3 text-gray-400 hover:text-gray-600">
119
+ <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24"
120
+ fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
121
+ stroke-linejoin="round" class="lucide lucide-mic">
122
+ <path d="M12 2a3 3 0 0 0-3 3v7a3 3 0 0 0 6 0V5a3 3 0 0 0-3-3Z" />
123
+ <path d="M19 10v2a7 7 0 0 1-14 0v-2" />
124
+ <path d="M12 19v3" />
125
+ </svg>
126
+ </button>
127
+ <button type="submit" class="p-3 text-gray-400 hover:text-gray-600">
128
+ <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24"
129
+ fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
130
+ stroke-linejoin="round" class="lucide lucide-arrow-up">
131
+ <path d="m12 19-7-7 7-7" />
132
+ <path d="M5 12h14" />
133
+ </svg>
134
+ </button>
135
+ </div>
136
+ </form>
137
+
138
+ <!-- Footer text -->
139
+ <div class="text-center text-gray-400 text-sm mt-3">
140
+ LLMs can make mistakes. Verify important information.
141
+ </div>
142
+ </div>
143
+ </div>
144
+
145
+ <!-- Help button -->
146
+ <button
147
+ class="fixed bottom-4 right-4 w-10 h-10 bg-white rounded-full shadow-md flex items-center justify-center text-gray-500 hover:bg-gray-100">
148
+ <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none"
149
+ stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"
150
+ class="lucide lucide-help-circle">
151
+ <circle cx="12" cy="12" r="10" />
152
+ <path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3" />
153
+ <path d="M12 17h.01" />
154
+ </svg>
155
+ </button>
156
+ </div>
157
+
158
+ <style>
159
+ .typing-indicator {
160
+ display: flex;
161
+ align-items: center;
162
+ }
163
+
164
+ .dot {
165
+ height: 8px;
166
+ width: 8px;
167
+ margin-right: 4px;
168
+ border-radius: 50%;
169
+ background-color: #6b7280;
170
+ display: inline-block;
171
+ animation: pulse 1.5s infinite ease-in-out;
172
+ }
173
+
174
+ .dot:nth-child(2) {
175
+ animation-delay: 0.2s;
176
+ }
177
+
178
+ .dot:nth-child(3) {
179
+ animation-delay: 0.4s;
180
+ margin-right: 0;
181
+ }
182
+
183
+ @keyframes pulse {
184
+
185
+ 0%,
186
+ 100% {
187
+ transform: scale(0.7);
188
+ opacity: 0.5;
189
+ }
190
+
191
+ 50% {
192
+ transform: scale(1);
193
+ opacity: 1;
194
+ }
195
+ }
196
+
197
+ .message-content p {
198
+ margin-bottom: 0.5rem;
199
+ }
200
+
201
+ .message-content p:last-child {
202
+ margin-bottom: 0;
203
+ }
204
+
205
+ .message-content strong {
206
+ font-weight: 600;
207
+ }
208
+
209
+ .message-content em {
210
+ font-style: normal;
211
+ color: #4B5563;
212
+ }
213
+
214
+ .message-content code {
215
+ font-family: 'Menlo', 'Monaco', 'Courier New', monospace;
216
+ background-color: #f1f5f9;
217
+ padding: 0.1em 0.3em;
218
+ border-radius: 0.25rem;
219
+ font-size: 0.9em;
220
+ border: 1px solid #e2e8f0;
221
+ }
222
+
223
+ .message-content pre {
224
+ background-color: #f8fafc;
225
+ border: 1px solid #e2e8f0;
226
+ border-radius: 0.5rem;
227
+ padding: 1rem;
228
+ margin: 0.75rem 0;
229
+ overflow-x: auto;
230
+ }
231
+
232
+ .message-content pre code {
233
+ background-color: transparent;
234
+ padding: 0;
235
+ border: none;
236
+ font-size: 0.9em;
237
+ display: block;
238
+ white-space: pre;
239
+ }
240
+
241
+ .message-content ul,
242
+ .message-content ol {
243
+ margin-left: 1.5rem;
244
+ margin-bottom: 0.75rem;
245
+ }
246
+
247
+ .message-content ul li,
248
+ .message-content ol li {
249
+ margin-bottom: 0.25rem;
250
+ }
251
+
252
+ .message-content blockquote {
253
+ border-left: 3px solid #cbd5e1;
254
+ padding-left: 1rem;
255
+ margin: 0.75rem 0;
256
+ color: #64748b;
257
+ }
258
+ </style>
259
+
260
+ <script>
261
+ document.addEventListener('DOMContentLoaded', () => {
262
+ const chatForm = document.getElementById('chat-form');
263
+ const userInput = document.getElementById('user-input');
264
+ const chatContainer = document.getElementById('chat-container');
265
+ const loadingIndicator = document.getElementById('loading');
266
+ const suggestionButtons = document.querySelectorAll('.max-w-screen-md.mx-auto.px-4.md\\:px-0.mb-6 button');
267
+
268
+
269
+
270
+ // Function to add a message to the chat
271
+ function formatMessage(text) {
272
+ // First, preserve code blocks by replacing them with placeholders
273
+ const codeBlocks = [];
274
+ text = text.replace(/\`\`\`([\s\S]*?)\`\`\`/g, function (match, code) {
275
+ const id = codeBlocks.length;
276
+ codeBlocks.push(code.trim());
277
+ return `__CODE_BLOCK_${id}__`;
278
+ });
279
+
280
+ // Handle inline code
281
+ const inlineCodes = [];
282
+ text = text = text.replace(/`([^`]+)`/g, function (match, code) {
283
+ const id = inlineCodes.length;
284
+ inlineCodes.push(code);
285
+ return `__INLINE_CODE_${id}__`;
286
+ });
287
+
288
+ // Replace ** with proper styling
289
+ text = text.replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>');
290
+
291
+ // Handle numbered lists
292
+ text = text.replace(/(\d+\.\s[^*]*?)(?=\d+\.|$)/g, '<div class="mb-3">$1</div>');
293
+
294
+ // Handle sections with asterisks
295
+ text = text.replace(/\*(.*?)\*/g, '<em>$1</em>');
296
+
297
+ // Handle unordered lists
298
+ text = text.replace(/^- (.*?)$/gm, '<li>$1</li>');
299
+ text = text.replace(/<li>.*?<\/li>(?:\s*<li>.*?<\/li>)+/gs, function (match) {
300
+ return '<ul>' + match + '</ul>';
301
+ });
302
+
303
+ // Handle ordered lists
304
+ text = text.replace(/^(\d+)\. (.*?)$/gm, '<li>$2</li>');
305
+ text = text.replace(/<li>.*?<\/li>(?:\s*<li>.*?<\/li>)+/gs, function (match) {
306
+ return '<ol>' + match + '</ol>';
307
+ });
308
+
309
+ // Handle blockquotes
310
+ text = text.replace(/^> (.*?)$/gm, '<blockquote>$1</blockquote>');
311
+
312
+ // Add proper spacing between sections
313
+ text = text.split('\n').map(line => line.trim()).filter(line => line).join('</p><p>');
314
+
315
+ // Restore code blocks
316
+ codeBlocks.forEach((code, i) => {
317
+ text = text.replace(`__CODE_BLOCK_${i}__`, `</p><pre><code>${escapeHtml(code)}</code></pre><p>`);
318
+ });
319
+
320
+ // Restore inline code
321
+ inlineCodes.forEach((code, i) => {
322
+ text = text.replace(`__INLINE_CODE_${i}__`, `<code>${escapeHtml(code)}</code>`);
323
+ });
324
+
325
+ return `<p>${text}</p>`;
326
+ }
327
+
328
+ // Helper function to escape HTML in code blocks
329
+ function escapeHtml(text) {
330
+ return text
331
+ .replace(/&/g, "&amp;")
332
+ .replace(/</g, "&lt;")
333
+ .replace(/>/g, "&gt;")
334
+ .replace(/"/g, "&quot;")
335
+ .replace(/'/g, "&#039;");
336
+ }
337
+
338
+ // Function to add a message to the chat
339
+ function addMessage(content, isUser = false) {
340
+ // Hide the welcome message when chat starts
341
+ const welcomeMessage = chatContainer.querySelector('.flex.flex-col.items-center.justify-center');
342
+ if (welcomeMessage) {
343
+ welcomeMessage.remove();
344
+ }
345
+
346
+ // Hide suggestion buttons when chat starts
347
+ const suggestionContainer = document.querySelector('.max-w-screen-md.mx-auto.px-4.md\\:px-0.mb-6');
348
+ if (suggestionContainer && !suggestionContainer.classList.contains('hidden')) {
349
+ suggestionContainer.classList.add('hidden');
350
+ }
351
+
352
+ const messageDiv = document.createElement('div');
353
+ messageDiv.className = 'max-w-screen-md mx-auto mb-6';
354
+
355
+ const formattedContent = isUser ? content : formatMessage(content);
356
+
357
+ const html = `
358
+ <div class="flex items-start ${isUser ? 'justify-end' : ''}">
359
+ ${!isUser ? `
360
+ <div class="w-8 h-8 rounded-full bg-gray-100 flex items-center justify-center mr-2">
361
+ <span class="font-semibold text-sm">AR</span>
362
+ </div>
363
+ ` : ''}
364
+ <div class="${isUser ? 'bg-blue-50 text-blue-800' : 'bg-gray-100 text-gray-800'} p-3 rounded-lg max-w-[80%] message-content">
365
+ ${formattedContent}
366
+ </div>
367
+ ${isUser ? `
368
+ <div class="w-8 h-8 rounded-full bg-blue-100 flex items-center justify-center text-blue-800 ml-2">
369
+ <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-user"><circle cx="12" cy="8" r="5"/><path d="M20 21a8 8 0 0 0-16 0"/></svg>
370
+ </div>
371
+ ` : ''}
372
+ </div>
373
+ `;
374
+
375
+ messageDiv.innerHTML = html;
376
+ chatContainer.appendChild(messageDiv);
377
+
378
+ // Scroll to bottom
379
+ chatContainer.scrollTop = chatContainer.scrollHeight;
380
+ }
381
+
382
+ // Function to show loading indicator
383
+ function showLoading() {
384
+ loadingIndicator.classList.remove('hidden');
385
+ chatContainer.scrollTop = chatContainer.scrollHeight;
386
+ }
387
+
388
+ // Function to hide loading indicator
389
+ function hideLoading() {
390
+ loadingIndicator.classList.add('hidden');
391
+ }
392
+
393
+ // Handle form submission
394
+ chatForm.addEventListener('submit', async (e) => {
395
+ e.preventDefault();
396
+
397
+ const message = userInput.value.trim();
398
+ if (!message) return;
399
+
400
+ // Add user message to chat
401
+ addMessage(message, true);
402
+
403
+ // Clear input
404
+ userInput.value = '';
405
+
406
+ // Show loading indicator
407
+ showLoading();
408
+
409
+ try {
410
+ // Send message to API
411
+ const response = await fetch('/chat', {
412
+ method: 'POST',
413
+ headers: {
414
+ 'Content-Type': 'application/json',
415
+ },
416
+ body: JSON.stringify({ message }),
417
+ });
418
+
419
+ if (!response.ok) {
420
+ throw new Error('API request failed');
421
+ }
422
+
423
+ const data = await response.json();
424
+
425
+ // Hide loading indicator
426
+ hideLoading();
427
+
428
+ // Add AI response to chat
429
+ addMessage(data.response);
430
+
431
+ } catch (error) {
432
+ console.error('Error:', error);
433
+
434
+ // Hide loading indicator
435
+ hideLoading();
436
+
437
+ // Add error message
438
+ addMessage('Sorry, there was an error processing your request. Please try again.');
439
+ }
440
+ });
441
+
442
+ // Handle suggestion button clicks
443
+ suggestionButtons.forEach(button => {
444
+ button.addEventListener('click', () => {
445
+ const mainText = button.querySelector('.font-medium').textContent;
446
+ const subText = button.querySelector('.text-gray-500').textContent;
447
+ const fullText = `${mainText} ${subText}`;
448
+
449
+ // Set the input value
450
+ userInput.value = fullText;
451
+
452
+ // Submit the form
453
+ chatForm.dispatchEvent(new Event('submit'));
454
+ });
455
+ });
456
+
457
+ // Focus input on page load
458
+ userInput.focus();
459
+ });
460
+ </script>
461
+ </body>
462
+
463
+ </html>