feat: Refine keyword generation logic, enforce Serper API usage, and enhance search query construction with platform-specific templates.

This commit is contained in:
2026-02-03 22:52:13 +00:00
parent 358f2a42dd
commit f9222627ef
7 changed files with 274 additions and 209 deletions

View File

@@ -86,36 +86,59 @@ Include: Direct competitors (same space), Big players, Popular alternatives, Too
}
async function generateKeywords(features: Feature[], content: ScrapedContent, competitors: Competitor[]): Promise<Keyword[]> {
const systemPrompt = `Generate SEO keywords. PRIORITY: 1) Single words, 2) Differentiation keywords showing competitive advantage.`
const systemPrompt = `Generate search-ready phrases users would actually type.`
const featuresText = features.map(f => f.name).join(', ')
const competitorNames = competitors.map(c => c.name).filter(n => n.length > 1).join(', ') || 'Jira, Asana, Monday, Trello'
const prompt = `Generate 60-80 keywords for: ${content.title}
const prompt = `Generate 60-80 search phrases for: ${content.title}
Features: ${featuresText}
Competitors: ${competitorNames}
CRITICAL - Follow this priority:
1. 40% SINGLE WORDS (e.g., "tracker", "automate", "sync", "fast")
2. 30% DIFFERENTIATION keywords (e.g., "vs-jira", "asana-alternative", "faster", "simpler")
3. 30% Short 2-word phrases only when needed
1. 60% 2-4 word phrases (e.g., "client onboarding checklist", "bug triage workflow")
2. 25% differentiation phrases (e.g., "asana alternative", "faster than jira")
3. 15% single-word brand terms only (product/competitor names)
Return JSON: {"keywords": [{"term": "word", "type": "differentiator|product|feature|problem|solution|competitor", "searchVolume": "high|medium|low", "intent": "informational|navigational|transactional", "funnel": "awareness|consideration|decision", "emotionalIntensity": "frustrated|curious|ready"}]}
Return JSON: {"keywords": [{"term": "phrase", "type": "differentiator|product|feature|problem|solution|competitor", "searchVolume": "high|medium|low", "intent": "informational|navigational|transactional", "funnel": "awareness|consideration|decision", "emotionalIntensity": "frustrated|curious|ready"}]}
Generate 20+ differentiator keywords comparing to: ${competitorNames}`
Generate 20+ differentiator phrases comparing to: ${competitorNames}`
const result = await aiGenerate<{ keywords: Keyword[] }>(prompt, systemPrompt, 0.4)
const stopTerms = new Set([
'platform',
'solution',
'tool',
'software',
'app',
'system',
'product',
'service',
])
const normalized = result.keywords
.map((keyword) => ({ ...keyword, term: keyword.term.trim() }))
.filter((keyword) => keyword.term.length > 2)
.filter((keyword) => {
const words = keyword.term.split(/\s+/).filter(Boolean)
if (words.length === 1) {
return keyword.type === 'product' || keyword.type === 'competitor' || keyword.type === 'differentiator'
}
return words.length <= 4
})
.filter((keyword) => !stopTerms.has(keyword.term.toLowerCase()))
const result = await aiGenerate<{ keywords: Keyword[] }>(prompt, systemPrompt, 0.5)
// Sort: differentiators first, then by word count
return result.keywords.sort((a, b) => {
return normalized.sort((a, b) => {
const aDiff = a.type === 'differentiator' ? 0 : 1
const bDiff = b.type === 'differentiator' ? 0 : 1
if (aDiff !== bDiff) return aDiff - bDiff
const aWords = a.term.split(/\s+/).length
const bWords = b.term.split(/\s+/).length
if (aWords !== bWords) return aWords - bWords
return a.term.length - b.term.length
}).slice(0, 80)
}
@@ -249,10 +272,8 @@ export async function performDeepAnalysis(
console.log(' 🎯 Pass 4: Problems...')
await onProgress?.({ key: "problems", status: "running" })
const [problems, personas] = await Promise.all([
identifyProblems(features, content),
generatePersonas(content, [])
])
const problems = await identifyProblems(features, content)
const personas = await generatePersonas(content, problems)
console.log(`${problems.length} problems, ${personas.length} personas`)
await onProgress?.({
key: "problems",