Active vs. Passive Voice Analyzer
Identify passive sentences to make your writing more direct.
Voice Analysis Report
0Active Sentences
0Passive Sentences
StrongOverall Voice
Annotated Text
Sentences identified as passive are highlighted. This analysis is a guideline and may not be 100% accurate.
Please enter some text to analyze.
'; return; } // A simplified list of irregular past participles const irregulars = new Set(['been', 'begun', 'broken', 'brought', 'built', 'bought', 'chosen', 'come', 'done', 'drawn', 'driven', 'eaten', 'fallen', 'felt', 'found', 'given', 'gone', 'had', 'heard', 'held', 'kept', 'known', 'left', 'led', 'lost', 'made', 'meant', 'met', 'paid', 'put', 'read', 'run', 'said', 'seen', 'sent', 'shown', 'sung', 'sat', 'spoken', 'spent', 'stood', 'taken', 'taught', 'told', 'thought', 'thrown', 'understood', 'won', 'written']); const isPassive = (sentence) => { // Regex to find a form of 'to be' followed by a word const beVerbs = /\b(am|are|is|was|were|be|being|been)\b/; const match = sentence.toLowerCase().match(beVerbs); if (!match) return false; // Get the word following the 'be' verb const followingText = sentence.slice(match.index + match[0].length).trim(); const nextWord = followingText.split(/\s+/)[0].replace(/[^a-z]/gi, ''); // Check if the next word is a past participle (ends in 'ed' or is in our irregular list) if (nextWord.endsWith('ed') || irregulars.has(nextWord)) { return true; } return false; }; const sentences = text.match(/[^.?!]+[.?!]+(\s|$)/g) || [text]; let passiveCount = 0; let activeCount = 0; let outputHTML = ''; sentences.forEach(sentenceStr => { const sentence = sentenceStr.trim(); if (isPassive(sentence)) { passiveCount++; outputHTML += `${sentence} `; } else { activeCount++; outputHTML += `${sentence} `; } }); analysisOutput.innerHTML = outputHTML; // Update scores activeCountEl.textContent = activeCount; passiveCountEl.textContent = passiveCount; let score = 'Strong'; const totalSentences = activeCount + passiveCount; if (totalSentences > 0) { const passiveRatio = passiveCount / totalSentences; if (passiveRatio > 0.5) score = 'Needs Improvement'; else if (passiveRatio > 0.25) score = 'Fair'; } scoreEl.textContent = score; outputSection.classList.remove('hidden'); }; const downloadPdf = () => { const { jsPDF } = window.jspdf; const doc = new jsPDF({ orientation: 'p', unit: 'mm', format: 'a4' }); const reportTitle = "Voice Analysis Report"; const genDate = new Date().toLocaleDateString('en-US'); const pageWidth = doc.internal.pageSize.getWidth(); const margin = 15; let yPos = 0; // --- PDF Template: Voice Analysis Report --- doc.setFillColor(13, 148, 136); // teal-600 doc.rect(0, 0, pageWidth, 28, 'F'); doc.setFont('helvetica', 'bold'); doc.setFontSize(16); doc.setTextColor(255, 255, 255); doc.text(reportTitle, margin, 18); yPos = 40; // Summary Section doc.setFont('helvetica', 'bold'); doc.setFontSize(12); doc.setTextColor(30, 41, 59); doc.text("Analysis Summary", margin, yPos); yPos += 8; doc.autoTable({ startY: yPos, head: [['Metric', 'Count', 'Recommendation']], body: [ ['Active Sentences', activeCountEl.textContent, 'Good for direct, clear writing.'], ['Passive Sentences', passiveCountEl.textContent, 'Use sparingly. Can be useful but often indirect.'], ['Overall Voice Score', scoreEl.textContent, 'Aim for a "Strong" active voice.'], ], theme: 'striped', headStyles: { fillColor: [15, 118, 110] }, // teal-700 margin: { left: margin, right: margin } }); yPos = doc.autoTable.previous.finalY + 15; // Annotated Text doc.setFont('helvetica', 'bold'); doc.setFontSize(12); doc.setTextColor(30, 41, 59); doc.text("Annotated Text (Passive sentences highlighted)", margin, yPos); yPos += 8; html2canvas(analysisOutput, { scale: 2, useCORS: true }).then(canvas => { const imgData = canvas.toDataURL('image/png'); const imgProps = doc.getImageProperties(imgData); const pdfWidth = pageWidth - (margin * 2); const pdfHeight = (imgProps.height * pdfWidth) / imgProps.width; if (yPos + pdfHeight > 280) { doc.addPage(); yPos = 20; } doc.addImage(imgData, 'PNG', margin, yPos, pdfWidth, pdfHeight); // Footer const pageCount = doc.internal.getNumberOfPages(); for(let i = 1; i <= pageCount; i++) { doc.setPage(i); const footerY = doc.internal.pageSize.getHeight() - 15; doc.setLineWidth(0.2); doc.setDrawColor(94, 234, 212); // teal-300 doc.line(margin, footerY, pageWidth - margin, footerY); doc.setFontSize(8); doc.setTextColor(100, 116, 139); doc.text(`Report Generated on: ${genDate}`, margin, footerY + 8); doc.text(`Page ${i} of ${pageCount}`, pageWidth - margin, footerY + 8, { align: 'right' }); } doc.save(`Voice_Analysis_Report.pdf`); }).catch(err => { console.error("Error generating PDF:", err); alert("Could not generate PDF. See console for details."); }); }; // --- External libraries for PDF --- if (typeof window.jspdf.jsPDF.autoTable !== 'function') { const script = document.createElement('script'); script.src = 'https://cdnjs.cloudflare.com/ajax/libs/jspdf-autotable/3.5.23/jspdf.plugin.autotable.min.js'; document.head.appendChild(script); } // --- Event Listeners --- analyzeBtn.addEventListener('click', analyzeVoice); downloadPdfBtn.addEventListener('click', downloadPdf); });