import { NextResponse } from 'next/server'; import { getAdminAuth, getAdminDb } from '@/lib/firebase/admin'; import { GeminiLlmClient } from '@/lib/ai/gemini-client'; import { z } from 'zod'; const MarketResearchSchema = z.object({ targetNiches: z.array(z.object({ name: z.string(), description: z.string(), marketSize: z.string(), competitionLevel: z.enum(['low', 'medium', 'high']), opportunity: z.string(), })), competitors: z.array(z.object({ name: z.string(), positioning: z.string(), strengths: z.array(z.string()), weaknesses: z.array(z.string()), })), marketGaps: z.array(z.object({ gap: z.string(), impact: z.enum(['low', 'medium', 'high']), reasoning: z.string(), })), recommendations: z.array(z.string()), sources: z.array(z.string()), }); export async function POST( request: Request, { params }: { params: Promise<{ projectId: string }> } ) { try { const { projectId } = await params; const authHeader = request.headers.get('Authorization'); if (!authHeader?.startsWith('Bearer ')) { return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); } const token = authHeader.substring(7); const auth = getAdminAuth(); const decoded = await auth.verifyIdToken(token); if (!decoded?.uid) { return NextResponse.json({ error: 'Invalid token' }, { status: 401 }); } // Get project data const adminDb = getAdminDb(); const projectRef = adminDb.collection('projects').doc(projectId); const projectDoc = await projectRef.get(); if (!projectDoc.exists) { return NextResponse.json({ error: 'Project not found' }, { status: 404 }); } const projectData = projectDoc.data(); const productVision = projectData?.productVision || ''; const productName = projectData?.productName || ''; const phaseData = projectData?.phaseData || {}; const canonicalModel = phaseData.canonicalProductModel || {}; // Build context for the agent const ideaContext = canonicalModel.oneLiner || productVision || `${productName}: Help users build and launch products faster`; console.log('[Market Research] Starting research for:', ideaContext); // Initialize LLM client const llm = new GeminiLlmClient(); // Conduct market research using the agent const systemPrompt = `You are a market research analyst specializing in finding product-market fit and identifying underserved niches. Your task is to analyze the given product idea and conduct comprehensive market research to: 1. Identify specific target niches that would benefit most from this product 2. Analyze competitors and their positioning 3. Find market gaps and opportunities 4. Provide actionable recommendations Be specific, data-driven, and focused on actionable insights.`; const userPrompt = `Analyze this product idea and conduct market research: Product Idea: "${ideaContext}" ${canonicalModel.problem ? `Problem Being Solved: ${canonicalModel.problem}` : ''} ${canonicalModel.targetUser ? `Target User: ${canonicalModel.targetUser}` : ''} ${canonicalModel.coreSolution ? `Core Solution: ${canonicalModel.coreSolution}` : ''} Provide a comprehensive market research analysis including: - Target niches with high potential - Competitor analysis - Market gaps and opportunities - Strategic recommendations Focus on finding specific, underserved niches where this product can win.`; const research = await llm.structuredCall({ model: 'gemini', systemPrompt, messages: [ { role: 'user', content: userPrompt, }, ], schema: MarketResearchSchema, temperature: 0.7, }); console.log('[Market Research] Research completed:', { niches: research.targetNiches.length, competitors: research.competitors.length, gaps: research.marketGaps.length, }); // Store research results in Firestore const researchRef = adminDb.collection('marketResearch').doc(); await researchRef.set({ id: researchRef.id, projectId, userId: decoded.uid, research, ideaContext, createdAt: new Date(), updatedAt: new Date(), }); // Also store as knowledge items for vector search const knowledgePromises = []; // Store each niche as a knowledge item for (const niche of research.targetNiches) { const nicheRef = adminDb.collection('knowledge').doc(); knowledgePromises.push( nicheRef.set({ id: nicheRef.id, projectId, userId: decoded.uid, sourceType: 'research', title: `Target Niche: ${niche.name}`, content: `${niche.description}\n\nMarket Size: ${niche.marketSize}\nCompetition: ${niche.competitionLevel}\n\nOpportunity: ${niche.opportunity}`, sourceMeta: { origin: 'vibn', researchType: 'market_niche', researchId: researchRef.id, }, createdAt: new Date(), updatedAt: new Date(), }) ); } // Store market gaps for (const gap of research.marketGaps) { const gapRef = adminDb.collection('knowledge').doc(); knowledgePromises.push( gapRef.set({ id: gapRef.id, projectId, userId: decoded.uid, sourceType: 'research', title: `Market Gap: ${gap.gap.substring(0, 50)}`, content: `${gap.gap}\n\nImpact: ${gap.impact}\n\nReasoning: ${gap.reasoning}`, sourceMeta: { origin: 'vibn', researchType: 'market_gap', researchId: researchRef.id, }, createdAt: new Date(), updatedAt: new Date(), }) ); } await Promise.all(knowledgePromises); console.log('[Market Research] Stored', knowledgePromises.length, 'knowledge items'); return NextResponse.json({ success: true, research, researchId: researchRef.id, knowledgeItemsCreated: knowledgePromises.length, }); } catch (error) { console.error('[Market Research] Error:', error); return NextResponse.json( { error: 'Failed to conduct market research', details: error instanceof Error ? error.message : 'Unknown error' }, { status: 500 } ); } }