ParthSadaria commited on
Commit
0a70991
·
verified ·
1 Parent(s): 8ccaf6f

hehe update playground

Browse files

fixed many bugs upgraded the relaiablity :)

Files changed (1) hide show
  1. playground.html +385 -319
playground.html CHANGED
@@ -5,16 +5,17 @@
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 rel="icon" type="image/x-icon" href="favicon.ico">
9
  <link
10
  href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=JetBrains+Mono:wght@300;400;500;600&display=swap"
11
  rel="stylesheet">
12
  <link href="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.13/css/select2.min.css" rel="stylesheet" />
13
  <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
14
  <script src="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.13/js/select2.min.js"></script>
15
-
16
  <style>
17
  @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');
 
18
  :root {
19
  --bg-dark: #0a0a0f;
20
  --bg-darker: #040409;
@@ -30,6 +31,7 @@
30
  --header-height: 60px;
31
  --input-height: 80px;
32
  }
 
33
  * {
34
  margin: 0;
35
  padding: 0;
@@ -37,16 +39,20 @@
37
  scrollbar-width: thin;
38
  scrollbar-color: var(--primary-blue) transparent;
39
  }
 
40
  *::-webkit-scrollbar {
41
  width: 8px;
42
  }
 
43
  *::-webkit-scrollbar-track {
44
  background: transparent;
45
  }
 
46
  *::-webkit-scrollbar-thumb {
47
  background-color: var(--primary-blue);
48
  border-radius: 20px;
49
  }
 
50
  body {
51
  font-family: 'Inter', sans-serif;
52
  background-color: var(--bg-dark);
@@ -58,6 +64,7 @@
58
  overflow: hidden;
59
  perspective: 2000px;
60
  }
 
61
  .chat-wrapper {
62
  position: relative;
63
  width: 100%;
@@ -74,6 +81,7 @@
74
  transition: all 0.6s cubic-bezier(0.23, 1, 0.32, 1);
75
  border: 1px solid var(--border-color);
76
  }
 
77
  .chat-header {
78
  background-color: var(--bg-deepest);
79
  padding: 15px 20px;
@@ -84,12 +92,14 @@
84
  flex-shrink: 0;
85
  height: var(--header-height);
86
  }
 
87
  .chat-container {
88
  display: none;
89
  flex-direction: column;
90
  height: calc(100% - var(--header-height));
91
  position: relative;
92
  }
 
93
  .chat-messages {
94
  flex: 1;
95
  overflow-y: auto;
@@ -102,6 +112,7 @@
102
  height: calc(100% - var(--input-height));
103
  margin-bottom: var(--input-height);
104
  }
 
105
  .chat-input {
106
  position: absolute;
107
  bottom: 0;
@@ -116,12 +127,14 @@
116
  z-index: 10;
117
  align-items: center;
118
  }
 
119
  .chat-input-container {
120
  position: relative;
121
  flex: 1;
122
  display: flex;
123
  align-items: center;
124
  }
 
125
  .chat-input input {
126
  width: 100%;
127
  padding: 12px 16px;
@@ -135,10 +148,12 @@
135
  font-family: 'JetBrains Mono', monospace;
136
  outline: none;
137
  }
 
138
  .chat-input input:focus {
139
  border-color: var(--primary-blue);
140
  box-shadow: 0 0 0 3px rgba(74, 108, 247, 0.2);
141
  }
 
142
  .message {
143
  max-width: 80%;
144
  width: fit-content;
@@ -150,17 +165,20 @@
150
  animation: fadeIn 0.4s forwards;
151
  margin-bottom: 8px;
152
  }
 
153
  .message.user {
154
  align-self: flex-end;
155
  background-color: var(--primary-blue);
156
  color: white;
157
  }
 
158
  .message.bot {
159
  align-self: flex-start;
160
  background-color: rgba(40, 40, 70, 0.8);
161
  color: var(--text-light);
162
  border: 1px solid var(--border-color);
163
  }
 
164
  .message::before {
165
  content: '';
166
  position: absolute;
@@ -172,9 +190,11 @@
172
  opacity: 0;
173
  transition: opacity 0.3s ease;
174
  }
 
175
  .message:hover::before {
176
  opacity: 1;
177
  }
 
178
  .initial-input {
179
  flex: 1;
180
  display: flex;
@@ -185,6 +205,7 @@
185
  text-align: center;
186
  background: linear-gradient(145deg, var(--bg-dark), var(--bg-darker));
187
  }
 
188
  .initial-input h2 {
189
  font-size: 24px;
190
  margin-bottom: 16px;
@@ -192,11 +213,13 @@
192
  font-weight: 600;
193
  font-family: 'JetBrains Mono', monospace;
194
  }
 
195
  .input-container {
196
  width: 100%;
197
  max-width: 400px;
198
  position: relative;
199
  }
 
200
  .initial-input input {
201
  width: 100%;
202
  padding: 16px 24px;
@@ -209,6 +232,7 @@
209
  outline: none;
210
  transition: all 0.3s ease;
211
  }
 
212
  .send-icon {
213
  position: absolute;
214
  right: 12px;
@@ -224,55 +248,84 @@
224
  cursor: pointer;
225
  transition: all 0.3s ease;
226
  }
 
227
  .send-icon:hover {
228
  background-color: var(--accent-color);
229
  transform: translateY(-50%) scale(1.05);
230
  border-radius: 15px;
231
  }
 
232
  @keyframes fadeIn {
233
  from {
234
  opacity: 0;
235
  transform: translateY(20px);
236
  }
 
237
  to {
238
  opacity: 1;
239
  transform: translateY(0);
240
  }
241
  }
 
242
  /* Header actions */
243
  .header-actions {
244
  display: flex;
245
  align-items: center;
246
  gap: 10px;
 
247
  }
 
248
  .model-select {
249
  background-color: black;
250
  color: var(--text-light);
251
  border: 1px solid var(--border-color);
252
  border-radius: 8px;
253
- padding: 10px 14px;
254
  font-family: 'JetBrains Mono', monospace;
255
- font-size: 10px;
256
  cursor: pointer;
257
  transition: all 0.3s ease;
 
 
 
 
 
 
 
 
 
258
  }
 
 
 
 
 
 
 
259
  .clear-chat {
260
  background-color: var(--delete-red);
261
  color: white;
262
  border: none;
263
  border-radius: 8px;
264
- padding: 10px 14px;
265
- font-family: 'JetBrains Mono', monospace;
266
- font-size: 14px;
267
- cursor: pointer;
268
- transition: all 0.3s ease;
269
  display: flex;
270
  align-items: center;
271
- gap: 5px;
 
 
272
  }
 
273
  .clear-chat:hover {
274
  background-color: #ff6666;
275
  }
 
 
 
 
 
 
276
  .watermark {
277
  position: absolute;
278
  bottom: 10px;
@@ -283,150 +336,190 @@
283
  transition: opacity 0.3s ease;
284
  z-index: 11;
285
  }
 
286
  .watermark:hover {
287
  opacity: 0.8;
288
  }
289
- /* Select2 customization */
290
- .select2-container--default .select2-selection--single {
291
- background-color: transparent;
292
- color: white;
293
- border: 2px solid var(--border-color);
294
- font-size: 14px;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
295
  }
296
- .select2-container--default .select2-selection--single .select2-selection__rendered {
297
- background-color: transparent;
298
- color: white;
299
- padding: 0px 10px;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
300
  }
301
- .select2-dropdown {
302
- background-color: transparent;
303
- color: white;
304
- max-height: 300px;
305
- overflow-y: auto;
306
  }
307
- .select2-container--default .select2-results__option {
308
- background-color: transparent;
309
- color: white;
310
  }
311
- .select2-container--default .select2-results__option--highlighted {
312
- background-color: transparent;
313
- color: white;
 
 
 
314
  }
315
- @media screen and (max-width: 768px) {
316
- body {
317
- align-items: flex-start;
318
- padding: 10px;
319
- }
320
- .chat-wrapper {
321
- max-width: 100%;
322
- height: 100vh;
323
- border-radius: 16px;
324
- margin: 0;
325
- }
326
- .chat-header {
327
- font-size: 10px;
328
- padding: 10px 15px;
329
- height: 50px;
330
- }
331
- .chat-messages {
332
- padding: 10px;
333
- gap: 10px;
334
- }
335
- .message {
336
- max-width: 90%;
337
- font-size: 13px;
338
- padding: 10px 15px;
339
- }
340
- .chat-input {
341
- padding: 10px;
342
- height: 70px;
343
- }
344
- .chat-input input {
345
- padding: 10px 14px;
346
- padding-right: 40px;
347
- font-size: 13px;
348
- }
349
- .send-icon {
350
- width: 35px;
351
- height: 35px;
352
- }
353
- .initial-input {
354
- padding: 15px;
355
- }
356
- .initial-input h2 {
357
- font-size: 20px;
358
- }
359
- .initial-input input {
360
- padding: 19px 20px;
361
- font-size: 12px;
362
- }
363
- .header-actions {
364
- gap: 5px;
365
- }
366
- .model-select,
367
- .clear-chat {
368
- padding: 8px 10px;
369
- font-size: 12px;
370
- }
371
- .watermark {
372
- font-size: 8px;
373
- }
374
- }
375
- @media screen and (max-width: 480px) {
376
- .chat-wrapper {
377
- border-radius: 12px;
378
- }
379
- .message {
380
- max-width: 95%;
381
- font-size: 12px;
382
- padding: 8px 12px;
383
- }
384
- .chat-input input {
385
- font-size: 12px;
386
- }
387
- .header-actions {
388
- flex-direction: column;
389
- gap: 5px;
390
- }
391
- .clear-chat {
392
- width: 50%;
393
- }
394
- .model-select{
395
- width: 20% !important;
396
- }
397
- }
398
- /* Additional responsive adjustments to existing CSS */
399
- * {
400
- -webkit-tap-highlight-color: transparent;
401
- }
402
- body {
403
- touch-action: manipulation;
404
- }
405
- input, button {
406
- -webkit-appearance: none;
407
- -moz-appearance: none;
408
- appearance: none;
409
  }
410
- @media (hover: hover) {
411
- .send-icon:hover {
412
- background-color: var(--accent-color);
413
- transform: translateY(-50%) scale(1.05);
414
- border-radius: 15px;
415
- }
416
  }
417
- @media (pointer: coarse) {
418
- .send-icon {
419
- width: 45px;
420
- height: 45px;
421
- }
422
- .chat-input input {
423
- font-size: 16px; /* Larger font for touch devices */
424
- }
425
  }
 
426
  </style>
427
  </head>
428
 
429
  <body>
 
 
 
 
 
430
  <div class="chat-wrapper">
431
  <div class="chat-header">
432
  <h2 style="font-family: 'JetBrains Mono', monospace;">LOKI.AI Playground</h2>
@@ -435,8 +528,8 @@ input, button {
435
  <option value="gpt-4o-mini">GPT-4o Mini</option>
436
  <option value="gpt-4o">GPT-4o</option>
437
  <option value="gpt-3.5-turbo">GPT-3.5 Turbo</option>
438
- <option value="searchgpt">SearchGPT(Realtime Stuff)</option>
439
- <option value="claude-3-haiku">Claude 3 Haiku</option>
440
  <option value="llama-3.1-8b">Llama 3.1 8B</option>
441
  <option value="llama-3.1-70b">Llama 3.1 70B</option>
442
  <option value="llama-3.1-405b">Llama 3.1 405b</option>
@@ -447,14 +540,13 @@ input, button {
447
  <option value="command">Command</option>
448
  </select>
449
  <button id="clearChatButton" class="clear-chat">
450
- <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none"
451
- stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
452
  <polyline points="3 6 5 6 21 6"></polyline>
453
  <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>
454
  <line x1="10" y1="11" x2="10" y2="17"></line>
455
  <line x1="14" y1="11" x2="14" y2="17"></line>
456
  </svg>
457
- Clear
458
  </button>
459
  </div>
460
  </div>
@@ -496,69 +588,71 @@ input, button {
496
  const sendButton = document.getElementById('sendButton');
497
  const modelSelect = document.getElementById('modelSelect');
498
  const clearChatButton = document.getElementById('clearChatButton');
499
-
500
  let currentStreamingMessage = null;
 
501
  let conversationHistory = [];
502
  function scrollToBottom() {
503
  const chatMessages = document.getElementById('chatMessages');
504
  chatMessages.scrollTop = chatMessages.scrollHeight;
505
  }
506
  function appendMessage(content, type = 'bot', isStreaming = false) {
507
- if (type === 'bot' && isStreaming) {
508
- if (!currentStreamingMessage) {
509
- currentStreamingMessage = document.createElement('div');
510
- currentStreamingMessage.className = `message ${type}`;
511
- chatMessages.appendChild(currentStreamingMessage);
512
- }
513
-
514
- // Replace consecutive numbers followed by spaces with numbered list format
515
- // Convert text between ** to bold, handling multiple occurrences
516
- const formattedContent = content
517
- .replace(/(\d+)\.\s*/g, '<br>$1. ') // Ensure proper spacing and line breaks
518
- .replace(/\n/g, '<br>') // Convert remaining newlines
519
- .replace(/\*\*(.*?)\*\*/g, function(match, p1) {
520
- return '<strong>' + p1 + '</strong>';
521
- });
522
-
523
- // Safely set innerHTML
524
- currentStreamingMessage.innerHTML += formattedContent;
525
-
526
- chatMessages.scrollTop = chatMessages.scrollHeight;
527
- } else {
528
- // Similar logic for non-streaming messages
529
- if (currentStreamingMessage) {
530
- currentStreamingMessage = null;
531
- }
532
-
533
- const messageBox = document.createElement('div');
534
- messageBox.className = `message ${type}`;
535
-
536
- // Format content similarly
537
- const formattedContent = content
538
- .replace(/(\d+)\.\s*/g, '<br>$1. ')
539
- .replace(/\n/g, '<br>')
540
- .replace(/\*\*(.*?)\*\*/g, function(match, p1) {
541
- return '<strong>' + p1 + '</strong>';
542
- });
543
-
544
- messageBox.innerHTML = formattedContent;
545
-
546
- chatMessages.appendChild(messageBox);
547
- chatMessages.scrollTop = chatMessages.scrollHeight;
548
-
549
- // Update conversation history
550
- conversationHistory.push({
551
- role: type === 'user' ? 'user' : 'assistant',
552
- content: content
553
- });
554
- }
555
- }
556
- $(document).ready(function () {
557
- $('#modelSelect').select2({
558
- placeholder: 'Select a model', // Placeholder text
559
- minimumResultsForSearch: 1 // Show search when there is at least 1 item
560
- });
561
- });
 
 
562
  function clearChat() {
563
  chatMessages.innerHTML = '';
564
  conversationHistory = [];
@@ -566,16 +660,13 @@ input, button {
566
  chatContainer.style.display = 'none';
567
  chatWrapper.classList.remove('active');
568
  }
569
-
570
  async function sendInitialMessage() {
571
  const userMessage = initialChatInput.value.trim();
572
  const selectedModel = modelSelect.value;
573
  if (!userMessage) return;
574
-
575
  initialInput.style.display = 'none';
576
  chatContainer.style.display = 'flex';
577
  chatWrapper.classList.add('active');
578
-
579
  appendMessage(userMessage, 'user');
580
  initialChatInput.value = '';
581
  scrollToBottom();
@@ -586,15 +677,12 @@ input, button {
586
  console.error("API Error:", error);
587
  }
588
  }
589
-
590
  async function sendMessage() {
591
  const userMessage = chatInput.value.trim();
592
  const selectedModel = modelSelect.value;
593
  if (!userMessage) return;
594
-
595
  appendMessage(userMessage, 'user');
596
  chatInput.value = '';
597
-
598
  try {
599
  await callApi(userMessage, selectedModel);
600
  } catch (error) {
@@ -602,140 +690,118 @@ input, button {
602
  console.error("API Error:", error);
603
  }
604
  }
605
-
606
  async function callApi(userMessage, model) {
607
- let fullResponse = "";
608
-
609
- if (model === "searchgpt") {
610
- const url = `https://parthsadaria-lokiai.hf.space/searchgpt?q=${encodeURIComponent(userMessage)}&stream=true&systemprompt=You are **SearchGPT**, an AI with internet access. Reply directly and accurately to user requests.`;
611
- try {
612
- const response = await fetch(url);
613
-
614
- if (response.ok) {
615
- const reader = response.body.getReader();
616
- const decoder = new TextDecoder("utf-8");
617
- let done = false;
618
-
619
- while (!done) {
620
- const { value, done: streamDone } = await reader.read();
621
- done = streamDone;
622
-
623
- if (value) {
624
- const chunk = decoder.decode(value);
625
- const cleanedChunk = chunk.trim().replace(/^data:\s*/, '');
626
- const jsonChunks = cleanedChunk.split("data:").filter(Boolean);
627
-
628
- jsonChunks.forEach(jsonString => {
629
- try {
630
- const jsonData = JSON.parse(jsonString);
631
- const content = jsonData.choices?.[0]?.message?.content || "";
632
-
633
- if (content) {
634
- // Comprehensive newline conversion
635
- const formattedContent = content
636
- .replace(/\r\n/g, '<br>') // Windows-style newlines
637
- .replace(/\n/g, '<br>') // Unix/Linux-style newlines
638
- .replace(/\r/g, '<br>'); // Old Mac-style newlines
639
-
640
- appendMessage(formattedContent, 'bot', true);
641
- }
642
- } catch (err) {
643
- console.warn("Parsing error:", err);
644
  }
645
- });
 
 
646
  }
 
 
 
647
  }
648
  } else {
649
- throw new Error(`API responded with status ${response.status}`);
650
- }
651
- } catch (error) {
652
- console.error("API call error:", error);
653
- throw error;
654
- }
655
-
656
- } else {
657
- // Similar changes for other models
658
- const url = "https://parthsadaria-lokiai.hf.space/chat/completions";
659
- const payload = {
660
- model: model,
661
- messages: [
662
- ...conversationHistory,
663
- { role: "user", content: userMessage }
664
- ],
665
- stream: true
666
- };
667
-
668
- const headers = {
669
- "Content-Type": "application/json"
670
- };
671
-
672
- try {
673
- const response = await fetch(url, {
674
- method: "POST",
675
- headers: headers,
676
- body: JSON.stringify(payload)
677
- });
678
-
679
- if (response.ok) {
680
- const reader = response.body.getReader();
681
- const decoder = new TextDecoder("utf-8");
682
- let done = false;
683
-
684
- while (!done) {
685
- const { value, done: streamDone } = await reader.read();
686
- done = streamDone;
687
-
688
- if (value) {
689
- const chunk = decoder.decode(value);
690
- const cleanedChunk = chunk.trim().replace(/^data:\s*/, '');
691
- const jsonChunks = cleanedChunk.split("data:").filter(Boolean);
692
-
693
- jsonChunks.forEach(jsonString => {
694
- try {
695
- const jsonData = JSON.parse(jsonString);
696
- const delta = jsonData.choices?.[0]?.delta || {};
697
- let content = delta.content || "";
698
-
699
- // Comprehensive newline conversion
700
- content = content
701
- .replace(/\r\n/g, '<br>') // Windows-style newlines
702
- .replace(/\n/g, '<br>') // Unix/Linux-style newlines
703
- .replace(/\r/g, '<br>'); // Old Mac-style newlines
704
-
705
- if (content) {
706
- appendMessage(content, 'bot', true);
707
- }
708
- } catch (err) {
709
- console.warn("Parsing error:", err);
710
  }
711
- });
 
 
712
  }
 
 
 
713
  }
714
- } else {
715
- throw new Error(`API responded with status ${response.status}`);
716
  }
717
- } catch (error) {
718
- console.error("API call error:", error);
719
- throw error;
720
  }
721
- }
722
-
723
- return fullResponse.trim();
724
- }
725
  // Event Listeners
726
  initialSendIcon.addEventListener('click', sendInitialMessage);
727
  initialChatInput.addEventListener('keypress', (event) => {
728
  if (event.key === 'Enter') sendInitialMessage();
729
  });
730
-
731
  sendButton.addEventListener('click', sendMessage);
732
  chatInput.addEventListener('keypress', (event) => {
733
  if (event.key === 'Enter') sendMessage();
734
  });
735
-
736
  // Clear Chat Button Event Listener
737
  clearChatButton.addEventListener('click', clearChat);
738
  </script>
739
  </body>
740
- <!-- random comments to get 800 lines -->
741
  </html>
 
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 rel="icon" type="image/x-icon" href="favicon.ico">
9
  <link
10
  href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=JetBrains+Mono:wght@300;400;500;600&display=swap"
11
  rel="stylesheet">
12
  <link href="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.13/css/select2.min.css" rel="stylesheet" />
13
  <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
14
  <script src="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.13/js/select2.min.js"></script>
15
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/animejs/3.2.1/anime.min.js"></script>
16
  <style>
17
  @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');
18
+
19
  :root {
20
  --bg-dark: #0a0a0f;
21
  --bg-darker: #040409;
 
31
  --header-height: 60px;
32
  --input-height: 80px;
33
  }
34
+
35
  * {
36
  margin: 0;
37
  padding: 0;
 
39
  scrollbar-width: thin;
40
  scrollbar-color: var(--primary-blue) transparent;
41
  }
42
+
43
  *::-webkit-scrollbar {
44
  width: 8px;
45
  }
46
+
47
  *::-webkit-scrollbar-track {
48
  background: transparent;
49
  }
50
+
51
  *::-webkit-scrollbar-thumb {
52
  background-color: var(--primary-blue);
53
  border-radius: 20px;
54
  }
55
+
56
  body {
57
  font-family: 'Inter', sans-serif;
58
  background-color: var(--bg-dark);
 
64
  overflow: hidden;
65
  perspective: 2000px;
66
  }
67
+
68
  .chat-wrapper {
69
  position: relative;
70
  width: 100%;
 
81
  transition: all 0.6s cubic-bezier(0.23, 1, 0.32, 1);
82
  border: 1px solid var(--border-color);
83
  }
84
+
85
  .chat-header {
86
  background-color: var(--bg-deepest);
87
  padding: 15px 20px;
 
92
  flex-shrink: 0;
93
  height: var(--header-height);
94
  }
95
+
96
  .chat-container {
97
  display: none;
98
  flex-direction: column;
99
  height: calc(100% - var(--header-height));
100
  position: relative;
101
  }
102
+
103
  .chat-messages {
104
  flex: 1;
105
  overflow-y: auto;
 
112
  height: calc(100% - var(--input-height));
113
  margin-bottom: var(--input-height);
114
  }
115
+
116
  .chat-input {
117
  position: absolute;
118
  bottom: 0;
 
127
  z-index: 10;
128
  align-items: center;
129
  }
130
+
131
  .chat-input-container {
132
  position: relative;
133
  flex: 1;
134
  display: flex;
135
  align-items: center;
136
  }
137
+
138
  .chat-input input {
139
  width: 100%;
140
  padding: 12px 16px;
 
148
  font-family: 'JetBrains Mono', monospace;
149
  outline: none;
150
  }
151
+
152
  .chat-input input:focus {
153
  border-color: var(--primary-blue);
154
  box-shadow: 0 0 0 3px rgba(74, 108, 247, 0.2);
155
  }
156
+
157
  .message {
158
  max-width: 80%;
159
  width: fit-content;
 
165
  animation: fadeIn 0.4s forwards;
166
  margin-bottom: 8px;
167
  }
168
+
169
  .message.user {
170
  align-self: flex-end;
171
  background-color: var(--primary-blue);
172
  color: white;
173
  }
174
+
175
  .message.bot {
176
  align-self: flex-start;
177
  background-color: rgba(40, 40, 70, 0.8);
178
  color: var(--text-light);
179
  border: 1px solid var(--border-color);
180
  }
181
+
182
  .message::before {
183
  content: '';
184
  position: absolute;
 
190
  opacity: 0;
191
  transition: opacity 0.3s ease;
192
  }
193
+
194
  .message:hover::before {
195
  opacity: 1;
196
  }
197
+
198
  .initial-input {
199
  flex: 1;
200
  display: flex;
 
205
  text-align: center;
206
  background: linear-gradient(145deg, var(--bg-dark), var(--bg-darker));
207
  }
208
+
209
  .initial-input h2 {
210
  font-size: 24px;
211
  margin-bottom: 16px;
 
213
  font-weight: 600;
214
  font-family: 'JetBrains Mono', monospace;
215
  }
216
+
217
  .input-container {
218
  width: 100%;
219
  max-width: 400px;
220
  position: relative;
221
  }
222
+
223
  .initial-input input {
224
  width: 100%;
225
  padding: 16px 24px;
 
232
  outline: none;
233
  transition: all 0.3s ease;
234
  }
235
+
236
  .send-icon {
237
  position: absolute;
238
  right: 12px;
 
248
  cursor: pointer;
249
  transition: all 0.3s ease;
250
  }
251
+
252
  .send-icon:hover {
253
  background-color: var(--accent-color);
254
  transform: translateY(-50%) scale(1.05);
255
  border-radius: 15px;
256
  }
257
+
258
  @keyframes fadeIn {
259
  from {
260
  opacity: 0;
261
  transform: translateY(20px);
262
  }
263
+
264
  to {
265
  opacity: 1;
266
  transform: translateY(0);
267
  }
268
  }
269
+
270
  /* Header actions */
271
  .header-actions {
272
  display: flex;
273
  align-items: center;
274
  gap: 10px;
275
+ justify-content: center;
276
  }
277
+
278
  .model-select {
279
  background-color: black;
280
  color: var(--text-light);
281
  border: 1px solid var(--border-color);
282
  border-radius: 8px;
283
+ padding: 8px 12px;
284
  font-family: 'JetBrains Mono', monospace;
285
+ font-size: 14px;
286
  cursor: pointer;
287
  transition: all 0.3s ease;
288
+ max-width: 150px;
289
+ overflow-y: auto;
290
+ -webkit-appearance: none;
291
+ -moz-appearance: none;
292
+ appearance: none;
293
+ background-image: url("data:image/svg+xml;charset=US-ASCII,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2214%22%20height%3D%2214%22%20viewBox%3D%220%200%2024%2024%22%20fill%3D%22none%22%20stroke%3D%22%23ffffff%22%20stroke-width%3D%222%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%3E%3Cpolyline%20points%3D%226%209%2012%2015%2018%209%22%3E%3C%2Fpolyline%3E%3C%2Fsvg%3E");
294
+ background-repeat: no-repeat;
295
+ background-position: right 8px center;
296
+ padding-right: 28px;
297
  }
298
+
299
+ .model-select option {
300
+ background-color: var(--bg-dark);
301
+ color: var(--text-light);
302
+ padding: 8px;
303
+ }
304
+
305
  .clear-chat {
306
  background-color: var(--delete-red);
307
  color: white;
308
  border: none;
309
  border-radius: 8px;
310
+ width: 36px;
311
+ height: 36px;
312
+ padding: 8px;
 
 
313
  display: flex;
314
  align-items: center;
315
+ justify-content: center;
316
+ cursor: pointer;
317
+ transition: all 0.3s ease;
318
  }
319
+
320
  .clear-chat:hover {
321
  background-color: #ff6666;
322
  }
323
+
324
+ .clear-chat svg {
325
+ width: 18px;
326
+ height: 18px;
327
+ }
328
+
329
  .watermark {
330
  position: absolute;
331
  bottom: 10px;
 
336
  transition: opacity 0.3s ease;
337
  z-index: 11;
338
  }
339
+
340
  .watermark:hover {
341
  opacity: 0.8;
342
  }
343
+
344
+ @media screen and (max-width: 768px) {
345
+ .chat-header {
346
+ padding: 8px 12px;
347
+ height: auto;
348
+ min-height: 50px;
349
+ }
350
+
351
+ .header-actions {
352
+ gap: 8px;
353
+ }
354
+
355
+ .model-select {
356
+ font-size: 12px;
357
+ padding: 6px 24px 6px 8px;
358
+ max-width: 120px;
359
+ }
360
+
361
+ .clear-chat {
362
+ width: 32px;
363
+ height: 32px;
364
+ padding: 6px;
365
+ }
366
+
367
+ .clear-chat svg {
368
+ width: 16px;
369
+ height: 16px;
370
+ }
371
+
372
+ .chat-input {
373
+ padding: 8px;
374
+ height: auto;
375
+ min-height: 60px;
376
+ }
377
+
378
+ .chat-input input {
379
+ padding: 10px 12px;
380
+ font-size: 14px;
381
+ height: 40px;
382
+ }
383
  }
384
+
385
+ @media screen and (max-width: 480px) {
386
+ .chat-header h2 {
387
+ font-size: 14px;
388
+ }
389
+
390
+ .message {
391
+ font-size: 12px;
392
+ }
393
+
394
+ .header-actions {
395
+ flex-direction: row;
396
+ gap: 6px;
397
+ }
398
+
399
+ .model-select {
400
+ max-width: 100px;
401
+ font-size: 11px;
402
+ }
403
+
404
+ .clear-chat {
405
+ width: 28px;
406
+ height: 28px;
407
+ padding: 5px;
408
+ }
409
+
410
+ .clear-chat svg {
411
+ width: 14px;
412
+ height: 14px;
413
+ }
414
+
415
+ .chat-input input {
416
+ font-size: 13px;
417
+ height: 36px;
418
+ }
419
+
420
+ .initial-input input {
421
+ font-size: 15px;
422
+ }
423
+
424
+ .initial-input h2 {
425
+ font-size: 20px;
426
+ }
427
  }
428
+
429
+ /* Additional responsive adjustments to existing CSS */
430
+ * {
431
+ -webkit-tap-highlight-color: transparent;
 
432
  }
433
+
434
+ body {
435
+ touch-action: manipulation;
436
  }
437
+
438
+ input,
439
+ button {
440
+ -webkit-appearance: none;
441
+ -moz-appearance: none;
442
+ appearance: none;
443
  }
444
+
445
+ @media (hover: hover) {
446
+ .send-icon:hover {
447
+ background-color: var(--accent-color);
448
+ transform: translateY(-50%) scale(1.05);
449
+ border-radius: 15px;
450
+ }
451
+ }
452
+
453
+ @media (pointer: coarse) {
454
+ .send-icon {
455
+ width: 45px;
456
+ height: 45px;
457
+ }
458
+
459
+ .chat-input input {
460
+ font-size: 16px;
461
+ /* Larger font for touch devices */
462
+ }
463
+ }
464
+
465
+ .model-select::-webkit-scrollbar {
466
+ width: 4px;
467
+ }
468
+
469
+ .model-select::-webkit-scrollbar-track {
470
+ background: var(--bg-dark);
471
+ }
472
+
473
+ .model-select::-webkit-scrollbar-thumb {
474
+ background-color: var(--primary-blue);
475
+ border-radius: 4px;
476
+ }
477
+
478
+ .chat-input input:focus,
479
+ .initial-input input:focus,
480
+ .model-select:focus,
481
+ .clear-chat:focus,
482
+ .send-icon:focus {
483
+ outline: 2px solid var(--primary-blue);
484
+ outline-offset: 2px;
485
+ }
486
+ .github-link {
487
+ display: flex;
488
+ align-items: center;
489
+ justify-content: center;
490
+ width: 36px;
491
+ height: 36px;
492
+ z-index: 999;
493
+ border-radius: 8px;
494
+ background-color: transparent;
495
+ border: 1px solid var(--border-color);
496
+ transition: all 0.3s ease;
497
+ color: var(--text-light);
498
+ position: absolute; /* Allows placement in the corner */
499
+ bottom: 0; /* Aligns to the top */
500
+ left: 0; /* Aligns to the left */
501
+ margin: 10px; /* Adds spacing from the edges */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
502
  }
503
+
504
+ .github-link:hover {
505
+ background-color: var(--hover-color);
506
+ transform: translateY(-2px);
 
 
507
  }
508
+
509
+ .github-link svg {
510
+ width: 22px;
511
+ height: 22px;
 
 
 
 
512
  }
513
+
514
  </style>
515
  </head>
516
 
517
  <body>
518
+ <a href="https://github.com/ParthSadaria" target="_blank" rel="noopener noreferrer" class="github-link" aria-label="Visit Parth Sadaria's GitHub profile">
519
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
520
+ <path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"></path>
521
+ </svg>
522
+ </a>
523
  <div class="chat-wrapper">
524
  <div class="chat-header">
525
  <h2 style="font-family: 'JetBrains Mono', monospace;">LOKI.AI Playground</h2>
 
528
  <option value="gpt-4o-mini">GPT-4o Mini</option>
529
  <option value="gpt-4o">GPT-4o</option>
530
  <option value="gpt-3.5-turbo">GPT-3.5 Turbo</option>
531
+ <option value="searchgpt">SearchGPT(Web-access)</option>
532
+ <option value="claude-sonnet" <option value="claude-3-haiku">Claude 3 Haiku</option>
533
  <option value="llama-3.1-8b">Llama 3.1 8B</option>
534
  <option value="llama-3.1-70b">Llama 3.1 70B</option>
535
  <option value="llama-3.1-405b">Llama 3.1 405b</option>
 
540
  <option value="command">Command</option>
541
  </select>
542
  <button id="clearChatButton" class="clear-chat">
543
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor"
544
+ stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
545
  <polyline points="3 6 5 6 21 6"></polyline>
546
  <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>
547
  <line x1="10" y1="11" x2="10" y2="17"></line>
548
  <line x1="14" y1="11" x2="14" y2="17"></line>
549
  </svg>
 
550
  </button>
551
  </div>
552
  </div>
 
588
  const sendButton = document.getElementById('sendButton');
589
  const modelSelect = document.getElementById('modelSelect');
590
  const clearChatButton = document.getElementById('clearChatButton');
 
591
  let currentStreamingMessage = null;
592
+ let isStreamingInProgress = false;
593
  let conversationHistory = [];
594
  function scrollToBottom() {
595
  const chatMessages = document.getElementById('chatMessages');
596
  chatMessages.scrollTop = chatMessages.scrollHeight;
597
  }
598
  function appendMessage(content, type = 'bot', isStreaming = false) {
599
+ if (type === 'bot' && isStreaming) {
600
+ if (!currentStreamingMessage) {
601
+ currentStreamingMessage = document.createElement('div');
602
+ currentStreamingMessage.className = `message ${type}`;
603
+ chatMessages.appendChild(currentStreamingMessage);
604
+
605
+ // Add to conversation history only at the start of streaming
606
+ if (!isStreamingInProgress) {
607
+ conversationHistory.push({
608
+ role: 'assistant',
609
+ content: ''
610
+ });
611
+ isStreamingInProgress = true;
612
+ }
613
+ }
614
+
615
+ const formattedContent = content
616
+ .replace(/(\d+)\.\s*/g, '<br>$1. ')
617
+ .replace(/\n/g, '<br>')
618
+ .replace(/\*\*(.*?)\*\*/g, (match, p1) => '<strong>' + p1 + '</strong>');
619
+
620
+ currentStreamingMessage.innerHTML += formattedContent;
621
+
622
+ // Update the last message in conversation history
623
+ if (conversationHistory.length > 0) {
624
+ conversationHistory[conversationHistory.length - 1].content += content;
625
+ }
626
+
627
+ chatMessages.scrollTop = chatMessages.scrollHeight;
628
+ } else {
629
+ if (currentStreamingMessage) {
630
+ isStreamingInProgress = false;
631
+ currentStreamingMessage = null;
632
+ }
633
+
634
+ const messageBox = document.createElement('div');
635
+ messageBox.className = `message ${type}`;
636
+
637
+ const formattedContent = content
638
+ .replace(/(\d+)\.\s*/g, '<br>$1. ')
639
+ .replace(/\n/g, '<br>')
640
+ .replace(/\*\*(.*?)\*\*/g, (match, p1) => '<strong>' + p1 + '</strong>');
641
+
642
+ messageBox.innerHTML = formattedContent;
643
+ chatMessages.appendChild(messageBox);
644
+
645
+ // Add to conversation history only for new messages
646
+ if (type === 'user') {
647
+ conversationHistory.push({
648
+ role: 'user',
649
+ content: content
650
+ });
651
+ }
652
+
653
+ chatMessages.scrollTop = chatMessages.scrollHeight;
654
+ }
655
+ }
656
  function clearChat() {
657
  chatMessages.innerHTML = '';
658
  conversationHistory = [];
 
660
  chatContainer.style.display = 'none';
661
  chatWrapper.classList.remove('active');
662
  }
 
663
  async function sendInitialMessage() {
664
  const userMessage = initialChatInput.value.trim();
665
  const selectedModel = modelSelect.value;
666
  if (!userMessage) return;
 
667
  initialInput.style.display = 'none';
668
  chatContainer.style.display = 'flex';
669
  chatWrapper.classList.add('active');
 
670
  appendMessage(userMessage, 'user');
671
  initialChatInput.value = '';
672
  scrollToBottom();
 
677
  console.error("API Error:", error);
678
  }
679
  }
 
680
  async function sendMessage() {
681
  const userMessage = chatInput.value.trim();
682
  const selectedModel = modelSelect.value;
683
  if (!userMessage) return;
 
684
  appendMessage(userMessage, 'user');
685
  chatInput.value = '';
 
686
  try {
687
  await callApi(userMessage, selectedModel);
688
  } catch (error) {
 
690
  console.error("API Error:", error);
691
  }
692
  }
 
693
  async function callApi(userMessage, model) {
694
+ let fullResponse = "";
695
+ if (model === "searchgpt") {
696
+ const url = `https://parthsadaria-lokiai.hf.space/searchgpt?q=${encodeURIComponent(userMessage)}&stream=true&systemprompt=You are **SearchGPT**, an AI with internet access. Reply directly and accurately to user requests.`;
697
+ try {
698
+ const response = await fetch(url);
699
+ if (response.ok) {
700
+ const reader = response.body.getReader();
701
+ const decoder = new TextDecoder("utf-8");
702
+ let done = false;
703
+ while (!done) {
704
+ const { value, done: streamDone } = await reader.read();
705
+ done = streamDone;
706
+ if (value) {
707
+ const chunk = decoder.decode(value);
708
+ const cleanedChunk = chunk.trim().replace(/^data:\s*/, '');
709
+ const jsonChunks = cleanedChunk.split("data:").filter(Boolean);
710
+ jsonChunks.forEach(jsonString => {
711
+ try {
712
+ const jsonData = JSON.parse(jsonString);
713
+ const content = jsonData.choices?.[0]?.message?.content || "";
714
+ if (content) {
715
+ // Comprehensive newline conversion
716
+ const formattedContent = content
717
+ .replace(/\r\n/g, '<br>') // Windows-style newlines
718
+ .replace(/\n/g, '<br>') // Unix/Linux-style newlines
719
+ .replace(/\r/g, '<br>'); // Old Mac-style newlines
720
+ appendMessage(formattedContent, 'bot', true);
721
+ }
722
+ } catch (err) {
723
+ console.warn("Parsing error:", err);
724
+ }
725
+ });
 
 
 
 
 
726
  }
727
+ }
728
+ } else {
729
+ throw new Error(`API responded with status ${response.status}`);
730
  }
731
+ } catch (error) {
732
+ console.error("API call error:", error);
733
+ throw error;
734
  }
735
  } else {
736
+ const url = "https://parthsadaria-lokiai.hf.space/chat/completions";
737
+ const payload = {
738
+ model: model,
739
+ messages: [
740
+ ...conversationHistory
741
+ ],
742
+ stream: true
743
+ };
744
+ const headers = {
745
+ "Content-Type": "application/json"
746
+ };
747
+ try {
748
+ const response = await fetch(url, {
749
+ method: "POST",
750
+ headers: headers,
751
+ body: JSON.stringify(payload)
752
+ });
753
+ if (response.ok) {
754
+ const reader = response.body.getReader();
755
+ const decoder = new TextDecoder("utf-8");
756
+ let done = false;
757
+ while (!done) {
758
+ const { value, done: streamDone } = await reader.read();
759
+ done = streamDone;
760
+ if (value) {
761
+ const chunk = decoder.decode(value);
762
+ const cleanedChunk = chunk.trim().replace(/^data:\s*/, '');
763
+ const jsonChunks = cleanedChunk.split("data:").filter(Boolean);
764
+ jsonChunks.forEach(jsonString => {
765
+ try {
766
+ const jsonData = JSON.parse(jsonString);
767
+ const delta = jsonData.choices?.[0]?.delta || {};
768
+ let content = delta.content || "";
769
+
770
+ // Comprehensive newline conversion
771
+ content = content
772
+ .replace(/\r\n/g, '<br>') // Windows-style newlines
773
+ .replace(/\n/g, '<br>') // Unix/Linux-style newlines
774
+ .replace(/\r/g, '<br>'); // Old Mac-style newlines
775
+ if (content) {
776
+ appendMessage(content, 'bot', true);
777
+ }
778
+ } catch (err) {
779
+ console.warn("Parsing error:", err);
780
+ }
781
+ });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
782
  }
783
+ }
784
+ } else {
785
+ throw new Error(`API responded with status ${response.status}`);
786
  }
787
+ } catch (error) {
788
+ console.error("API call error:", error);
789
+ throw error;
790
  }
 
 
791
  }
792
+ return fullResponse.trim();
 
 
793
  }
 
 
 
 
794
  // Event Listeners
795
  initialSendIcon.addEventListener('click', sendInitialMessage);
796
  initialChatInput.addEventListener('keypress', (event) => {
797
  if (event.key === 'Enter') sendInitialMessage();
798
  });
 
799
  sendButton.addEventListener('click', sendMessage);
800
  chatInput.addEventListener('keypress', (event) => {
801
  if (event.key === 'Enter') sendMessage();
802
  });
 
803
  // Clear Chat Button Event Listener
804
  clearChatButton.addEventListener('click', clearChat);
805
  </script>
806
  </body>
 
807
  </html>