ParthSadaria commited on
Commit
ebcd29c
·
verified ·
1 Parent(s): 9bfb2c6

Create playground.html

Browse files
Files changed (1) hide show
  1. playground.html +561 -0
playground.html ADDED
@@ -0,0 +1,561 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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>LOKI.AI Playground</title>
8
+ <link
9
+ href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=JetBrains+Mono:wght@300;400;500;600&display=swap"
10
+ rel="stylesheet">
11
+ <link href="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.13/css/select2.min.css" rel="stylesheet" />
12
+ <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
13
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.13/js/select2.min.js"></script>
14
+
15
+ <style>
16
+ @import url('https://fonts.googleapis.com/css2?family=Encode+Sans:[email protected]&family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&family=Protest+Revolution&display=swap');
17
+
18
+ :root {
19
+ --bg-dark: #0a0a0f;
20
+ --bg-darker: #040409;
21
+ --bg-deepest: #020205;
22
+ --primary-blue: #4a6cf7;
23
+ --secondary-blue: #6678e3;
24
+ --accent-color: #7e57c2;
25
+ --text-light: #e0e0e8;
26
+ --text-muted: #8a8a9b;
27
+ --border-color: #1a1a2e;
28
+ --hover-color: rgba(78, 108, 247, 0.1);
29
+ --delete-red: #ff4d4d;
30
+ }
31
+
32
+ * {
33
+ margin: 0;
34
+ padding: 0;
35
+ box-sizing: border-box;
36
+ scrollbar-width: thin;
37
+ scrollbar-color: var(--primary-blue) transparent;
38
+ }
39
+
40
+ *::-webkit-scrollbar {
41
+ width: 8px;
42
+ }
43
+
44
+ *::-webkit-scrollbar-track {
45
+ background: transparent;
46
+ }
47
+
48
+ *::-webkit-scrollbar-thumb {
49
+ background-color: var(--primary-blue);
50
+ border-radius: 20px;
51
+ }
52
+
53
+ body {
54
+ font-family: 'Inter', sans-serif;
55
+ background-color: var(--bg-dark);
56
+ color: var(--text-light);
57
+ display: flex;
58
+ justify-content: center;
59
+ align-items: center;
60
+ height: 100vh;
61
+ overflow: hidden;
62
+ perspective: 2000px;
63
+ }
64
+
65
+ .chat-wrapper {
66
+ position: relative;
67
+ width: 100%;
68
+ max-width: 600px;
69
+ height: 90vh;
70
+ background-color: var(--bg-darker);
71
+ border-radius: 24px;
72
+ overflow: hidden;
73
+ box-shadow: 0 20px 50px rgba(5, 5, 10, 0.7);
74
+ display: flex;
75
+ flex-direction: column;
76
+ opacity: 1;
77
+ transform: scale(1);
78
+ transition: all 0.6s cubic-bezier(0.23, 1, 0.32, 1);
79
+ border: 1px solid var(--border-color);
80
+ }
81
+
82
+ .watermark {
83
+ position: absolute;
84
+ bottom: 10px;
85
+ right: 15px;
86
+ color: var(--text-muted);
87
+ font-size: 10px;
88
+ opacity: 0.5;
89
+ transition: opacity 0.3s ease;
90
+ }
91
+
92
+ .watermark:hover {
93
+ opacity: 0.8;
94
+ }
95
+
96
+ .chat-header {
97
+ background-color: var(--bg-deepest);
98
+ padding: 15px 20px;
99
+ display: flex;
100
+ justify-content: space-between;
101
+ align-items: center;
102
+ border-bottom: 1px solid var(--border-color);
103
+ }
104
+
105
+ .header-actions {
106
+ display: flex;
107
+ align-items: center;
108
+ gap: 10px;
109
+ }
110
+
111
+ .model-select {
112
+ background-color: black;
113
+ color: var(--text-light);
114
+ border: 1px solid var(--border-color);
115
+ border-radius: 8px;
116
+ padding: 10px 14px;
117
+ font-family: 'JetBrains Mono', monospace;
118
+ font-size: 14px;
119
+ cursor: pointer;
120
+ transition: all 0.3s ease;
121
+ }
122
+
123
+ .clear-chat {
124
+ background-color: var(--delete-red);
125
+ color: white;
126
+ border: none;
127
+ border-radius: 8px;
128
+ padding: 10px 14px;
129
+ font-family: 'JetBrains Mono', monospace;
130
+ font-size: 14px;
131
+ cursor: pointer;
132
+ transition: all 0.3s ease;
133
+ display: flex;
134
+ align-items: center;
135
+ gap: 5px;
136
+ }
137
+
138
+ .clear-chat:hover {
139
+ background-color: #ff6666;
140
+ }
141
+
142
+ .initial-input {
143
+ flex: 1;
144
+ display: flex;
145
+ flex-direction: column;
146
+ justify-content: center;
147
+ align-items: center;
148
+ padding: 24px;
149
+ text-align: center;
150
+ background: linear-gradient(145deg, var(--bg-dark), var(--bg-darker));
151
+ transition: all 0.5s ease;
152
+ }
153
+
154
+ .initial-input h2 {
155
+ font-size: 24px;
156
+ margin-bottom: 16px;
157
+ color: var(--text-light);
158
+ font-weight: 600;
159
+ font-family: 'JetBrains Mono', monospace;
160
+ }
161
+
162
+ .input-container {
163
+ width: 100%;
164
+ max-width: 400px;
165
+ position: relative;
166
+ }
167
+
168
+ .initial-input input,
169
+ .chat-input input {
170
+ width: 100%;
171
+ padding: 16px 24px;
172
+ background-color: rgba(30, 30, 50, 0.8);
173
+ border: 1px solid var(--border-color);
174
+ border-radius: 12px;
175
+ color: var(--text-light);
176
+ font-size: 16px;
177
+ font-family: 'JetBrains Mono', monospace;
178
+ outline: none;
179
+ transition: all 0.3s ease;
180
+ }
181
+
182
+ .initial-input input:focus,
183
+ .chat-input input:focus {
184
+ border-color: var(--primary-blue);
185
+ box-shadow: 0 0 0 3px rgba(74, 108, 247, 0.2);
186
+ }
187
+
188
+ .send-icon {
189
+ position: absolute;
190
+ right: 12px;
191
+ top: 50%;
192
+ transform: translateY(-50%);
193
+ background-color: var(--primary-blue);
194
+ border-radius: 8px;
195
+ width: 40px;
196
+ height: 40px;
197
+ display: flex;
198
+ justify-content: center;
199
+ align-items: center;
200
+ cursor: pointer;
201
+ transition: all 0.3s ease;
202
+ }
203
+
204
+ .send-icon:hover {
205
+ background-color: var(--accent-color);
206
+ transform: translateY(-50%) scale(1.05);
207
+ border-radius: 15px;
208
+ }
209
+
210
+ .chat-container {
211
+ display: none;
212
+ flex-direction: column;
213
+ height: 100%;
214
+ }
215
+
216
+ .chat-messages {
217
+ flex: 1;
218
+ overflow-y: auto;
219
+ padding: 20px;
220
+ display: flex;
221
+ flex-direction: column;
222
+ gap: 16px;
223
+ background-color: var(--bg-dark);
224
+ font-family: 'JetBrains Mono', monospace;
225
+ overscroll-behavior: contain;
226
+ }
227
+
228
+ .message {
229
+ max-width: 80%;
230
+ width: fit-content;
231
+ padding: 12px 18px;
232
+ border-radius: 12px;
233
+ font-size: 14px;
234
+ line-height: 1.5;
235
+ opacity: 0;
236
+ transform: translateY(20px);
237
+ animation: fadeIn 0.4s forwards;
238
+ position: relative;
239
+ overflow: hidden;
240
+ }
241
+
242
+ .message::before {
243
+ content: '';
244
+ position: absolute;
245
+ top: 0;
246
+ left: 0;
247
+ right: 0;
248
+ bottom: 0;
249
+ background: linear-gradient(to right, transparent, rgba(255, 255, 255, 0.1));
250
+ opacity: 0;
251
+ transition: opacity 0.3s ease;
252
+ }
253
+
254
+ .message:hover::before {
255
+ opacity: 1;
256
+ }
257
+
258
+ .message.user {
259
+ align-self: flex-end;
260
+ background-color: var(--primary-blue);
261
+ color: white;
262
+ }
263
+
264
+ .message.bot {
265
+ align-self: flex-start;
266
+ background-color: rgba(40, 40, 70, 0.8);
267
+ color: var(--text-light);
268
+ border: 1px solid var(--border-color);
269
+ }
270
+
271
+ .chat-input {
272
+ display: flex;
273
+ gap: 12px;
274
+ padding: 16px;
275
+ background-color: var(--bg-darker);
276
+ border-top: 1px solid var(--border-color);
277
+ }
278
+
279
+ .chat-input button {
280
+ background-color: var(--accent-color);
281
+ color: white;
282
+ border: none;
283
+ border-radius: 12px;
284
+ padding: 12px 24px;
285
+ cursor: pointer;
286
+ font-family: 'JetBrains Mono', monospace;
287
+ transition: all 0.3s ease;
288
+ }
289
+
290
+ .chat-input button:hover {
291
+ background-color: var(--primary-blue);
292
+ transform: scale(1.02);
293
+ }
294
+
295
+ @keyframes fadeIn {
296
+ to {
297
+ opacity: 1;
298
+ transform: translateY(0);
299
+ }
300
+ }
301
+ /* Dark theme customization for Select2 */
302
+ .select2-container--default .select2-selection--single {
303
+ background-color: #333; /* Dark background */
304
+ color: white; /* White text */
305
+ border: 1px solid #555; /* Dark border */
306
+ font-size: 14px;
307
+ }
308
+
309
+ /* Customize selected item background */
310
+ .select2-container--default .select2-selection--single .select2-selection__rendered {
311
+ background-color: #333; /* Dark background */
312
+ color: white; /* White text */
313
+ }
314
+
315
+ .select2-dropdown {
316
+ background-color: #333; /* Dark dropdown background */
317
+ color: white; /* White text in dropdown */
318
+ max-height: 300px; /* Limit dropdown height */
319
+ overflow-y: auto; /* Add scrollbar */
320
+ }
321
+
322
+ .select2-container--default .select2-results__option {
323
+ background-color: #333; /* Dark background for options */
324
+ color: white; /* White text for options */
325
+ }
326
+
327
+ .select2-container--default .select2-results__option--highlighted {
328
+ background-color: #555; /* Highlighted option color */
329
+ color: white; /* White text on hover */
330
+ }
331
+ </style>
332
+ </head>
333
+
334
+ <body>
335
+ <div class="chat-wrapper">
336
+ <div class="chat-header">
337
+ <h2 style="font-family: 'JetBrains Mono', monospace;">LOKI.AI Playground</h2>
338
+ <div class="header-actions">
339
+ <select id="modelSelect" class="model-select">
340
+ <option value="gpt-4o-mini">GPT-4o Mini</option>
341
+ <option value="gpt-4o">GPT-4o</option>
342
+ <option value="claude-3-haiku">Claude 3 Haiku</option>
343
+ <option value="llama-3.1-8b">Llama 3.1 8B</option>
344
+ <option value="llama-3.1-70b">Llama 3.1 70B</option>
345
+ <option value="meta-llama/Meta-Llama-3.1-70B-Instruct-Turbo">Llama-3.1-70B-Turbo</option>
346
+ <option value="llama-3.1-405b">Llama 3.1 405b</option>
347
+ <option value="llama-3.1-70b">Mixtral 8x7b</option>
348
+ </select>
349
+ <button id="clearChatButton" class="clear-chat">
350
+ <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none"
351
+ stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
352
+ <polyline points="3 6 5 6 21 6"></polyline>
353
+ <path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"></path>
354
+ <line x1="10" y1="11" x2="10" y2="17"></line>
355
+ <line x1="14" y1="11" x2="14" y2="17"></line>
356
+ </svg>
357
+ Clear
358
+ </button>
359
+ </div>
360
+ </div>
361
+
362
+ <div class="initial-input">
363
+ <h2>Welcome to LOKI.AI</h2>
364
+ <div class="input-container">
365
+ <input type="text" id="initialChatInput" placeholder="What can I help you with today?">
366
+ <div class="send-icon" id="initialSendIcon">
367
+ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none"
368
+ stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
369
+ <line x1="22" y1="2" x2="11" y2="13"></line>
370
+ <polygon points="22 2 15 22 11 13 2 9 22 2"></polygon>
371
+ </svg>
372
+ </div>
373
+ </div>
374
+ </div>
375
+
376
+ <div class="chat-container" id="chatContainer">
377
+ <div class="chat-messages" id="chatMessages"></div>
378
+ <div class="chat-input">
379
+ <input type="text" id="chatInput" placeholder="Type your message...">
380
+ <button id="sendButton">Send</button>
381
+ </div>
382
+ </div>
383
+ </div>
384
+ <div class="watermark">
385
+ Made with ❤️ by Parth Sadaria
386
+ </div>
387
+ <script>
388
+ const chatWrapper = document.querySelector('.chat-wrapper');
389
+ const initialInput = document.querySelector('.initial-input');
390
+ const chatContainer = document.getElementById('chatContainer');
391
+ const initialChatInput = document.getElementById('initialChatInput');
392
+ const initialSendIcon = document.getElementById('initialSendIcon');
393
+ const chatMessages = document.getElementById('chatMessages');
394
+ const chatInput = document.getElementById('chatInput');
395
+ const sendButton = document.getElementById('sendButton');
396
+ const modelSelect = document.getElementById('modelSelect');
397
+ const clearChatButton = document.getElementById('clearChatButton');
398
+
399
+ let currentStreamingMessage = null;
400
+ let conversationHistory = [];
401
+
402
+ function appendMessage(content, type = 'bot', isStreaming = false) {
403
+ if (type === 'bot' && isStreaming) {
404
+ if (!currentStreamingMessage) {
405
+ currentStreamingMessage = document.createElement('div');
406
+ currentStreamingMessage.className = `message ${type}`;
407
+ chatMessages.appendChild(currentStreamingMessage);
408
+ }
409
+ currentStreamingMessage.textContent += content;
410
+ chatMessages.scrollTop = chatMessages.scrollHeight;
411
+ } else {
412
+ if (currentStreamingMessage) {
413
+ currentStreamingMessage = null;
414
+ }
415
+
416
+ const messageBox = document.createElement('div');
417
+ messageBox.className = `message ${type}`;
418
+ messageBox.textContent = content;
419
+ chatMessages.appendChild(messageBox);
420
+ chatMessages.scrollTop = chatMessages.scrollHeight;
421
+
422
+ // Update conversation history
423
+ conversationHistory.push({
424
+ role: type === 'user' ? 'user' : 'assistant',
425
+ content: content
426
+ });
427
+ }
428
+ }
429
+ $(document).ready(function() {
430
+ $('#modelSelect').select2({
431
+ placeholder: 'Select a model', // Placeholder text
432
+ minimumResultsForSearch: 1 // Show search when there is at least 1 item
433
+ });
434
+ });
435
+ function clearChat() {
436
+ chatMessages.innerHTML = '';
437
+ conversationHistory = [];
438
+ initialInput.style.display = 'flex';
439
+ chatContainer.style.display = 'none';
440
+ chatWrapper.classList.remove('active');
441
+ }
442
+
443
+ async function sendInitialMessage() {
444
+ const userMessage = initialChatInput.value.trim();
445
+ const selectedModel = modelSelect.value;
446
+ if (!userMessage) return;
447
+
448
+ initialInput.style.display = 'none';
449
+ chatContainer.style.display = 'flex';
450
+ chatWrapper.classList.add('active');
451
+
452
+ appendMessage(userMessage, 'user');
453
+ initialChatInput.value = '';
454
+
455
+ try {
456
+ await callApi(userMessage, selectedModel);
457
+ } catch (error) {
458
+ appendMessage("Oops! Something went wrong.", 'bot');
459
+ console.error("API Error:", error);
460
+ }
461
+ }
462
+
463
+ async function sendMessage() {
464
+ const userMessage = chatInput.value.trim();
465
+ const selectedModel = modelSelect.value;
466
+ if (!userMessage) return;
467
+
468
+ appendMessage(userMessage, 'user');
469
+ chatInput.value = '';
470
+
471
+ try {
472
+ await callApi(userMessage, selectedModel);
473
+ } catch (error) {
474
+ appendMessage("Oops! Something went wrong.", 'bot');
475
+ console.error("API Error:", error);
476
+ }
477
+ }
478
+
479
+ async function callApi(userMessage, model) {
480
+ const url = "https://parthsadaria-lokiai.hf.space/chat/completions";
481
+ const payload = {
482
+ model: model,
483
+ messages: [
484
+ // Send entire conversation history
485
+ ...conversationHistory,
486
+ { role: "user", content: userMessage }
487
+ ],
488
+ stream: true
489
+ };
490
+
491
+ const headers = {
492
+ "Content-Type": "application/json"
493
+ };
494
+
495
+ let fullResponse = "";
496
+
497
+ try {
498
+ const response = await fetch(url, {
499
+ method: "POST",
500
+ headers: headers,
501
+ body: JSON.stringify(payload)
502
+ });
503
+
504
+ if (response.ok) {
505
+ const reader = response.body.getReader();
506
+ const decoder = new TextDecoder("utf-8");
507
+ let done = false;
508
+
509
+ while (!done) {
510
+ const { value, done: streamDone } = await reader.read();
511
+ done = streamDone;
512
+
513
+ if (value) {
514
+ const chunk = decoder.decode(value);
515
+ const cleanedChunk = chunk.trim().replace(/^data:\s*/, '');
516
+ const jsonChunks = cleanedChunk.split("data:").filter(Boolean);
517
+
518
+ jsonChunks.forEach(jsonString => {
519
+ try {
520
+ const jsonData = JSON.parse(jsonString);
521
+ const delta = jsonData.choices?.[0]?.delta || {};
522
+ const content = delta.content || "";
523
+
524
+ if (content) {
525
+ fullResponse += content;
526
+ appendMessage(content, 'bot', true);
527
+ }
528
+ } catch (err) {
529
+ console.warn("Parsing error:", err);
530
+ }
531
+ });
532
+ }
533
+ }
534
+ } else {
535
+ throw new Error(`API responded with status ${response.status}`);
536
+ }
537
+ } catch (error) {
538
+ console.error("API call error:", error);
539
+ throw error;
540
+ }
541
+
542
+ return fullResponse.trim();
543
+ }
544
+
545
+ // Event Listeners
546
+ initialSendIcon.addEventListener('click', sendInitialMessage);
547
+ initialChatInput.addEventListener('keypress', (event) => {
548
+ if (event.key === 'Enter') sendInitialMessage();
549
+ });
550
+
551
+ sendButton.addEventListener('click', sendMessage);
552
+ chatInput.addEventListener('keypress', (event) => {
553
+ if (event.key === 'Enter') sendMessage();
554
+ });
555
+
556
+ // Clear Chat Button Event Listener
557
+ clearChatButton.addEventListener('click', clearChat);
558
+ </script>
559
+ </body>
560
+
561
+ </html>