← 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()