Skip to main content
Glama

MCP Orchestration Server

pdf_chat_interface.html18.8 kB
<!DOCTYPE html> <html> <head> <title>PDF Chat Interface - MCP System</title> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <style> * { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; min-height: 100vh; } .container { max-width: 1200px; margin: 0 auto; padding: 20px; } .header { text-align: center; margin-bottom: 30px; background: rgba(255,255,255,0.1); padding: 30px; border-radius: 15px; backdrop-filter: blur(10px); } .upload-section, .chat-section { background: rgba(255,255,255,0.1); padding: 30px; border-radius: 15px; margin-bottom: 30px; backdrop-filter: blur(10px); } .file-drop-zone { border: 3px dashed rgba(255,255,255,0.5); border-radius: 15px; padding: 40px; text-align: center; cursor: pointer; transition: all 0.3s; margin-bottom: 20px; } .file-drop-zone:hover { border-color: #4CAF50; background: rgba(76, 175, 80, 0.1); } .file-drop-zone.dragover { border-color: #4CAF50; background: rgba(76, 175, 80, 0.2); } .file-input { display: none; } .btn { background: #4CAF50; color: white; padding: 15px 30px; border: none; border-radius: 10px; font-size: 16px; cursor: pointer; margin: 5px; transition: all 0.3s; } .btn:hover { background: #45a049; transform: translateY(-2px); } .btn:disabled { background: #666; cursor: not-allowed; transform: none; } .chat-input { width: 100%; padding: 15px; font-size: 16px; border: none; border-radius: 10px; margin-bottom: 15px; background: rgba(255,255,255,0.9); color: #333; outline: none; } .chat-messages { max-height: 400px; overflow-y: auto; background: rgba(255,255,255,0.05); padding: 20px; border-radius: 10px; margin-bottom: 20px; } .message { margin-bottom: 15px; padding: 15px; border-radius: 10px; animation: fadeIn 0.5s ease-in; } .message.user { background: rgba(76, 175, 80, 0.3); margin-left: 20px; } .message.assistant { background: rgba(33, 150, 243, 0.3); margin-right: 20px; } @keyframes fadeIn { from { opacity: 0; transform: translateY(20px); } to { opacity: 1; transform: translateY(0); } } .document-info { background: rgba(255,255,255,0.1); padding: 15px; border-radius: 10px; margin-bottom: 20px; } .loading { text-align: center; padding: 20px; } .spinner { border: 4px solid rgba(255,255,255,0.3); border-radius: 50%; border-top: 4px solid #4CAF50; width: 40px; height: 40px; animation: spin 1s linear infinite; margin: 20px auto; } @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } .notification { position: fixed; top: 20px; right: 20px; padding: 15px 20px; border-radius: 10px; color: white; font-weight: bold; z-index: 1000; animation: slideIn 0.3s ease-out; } @keyframes slideIn { from { transform: translateX(100%); } to { transform: translateX(0); } } .notification.success { background: #4CAF50; } .notification.error { background: #f44336; } .back-btn { background: #2196F3; margin-bottom: 20px; } </style> </head> <body> <div class="container"> <div class="header"> <h1>📄 PDF Chat Interface</h1> <p>Upload PDF documents and chat with them using AI</p> <button class="btn back-btn" onclick="window.location.href='/'">🏠 Back to Main Interface</button> </div> <div class="upload-section"> <h2>📁 Upload PDF Document</h2> <div class="file-drop-zone" id="fileDropZone" onclick="document.getElementById('fileInput').click()"> <div> <p style="font-size: 24px; margin-bottom: 10px;">📄</p> <p style="font-size: 18px; margin-bottom: 10px;">Drop PDF here or click to browse</p> <p style="font-size: 14px; opacity: 0.8;">Supports PDF files up to 50MB</p> </div> </div> <input type="file" id="fileInput" class="file-input" accept=".pdf"> <div id="uploadStatus" style="display: none;"> <div class="loading"> <div class="spinner"></div> <p>Uploading and processing PDF...</p> </div> </div> <div id="documentInfo" class="document-info" style="display: none;"> <h3>📄 Uploaded Document</h3> <p><strong>Filename:</strong> <span id="docFilename"></span></p> <p><strong>File Size:</strong> <span id="docSize"></span></p> <p><strong>Text Length:</strong> <span id="docTextLength"></span> characters</p> <p><strong>Upload Time:</strong> <span id="docUploadTime"></span></p> </div> </div> <div class="chat-section" id="chatSection" style="display: none;"> <h2>💬 Chat with Your PDF</h2> <div class="chat-messages" id="chatMessages"> <div class="message assistant"> <strong>🤖 Assistant:</strong> Hello! I've processed your PDF document. Ask me any questions about its content! </div> </div> <div> <input type="text" id="chatInput" class="chat-input" placeholder="Ask a question about your PDF document..." /> <button id="sendBtn" class="btn">🚀 Send Question</button> <button id="clearBtn" class="btn" style="background: #ff9800;">🗑️ Clear Chat</button> </div> <h3 style="margin-top: 20px;">💡 Example Questions:</h3> <div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 15px; margin-top: 15px;"> <button class="btn" onclick="askQuestion('What is the main topic of this document?')" style="background: #9c27b0;">📋 Main Topic</button> <button class="btn" onclick="askQuestion('Summarize the key points')" style="background: #9c27b0;">📝 Summary</button> <button class="btn" onclick="askQuestion('What are the important dates mentioned?')" style="background: #9c27b0;">📅 Dates</button> <button class="btn" onclick="askQuestion('List any numbers or statistics')" style="background: #9c27b0;">📊 Statistics</button> </div> </div> </div> <script> let currentPdfId = null; let sessionId = 'session_' + Date.now(); let isProcessing = false; // Initialize document.addEventListener('DOMContentLoaded', function() { setupEventListeners(); }); function setupEventListeners() { // File input change document.getElementById('fileInput').addEventListener('change', handleFileSelect); // Drag and drop const dropZone = document.getElementById('fileDropZone'); dropZone.addEventListener('dragover', handleDragOver); dropZone.addEventListener('drop', handleDrop); dropZone.addEventListener('dragleave', handleDragLeave); // Chat input document.getElementById('chatInput').addEventListener('keypress', function(e) { if (e.key === 'Enter' && !isProcessing) { sendQuestion(); } }); // Send button document.getElementById('sendBtn').addEventListener('click', sendQuestion); // Clear button document.getElementById('clearBtn').addEventListener('click', clearChat); } function handleDragOver(e) { e.preventDefault(); e.currentTarget.classList.add('dragover'); } function handleDragLeave(e) { e.currentTarget.classList.remove('dragover'); } function handleDrop(e) { e.preventDefault(); e.currentTarget.classList.remove('dragover'); const files = e.dataTransfer.files; if (files.length > 0) { handleFile(files[0]); } } function handleFileSelect(e) { const files = e.target.files; if (files.length > 0) { handleFile(files[0]); } } async function handleFile(file) { if (!file.name.toLowerCase().endsWith('.pdf')) { showNotification('Please select a PDF file', 'error'); return; } if (file.size > 50 * 1024 * 1024) { // 50MB limit showNotification('File too large. Please select a PDF under 50MB', 'error'); return; } // Show upload status document.getElementById('uploadStatus').style.display = 'block'; document.getElementById('documentInfo').style.display = 'none'; document.getElementById('chatSection').style.display = 'none'; try { const formData = new FormData(); formData.append('file', file); const response = await fetch('/api/upload/pdf', { method: 'POST', body: formData }); const result = await response.json(); if (result.status === 'success') { currentPdfId = result.file_id; // Show document info document.getElementById('docFilename').textContent = result.filename; document.getElementById('docSize').textContent = formatFileSize(file.size); document.getElementById('docTextLength').textContent = result.text_length; document.getElementById('docUploadTime').textContent = new Date().toLocaleString(); document.getElementById('uploadStatus').style.display = 'none'; document.getElementById('documentInfo').style.display = 'block'; document.getElementById('chatSection').style.display = 'block'; showNotification('PDF uploaded and processed successfully!', 'success'); // Focus chat input document.getElementById('chatInput').focus(); } else { throw new Error(result.message || 'Upload failed'); } } catch (error) { document.getElementById('uploadStatus').style.display = 'none'; showNotification('Upload failed: ' + error.message, 'error'); } } function askQuestion(question) { document.getElementById('chatInput').value = question; sendQuestion(); } async function sendQuestion() { if (isProcessing) { showNotification('Please wait for the current question to be processed', 'error'); return; } const question = document.getElementById('chatInput').value.trim(); if (!question) { showNotification('Please enter a question', 'error'); return; } if (!currentPdfId) { showNotification('Please upload a PDF first', 'error'); return; } isProcessing = true; document.getElementById('sendBtn').disabled = true; document.getElementById('sendBtn').innerHTML = '⏳ Processing...'; // Add user message addMessage('user', question); // Clear input document.getElementById('chatInput').value = ''; try { const response = await fetch('/api/chat/pdf', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ question: question, pdf_id: currentPdfId, session_id: sessionId }) }); const result = await response.json(); if (result.status === 'success') { let answer = 'I processed your question about the PDF document.'; let answerDetails = ''; // Check if LangChain RAG was used if (result.rag_enabled && result.llm_powered) { answerDetails = '🧠 <strong>LangChain RAG Powered</strong><br>'; } else if (result.fallback_reason) { answerDetails = `⚠️ <strong>Fallback Mode:</strong> ${result.fallback_reason}<br>`; } // Check if content was chunked if (result.content_chunked) { answerDetails += '📄 <strong>Smart Chunking:</strong> Large document processed with intelligent content selection<br>'; } // Get the main answer if (result.answer) { answer = result.answer; } else if (result.message) { answer = result.message; } else if (result.result) { answer = `Answer: ${result.result}`; } else if (result.total_documents) { answer = `I analyzed ${result.total_documents} document(s) to answer your question.`; } // Add document summary if available if (result.document_summary) { answerDetails += `📄 <strong>Document Summary:</strong> ${result.document_summary}<br><br>`; } // Combine details and answer const fullAnswer = answerDetails + answer; addMessage('assistant', fullAnswer); // Show appropriate notification if (result.rag_enabled) { showNotification('Question answered using LangChain RAG!', 'success'); } else { showNotification('Question answered successfully!', 'success'); } } else { addMessage('assistant', `Sorry, I couldn't process your question: ${result.message}`); showNotification('Failed to process question', 'error'); } } catch (error) { addMessage('assistant', `Sorry, there was an error processing your question: ${error.message}`); showNotification('Error processing question', 'error'); } finally { isProcessing = false; document.getElementById('sendBtn').disabled = false; document.getElementById('sendBtn').innerHTML = '🚀 Send Question'; document.getElementById('chatInput').focus(); } } function addMessage(type, content) { const messagesContainer = document.getElementById('chatMessages'); const messageDiv = document.createElement('div'); messageDiv.className = `message ${type}`; const icon = type === 'user' ? '👤' : '🤖'; const label = type === 'user' ? 'You' : 'Assistant'; messageDiv.innerHTML = `<strong>${icon} ${label}:</strong> ${content}`; messagesContainer.appendChild(messageDiv); messagesContainer.scrollTop = messagesContainer.scrollHeight; } function clearChat() { const messagesContainer = document.getElementById('chatMessages'); messagesContainer.innerHTML = ` <div class="message assistant"> <strong>🤖 Assistant:</strong> Chat cleared! Ask me any questions about your PDF document. </div> `; } function formatFileSize(bytes) { if (bytes === 0) return '0 Bytes'; const k = 1024; const sizes = ['Bytes', 'KB', 'MB', 'GB']; const i = Math.floor(Math.log(bytes) / Math.log(k)); return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]; } function showNotification(message, type = 'success') { // Remove existing notifications const existing = document.querySelector('.notification'); if (existing) { existing.remove(); } const notification = document.createElement('div'); notification.className = `notification ${type}`; notification.textContent = message; document.body.appendChild(notification); // Auto-remove after 3 seconds setTimeout(() => { if (notification.parentNode) { notification.remove(); } }, 3000); } </script> </body> </html>

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Nisarg-123-web/MCP2'

If you have feedback or need assistance with the MCP directory API, please join our Discord server