Content Topic Clustering Tool

Content Topic Clustering Tool

Organize keywords into relevant topic clusters automatically.

Generated Topic Clusters

Your topic clusters will appear here.
Go to 'Data Configuration' to enter your keywords.

Could not generate clusters. The AI service may be temporarily unavailable.

`; } finally { showLoadingState(false); } } function parseAndRenderClusters(text) { const clustersRaw = text.trim().split(/\n\n+/); let html = ''; const structuredClusters = []; clustersRaw.forEach(clusterBlock => { const lines = clusterBlock.trim().split('\n'); const titleLine = lines.shift() || ''; const titleMatch = titleLine.match(/Cluster:\s*(.*)/); if (!titleMatch) return; const title = titleMatch[1].trim(); const keywords = lines.map(line => (line.match(/-\s*(.*)/)?.[1] || '').trim()).filter(Boolean); if (title && keywords.length > 0) { structuredClusters.push({ title, keywords }); html += `

${title}

${keywords.map(k => `${k}`).join('')}
`; } }); return { structuredClusters, html }; } function renderClusters(text) { const { structuredClusters, html } = parseAndRenderClusters(text); if (structuredClusters.length > 0) { lastGeneratedClusters = structuredClusters; previewPlaceholder.classList.add('hidden'); resultsPreview.innerHTML = html; } else { resultsPreview.innerHTML = `

The AI could not form clusters from the provided keywords. Please try a different or more specific list.

`; } } function showLoadingState(isLoading) { if (isLoading) { previewPlaceholder.classList.add('hidden'); resultsPreview.innerHTML = '
'; generateBtn.disabled = true; generateBtn.textContent = 'Generating...'; showFeedback('AI is clustering keywords...', false, 0); } else { generateBtn.disabled = false; generateBtn.textContent = 'Generate Clusters'; } } downloadPdfBtn.addEventListener('click', () => { if (!lastGeneratedClusters || lastGeneratedClusters.length === 0) { showFeedback('Please generate clusters before downloading.', true, 3000); return; } showFeedback('Generating PDF...', false, 2000); try { const { jsPDF } = window.jspdf; const pdf = new jsPDF({ unit: 'pt', format: 'letter' }); const pageMargin = 72; const pageWidth = pdf.internal.pageSize.getWidth(); const textWidth = pageWidth - (pageMargin * 2); let cursorY = pageMargin; pdf.setFont('Helvetica', 'bold'); pdf.setFontSize(20); pdf.text('Content Topic Cluster Report', pageWidth / 2, cursorY, { align: 'center' }); cursorY += 40; lastGeneratedClusters.forEach(cluster => { pdf.setFont('Helvetica', 'bold'); pdf.setFontSize(14); const titleLines = pdf.splitTextToSize(`Cluster: ${cluster.title}`, textWidth); const keywordsText = cluster.keywords.join(', '); const keywordLines = pdf.splitTextToSize(keywordsText, textWidth - 20); // Indented const totalHeight = (titleLines.length * 16) + (keywordLines.length * 12) + 20; if (cursorY + totalHeight > pdf.internal.pageSize.getHeight() - pageMargin) { pdf.addPage(); cursorY = pageMargin; } pdf.text(titleLines, pageMargin, cursorY); cursorY += titleLines.length * 14 * 1.2; pdf.setFont('Helvetica', 'normal'); pdf.setFontSize(11); pdf.text(keywordLines, pageMargin + 20, cursorY); cursorY += keywordLines.length * 11 * 1.2 + 25; }); pdf.save('topic-cluster-report.pdf'); } catch(err) { console.error("PDF Generation Error: ", err); showFeedback("Error generating PDF.", true, 3000); } }); let feedbackTimeout; function showFeedback(message, isError = false, duration = 3000) { clearTimeout(feedbackTimeout); feedbackMessage.innerHTML = message; feedbackMessage.style.color = isError ? '#ef4444' : '#4a5568'; if (duration !== 0) { feedbackTimeout = setTimeout(() => { feedbackMessage.innerHTML = ''; }, duration); } } });
Scroll to Top