Active vs. Passive Voice Analyzer

Active vs. Passive Voice Analyzer

Identify passive sentences to make your writing more direct.

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); });
Scroll to Top