Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8" /> | |
| <title>AI Text Humanizer</title> | |
| <style> | |
| * { | |
| margin: 0; | |
| padding: 0; | |
| box-sizing: border-box; | |
| } | |
| html, body { | |
| height: 100%; | |
| } | |
| body { | |
| font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; | |
| background: linear-gradient(135deg, #6366f1 0%, #8b5cf6 50%, #ec4899 100%); | |
| color: #1f2937; | |
| overflow-y: auto; /* Allow page scrolling */ | |
| min-height: 100vh; | |
| } | |
| .container { | |
| min-height: 100vh; | |
| max-width: 1400px; | |
| margin: 0 auto; | |
| display: flex; | |
| flex-direction: column; | |
| padding: 16px; | |
| } | |
| /* ===== HEADER (Title + Subtitle) ===== */ | |
| .header { | |
| text-align: center; | |
| margin-bottom: 16px; /* Reduced bottom margin so header sits higher */ | |
| } | |
| h1 { | |
| font-size: 2.0em; /* Slightly smaller */ | |
| font-weight: 800; | |
| background: linear-gradient(135deg, #ffffff 0%, #f8fafc 100%); | |
| -webkit-background-clip: text; | |
| -webkit-text-fill-color: transparent; | |
| background-clip: text; | |
| margin-bottom: 6px; | |
| text-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); | |
| } | |
| p.description { | |
| color: rgba(255, 255, 255, 0.9); | |
| font-size: 1.2em; | |
| font-weight: 300; | |
| } | |
| /* ===== MAIN GRID (Input + Output Panels) ===== */ | |
| .main-content { | |
| display: grid; | |
| grid-template-columns: 1fr 1fr; | |
| gap: 24px; | |
| min-height: 70vh; /* Fixed height for the main panels */ | |
| margin-bottom: 24px; | |
| } | |
| @media (max-width: 1200px) { | |
| .main-content { | |
| grid-template-columns: 1fr; | |
| grid-template-rows: 1fr 1fr; | |
| gap: 20px; | |
| } | |
| h1 { | |
| font-size: 1.8em; | |
| } | |
| } | |
| @media (max-width: 768px) { | |
| .container { | |
| padding: 12px; | |
| } | |
| .panel { | |
| padding: 16px; | |
| } | |
| h1 { | |
| font-size: 1.6em; | |
| } | |
| p.description { | |
| font-size: 1em; | |
| } | |
| } | |
| /* ===== PANEL BASE STYLES ===== */ | |
| .panel { | |
| background: rgba(255, 255, 255, 0.95); | |
| backdrop-filter: blur(20px); | |
| border-radius: 20px; | |
| box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1); | |
| border: 1px solid rgba(255, 255, 255, 0.2); | |
| display: flex; | |
| flex-direction: column; | |
| height: 100%; | |
| overflow: hidden; | |
| padding: 24px; | |
| } | |
| .input-panel { | |
| background: rgba(255, 255, 255, 0.98); | |
| } | |
| .output-panel { | |
| background: rgba(248, 250, 252, 0.98); | |
| } | |
| /* ===== PANEL HEADER (Title + Subtitle inside each panel) ===== */ | |
| .panel-header { | |
| margin-bottom: 16px; | |
| padding-bottom: 12px; | |
| border-bottom: 2px solid rgba(99, 102, 241, 0.1); | |
| } | |
| .panel-title { | |
| font-size: 1.3em; | |
| font-weight: 600; | |
| color: #374151; | |
| margin-bottom: 6px; | |
| } | |
| .panel-subtitle { | |
| color: #6b7280; | |
| font-size: 0.9em; | |
| } | |
| /* ===== INPUT PANEL CONTROLS ===== */ | |
| textarea { | |
| flex: 1; /* Takes all available vertical space */ | |
| font-size: 15px; | |
| padding: 16px; | |
| border: 2px solid #e5e7eb; | |
| border-radius: 12px; | |
| resize: none; | |
| transition: all 0.3s ease; | |
| font-family: inherit; | |
| line-height: 1.6; | |
| background: #fafafa; | |
| overflow-y: auto; | |
| } | |
| textarea:focus { | |
| outline: none; | |
| border-color: #6366f1; | |
| box-shadow: 0 0 0 3px rgba(99, 102, 241, 0.1); | |
| background: white; | |
| } | |
| textarea::placeholder { | |
| color: #9ca3af; | |
| } | |
| /* ===== BUTTON STYLES ===== */ | |
| button { | |
| background: linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%); | |
| color: white; | |
| padding: 8px 16px; /* Further reduced */ | |
| font-size: 13px; /* Further reduced */ | |
| font-weight: 600; | |
| border: none; | |
| border-radius: 8px; /* Smaller radius */ | |
| cursor: pointer; | |
| transition: all 0.3s ease; | |
| box-shadow: 0 2px 8px rgba(99, 102, 241, 0.3); | |
| max-width: 200px; /* Limit button width */ | |
| } | |
| button:hover { | |
| transform: translateY(-1px); | |
| box-shadow: 0 4px 12px rgba(99, 102, 241, 0.4); | |
| } | |
| button:active { | |
| transform: translateY(0); | |
| } | |
| .copy-button { | |
| background: linear-gradient(135deg, #10b981 0%, #059669 100%); | |
| box-shadow: 0 2px 8px rgba(16, 185, 129, 0.3); | |
| margin-top: 0; | |
| flex-shrink: 0; | |
| max-width: 140px; /* Same as file input button */ | |
| } | |
| .copy-button:hover { | |
| box-shadow: 0 4px 12px rgba(16, 185, 129, 0.4); | |
| } | |
| .copy-button.copied { | |
| background: linear-gradient(135deg, #22c55e 0%, #16a34a 100%); | |
| } | |
| .detector-button { | |
| background: linear-gradient(135deg, #f59e0b 0%, #d97706 100%); | |
| box-shadow: 0 2px 8px rgba(245, 158, 11, 0.3); | |
| margin-top: 0; /* Remove top margin */ | |
| flex-shrink: 0; | |
| max-width: 180px; /* Slightly wider for longer text */ | |
| } | |
| .detector-button:hover { | |
| box-shadow: 0 4px 12px rgba(245, 158, 11, 0.4); | |
| } | |
| /* ===== FILE UPLOAD STYLES ===== */ | |
| .file-upload-area { | |
| margin-top: 12px; | |
| display: flex; | |
| gap: 8px; | |
| align-items: center; | |
| justify-content: center; | |
| } | |
| .buttons-row { | |
| display: flex; | |
| gap: 8px; | |
| align-items: center; | |
| justify-content: center; | |
| flex-wrap: wrap; | |
| } | |
| .file-input-wrapper { | |
| position: relative; | |
| } | |
| .file-input { | |
| position: absolute; | |
| opacity: 0; | |
| width: 100%; | |
| height: 100%; | |
| cursor: pointer; | |
| } | |
| .file-input-label { | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| padding: 8px 16px; | |
| background: linear-gradient(135deg, #8b5cf6 0%, #a855f7 100%); | |
| color: white; | |
| border-radius: 8px; | |
| cursor: pointer; | |
| transition: all 0.3s ease; | |
| font-size: 13px; | |
| font-weight: 600; | |
| box-shadow: 0 2px 8px rgba(139, 92, 246, 0.3); | |
| min-height: 32px; | |
| max-width: 140px; /* Limit width */ | |
| } | |
| .file-input-label:hover { | |
| transform: translateY(-1px); | |
| box-shadow: 0 4px 12px rgba(139, 92, 246, 0.4); | |
| } | |
| .clear-button { | |
| background: linear-gradient(135deg, #ef4444 0%, #dc2626 100%); | |
| box-shadow: 0 2px 8px rgba(239, 68, 68, 0.3); | |
| padding: 8px 16px; | |
| max-width: 100px; /* Limit width */ | |
| } | |
| .clear-button:hover { | |
| box-shadow: 0 4px 12px rgba(239, 68, 68, 0.4); | |
| } | |
| .file-info { | |
| font-size: 12px; | |
| color: #6b7280; | |
| margin-top: 8px; | |
| padding: 0 4px; | |
| text-align: center; | |
| } | |
| /* ===== OUTPUT CONTENT CONTAINER ===== */ | |
| .output-container { | |
| display: flex; | |
| flex-direction: column; | |
| height: 400px; /* Fixed height for the container */ | |
| overflow: hidden; /* Prevent container from expanding */ | |
| } | |
| /* ===== OUTPUT CONTENT (scrollable) ===== */ | |
| .output-content { | |
| flex: 1; /* Fill vertical space between header and bottom button */ | |
| padding: 16px; | |
| background: #f8fafc; | |
| border: 2px solid #e2e8f0; | |
| border-radius: 12px; | |
| font-size: 15px; | |
| line-height: 1.7; | |
| white-space: pre-wrap; | |
| overflow-y: auto; /* Only this area scrolls */ | |
| color: #334155; | |
| height: 400px; /* Fixed height instead of min-height */ | |
| max-height: 400px; /* Prevent expansion */ | |
| } | |
| /* ===== BOTTOM BUTTON CONTAINER (flexible height) ===== */ | |
| .panel-bottom { | |
| margin-top: 16px; | |
| display: flex; | |
| flex-direction: column; | |
| gap: 8px; | |
| flex-shrink: 0; /* Prevent buttons from shrinking */ | |
| } | |
| /* ===== AI DETECTOR SECTION STYLES ===== */ | |
| .detector-section { | |
| display: none; /* Hidden by default */ | |
| background: rgba(255, 255, 255, 0.95); | |
| backdrop-filter: blur(20px); | |
| border-radius: 20px; | |
| box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1); | |
| border: 1px solid rgba(255, 255, 255, 0.2); | |
| padding: 24px; | |
| margin-bottom: 24px; | |
| animation: slideIn 0.5s ease-out; | |
| } | |
| @keyframes slideIn { | |
| from { | |
| opacity: 0; | |
| transform: translateY(20px); | |
| } | |
| to { | |
| opacity: 1; | |
| transform: translateY(0); | |
| } | |
| } | |
| .detector-results { | |
| padding: 16px; | |
| background: #ffffff; | |
| border: 2px solid #e2e8f0; | |
| border-radius: 12px; | |
| } | |
| .detector-table-title { | |
| font-size: 1.1em; | |
| font-weight: 600; | |
| color: #374151; | |
| margin-bottom: 12px; | |
| text-align: center; | |
| } | |
| .detector-table { | |
| width: 100%; | |
| border-collapse: collapse; | |
| font-size: 14px; | |
| } | |
| .detector-table th { | |
| background: linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%); | |
| color: white; | |
| padding: 12px 8px; | |
| text-align: left; | |
| font-weight: 600; | |
| border-radius: 8px 8px 0 0; | |
| } | |
| .detector-table th:first-child { | |
| border-radius: 8px 0 0 0; | |
| } | |
| .detector-table th:last-child { | |
| border-radius: 0 8px 0 0; | |
| } | |
| .detector-table td { | |
| padding: 10px 8px; | |
| border-bottom: 1px solid #e5e7eb; | |
| } | |
| .detector-table tr:nth-child(even) { | |
| background-color: #f8fafc; | |
| } | |
| .detector-table tr:hover { | |
| background-color: #f1f5f9; | |
| } | |
| .ai-percentage { | |
| font-weight: 600; | |
| color: #ef4444; | |
| } | |
| .ai-percentage.low { | |
| color: #10b981; | |
| } | |
| .ai-percentage.medium { | |
| color: #f59e0b; | |
| } | |
| .ai-percentage.high { | |
| color: #ef4444; | |
| } | |
| /* ===== LOADING & ERROR STATES ===== */ | |
| .loading { | |
| color: #64748b; | |
| font-style: italic; | |
| text-align: center; | |
| padding: 40px 20px; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| gap: 8px; | |
| } | |
| .loading::before { | |
| content: "β¨"; | |
| animation: pulse 1.5s infinite; | |
| } | |
| .detector-loading { | |
| color: #64748b; | |
| font-style: italic; | |
| text-align: center; | |
| padding: 20px; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| gap: 8px; | |
| } | |
| .detector-loading::before { | |
| content: "π"; | |
| animation: pulse 1.5s infinite; | |
| } | |
| @keyframes pulse { | |
| 0%, 100% { | |
| opacity: 1; | |
| } | |
| 50% { | |
| opacity: 0.5; | |
| } | |
| } | |
| .error { | |
| color: #ef4444; | |
| font-weight: 500; | |
| text-align: center; | |
| padding: 24px 16px; | |
| background: rgba(239, 68, 68, 0.05); | |
| border-radius: 8px; | |
| } | |
| /* ===== CUSTOM SCROLLBAR for output ===== */ | |
| .output-content::-webkit-scrollbar { | |
| width: 8px; | |
| } | |
| .output-content::-webkit-scrollbar-track { | |
| background: #f1f5f9; | |
| border-radius: 4px; | |
| } | |
| .output-content::-webkit-scrollbar-thumb { | |
| background: #cbd5e1; | |
| border-radius: 4px; | |
| } | |
| .output-content::-webkit-scrollbar-thumb:hover { | |
| background: #94a3b8; | |
| } | |
| /* ===== DEBUG STYLES (temporary - remove in production) ===== */ | |
| .debug-info { | |
| position: fixed; | |
| top: 10px; | |
| right: 10px; | |
| background: rgba(0, 0, 0, 0.8); | |
| color: white; | |
| padding: 10px; | |
| border-radius: 5px; | |
| font-size: 12px; | |
| z-index: 1000; | |
| display: none; /* Hidden by default */ | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="container"> | |
| <!-- Debug info (remove in production) --> | |
| <div id="debugInfo" class="debug-info"></div> | |
| <!-- ===== HEADER ===== --> | |
| <div class="header"> | |
| <h1>π AI Text Humanizer</h1> | |
| <p class="description">Transform AI text into natural, human-like language</p> | |
| </div> | |
| <!-- ===== MAIN PANELS ===== --> | |
| <div class="main-content"> | |
| <!-- ==================== INPUT PANEL ==================== --> | |
| <div class="panel input-panel"> | |
| <div class="panel-header"> | |
| <div class="panel-title">π Input Text</div> | |
| <div class="panel-subtitle">Paste your AI-generated content or upload a file</div> | |
| </div> | |
| <textarea | |
| id="inputText" | |
| placeholder="Paste your AI-generated text here and watch the magic happen..." | |
| ></textarea> | |
| <div class="panel-bottom"> | |
| <!-- All buttons in one row --> | |
| <div class="buttons-row"> | |
| <button type="button" onclick="humanize()">π Humanize Text</button> | |
| <div class="file-input-wrapper"> | |
| <input type="file" id="fileInput" class="file-input" accept=".txt,.doc,.docx,.pdf" onchange="handleFileUpload(event)"> | |
| <label for="fileInput" class="file-input-label"> | |
| π Choose File | |
| </label> | |
| </div> | |
| <button type="button" class="clear-button" onclick="clearText()">ποΈ Clear</button> | |
| </div> | |
| <div id="fileInfo" class="file-info" style="display: none;"></div> | |
| </div> | |
| </div> | |
| <!-- ==================== OUTPUT PANEL ==================== --> | |
| <div class="panel output-panel"> | |
| <div class="panel-header"> | |
| <div class="panel-title">β¨ Humanized Result</div> | |
| <div class="panel-subtitle">Your transformed, natural text</div> | |
| </div> | |
| <div class="output-container"> | |
| <!-- #result holds loading / error / final text; scrollable --> | |
| <div id="result" class="output-content"> | |
| <div class="loading">Your humanized text will appear here...</div> | |
| </div> | |
| </div> | |
| <div class="panel-bottom"> | |
| <!-- Copy and Detector buttons in one row --> | |
| <div class="buttons-row"> | |
| <button | |
| id="copyBtn" | |
| type="button" | |
| class="copy-button" | |
| style="display: none;" | |
| onclick="copyText()" | |
| > | |
| π Copy Text | |
| </button> | |
| <button | |
| id="detectorBtn" | |
| type="button" | |
| class="detector-button" | |
| style="display: none;" | |
| onclick="runDetector()" | |
| > | |
| π AI Detector Results | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- ===== AI DETECTOR SECTION (appears at bottom) ===== --> | |
| <div id="detectorSection" class="detector-section"> | |
| <div class="panel-header"> | |
| <div class="panel-title">π AI Detector Analysis</div> | |
| <div class="panel-subtitle">Detailed analysis of your humanized text</div> | |
| </div> | |
| <div id="detectorResults"></div> | |
| </div> | |
| </div> | |
| <!-- ===== JAVASCRIPT ===== --> | |
| <script> | |
| let currentHumanizedText = ''; | |
| let debugMode = false; // Set to true for debugging | |
| // Debug function | |
| function updateDebugInfo(message) { | |
| if (!debugMode) return; | |
| const debugEl = document.getElementById('debugInfo'); | |
| debugEl.textContent = message; | |
| debugEl.style.display = 'block'; | |
| console.log('DEBUG:', message); | |
| } | |
| // Toggle debug mode with Ctrl+D | |
| document.addEventListener('keydown', (e) => { | |
| if (e.ctrlKey && e.key === 'd') { | |
| e.preventDefault(); | |
| debugMode = !debugMode; | |
| const debugEl = document.getElementById('debugInfo'); | |
| debugEl.style.display = debugMode ? 'block' : 'none'; | |
| updateDebugInfo('Debug mode: ' + (debugMode ? 'ON' : 'OFF')); | |
| } | |
| }); | |
| // File upload handler | |
| async function handleFileUpload(event) { | |
| const file = event.target.files[0]; | |
| if (!file) return; | |
| updateDebugInfo('File selected: ' + file.name); | |
| const fileInfo = document.getElementById('fileInfo'); | |
| const textArea = document.getElementById('inputText'); | |
| // Show file info | |
| fileInfo.textContent = `π ${file.name} (${(file.size / 1024).toFixed(1)} KB)`; | |
| fileInfo.style.display = 'block'; | |
| try { | |
| let text = ''; | |
| if (file.type === 'text/plain' || file.name.endsWith('.txt')) { | |
| // Handle plain text files | |
| text = await file.text(); | |
| } else if (file.name.endsWith('.docx')) { | |
| // For DOCX files, show a message since mammoth requires external library | |
| textArea.value = 'β οΈ DOCX files are not yet supported. Please copy and paste the text manually or use a .txt file.'; | |
| fileInfo.textContent += ' - DOCX support coming soon!'; | |
| return; | |
| } else if (file.name.endsWith('.pdf')) { | |
| // For PDF files, show a message since PDF parsing is complex | |
| textArea.value = 'β οΈ PDF files are not yet supported. Please copy and paste the text manually or use a .txt file.'; | |
| fileInfo.textContent += ' - PDF support coming soon!'; | |
| return; | |
| } else { | |
| // Try to read as text for other formats | |
| text = await file.text(); | |
| } | |
| // Set the text in the textarea | |
| textArea.value = text; | |
| // Trigger the auto-resize | |
| textArea.style.height = 'auto'; | |
| textArea.style.height = textArea.scrollHeight + 'px'; | |
| updateDebugInfo('File loaded successfully, text length: ' + text.length); | |
| fileInfo.textContent += ' - β Loaded successfully!'; | |
| } catch (error) { | |
| updateDebugInfo('Error reading file: ' + error.message); | |
| fileInfo.textContent = `β Error reading ${file.name}: ${error.message}`; | |
| fileInfo.style.color = '#ef4444'; | |
| console.error('File reading error:', error); | |
| } | |
| } | |
| // Clear text and file | |
| function clearText() { | |
| const textArea = document.getElementById('inputText'); | |
| const fileInput = document.getElementById('fileInput'); | |
| const fileInfo = document.getElementById('fileInfo'); | |
| const outputDiv = document.getElementById('result'); | |
| const copyBtn = document.getElementById('copyBtn'); | |
| const detectorBtn = document.getElementById('detectorBtn'); | |
| const detectorSection = document.getElementById('detectorSection'); | |
| // Clear all inputs and outputs | |
| textArea.value = ''; | |
| fileInput.value = ''; | |
| fileInfo.style.display = 'none'; | |
| fileInfo.style.color = '#6b7280'; // Reset color | |
| // Reset output area | |
| outputDiv.innerHTML = '<div class="loading">Your humanized text will appear here...</div>'; | |
| copyBtn.style.display = 'none'; | |
| detectorBtn.style.display = 'none'; | |
| detectorSection.style.display = 'none'; | |
| // Reset stored text | |
| currentHumanizedText = ''; | |
| // Reset textarea height | |
| textArea.style.height = 'auto'; | |
| updateDebugInfo('All content cleared'); | |
| } | |
| async function humanize() { | |
| const textArea = document.getElementById("inputText"); | |
| const outputDiv = document.getElementById("result"); | |
| const copyBtn = document.getElementById("copyBtn"); | |
| const detectorBtn = document.getElementById("detectorBtn"); | |
| const detectorSection = document.getElementById("detectorSection"); | |
| const text = textArea.value.trim(); | |
| if (!text) { | |
| alert("Please enter some text first!"); | |
| return; | |
| } | |
| updateDebugInfo('Starting humanize process...'); | |
| // Hide detector section when starting new humanization | |
| detectorSection.style.display = "none"; | |
| // Clear previous results completely | |
| outputDiv.innerHTML = ""; | |
| // Show loading spinner | |
| const spinner = document.createElement("div"); | |
| spinner.className = "loading"; | |
| spinner.textContent = "Processing your text..."; | |
| outputDiv.appendChild(spinner); | |
| // Hide buttons until we have a successful response | |
| copyBtn.style.display = "none"; | |
| detectorBtn.style.display = "none"; | |
| try { | |
| updateDebugInfo('Sending request to /humanize...'); | |
| const response = await fetch("/humanize", { | |
| method: "POST", | |
| headers: { | |
| "Content-Type": "application/json", | |
| }, | |
| body: JSON.stringify({ text }), | |
| }); | |
| updateDebugInfo(`Response status: ${response.status}`); | |
| if (!response.ok) { | |
| throw new Error(`Server responded with status ${response.status}`); | |
| } | |
| const data = await response.json(); | |
| updateDebugInfo('Received humanized text, length: ' + data.humanized.length); | |
| // Store the humanized text for detector | |
| currentHumanizedText = data.humanized; | |
| // Replace spinner with the actual humanized text | |
| outputDiv.innerHTML = ""; | |
| const textNode = document.createTextNode(data.humanized); | |
| outputDiv.appendChild(textNode); | |
| // Show buttons | |
| copyBtn.style.display = "block"; | |
| detectorBtn.style.display = "block"; | |
| updateDebugInfo('Humanize completed successfully'); | |
| } catch (error) { | |
| updateDebugInfo('Error in humanize: ' + error.message); | |
| outputDiv.innerHTML = ""; | |
| const errDiv = document.createElement("div"); | |
| errDiv.className = "error"; | |
| errDiv.textContent = `β Error: ${error.message}`; | |
| outputDiv.appendChild(errDiv); | |
| console.error("Error:", error); | |
| } | |
| } | |
| async function runDetector() { | |
| if (!currentHumanizedText) { | |
| alert("No humanized text available for detection!"); | |
| return; | |
| } | |
| updateDebugInfo('Starting detector process...'); | |
| const detectorSection = document.getElementById("detectorSection"); | |
| const detectorResults = document.getElementById("detectorResults"); | |
| const detectorBtn = document.getElementById("detectorBtn"); | |
| // Show the detector section and scroll to it | |
| detectorSection.style.display = "block"; | |
| setTimeout(() => { | |
| detectorSection.scrollIntoView({ behavior: 'smooth', block: 'start' }); | |
| }, 100); | |
| // Show loading state in the detector results area | |
| detectorResults.innerHTML = ""; | |
| const spinner = document.createElement("div"); | |
| spinner.className = "detector-loading"; | |
| spinner.textContent = "Running AI detection..."; | |
| detectorResults.appendChild(spinner); | |
| // Disable button during processing | |
| detectorBtn.disabled = true; | |
| detectorBtn.textContent = "π Analyzing..."; | |
| try { | |
| updateDebugInfo('Sending request to /detect...'); | |
| const response = await fetch("/detect", { | |
| method: "POST", | |
| headers: { | |
| "Content-Type": "application/json", | |
| }, | |
| body: JSON.stringify({ text: currentHumanizedText }), | |
| }); | |
| updateDebugInfo(`Detect response status: ${response.status}`); | |
| if (!response.ok) { | |
| throw new Error(`Server responded with status ${response.status}`); | |
| } | |
| const data = await response.json(); | |
| updateDebugInfo('Received detector results, count: ' + data.results.length); | |
| // Create the detector results table | |
| detectorResults.innerHTML = ` | |
| <div class="detector-results"> | |
| <div class="detector-table-title">π AI Detector Tool Results</div> | |
| <table class="detector-table"> | |
| <thead> | |
| <tr> | |
| <th>AI Detector Tool</th> | |
| <th>AI Probability</th> | |
| </tr> | |
| </thead> | |
| <tbody> | |
| ${data.results.map(result => { | |
| const label = result.ai_probability > 0.9 ? "AI-generated" : "Human-written"; | |
| return ` | |
| <tr> | |
| <td>${result.detector_name}</td> | |
| <td class="ai-label">${label}</td> | |
| </tr> | |
| `; | |
| }).join('')} | |
| </tbody> | |
| </table> | |
| </div> | |
| `; | |
| updateDebugInfo('Detector results displayed successfully'); | |
| } catch (error) { | |
| updateDebugInfo('Error in detector: ' + error.message); | |
| // Add error message | |
| detectorResults.innerHTML = ""; | |
| const errDiv = document.createElement("div"); | |
| errDiv.className = "error"; | |
| errDiv.textContent = `β Detection Error: ${error.message}`; | |
| detectorResults.appendChild(errDiv); | |
| console.error("Detection Error:", error); | |
| } finally { | |
| // Re-enable button | |
| detectorBtn.disabled = false; | |
| detectorBtn.textContent = "π AI Detector Results"; | |
| } | |
| } | |
| async function copyText() { | |
| const copyBtn = document.getElementById("copyBtn"); | |
| const textToCopy = currentHumanizedText; | |
| if (!textToCopy) { | |
| alert("No text to copy!"); | |
| return; | |
| } | |
| try { | |
| await navigator.clipboard.writeText(textToCopy); | |
| // Instant feedback on the button | |
| const original = copyBtn.innerHTML; | |
| copyBtn.innerHTML = "β Copied!"; | |
| copyBtn.classList.add("copied"); | |
| setTimeout(() => { | |
| copyBtn.innerHTML = original; | |
| copyBtn.classList.remove("copied"); | |
| }, 2000); | |
| } catch { | |
| // Fallback for older browsers | |
| const tmp = document.createElement("textarea"); | |
| tmp.value = textToCopy; | |
| document.body.appendChild(tmp); | |
| tmp.select(); | |
| document.execCommand("copy"); | |
| document.body.removeChild(tmp); | |
| copyBtn.innerHTML = "β Copied!"; | |
| setTimeout(() => { | |
| copyBtn.innerHTML = "π Copy Text"; | |
| }, 2000); | |
| } | |
| } | |
| // Ctrl+Enter = humanize | |
| document.addEventListener("keydown", (e) => { | |
| if (e.ctrlKey && e.key === "Enter") { | |
| humanize(); | |
| } | |
| }); | |
| // Auto-resize the input textarea as you type | |
| document.getElementById("inputText").addEventListener("input", function () { | |
| this.style.height = "auto"; | |
| this.style.height = this.scrollHeight + "px"; | |
| }); | |
| </script> | |
| </body> | |
| </html> |