FourLabs-UN2's picture
Faça o background do modal de gerar código ser dessa cor apenas:
7c56d19 verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Mr. Mxyzptlk - Converse com um Modelo | Fourlabs</title>
<script src="https://cdn.tailwindcss.com"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<link rel="icon" type="image/x-icon" href="/static/imgs/icon.svg">
<link rel="stylesheet" href="/static/style/dashboard.css">
<link rel="stylesheet" type="text/css" href="/static/style/alert.css">
<script src="https://unpkg.com/feather-icons"></script>
<script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vanta@latest/dist/vanta.net.min.js"></script>
<script>
tailwind.config = {
theme: {
extend: {
colors: {
primary: '#21223a',
secondary: '#ff580f',
}
}
}
}
</script>
</head>
<body class="bg-gray-100">
<div id="alert-container" style="position: fixed; top: 80px; right: 20px; z-index: 1000; width: 100%; max-width: 500px;"></div>
<div class="flex h-screen overflow-hidden">
<!-- Sidebar -->
<div class="sidebar bg-primary text-white w-64 md:w-20 lg:w-64 fixed h-full overflow-y-auto">
<div class="p-4 border-b border-gray-700">
<div class="w-full flex flex-col items-center justify-center">
<img
alt="logo"
loading="lazy"
width="100"
height="100"
decoding="async"
data-nimg="1"
class="w-36"
src="/static/imgs/logo-branco-labs.svg"
style="color: transparent;margin-top: 8px;"
>
<p
class="text-[10px] text-white mt-2 text-center"
style="margin-top: -1px; margin-left: 12px;font-size: 9px;">
Inovação e experimentação
</p>
</div>
</div>
<div class="p-4">
<div class="flex items-center space-x-3 mb-6">
<div class="w-10 h-10 rounded-full bg-secondary flex items-center justify-center">
<span class="font-bold">MS</span>
</div>
<div class="lg:block hidden">
<h3 class="font-semibold">Marlon Sousa</h3>
<p class="text-xs text-gray-400">Admin</p>
</div>
</div>
<nav>
<ul class="space-y-2">
<li>
<a href="/"
class="sidebar-item flex items-center p-3 rounded-lg
active">
<i class="fa-solid fa-server text-secondary w-6 text-center"></i>
<span class="ml-3 lg:block hidden">Instances</span>
</a>
</li>
<li>
<a href=""
class="sidebar-item flex items-center p-3 rounded-lg
">
<i class="fa-solid fa-cubes text-secondary w-6 text-center"></i>
<span class="ml-3 lg:block hidden">Moxe</span>
</a>
</li>
<li>
<a href="/"
class="sidebar-item flex items-center p-3 rounded-lg
">
<i class="fa-solid fa-robot text-secondary w-5 h-5 mr-3"></i>
<span class="ml-3 lg:block hidden">Agentes</span>
</a>
</li>
<li>
<a href="/"
class="sidebar-item flex items-center p-3 rounded-lg
">
<i class="fa-solid fa-diagram-project text-secondary w-5 h-5 mr-3"></i>
<span class="ml-3 lg:block hidden">Projetos</span>
</a>
</li>
<li>
<a href="/"
class="sidebar-item flex items-center p-3 rounded-lg
">
<i data-feather="activity" class="text-secondary w-5 h-5 mr-3"></i>
<span class="ml-3 lg:block hidden">Atividade</span>
</a>
</li>
<li>
<a href="/settings/"
class="sidebar-item flex items-center p-3 rounded-lg
">
<i class="fa-solid fa-screwdriver-wrench text-secondary w-6 text-center"></i>
<span class="ml-3 lg:block hidden">Configurações</span>
</a>
</li>
</ul>
</nav>
</div>
<div class="absolute bottom-0 w-full p-4 border-t border-gray-700">
<form id="logout-form" method="POST" action="/account/logout/" class="hidden">
<input type="hidden" name="csrfmiddlewaretoken" value="MnYe4YaLuTb5AZgEnVFzWrZPFMBdPA80wkFGxjael4hIsejNxadyoK7h2ziCbTe5">
</form>
<a href="#" onclick="document.getElementById('logout-form').submit(); return false;" class="sidebar-item flex items-center p-3 rounded-lg">
<i class="fas fa-sign-out-alt text-secondary w-6 text-center"></i>
<span class="ml-3 lg:block hidden">Logout</span>
</a>
</div>
</div>
<!-- Main Content -->
<div class="flex-1 ml-0 md:ml-20 lg:ml-64 overflow-y-auto">
<!-- Top Navigation -->
<header class="bg-white shadow-sm">
<div class="flex items-center justify-between p-4">
<div class="flex items-center space-x-4">
<button id="mobileToggleSidebar" class="text-gray-600 lg:hidden block">
<i class="fas fa-bars text-xl"></i>
</button>
<h1 class="text-xl font-bold text-primary">Converse com um Modelo</h1>
</div>
<div class="flex items-center space-x-4">
<a href="/launch/" class="inline-flex items-center px-4 py-2 border border-transparent text-sm font-medium rounded-md shadow-sm text-white bg-primary hover:bg-primary-600 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary-500">
<i data-feather="plus" class="mr-2 w-4 h-4"></i>
Subir Instância
</a>
<div class="relative">
<button id="notificationsBtn" class="relative">
<i class="fas fa-bell text-xl text-gray-600"></i>
<span class="absolute -top-1 -right-1 bg-secondary text-white text-xs rounded-full h-4 w-4 flex items-center justify-center">0</span>
</button>
<div id="notificationsDropdown" class="hidden absolute right-0 mt-2 w-80 bg-white rounded-md shadow-lg overflow-hidden z-50">
<div class="py-1">
<div class="px-4 py-2 border-b border-gray-200">
<h3 class="text-sm font-medium text-gray-700">Notifications</h3>
</div>
</div>
<div class="px-4 py-2 bg-gray-50 text-center">
<a href="#" class="text-sm font-medium text-secondary hover:text-primary">View all notifications</a>
</div>
</div>
</div>
</div>
</div>
</header>
<!-- Dashboard Content -->
<style>
:root {
--primary: #21223a;
--secondary: #ff580f;
}
.chat-container {
scroll-behavior: smooth;
height: calc(100% - 28%);
overflow-y: auto;
}
.message-bubble {
max-width: 80%;
animation: fadeIn 0.3s ease-in;
}
.typing-indicator {
display: inline-flex;
align-items: center;
gap: 4px;
}
.typing-dot {
width: 6px;
height: 6px;
background-color: var(--secondary);
border-radius: 50%;
animation: typing 1.4s infinite ease-in-out;
}
.typing-dot:nth-child(2) { animation-delay: 0.16s; }
.typing-dot:nth-child(3) { animation-delay: 0.32s; }
@keyframes typing {
0%, 60%, 100% { transform: translateY(0); opacity: 0.4; }
30% { transform: translateY(-10px); opacity: 1; }
}
@keyframes fadeIn {
from { opacity: 0; transform: translateY(10px); }
to { opacity: 1; transform: translateY(0); }
}
.llm-option:hover {
transform: translateY(-2px);
box-shadow: 0 8px 25px rgba(33, 34, 58, 0.15);
}
</style>
<div class="bg-gray-50 border-b border-gray-200 p-3">
<div class="flex items-center justify-between">
<div class="flex items-center space-x-3">
<span class="text-sm text-gray-600">Modelo:</span>
<select class="w-full px-4 py-3 border border-gray-200 rounded-xl" name="model" id="modelSelect">
<option value="2c387c0e-838d-4c68-8257-296cf0b68469" selected>
granite-code:8b
</option>
<option value="5fef64b9-ac1d-4461-a9e9-148582e780f0" >
deepseek-r1:7b
</option>
<option value="95d05e19-6063-4fa2-804a-c551e37358b5" >
deepseek-r1:1.5b
</option>
<option value="0b685e78-a520-4d3a-8adc-f3f3305d4162" >
llama3.2:3b
</option>
</select>
</div>
<div class="flex items-center space-x-2">
<button
id="uploadPdfBtn"
class="inline-flex items-center px-4 py-2 border border-gray-300 text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-[#ff580f]"
>
<i data-feather="upload" class="mr-2 w-4 h-4"></i>
Enviar PDF
</button>
<button
id="generateCodeBtn"
class="inline-flex items-center px-4 py-2 border border-gray-300 text-sm font-medium
rounded-md text-white bg-secondary focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-[#ff580f]"
>
<i data-feather="code" class="mr-2 w-4 h-4"></i>
Gerar Código
</button>
</div>
</div>
</div>
<!-- Chat Messages -->
<div class="flex-1 p-6 space-y-6 chat-container overflow-y-auto" id="chatMessages">
</div>
<!-- Input Area -->
<div class="bg-white border-t border-gray-200 p-6">
<div class="flex items-center space-x-4">
<div class="flex-1 relative">
<input
type="text"
placeholder="Digite sua mensagem..."
class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-[#ff580f] focus:border-transparent"
id="messageInput"
>
<div class="absolute right-3 top-3 flex items-center space-x-2">
<button class="text-gray-400 hover:text-[#ff580f] transition-colors">
<i data-feather="paperclip"></i>
</button>
<button class="text-gray-400 hover:text-[#ff580f] transition-colors">
<i data-feather="mic"></i>
</button>
</div>
</div>
<button
class="bg-[#ff580f] hover:bg-[#e64a0c] text-white p-3 rounded-lg transition-colors duration-200"
onclick="sendMessage()"
>
<i data-feather="send"></i>
</button>
</div>
<div class="mt-3 flex items-center justify-end">
<span class="text-sm text-gray-500">⌘K para atalhos</span>
</div>
</div>
<div id="pdfUploadModal" class="hidden fixed inset-0 bg-gray-600 bg-opacity-50 overflow-y-auto h-full w-full z-50">
<div class="relative top-20 mx-auto p-5 border max-w-3xl shadow-lg rounded-md bg-white">
<div class="mt-3 text-center">
<div class="mx-auto flex items-center justify-center h-12 w-12 rounded-full bg-[#ff580f]">
<i data-feather="file-text" class="text-white"></i>
</div>
<h3 class="text-lg leading-6 font-medium text-gray-900 mt-2">
Enviar PDF
</h3>
<div class="mt-2 px-7 py-3">
<p class="text-sm text-gray-500">
Selecione um arquivo PDF para enviar e processar.
</p>
<form class="mt-4">
<div class="flex items-center justify-center w-full">
<label for="pdfFile" class="flex flex-col items-center justify-center w-full h-32 border-2 border-gray-300 border-dashed rounded-lg cursor-pointer bg-gray-50 hover:bg-gray-100">
<div class="flex flex-col items-center justify-center pt-5 pb-6">
<i data-feather="upload-cloud" class="w-8 h-8 text-gray-400"></i>
<p class="mb-2 text-sm text-gray-500"><span class="font-semibold">Clique para enviar</span> ou arraste e solte</p>
<p class="text-xs text-gray-500">PDF (MAX. 10MB)</p>
</div>
<input id="pdfFile" name="pdfFile" type="file" class="hidden" accept=".pdf">
</label>
</div>
</form>
<div class="items-center px-4 py-3 mt-4">
<button
id="uploadSubmitBtn"
class="px-4 py-2 bg-[#ff580f] text-white text-base font-medium rounded-md w-full shadow-sm hover:bg-[#e64a0c] focus:outline-none focus:ring-2 focus:ring-[#ff580f]">
Enviar PDF
</button>
<button
id="uploadCancelBtn"
class="mt-3 px-4 py-2 bg-gray-300 text-gray-700 text-base font-medium rounded-md w-full shadow-sm hover:bg-gray-400 focus:outline-none focus:ring-2 focus:ring-gray-500">
Cancelar
</button>
</div>
</div>
</div>
</div>
</div>
<div id="codeModal" class="fixed inset-0 z-50 hidden flex items-center justify-center">
<div class="bg-white rounded-lg shadow-lg w-full max-w-5xl h-[75vh] flex flex-col p-6">
<!-- Cabeçalho -->
<div class="flex justify-between items-center mb-4 border-b pb-2">
<h2 class="text-xl font-semibold text-gray-800">Código para Ollama</h2>
<button id="closeModal" class="text-gray-500 hover:text-gray-700 text-xl leading-none"></button>
</div>
<!-- Linha do select + botões -->
<div class="flex items-end space-x-3 mb-4">
<div class="flex-1">
<label for="languageSelect" class="block text-sm font-medium text-gray-700 mb-1">Linguagem:</label>
<select
id="languageSelect"
class="w-full border border-gray-300 rounded-md px-3 py-2 focus:outline-none focus:ring-2 focus:ring-[#ff580f]"
>
<option value="python">Python</option>
<option value="javascript">JavaScript</option>
<option value="java">Java</option>
<option value="csharp">C#</option>
</select>
</div>
<button
id="copyCodeBtn"
class="inline-flex items-center px-3 py-2 border border-gray-300 rounded-md text-sm text-gray-700 bg-white hover:bg-gray-50 focus:outline-none"
>
<i data-feather="copy" class="mr-2 w-4 h-4"></i>
Copiar Código
</button>
<button
id="viewDocsBtn"
class="inline-flex items-center px-3 py-2 border border-gray-300 rounded-md text-sm text-gray-700 bg-white hover:bg-gray-50 focus:outline-none"
>
<i data-feather="book-open" class="mr-2 w-4 h-4"></i>
Ver Documentação
</button>
</div>
<!-- Código com highlight -->
<div class="flex-1 rounded-md p-4 overflow-auto border border-gray-700" style="background-color: #21223a;">
<pre class="h-full"><code id="exampleCode" class="language-python"></code></pre>
</div>
</div>
</div>
<script>
feather.replace();
// PDF Upload Modal Functionality
const uploadPdfBtn = document.getElementById('uploadPdfBtn');
const pdfUploadModal = document.getElementById('pdfUploadModal');
const uploadCancelBtn = document.getElementById('uploadCancelBtn');
const uploadSubmitBtn = document.getElementById('uploadSubmitBtn');
const pdfFileInput = document.getElementById('pdfFile');
uploadPdfBtn.addEventListener('click', function() {
pdfUploadModal.classList.remove('hidden');
});
uploadCancelBtn.addEventListener('click', function() {
pdfUploadModal.classList.add('hidden');
pdfFileInput.value = '';
});
uploadSubmitBtn.addEventListener('click', function() {
const file = pdfFileInput.files[0];
if (!file) {
alert('Por favor, selecione um arquivo PDF.');
return;
}
if (file.type !== 'application/pdf') {
alert('Por favor, selecione apenas arquivos PDF.');
return;
}
if (file.size > 10 * 1024 * 1024) {
alert('O arquivo é muito grande. Tamanho máximo: 10MB.');
return;
}
// Simulate file upload
addMessage(`PDF enviado: ${file.name}`, 'user');
addMessage(`Estou processando o arquivo "${file.name}". Em breve poderei responder perguntas sobre seu conteúdo.`, 'ai');
pdfUploadModal.classList.add('hidden');
pdfFileInput.value = '';
});
// Close modal when clicking outside
pdfUploadModal.addEventListener('click', function(e) {
if (e.target === pdfUploadModal) {
pdfUploadModal.classList.add('hidden');
pdfFileInput.value = '';
}
});
const chatMessages = document.getElementById('chatMessages');
const messageInput = document.getElementById('messageInput');
function sendMessage() {
const message = messageInput.value.trim();
if (!message) return;
const modelSelect = document.querySelector("select");
const selectedModelId = modelSelect.value;
addMessage(message, 'user');
messageInput.value = '';
addTypingIndicator();
fetch("/chatbot/", {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-CSRFToken": getCookie("csrftoken")
},
body: JSON.stringify({
message: message,
model_id: selectedModelId
})
})
.then(response => {
const reader = response.body.getReader();
const decoder = new TextDecoder();
let accumulatedText = "";
function readChunk() {
reader.read().then(({ done, value }) => {
if (done) {
removeTypingIndicator();
addMessage(accumulatedText.trim(), 'ai');
return;
}
const chunk = decoder.decode(value, { stream: true });
const lines = chunk.split("\n\n");
for (const line of lines) {
if (line.startsWith("data: ")) {
const data = line.replace("data: ", "");
if (data === "[FIM]") {
removeTypingIndicator();
addMessage(accumulatedText.trim(), 'ai');
return;
} else {
console.log(data)
accumulatedText += data;
updateTypingIndicatorText(accumulatedText);
}
}
}
readChunk();
});
}
readChunk();
})
.catch(error => {
console.error(error);
removeTypingIndicator();
addMessage("Erro ao conectar com o servidor.", 'ai');
});
}
function getCookie(name) {
let cookieValue = null;
if (document.cookie && document.cookie !== '') {
const cookies = document.cookie.split(';');
for (let i = 0; i < cookies.length; i++) {
const cookie = cookies[i].trim();
if (cookie.substring(0, name.length + 1) === (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
function updateTypingIndicatorText(text) {
const typingIndicator = document.getElementById('typingIndicator');
if (typingIndicator) {
typingIndicator.innerHTML = `<p>${text}</p>`;
chatMessages.scrollTop = chatMessages.scrollHeight;
}
}
function addMessage(text, sender) {
const messageDiv = document.createElement('div');
messageDiv.className = `message-bubble ${sender === 'user' ? 'bg-white rounded-2xl p-4 shadow-md ml-auto' : 'bg-[#21223a] text-white rounded-2xl p-4 shadow-md'}`;
const messageContent = document.createElement('p');
messageContent.className = sender === 'user' ? 'text-gray-800' : 'text-white';
messageContent.textContent = text;
const timestamp = document.createElement('span');
timestamp.className = `text-xs block mt-2 ${sender === 'user' ? 'text-gray-500' : 'text-gray-300'}`;
timestamp.textContent = new Date().toLocaleTimeString([], {hour: '2-digit', minute:'2-digit'});
messageDiv.appendChild(messageContent);
messageDiv.appendChild(timestamp);
chatMessages.appendChild(messageDiv);
// Scroll to bottom
chatMessages.scrollTop = chatMessages.scrollHeight;
}
function addTypingIndicator() {
const typingDiv = document.createElement('div');
typingDiv.className = 'message-bubble bg-[#21223a] text-white rounded-2xl p-4 shadow-md';
typingDiv.id = 'typingIndicator';
const typingContent = document.createElement('div');
typingContent.className = 'typing-indicator';
for (let i = 0; i < 3; i++) {
const dot = document.createElement('div');
dot.className = 'typing-dot';
typingContent.appendChild(dot);
}
typingDiv.appendChild(typingContent);
chatMessages.appendChild(typingDiv);
// Scroll to bottom
chatMessages.scrollTop = chatMessages.scrollHeight;
}
function removeTypingIndicator() {
const typingIndicator = document.getElementById('typingIndicator');
if (typingIndicator) {
typingIndicator.remove();
}
}
// Enter key to send message
messageInput.addEventListener('keypress', function(e) {
if (e.key === 'Enter') {
sendMessage();
}
});
// LLM selection
document.querySelectorAll('.llm-option').forEach(option => {
option.addEventListener('click', function() {
document.querySelectorAll('.llm-option').forEach(opt => {
opt.classList.remove('border-[#ff580f]');
});
this.classList.add('border-[#ff580f]');
const modelName = this.querySelector('span').textContent;
document.querySelector('.mt-3 span:first-child').textContent = `Modelo selecionado: ${modelName}`;
});
});
</script>
<link href="https://cdn.jsdelivr.net/npm/prismjs/themes/prism-tomorrow.css" rel="stylesheet" />
<script src="https://cdn.jsdelivr.net/npm/prismjs/prism.js"></script>
<script src="https://cdn.jsdelivr.net/npm/prismjs/components/prism-python.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/prismjs/components/prism-javascript.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/prismjs/components/prism-java.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/prismjs/components/prism-csharp.min.js"></script>
<script>
document.addEventListener("DOMContentLoaded", () => {
feather.replace();
// Abrir modal
const openModal = document.getElementById("generateCodeBtn");
const codeModal = document.getElementById("codeModal");
const closeModal = document.getElementById("closeModal");
openModal.addEventListener("click", () => codeModal.classList.remove("hidden"));
closeModal.addEventListener("click", () => codeModal.classList.add("hidden"));
// Referências
const languageSelect = document.getElementById("languageSelect");
const codeEl = document.getElementById("exampleCode");
const copyBtn = document.getElementById("copyCodeBtn");
const docsBtn = document.getElementById("viewDocsBtn");
// Exemplos
const codeExamples = {
python: `import ollama
response = ollama.chat(model="llama3", messages=[
{"role": "user", "content": "Olá, mundo!"}
])
print(response['message']['content'])`,
javascript: `import ollama from "ollama";
const response = await ollama.chat({
model: "llama3",
messages: [{ role: "user", content: "Olá, mundo!" }],
});
console.log(response.message.content);`,
java: `import java.util.*;
public class Main {
public static void main(String[] args) {
System.out.println("Olá, mundo!");
}
}`,
csharp: `using System;
class Program {
static void Main() {
Console.WriteLine("Olá, mundo!");
}
}`
};
// Atualizar código + highlight
languageSelect.addEventListener("change", (e) => {
const lang = e.target.value;
codeEl.className = "language-" + lang;
codeEl.textContent = codeExamples[lang];
Prism.highlightElement(codeEl);
});
// Copiar código
copyBtn.addEventListener("click", () => {
navigator.clipboard.writeText(codeEl.textContent);
copyBtn.innerHTML = '<i data-feather="check" class="mr-2 w-4 h-4"></i>Copiado!';
feather.replace();
setTimeout(() => {
copyBtn.innerHTML = '<i data-feather="copy" class="mr-2 w-4 h-4"></i>Copiar Código';
feather.replace();
}, 1500);
});
// Ver documentação
const docsUrls = {
python: "https://docs.python.org/3/",
javascript: "https://developer.mozilla.org/pt-BR/docs/Web/JavaScript",
java: "https://docs.oracle.com/en/java/",
csharp: "https://learn.microsoft.com/dotnet/csharp/"
};
docsBtn.addEventListener("click", () => {
const lang = languageSelect.value;
window.open(docsUrls[lang], "_blank");
});
// Inicial highlight
Prism.highlightElement(codeEl);
});
</script>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script>
// Initialize Vanta.js background
VANTA.NET({
el: "#vanta-bg",
mouseControls: true,
touchControls: true,
gyroControls: false,
minHeight: 200.00,
minWidth: 200.00,
scale: 1.00,
scaleMobile: 1.00,
color: 0x3b82f6,
backgroundColor: 0xf8fafc,
points: 12.00,
maxDistance: 22.00,
spacing: 18.00
});
// Initialize feather icons
feather.replace();
// Pagination functionality
document.querySelectorAll('.pagination a').forEach(link => {
link.addEventListener('click', function(e) {
e.preventDefault();
// Here you would typically fetch the next page of results
// For demo purposes we'll just show an alert
if(this.textContent.trim() === '2' || this.textContent.trim() === '3') {
alert('Loading page ' + this.textContent.trim());
}
});
});
</script>
<script src="/static/script/alert.js"></script>
</body>
</html>