Files
ALwrity/frontend/src/utils/researchAngles.ts
2025-11-05 08:51:00 +05:30

194 lines
5.9 KiB
TypeScript

/**
* Alternative Research Angles Utility
* Generates related research angles based on user query intent using rule-based patterns
*/
// Pattern-based angle generation templates
const anglePatterns: Record<string, string[]> = {
tools: [
'Compare {topic}',
'{topic} ROI analysis',
'Best {topic} for {industry}',
'{topic} implementation guide',
'Top {topic} features and pricing',
],
trends: [
'Latest {topic} trends',
'{topic} market analysis',
'{topic} future predictions',
'{topic} adoption rates',
'Emerging {topic} technologies',
],
strategies: [
'{topic} implementation guide',
'{topic} best practices',
'{topic} case studies',
'{topic} success strategies',
'{topic} optimization techniques',
],
analysis: [
'{topic} competitive analysis',
'{topic} market share',
'{topic} industry leaders',
'{topic} SWOT analysis',
'{topic} benchmarking',
],
guides: [
'{topic} getting started guide',
'{topic} for beginners',
'{topic} step-by-step tutorial',
'{topic} troubleshooting',
'{topic} expert tips',
],
comparison: [
'{topic} vs alternatives',
'Best {topic} comparison',
'{topic} feature comparison',
'{topic} pricing comparison',
'{topic} pros and cons',
],
general: [
'What is {topic}',
'How {topic} works',
'{topic} benefits and challenges',
'{topic} industry insights',
'{topic} expert opinions',
],
};
// Keywords that indicate query intent
const intentKeywords: Record<string, string[]> = {
tools: ['tools', 'software', 'platform', 'system', 'solution', 'app', 'application', 'toolkit', 'suite'],
trends: ['trends', 'future', 'emerging', 'latest', 'new', 'innovation', 'development', 'growth'],
strategies: ['strategy', 'plan', 'approach', 'method', 'best practices', 'how to', 'guide', 'implementation'],
analysis: ['analysis', 'compare', 'review', 'evaluate', 'assessment', 'study', 'research'],
guides: ['guide', 'tutorial', 'how to', 'getting started', 'learn', 'tips', 'advice'],
comparison: ['vs', 'versus', 'compare', 'comparison', 'alternative', 'difference'],
};
/**
* Detects the primary intent of a query
*/
function detectQueryIntent(query: string): string {
const queryLower = query.toLowerCase();
// Check each intent category
for (const [intent, keywords] of Object.entries(intentKeywords)) {
if (keywords.some(keyword => queryLower.includes(keyword))) {
return intent;
}
}
return 'general';
}
/**
* Extracts the main topic from a query
*/
function extractTopic(query: string, industry: string): string {
// Remove common intent words to get the core topic
const intentWords = Object.values(intentKeywords).flat();
let topic = query.toLowerCase();
// Remove intent keywords
for (const word of intentWords) {
const regex = new RegExp(`\\b${word}\\b`, 'gi');
topic = topic.replace(regex, '').trim();
}
// Clean up extra whitespace and common stop words
topic = topic
.replace(/\s+/g, ' ')
.replace(/\b(a|an|the|in|on|at|for|with|to|of|and|or|but)\b/g, '')
.trim();
// If topic is too short or empty, use original query
if (topic.length < 3 || topic.split(' ').length === 0) {
topic = query.toLowerCase();
}
// Capitalize first letter
return topic.charAt(0).toUpperCase() + topic.slice(1);
}
/**
* Generates alternative research angles based on user query
* @param query - User's research query/keywords
* @param industry - Selected industry (optional)
* @returns Array of alternative research angle suggestions
*/
export function generateResearchAngles(query: string, industry: string = 'General'): string[] {
if (!query || query.trim().length === 0) {
return [];
}
// Detect primary intent
const intent = detectQueryIntent(query);
// Extract main topic
const topic = extractTopic(query, industry);
// Get patterns for detected intent (fallback to general)
const patterns = anglePatterns[intent] || anglePatterns.general;
// Generate angles using patterns
const angles: string[] = [];
for (const pattern of patterns.slice(0, 5)) { // Limit to 5 angles
let angle = pattern.replace('{topic}', topic);
// Replace industry placeholder if present
if (industry && industry !== 'General') {
angle = angle.replace('{industry}', industry);
} else {
// Remove industry-specific placeholder if no industry
angle = angle.replace(' for {industry}', '');
}
// Capitalize first letter
angle = angle.charAt(0).toUpperCase() + angle.slice(1);
// Skip if angle is too similar to original query
const angleLower = angle.toLowerCase();
const queryLower = query.toLowerCase();
if (angleLower !== queryLower && !queryLower.includes(angleLower) && !angleLower.includes(queryLower)) {
angles.push(angle);
}
}
// Add industry-specific angle if industry is set
if (industry && industry !== 'General' && angles.length < 5) {
const industryAngle = `${topic} in ${industry} industry`;
if (!angles.some(a => a.toLowerCase() === industryAngle.toLowerCase())) {
angles.push(industryAngle);
}
}
// If we have fewer than 3 angles, add some general ones
if (angles.length < 3) {
const generalPatterns = anglePatterns.general.slice(0, 3 - angles.length);
for (const pattern of generalPatterns) {
const angle = pattern.replace('{topic}', topic);
if (!angles.some(a => a.toLowerCase() === angle.toLowerCase())) {
angles.push(angle);
}
}
}
// Remove duplicates and limit to 5
const uniqueAngles = Array.from(new Set(angles.map(a => a.toLowerCase())))
.slice(0, 5)
.map(a => a.charAt(0).toUpperCase() + a.slice(1));
return uniqueAngles;
}
/**
* Formats an angle for display
*/
export function formatAngle(angle: string): string {
if (!angle) return angle;
return angle.charAt(0).toUpperCase() + angle.slice(1);
}