Skip to content

Commit 7e0f911

Browse files
Miriadresearch
andcommitted
refactor: make ingest fire-and-forget for NotebookLM research
When ENABLE_NOTEBOOKLM_RESEARCH is set: - Creates notebook + adds sources + starts research (~10s) - Does NOT poll for completion (was blocking 10+ min) - Generates basic script without research data - Creates Sanity doc with status "researching" - Stores researchNotebookId + researchTaskId on doc - check-research cron will poll and enrich later When research is NOT enabled: - Behavior unchanged — straight to "script_ready" Removes conductResearch() import (blocking call). Co-authored-by: research <research@miriad.systems>
1 parent 61a25d8 commit 7e0f911

File tree

1 file changed

+46
-15
lines changed

1 file changed

+46
-15
lines changed

app/api/cron/ingest/route.ts

Lines changed: 46 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ import type { NextRequest } from "next/server";
55
import { generateWithGemini, stripCodeFences } from "@/lib/gemini";
66
import { writeClient } from "@/lib/sanity-write-client";
77
import { discoverTrends, type TrendResult } from "@/lib/services/trend-discovery";
8-
import { conductResearch, type ResearchPayload } from "@/lib/services/research";
8+
import type { ResearchPayload } from "@/lib/services/research";
9+
import { NotebookLMClient } from "@/lib/services/notebooklm/client";
10+
import { initAuth } from "@/lib/services/notebooklm/auth";
911

1012
// ---------------------------------------------------------------------------
1113
// Types
@@ -329,8 +331,12 @@ async function createSanityDocuments(
329331
criticResult: CriticResult,
330332
trends: TrendResult[],
331333
research?: ResearchPayload,
334+
researchMeta?: { notebookId: string; taskId: string },
332335
) {
333336
const isFlagged = criticResult.score < 50;
337+
// When research is in-flight, status is "researching" (check-research cron will transition to script_ready)
338+
const isResearching = !!researchMeta?.notebookId;
339+
const status = isFlagged ? "flagged" : isResearching ? "researching" : "script_ready";
334340

335341
const contentIdea = await writeClient.create({
336342
_type: "contentIdea",
@@ -360,21 +366,22 @@ async function createSanityDocuments(
360366
})),
361367
},
362368
scriptQualityScore: criticResult.score,
363-
status: isFlagged ? "flagged" : "script_ready",
369+
status,
364370
...(isFlagged && {
365371
flaggedReason: `Quality score ${criticResult.score}/100. Issues: ${criticResult.issues.join("; ") || "Low quality score"}`,
366372
}),
367373
trendScore: trends[0]?.score,
368374
trendSources: trends[0]?.signals.map(s => s.source).join(", "),
369-
researchNotebookId: research?.notebookId,
375+
researchNotebookId: researchMeta?.notebookId ?? research?.notebookId,
376+
...(researchMeta?.taskId && { researchTaskId: researchMeta.taskId }),
370377
});
371378

372379
console.log(`[CRON/ingest] Created automatedVideo: ${automatedVideo._id}`);
373380

374381
return {
375382
contentIdeaId: contentIdea._id,
376383
automatedVideoId: automatedVideo._id,
377-
status: isFlagged ? "flagged" : "script_ready",
384+
status,
378385
};
379386
}
380387

@@ -409,26 +416,49 @@ export async function GET(request: NextRequest) {
409416
trends = FALLBACK_TRENDS;
410417
}
411418

412-
// Step 2: Optional deep research on top topic
413-
let research: ResearchPayload | undefined;
419+
// Step 2: Optional deep research on top topic (fire-and-forget)
420+
// When research is enabled, we create a notebook and start research
421+
// but DON'T wait for it — the check-research cron will poll and enrich later
422+
let researchMeta: { notebookId: string; taskId: string } | undefined;
414423
if (process.env.ENABLE_NOTEBOOKLM_RESEARCH === "true") {
415-
console.log(`[CRON/ingest] Conducting research on: "${trends[0].topic}"...`);
424+
console.log(`[CRON/ingest] Starting fire-and-forget research on: "${trends[0].topic}"...`);
416425
try {
417-
// Extract source URLs from trend signals to seed the notebook
426+
const auth = await initAuth();
427+
const nbClient = new NotebookLMClient(auth);
428+
429+
// Create notebook
430+
const notebook = await nbClient.createNotebook(trends[0].topic);
431+
const notebookId = notebook.id;
432+
console.log(`[CRON/ingest] Created notebook: ${notebookId}`);
433+
434+
// Add source URLs from trend signals
418435
const sourceUrls = (trends[0].signals ?? [])
419436
.map((s: { url?: string }) => s.url)
420437
.filter((u): u is string => !!u && u.startsWith("http"))
421438
.slice(0, 5);
422-
research = await conductResearch(trends[0].topic, { sourceUrls });
423-
console.log(`[CRON/ingest] Research complete: ${research.sources.length} sources, ${research.sceneHints.length} scene hints`);
439+
440+
for (const url of sourceUrls) {
441+
await nbClient.addSource(notebookId, url).catch((err) => {
442+
console.warn(`[CRON/ingest] Failed to add source ${url}:`, err);
443+
});
444+
}
445+
console.log(`[CRON/ingest] Added ${sourceUrls.length} source URLs to notebook`);
446+
447+
// Start deep research (fire-and-forget — don't poll!)
448+
const researchTask = await nbClient.startResearch(notebookId, trends[0].topic, "deep");
449+
const researchTaskId = researchTask?.taskId ?? "";
450+
console.log(`[CRON/ingest] Research started — taskId: ${researchTaskId}. check-research cron will poll.`);
451+
452+
researchMeta = { notebookId, taskId: researchTaskId };
424453
} catch (err) {
425-
console.warn("[CRON/ingest] Research failed, continuing without:", err);
454+
console.warn("[CRON/ingest] Research start failed, continuing without:", err);
426455
}
427456
}
428457

429-
// Step 3: Generate script with Gemini (enriched with research)
458+
// Step 3: Generate script with Gemini (basic — without research data)
459+
// When research is enabled, check-research will re-generate an enriched script later
430460
console.log("[CRON/ingest] Generating script with Gemini...");
431-
const prompt = buildPrompt(trends, research);
461+
const prompt = buildPrompt(trends);
432462
const rawResponse = await generateWithGemini(prompt, SYSTEM_INSTRUCTION);
433463

434464
let script: GeneratedScript;
@@ -459,7 +489,7 @@ export async function GET(request: NextRequest) {
459489
);
460490

461491
console.log("[CRON/ingest] Creating Sanity documents...");
462-
const result = await createSanityDocuments(script, criticResult, trends, research);
492+
const result = await createSanityDocuments(script, criticResult, trends, undefined, researchMeta);
463493

464494
console.log("[CRON/ingest] Done!", result);
465495

@@ -470,7 +500,8 @@ export async function GET(request: NextRequest) {
470500
criticScore: criticResult.score,
471501
trendCount: trends.length,
472502
trendScore: trends[0]?.score,
473-
researchEnabled: !!research,
503+
researchStarted: !!researchMeta,
504+
researchNotebookId: researchMeta?.notebookId,
474505
});
475506
} catch (err) {
476507
console.error("[CRON/ingest] Unexpected error:", err);

0 commit comments

Comments
 (0)