VIBN Frontend for Coolify deployment
This commit is contained in:
98
app/api/projects/[projectId]/extract-from-chat/route.ts
Normal file
98
app/api/projects/[projectId]/extract-from-chat/route.ts
Normal 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 },
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user