← back to Goodquestion
src/lib/ai-workflows.ts
509 lines
import JSON5 from 'json5'
import { mcpClient } from './mcp-client'
import { aiProvider } from './ai-provider-multi'
import type { SWOTAnalysis, HistoricalContext, MarketAnalysis, StartupCosts } from '@/types/swot'
/**
* AI Workflow for generating comprehensive SWOT analysis
*/
export class SWOTWorkflow {
/**
* Generate a complete SWOT analysis using Claude and MCP data
*/
async generateAnalysis(
businessName: string,
businessType: string,
location: string
): Promise<SWOTAnalysis> {
// Use Claude directly without MCP for now
const prompt = this.buildSWOTPromptSimple(
businessName,
businessType,
location
)
// Use multi-provider AI with automatic fallback
try {
const response = await aiProvider.generateCompletion(prompt, {
maxTokens: 5000,
temperature: 1.0,
})
console.log(`[SWOT] Generated using ${response.provider}${response.model ? ` (${response.model})` : ''} (${response.tokensUsed} tokens)`)
return this.parseSWOTResponse(response.content, businessName, businessType, location)
} catch (error) {
console.error('[SWOT] Analysis generation failed:', error)
throw error
}
}
private buildSWOTPromptSimple(
businessName: string,
businessType: string,
location: string
): string {
return `You are a business analyst conducting a comprehensive SWOT analysis for a new business venture.
Business Details:
- Name: ${businessName}
- Type: ${businessType}
- Location: ${location}
Using your knowledge of business trends, local market conditions, demographics, and economic factors, please provide a detailed SWOT analysis in the following JSON format:
{
"strengths": [
{
"title": "strength name",
"description": "detailed description",
"impact": "low|medium|high",
"confidence": 0-100,
"category": "competitive|financial|operational|market",
"sources": ["source references"]
}
],
"weaknesses": [
{
"title": "weakness name",
"description": "detailed description",
"impact": "low|medium|high",
"confidence": 0-100,
"category": "cost|market|operational|regulatory",
"sources": ["source references"],
"mitigationStrategy": "how to address this weakness"
}
],
"opportunities": [
{
"title": "opportunity name",
"description": "detailed description",
"impact": "low|medium|high",
"confidence": 0-100,
"category": "market|trend|technology|regulatory",
"timeframe": "immediate|short-term|medium-term|long-term",
"feasibility": 0-100,
"sources": ["source references"]
}
],
"threats": [
{
"title": "threat name",
"description": "detailed description",
"impact": "low|medium|high",
"confidence": 0-100,
"category": "competitive|economic|regulatory|market",
"severity": "low|medium|high|critical",
"likelihood": 0-100,
"sources": ["source references"]
}
],
"overallScore": 0-100,
"recommendation": "go|no-go|proceed-with-caution",
"recommendationReasoning": "detailed explanation"
}
IMPORTANT: Provide exactly 3-4 items for each SWOT category. Keep descriptions concise (under 25 words each). Return ONLY the JSON object, no additional text or markdown.`
}
private parseSWOTResponse(
response: string,
businessName: string,
businessType: string,
location: string
): SWOTAnalysis {
try {
// Extract JSON from response (handling potential markdown formatting)
const jsonMatch = response.match(/\{[\s\S]*\}/)
if (!jsonMatch) {
throw new Error('No valid JSON found in response')
}
// Use JSON5 for more lenient parsing (handles trailing commas, etc.)
const parsed = JSON5.parse(jsonMatch[0])
// Add IDs and ensure all required fields
const addIds = (items: any[]) =>
items.map((item, index) => ({
...item,
id: `${Date.now()}-${index}`,
}))
return {
businessName,
businessType,
location,
dateGenerated: new Date().toISOString(),
strengths: addIds(parsed.strengths || []),
weaknesses: addIds(parsed.weaknesses || []),
opportunities: addIds(parsed.opportunities || []),
threats: addIds(parsed.threats || []),
overallScore: parsed.overallScore || 50,
recommendation: parsed.recommendation || 'proceed-with-caution',
recommendationReasoning: parsed.recommendationReasoning || '',
}
} catch (error) {
console.error('Error parsing SWOT response:', error)
throw new Error('Failed to parse SWOT analysis response')
}
}
}
/**
* AI Workflow for generating historical context and trajectory analysis
*/
export class HistoricalWorkflow {
async generateHistoricalContext(location: string): Promise<HistoricalContext> {
// Use Claude to generate historical context directly
const prompt = `Create a comprehensive historical and economic context analysis for ${location}.
Using your knowledge of the area, provide a concise JSON response with:
1. A brief summary of the area's economic history (1-2 paragraphs, max 150 words)
2. Exactly 5 key historical events that shaped the local economy
3. 2-3 economic trajectory data points (population, employment, or business growth)
IMPORTANT: Keep all text concise. Return ONLY the JSON object, no additional text
Format:
{
"summary": "historical summary text",
"keyEvents": [
{
"year": 1990,
"title": "event name",
"description": "event description",
"economicImpact": "positive|negative|neutral",
"relevance": 0-100
}
],
"trajectories": [
{
"metric": "population",
"data": [{"year": 2000, "value": 50000}],
"trend": "increasing|decreasing|stable"
}
]
}`
// Use multi-provider AI with automatic fallback
try {
const response = await aiProvider.generateCompletion(prompt, {
maxTokens: 3000,
temperature: 1.0,
})
console.log(`[Historical] Generated using ${response.provider}${response.model ? ` (${response.model})` : ''} (${response.tokensUsed} tokens)`)
const jsonMatch = response.content.match(/\{[\s\S]*\}/)
let parsed = {}
if (jsonMatch) {
try {
// Clean up common JSON issues
let jsonString = jsonMatch[0]
.replace(/,(\s*[}\]])/g, '$1') // Remove trailing commas
.replace(/\b(\d+)([a-zA-Z])/g, '$1 $2') // Fix numbers touching letters
// Use JSON5 for more lenient parsing
parsed = JSON5.parse(jsonString)
} catch (parseError) {
console.error('[Historical] JSON Parse Error:', parseError)
console.error('[Historical] Attempted to parse:', jsonMatch[0].substring(0, 500))
// Return empty structure instead of failing
parsed = {
summary: 'Historical context temporarily unavailable',
keyEvents: [],
trajectories: []
}
}
}
return {
areaName: location,
summary: (parsed as any).summary || 'Historical context temporarily unavailable',
keyEvents: (parsed as any).keyEvents || [],
trajectories: (parsed as any).trajectories || [],
}
} catch (error) {
console.error('Historical workflow failed:', error)
// Return fallback data instead of throwing
return {
areaName: location,
summary: 'Historical context temporarily unavailable',
keyEvents: [],
trajectories: []
}
}
}
}
/**
* AI Workflow for generating startup costs breakdown
*/
export class StartupCostsWorkflow {
async generateStartupCosts(
businessType: string,
location: string
): Promise<StartupCosts> {
const prompt = `Create a detailed startup costs breakdown for a ${businessType} in ${location}.
Provide a comprehensive JSON response with:
1. One-time expenses including assets (equipment, furniture, technology, etc.) with purchase vs rental options
2. Recurring monthly expenses
3. Total startup capital required
4. Monthly burn rate and runway estimate
Format:
{
"oneTimeExpenses": {
"assets": [
{
"name": "Commercial espresso machine",
"category": "equipment",
"purchasePrice": 15000,
"rentalRate": {"amount": 500, "period": "monthly"},
"isRental": false,
"quantity": 1,
"description": "Professional grade espresso machine",
"priority": "essential"
}
],
"legalFees": 2000,
"permits": 1500,
"initialInventory": 5000,
"deposits": 10000,
"other": [{"description": "Initial marketing", "amount": 3000}]
},
"recurringExpenses": {
"rent": 4000,
"utilities": 500,
"insurance": 300,
"payroll": 8000,
"marketing": 1000,
"other": [{"description": "Supplies", "amount": 1500}]
},
"totalStartupCapital": 75000,
"monthlyBurnRate": 15300,
"runwayMonths": 12
}
IMPORTANT: Keep descriptions brief (under 20 words each). Include exactly 6-8 specific assets with realistic pricing for ${businessType} in ${location}.
For each asset, determine if purchase or rental makes more sense and provide both options when applicable.
Categories: equipment, furniture, technology, inventory, signage, renovation, other
Priorities: essential, recommended, optional
Return ONLY the JSON object, no additional text.`
// Use multi-provider AI with automatic fallback
try {
const response = await aiProvider.generateCompletion(prompt, {
maxTokens: 5000,
temperature: 1.0,
})
console.log(`[Startup Costs] Generated using ${response.provider}${response.model ? ` (${response.model})` : ''} (${response.tokensUsed} tokens)`)
const jsonMatch = response.content.match(/\{[\s\S]*\}/)
if (!jsonMatch) {
throw new Error('Failed to parse startup costs response')
}
// Use JSON5 for more lenient parsing (handles trailing commas, comments, etc.)
let parsed
try {
parsed = JSON5.parse(jsonMatch[0])
} catch (parseError) {
console.error('JSON Parse Error:', parseError)
console.error('Attempted to parse:', jsonMatch[0].substring(0, 500) + '...')
throw new Error(`Failed to parse startup costs response: ${parseError instanceof Error ? parseError.message : 'Unknown error'}`)
}
// Add IDs to assets
if (parsed.oneTimeExpenses && parsed.oneTimeExpenses.assets) {
parsed.oneTimeExpenses.assets = parsed.oneTimeExpenses.assets.map((asset: any, index: number) => ({
...asset,
id: `asset-${Date.now()}-${index}`,
}))
}
return parsed as StartupCosts
} catch (error) {
console.error('[Startup Costs] Generation failed:', error)
throw error
}
}
}
/**
* AI Workflow for generating market analysis with competitors
*/
export class MarketAnalysisWorkflow {
async generateMarketAnalysis(
businessType: string,
location: string,
radiusMiles: number
): Promise<MarketAnalysis> {
const prompt = `Create a comprehensive market analysis for a ${businessType} in ${location} within ${radiusMiles} mile radius.
Provide detailed market data including:
1. 5-8 real competitors in the area (mix of direct and indirect)
2. Market size calculations (TAM, SAM, SOM)
3. Demographics of target area
4. 5-year income projections (optimistic, realistic, pessimistic scenarios)
Format:
{
"competitors": [
{
"name": "Business Name",
"type": "Coffee Shop|Restaurant|etc",
"distance": 1.5,
"yearEstablished": 2015,
"estimatedRevenue": 500000,
"rating": 4.5
}
],
"marketSize": {
"totalAddressableMarket": 10000000,
"serviceableMarket": 3000000,
"targetMarket": 750000,
"marketSharePotential": 2.5,
"assumptions": [
"assumption 1",
"assumption 2"
]
},
"demographics": {
"population": 50000,
"medianIncome": 75000,
"averageHouseholdSize": 2.5,
"targetDemographicPercentage": 65
},
"incomeProjections": [
{
"year": 1,
"optimistic": 400000,
"realistic": 280000,
"pessimistic": 150000,
"confidence": 75
}
]
}
IMPORTANT:
- Use realistic business names and data for ${location}
- Include 5 years of projections with decreasing confidence over time
- Provide 4-5 market size assumptions explaining your calculations
- Return ONLY the JSON object, no additional text.`
try {
const response = await aiProvider.generateCompletion(prompt, {
maxTokens: 5000,
temperature: 1.0,
})
console.log(`[Market Analysis] Generated using ${response.provider}${response.model ? ` (${response.model})` : ''} (${response.tokensUsed} tokens)`)
const jsonMatch = response.content.match(/\{[\s\S]*\}/)
if (!jsonMatch) {
throw new Error('Failed to parse market analysis response')
}
const parsed = JSON5.parse(jsonMatch[0])
return parsed as MarketAnalysis
} catch (error) {
console.error('[Market Analysis] Generation failed:', error)
throw error
}
}
}
/**
* AI Workflow for generating action plan
*/
export class ActionPlanWorkflow {
async generateActionPlan(
businessType: string,
location: string
): Promise<Array<{
id: string
category: string
title: string
description: string
priority: string
estimatedCost?: number
estimatedTime: string
status: string
dependencies?: string[]
}>> {
const prompt = `Create a detailed action plan for launching a ${businessType} in ${location}.
Provide 12-15 actionable steps covering:
1. Domain registration and online presence
2. Infrastructure setup (servers, tools, etc.)
3. Market research and keyword analysis
4. Marketing campaign setup
5. Development/MVP creation
6. Deployment and operations
7. Legal and regulatory compliance
8. Financial planning and funding
Format:
{
"actionItems": [
{
"category": "domain|infrastructure|research|marketing|development|legal|financial|operations",
"title": "Action title",
"description": "Detailed description of the action (under 30 words)",
"priority": "critical|high|medium|low",
"estimatedCost": 500,
"estimatedTime": "1 day|3 days|1 week|2 weeks|1 month",
"dependencies": ["id1", "id2"]
}
]
}
IMPORTANT:
- Make actions specific to ${businessType} and ${location}
- Include realistic costs and timeframes
- Order actions logically (dependencies first)
- Keep descriptions concise and actionable
- Return ONLY the JSON object, no additional text.`
try {
const response = await aiProvider.generateCompletion(prompt, {
maxTokens: 4000,
temperature: 1.0,
})
console.log(`[Action Plan] Generated using ${response.provider}${response.model ? ` (${response.model})` : ''} (${response.tokensUsed} tokens)`)
const jsonMatch = response.content.match(/\{[\s\S]*\}/)
if (!jsonMatch) {
throw new Error('Failed to parse action plan response')
}
const parsed = JSON5.parse(jsonMatch[0])
// Add IDs and status to each action item
const actionItems = (parsed.actionItems || []).map((item: any, index: number) => ({
...item,
id: `action-${Date.now()}-${index}`,
status: 'not-started',
}))
return actionItems
} catch (error) {
console.error('[Action Plan] Generation failed:', error)
throw error
}
}
}
// Export workflow instances
export const swotWorkflow = new SWOTWorkflow()
export const historicalWorkflow = new HistoricalWorkflow()
export const startupCostsWorkflow = new StartupCostsWorkflow()
export const marketAnalysisWorkflow = new MarketAnalysisWorkflow()
export const actionPlanWorkflow = new ActionPlanWorkflow()