Faça com que ao apertar o botão de Enviar PDF abra um modal para enviar o arquivo pdf
db5e308 verified | <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"> | |
| <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 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 | |
| "> | |
| <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="/chat/" | |
| class="sidebar-item flex items-center p-3 rounded-lg | |
| active"> | |
| <i class="fa-solid fa-comment text-secondary w-6 text-center"></i> | |
| <span class="ml-3 lg:block hidden">Chat Model</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">Monitoring</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="p-4 border-t border-gray-700"> | |
| <h3 class="text-sm font-medium mb-2 lg:block hidden">Documentos Recentes</h3> | |
| <div class="agent-history"> | |
| <ul id="agent-history"> | |
| </ul> | |
| </div> | |
| </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="pyj7mp4hVdjHNtFct0e7FSPl52GkVOZ49v0zPK4KMopkFIIlDfM67bXNsPnJh759"> | |
| </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> | |
| Launch New Instance | |
| </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="text-sm border border-gray-300 rounded-md px-3 py-1 focus:outline-none focus:ring-1 focus:ring-[#ff580f]"> | |
| <option value="gpt-4" selected>GPT-4</option> | |
| <option value="claude-2">Claude 2</option> | |
| <option value="llama-2">Llama 2</option> | |
| <option value="mistral-7b">Mistral 7B</option> | |
| </select> | |
| </div> | |
| <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> | |
| </div> | |
| </div> | |
| <!-- Chat Messages --> | |
| <div class="flex-1 p-6 space-y-6 chat-container overflow-y-auto" id="chatMessages"> | |
| <div class="message-bubble bg-white rounded-2xl p-4 shadow-md ml-auto"> | |
| <p class="text-gray-800">Olá! Como posso ajudar você hoje?</p> | |
| <span class="text-xs text-gray-500 block mt-2">12:30 PM</span> | |
| </div> | |
| <div class="message-bubble bg-[#21223a] text-white rounded-2xl p-4 shadow-md"> | |
| <p>Estou aqui para assistir você! Posso responder perguntas, ajudar com pesquisas, escrever conteúdo e muito mais. O que você gostaria de fazer?</p> | |
| <span class="text-xs text-gray-300 block mt-2">12:31 PM</span> | |
| </div> | |
| </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> | |
| <!-- PDF Upload Modal --> | |
| <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 w-96 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> | |
| <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; | |
| // Add user message | |
| addMessage(message, 'user'); | |
| messageInput.value = ''; | |
| // Simulate AI response | |
| setTimeout(() => { | |
| addTypingIndicator(); | |
| setTimeout(() => { | |
| removeTypingIndicator(); | |
| addMessage(getAIResponse(message), 'ai'); | |
| }, 2000); | |
| }, 500); | |
| } | |
| 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(); | |
| } | |
| } | |
| function getAIResponse(userMessage) { | |
| const responses = [ | |
| "Entendi sua pergunta! Deixe-me ajudar com isso...", | |
| "Excelente pergunta! Aqui está a informação que você precisa:", | |
| "Com base na sua solicitação, aqui está o que posso compartilhar:", | |
| "Ótimo ponto! Deixe-me elaborar sobre isso:", | |
| "Obrigado pela pergunta. Aqui está minha resposta:" | |
| ]; | |
| return responses[Math.floor(Math.random() * responses.length)] + " Esta é uma resposta simulada do chatbot. Em uma implementação real, esta seria a resposta do modelo LLM selecionado."; | |
| } | |
| // Enter key to send message | |
| messageInput.addEventListener('keypress', function(e) { | |
| if (e.key === 'Enter') { | |
| sendMessage(); | |
| } | |
| }); | |
| // Drag and drop functionality | |
| const dropArea = pdfFileInput.parentElement; | |
| ['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => { | |
| dropArea.addEventListener(eventName, preventDefaults, false); | |
| }); | |
| function preventDefaults(e) { | |
| e.preventDefault(); | |
| e.stopPropagation(); | |
| } | |
| ['dragenter', 'dragover'].forEach(eventName => { | |
| dropArea.addEventListener(eventName, highlight, false); | |
| }); | |
| ['dragleave', 'drop'].forEach(eventName => { | |
| dropArea.addEventListener(eventName, unhighlight, false); | |
| }); | |
| function highlight() { | |
| dropArea.classList.add('border-[#ff580f]', 'bg-[#fff5f0]'); | |
| } | |
| function unhighlight() { | |
| dropArea.classList.remove('border-[#ff580f]', 'bg-[#fff5f0]'); | |
| } | |
| dropArea.addEventListener('drop', handleDrop, false); | |
| function handleDrop(e) { | |
| const dt = e.dataTransfer; | |
| const files = dt.files; | |
| pdfFileInput.files = files; | |
| } | |
| // 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> | |
| </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> | |
| </body> | |
| </html> |