VIBN Frontend for Coolify deployment

This commit is contained in:
2026-02-15 19:25:52 -08:00
commit 40bf8428cd
398 changed files with 76513 additions and 0 deletions

View File

@@ -0,0 +1,98 @@
import { NextResponse } from 'next/server';
import { FieldValue } from 'firebase-admin/firestore';
import { GeminiLlmClient } from '@/lib/ai/gemini-client';
import { runChatExtraction } from '@/lib/ai/chat-extractor';
import { getKnowledgeItem } from '@/lib/server/knowledge';
import { createChatExtraction } from '@/lib/server/chat-extraction';
import { getAdminDb } from '@/lib/firebase/admin';
import type { ProjectPhaseScores } from '@/lib/types/project-artifacts';
interface ExtractFromChatRequest {
knowledgeItemId?: string;
}
// Increase Vercel/Next timeout for large transcripts
export const maxDuration = 60;
export async function POST(
request: Request,
{ params }: { params: Promise<{ projectId: string }> },
) {
try {
const { projectId } = await params;
if (!projectId) {
return NextResponse.json({ error: 'Missing projectId' }, { status: 400 });
}
const body = (await request.json()) as ExtractFromChatRequest;
const knowledgeItemId = body.knowledgeItemId?.trim();
if (!knowledgeItemId) {
return NextResponse.json({ error: 'knowledgeItemId is required' }, { status: 400 });
}
const knowledgeItem = await getKnowledgeItem(projectId, knowledgeItemId);
if (!knowledgeItem) {
return NextResponse.json({ error: 'Knowledge item not found' }, { status: 404 });
}
console.log(`[extract-from-chat] Starting extraction for knowledgeItemId=${knowledgeItemId}, content length=${knowledgeItem.content.length}`);
const llm = new GeminiLlmClient();
const extractionData = await runChatExtraction(knowledgeItem, llm);
console.log(`[extract-from-chat] Extraction complete for knowledgeItemId=${knowledgeItemId}`);
const overallCompletion = extractionData.summary_scores.overall_completion ?? 0;
const overallConfidence = extractionData.summary_scores.overall_confidence ?? 0;
const extraction = await createChatExtraction({
projectId,
knowledgeItemId,
data: extractionData,
overallCompletion,
overallConfidence,
});
const adminDb = getAdminDb();
const projectRef = adminDb.collection('projects').doc(projectId);
const snapshot = await projectRef.get();
const docData = snapshot.data() ?? {};
const existingScores = (docData.phaseScores ?? {}) as ProjectPhaseScores;
const phaseHistory = Array.isArray(docData.phaseHistory) ? [...docData.phaseHistory] : [];
phaseHistory.push({
phase: 'extractor',
status: 'completed',
knowledgeItemId,
timestamp: new Date().toISOString(),
});
existingScores.extractor = {
knowledgeItemId,
overallCompletion,
overallConfidence,
updatedAt: new Date().toISOString(),
};
await projectRef.set(
{
currentPhase: 'analyzed',
phaseScores: existingScores,
phaseStatus: 'in_progress',
phaseHistory,
updatedAt: FieldValue.serverTimestamp(),
},
{ merge: true },
);
return NextResponse.json({ extraction });
} catch (error) {
console.error('[extract-from-chat] Extraction failed', error);
return NextResponse.json(
{
error: 'Failed to extract product signals',
details: error instanceof Error ? error.message : String(error),
},
{ status: 500 },
);
}
}