Spaces:
Running
Running
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>Loki.AI Playground</title> | |
<link rel="icon" type="image/x-icon" href="favicon.ico"> | |
<link | |
href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=JetBrains+Mono:wght@300;400;500;600&display=swap" | |
rel="stylesheet"> | |
<link href="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.13/css/select2.min.css" rel="stylesheet" /> | |
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.13/js/select2.min.js"></script> | |
<style> | |
@import url('https://fonts.googleapis.com/css2?family=Encode+Sans:wght@100..900&family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&family=Protest+Revolution&display=swap'); | |
:root { | |
--bg-dark: #0a0a0f; | |
--bg-darker: #040409; | |
--bg-deepest: #020205; | |
--primary-blue: #4a6cf7; | |
--secondary-blue: #6678e3; | |
--accent-color: #7e57c2; | |
--text-light: #e0e0e8; | |
--text-muted: #8a8a9b; | |
--border-color: #1a1a2e; | |
--hover-color: rgba(78, 108, 247, 0.1); | |
--delete-red: #ff4d4d; | |
--header-height: 60px; | |
--input-height: 80px; | |
} | |
* { | |
margin: 0; | |
padding: 0; | |
box-sizing: border-box; | |
scrollbar-width: thin; | |
scrollbar-color: var(--primary-blue) transparent; | |
} | |
*::-webkit-scrollbar { | |
width: 8px; | |
} | |
*::-webkit-scrollbar-track { | |
background: transparent; | |
} | |
*::-webkit-scrollbar-thumb { | |
background-color: var(--primary-blue); | |
border-radius: 20px; | |
} | |
body { | |
font-family: 'Inter', sans-serif; | |
background-color: var(--bg-dark); | |
color: var(--text-light); | |
display: flex; | |
justify-content: center; | |
align-items: center; | |
height: 100vh; | |
overflow: hidden; | |
perspective: 2000px; | |
} | |
.chat-wrapper { | |
position: relative; | |
width: 100%; | |
max-width: 800px; | |
height: 90vh; | |
background-color: var(--bg-darker); | |
border-radius: 24px; | |
overflow: hidden; | |
box-shadow: 0 20px 50px rgba(5, 5, 10, 0.7); | |
display: flex; | |
flex-direction: column; | |
opacity: 1; | |
transform: scale(1); | |
transition: all 0.6s cubic-bezier(0.23, 1, 0.32, 1); | |
border: 1px solid var(--border-color); | |
} | |
.chat-header { | |
background-color: var(--bg-deepest); | |
padding: 15px 20px; | |
display: flex; | |
justify-content: space-between; | |
align-items: center; | |
border-bottom: 1px solid var(--border-color); | |
flex-shrink: 0; | |
height: var(--header-height); | |
} | |
.chat-container { | |
display: none; | |
flex-direction: column; | |
height: calc(100% - var(--header-height)); | |
position: relative; | |
} | |
.chat-messages { | |
flex: 1; | |
overflow-y: auto; | |
padding: 20px; | |
display: flex; | |
flex-direction: column; | |
gap: 16px; | |
background-color: var(--bg-dark); | |
font-family: 'JetBrains Mono', monospace; | |
height: calc(100% - var(--input-height)); | |
margin-bottom: var(--input-height); | |
} | |
.chat-input { | |
position: absolute; | |
bottom: 0; | |
left: 0; | |
right: 0; | |
background-color: var(--bg-darker); | |
border-top: 1px solid var(--border-color); | |
padding: 16px; | |
height: var(--input-height); | |
display: flex; | |
gap: 12px; | |
z-index: 10; | |
align-items: center; | |
} | |
.chat-input-container { | |
position: relative; | |
flex: 1; | |
display: flex; | |
align-items: center; | |
} | |
.chat-input input { | |
width: 100%; | |
padding: 12px 16px; | |
padding-right: 50px; | |
/* Space for send icon */ | |
background-color: rgba(30, 30, 50, 0.8); | |
border: 1px solid var(--border-color); | |
border-radius: 12px; | |
color: var(--text-light); | |
font-size: 14px; | |
font-family: 'JetBrains Mono', monospace; | |
outline: none; | |
} | |
.chat-input input:focus { | |
border-color: var(--primary-blue); | |
box-shadow: 0 0 0 3px rgba(74, 108, 247, 0.2); | |
} | |
.message { | |
max-width: 80%; | |
width: fit-content; | |
padding: 12px 18px; | |
border-radius: 12px; | |
font-size: 14px; | |
line-height: 1.5; | |
position: relative; | |
animation: fadeIn 0.4s forwards; | |
margin-bottom: 8px; | |
} | |
.message.user { | |
align-self: flex-end; | |
background-color: var(--primary-blue); | |
color: white; | |
} | |
.message.bot { | |
align-self: flex-start; | |
background-color: rgba(40, 40, 70, 0.8); | |
color: var(--text-light); | |
border: 1px solid var(--border-color); | |
} | |
.message::before { | |
content: ''; | |
position: absolute; | |
top: 0; | |
left: 0; | |
right: 0; | |
bottom: 0; | |
background: linear-gradient(to right, transparent, rgba(255, 255, 255, 0.1)); | |
opacity: 0; | |
transition: opacity 0.3s ease; | |
} | |
.message:hover::before { | |
opacity: 1; | |
} | |
.initial-input { | |
flex: 1; | |
display: flex; | |
flex-direction: column; | |
justify-content: center; | |
align-items: center; | |
padding: 24px; | |
text-align: center; | |
background: linear-gradient(145deg, var(--bg-dark), var(--bg-darker)); | |
} | |
.initial-input h2 { | |
font-size: 24px; | |
margin-bottom: 16px; | |
color: var(--text-light); | |
font-weight: 600; | |
font-family: 'JetBrains Mono', monospace; | |
} | |
.input-container { | |
width: 100%; | |
max-width: 400px; | |
position: relative; | |
} | |
.initial-input input { | |
width: 100%; | |
padding: 16px 24px; | |
background-color: rgba(30, 30, 50, 0.8); | |
border: 1px solid var(--border-color); | |
border-radius: 12px; | |
color: var(--text-light); | |
font-size: 16px; | |
font-family: 'JetBrains Mono', monospace; | |
outline: none; | |
transition: all 0.3s ease; | |
} | |
.send-icon { | |
position: absolute; | |
right: 12px; | |
top: 50%; | |
transform: translateY(-50%); | |
background-color: var(--primary-blue); | |
border-radius: 8px; | |
width: 40px; | |
height: 40px; | |
display: flex; | |
justify-content: center; | |
align-items: center; | |
cursor: pointer; | |
transition: all 0.3s ease; | |
} | |
.send-icon:hover { | |
background-color: var(--accent-color); | |
transform: translateY(-50%) scale(1.05); | |
border-radius: 15px; | |
} | |
@keyframes fadeIn { | |
from { | |
opacity: 0; | |
transform: translateY(20px); | |
} | |
to { | |
opacity: 1; | |
transform: translateY(0); | |
} | |
} | |
/* Header actions */ | |
.header-actions { | |
display: flex; | |
align-items: center; | |
gap: 10px; | |
} | |
.model-select { | |
background-color: black; | |
color: var(--text-light); | |
border: 1px solid var(--border-color); | |
border-radius: 8px; | |
padding: 10px 14px; | |
font-family: 'JetBrains Mono', monospace; | |
font-size: 14px; | |
cursor: pointer; | |
transition: all 0.3s ease; | |
} | |
.clear-chat { | |
background-color: var(--delete-red); | |
color: white; | |
border: none; | |
border-radius: 8px; | |
padding: 10px 14px; | |
font-family: 'JetBrains Mono', monospace; | |
font-size: 14px; | |
cursor: pointer; | |
transition: all 0.3s ease; | |
display: flex; | |
align-items: center; | |
gap: 5px; | |
} | |
.clear-chat:hover { | |
background-color: #ff6666; | |
} | |
.watermark { | |
position: absolute; | |
bottom: 10px; | |
right: 15px; | |
color: var(--text-muted); | |
font-size: 10px; | |
opacity: 0.5; | |
transition: opacity 0.3s ease; | |
z-index: 11; | |
} | |
.watermark:hover { | |
opacity: 0.8; | |
} | |
/* Select2 customization */ | |
.select2-container--default .select2-selection--single { | |
background-color: #333; | |
color: white; | |
border: 1px solid #555; | |
font-size: 14px; | |
} | |
.select2-container--default .select2-selection--single .select2-selection__rendered { | |
background-color: #333; | |
color: white; | |
} | |
.select2-dropdown { | |
background-color: #333; | |
color: white; | |
max-height: 300px; | |
overflow-y: auto; | |
} | |
.select2-container--default .select2-results__option { | |
background-color: #333; | |
color: white; | |
} | |
.select2-container--default .select2-results__option--highlighted { | |
background-color: #555; | |
color: white; | |
} | |
</style> | |
</head> | |
<body> | |
<div class="chat-wrapper"> | |
<div class="chat-header"> | |
<h2 style="font-family: 'JetBrains Mono', monospace;">LOKI.AI Playground</h2> | |
<div class="header-actions"> | |
<select id="modelSelect" class="model-select"> | |
<option value="gpt-4o-mini">GPT-4o Mini</option> | |
<option value="gpt-4o">GPT-4o</option> | |
<option value="gpt-3.5-turbo">GPT-3.5 Turbo</option> | |
<option value="claude-3-haiku">Claude 3 Haiku</option> | |
<option value="llama-3.1-8b">Llama 3.1 8B</option> | |
<option value="llama-3.1-70b">Llama 3.1 70B</option> | |
<option value="llama-3.1-405b">Llama 3.1 405b</option> | |
<option value="gemini-1.5-flash">Gemini 1.5 Flash</option> | |
<option value="gemini-pro">Gemini Pro</option> | |
<option value="searchgpt">SearchGPT(Realtime Stuff)</option> | |
<option value="mixtral-8x7b">Mixtral 8x7b</option> | |
<option value="command-r">Command-R</option> | |
<option value="command">Command</option> | |
</select> | |
<button id="clearChatButton" class="clear-chat"> | |
<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"> | |
<polyline points="3 6 5 6 21 6"></polyline> | |
<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> | |
<line x1="10" y1="11" x2="10" y2="17"></line> | |
<line x1="14" y1="11" x2="14" y2="17"></line> | |
</svg> | |
Clear | |
</button> | |
</div> | |
</div> | |
<div class="initial-input"> | |
<h2>Welcome to LOKI.AI</h2> | |
<div class="input-container"> | |
<input type="text" id="initialChatInput" placeholder="What can I help you with today?"> | |
<div class="send-icon" id="initialSendIcon"> | |
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" | |
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> | |
<line x1="22" y1="2" x2="11" y2="13"></line> | |
<polygon points="22 2 15 22 11 13 2 9 22 2"></polygon> | |
</svg> | |
</div> | |
</div> | |
</div> | |
<div class="chat-container" id="chatContainer"> | |
<div class="chat-messages" id="chatMessages"></div> | |
<div class="chat-input"> | |
<input type="text" id="chatInput" placeholder="Type your message..."> | |
<button id="sendButton" | |
style="padding: 10px 10px; background-color: black;color: #e0e0e8; font-family: 'JetBrains Mono'; border: solid #1a1a2e 2px; border-radius: 15px;">Send</button> | |
</div> | |
</div> | |
</div> | |
<div class="watermark"> | |
Made with ❤️ by Parth Sadaria | |
</div> | |
<script> | |
const chatWrapper = document.querySelector('.chat-wrapper'); | |
const initialInput = document.querySelector('.initial-input'); | |
const chatContainer = document.getElementById('chatContainer'); | |
const initialChatInput = document.getElementById('initialChatInput'); | |
const initialSendIcon = document.getElementById('initialSendIcon'); | |
const chatMessages = document.getElementById('chatMessages'); | |
const chatInput = document.getElementById('chatInput'); | |
const sendButton = document.getElementById('sendButton'); | |
const modelSelect = document.getElementById('modelSelect'); | |
const clearChatButton = document.getElementById('clearChatButton'); | |
let currentStreamingMessage = null; | |
let conversationHistory = []; | |
function scrollToBottom() { | |
const chatMessages = document.getElementById('chatMessages'); | |
chatMessages.scrollTop = chatMessages.scrollHeight; | |
} | |
function appendMessage(content, type = 'bot', isStreaming = false) { | |
if (type === 'bot' && isStreaming) { | |
if (!currentStreamingMessage) { | |
currentStreamingMessage = document.createElement('div'); | |
currentStreamingMessage.className = `message ${type}`; | |
chatMessages.appendChild(currentStreamingMessage); | |
} | |
// Replace consecutive numbers followed by spaces with numbered list format | |
// Convert text between ** to bold, handling multiple occurrences | |
const formattedContent = content | |
.replace(/(\d+)\.\s*/g, '<br>$1. ') // Ensure proper spacing and line breaks | |
.replace(/\n/g, '<br>') // Convert remaining newlines | |
.replace(/\*\*(.*?)\*\*/g, function(match, p1) { | |
return '<strong>' + p1 + '</strong>'; | |
}); | |
// Safely set innerHTML | |
currentStreamingMessage.innerHTML += formattedContent; | |
chatMessages.scrollTop = chatMessages.scrollHeight; | |
} else { | |
// Similar logic for non-streaming messages | |
if (currentStreamingMessage) { | |
currentStreamingMessage = null; | |
} | |
const messageBox = document.createElement('div'); | |
messageBox.className = `message ${type}`; | |
// Format content similarly | |
const formattedContent = content | |
.replace(/(\d+)\.\s*/g, '<br>$1. ') | |
.replace(/\n/g, '<br>') | |
.replace(/\*\*(.*?)\*\*/g, function(match, p1) { | |
return '<strong>' + p1 + '</strong>'; | |
}); | |
messageBox.innerHTML = formattedContent; | |
chatMessages.appendChild(messageBox); | |
chatMessages.scrollTop = chatMessages.scrollHeight; | |
// Update conversation history | |
conversationHistory.push({ | |
role: type === 'user' ? 'user' : 'assistant', | |
content: content | |
}); | |
} | |
} | |
$(document).ready(function () { | |
$('#modelSelect').select2({ | |
placeholder: 'Select a model', // Placeholder text | |
minimumResultsForSearch: 1 // Show search when there is at least 1 item | |
}); | |
}); | |
function clearChat() { | |
chatMessages.innerHTML = ''; | |
conversationHistory = []; | |
initialInput.style.display = 'flex'; | |
chatContainer.style.display = 'none'; | |
chatWrapper.classList.remove('active'); | |
} | |
async function sendInitialMessage() { | |
const userMessage = initialChatInput.value.trim(); | |
const selectedModel = modelSelect.value; | |
if (!userMessage) return; | |
initialInput.style.display = 'none'; | |
chatContainer.style.display = 'flex'; | |
chatWrapper.classList.add('active'); | |
appendMessage(userMessage, 'user'); | |
initialChatInput.value = ''; | |
scrollToBottom(); | |
try { | |
await callApi(userMessage, selectedModel); | |
} catch (error) { | |
appendMessage("Oops! Something went wrong.", 'bot'); | |
console.error("API Error:", error); | |
} | |
} | |
async function sendMessage() { | |
const userMessage = chatInput.value.trim(); | |
const selectedModel = modelSelect.value; | |
if (!userMessage) return; | |
appendMessage(userMessage, 'user'); | |
chatInput.value = ''; | |
try { | |
await callApi(userMessage, selectedModel); | |
} catch (error) { | |
appendMessage("Oops! Something went wrong.", 'bot'); | |
console.error("API Error:", error); | |
} | |
} | |
async function callApi(userMessage, model) { | |
let fullResponse = ""; | |
if (model === "searchgpt") { | |
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.`; | |
try { | |
const response = await fetch(url); | |
if (response.ok) { | |
const reader = response.body.getReader(); | |
const decoder = new TextDecoder("utf-8"); | |
let done = false; | |
while (!done) { | |
const { value, done: streamDone } = await reader.read(); | |
done = streamDone; | |
if (value) { | |
const chunk = decoder.decode(value); | |
const cleanedChunk = chunk.trim().replace(/^data:\s*/, ''); | |
const jsonChunks = cleanedChunk.split("data:").filter(Boolean); | |
jsonChunks.forEach(jsonString => { | |
try { | |
const jsonData = JSON.parse(jsonString); | |
const content = jsonData.choices?.[0]?.message?.content || ""; | |
if (content) { | |
// Comprehensive newline conversion | |
const formattedContent = content | |
.replace(/\r\n/g, '<br>') // Windows-style newlines | |
.replace(/\n/g, '<br>') // Unix/Linux-style newlines | |
.replace(/\r/g, '<br>'); // Old Mac-style newlines | |
appendMessage(formattedContent, 'bot', true); | |
} | |
} catch (err) { | |
console.warn("Parsing error:", err); | |
} | |
}); | |
} | |
} | |
} else { | |
throw new Error(`API responded with status ${response.status}`); | |
} | |
} catch (error) { | |
console.error("API call error:", error); | |
throw error; | |
} | |
} else { | |
// Similar changes for other models | |
const url = "https://parthsadaria-lokiai.hf.space/chat/completions"; | |
const payload = { | |
model: model, | |
messages: [ | |
...conversationHistory, | |
{ role: "user", content: userMessage } | |
], | |
stream: true | |
}; | |
const headers = { | |
"Content-Type": "application/json" | |
}; | |
try { | |
const response = await fetch(url, { | |
method: "POST", | |
headers: headers, | |
body: JSON.stringify(payload) | |
}); | |
if (response.ok) { | |
const reader = response.body.getReader(); | |
const decoder = new TextDecoder("utf-8"); | |
let done = false; | |
while (!done) { | |
const { value, done: streamDone } = await reader.read(); | |
done = streamDone; | |
if (value) { | |
const chunk = decoder.decode(value); | |
const cleanedChunk = chunk.trim().replace(/^data:\s*/, ''); | |
const jsonChunks = cleanedChunk.split("data:").filter(Boolean); | |
jsonChunks.forEach(jsonString => { | |
try { | |
const jsonData = JSON.parse(jsonString); | |
const delta = jsonData.choices?.[0]?.delta || {}; | |
let content = delta.content || ""; | |
// Comprehensive newline conversion | |
content = content | |
.replace(/\r\n/g, '<br>') // Windows-style newlines | |
.replace(/\n/g, '<br>') // Unix/Linux-style newlines | |
.replace(/\r/g, '<br>'); // Old Mac-style newlines | |
if (content) { | |
appendMessage(content, 'bot', true); | |
} | |
} catch (err) { | |
console.warn("Parsing error:", err); | |
} | |
}); | |
} | |
} | |
} else { | |
throw new Error(`API responded with status ${response.status}`); | |
} | |
} catch (error) { | |
console.error("API call error:", error); | |
throw error; | |
} | |
} | |
return fullResponse.trim(); | |
} | |
// Event Listeners | |
initialSendIcon.addEventListener('click', sendInitialMessage); | |
initialChatInput.addEventListener('keypress', (event) => { | |
if (event.key === 'Enter') sendInitialMessage(); | |
}); | |
sendButton.addEventListener('click', sendMessage); | |
chatInput.addEventListener('keypress', (event) => { | |
if (event.key === 'Enter') sendMessage(); | |
}); | |
// Clear Chat Button Event Listener | |
clearChatButton.addEventListener('click', clearChat); | |
</script> | |
</body> | |
<!-- random | |
comments | |
to get | |
669 lines --> | |
</html> |