Skip to content

Commit 8c4feb9

Browse files
authored
Merge pull request #617 from CodingCatDev/dev
Prod release
2 parents 768d8a9 + e28b8a6 commit 8c4feb9

File tree

3 files changed

+111
-15
lines changed

3 files changed

+111
-15
lines changed

app/api/cron/check-research/route.ts

Lines changed: 77 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { ArtifactTypeCode, ArtifactStatus } from '@/lib/services/notebooklm/type
1010
import { generateWithGemini, stripCodeFences } from '@/lib/gemini';
1111
import { getConfigValue } from '@/lib/config';
1212
import type { ResearchPayload } from '@/lib/services/research';
13+
import { writeClient } from '@/lib/sanity-write-client';
1314

1415
// ---------------------------------------------------------------------------
1516
// Types
@@ -351,20 +352,77 @@ async function stepInfographicsGenerating(
351352
return { id: doc._id, title: doc.title, step: 'infographics_generating', outcome: 'still_generating' };
352353
}
353354

354-
// Collect infographic URLs from completed artifacts
355+
// Download and upload infographics to Sanity
356+
interface SanityImageRef {
357+
_type: 'image';
358+
_key: string;
359+
alt?: string;
360+
asset: { _type: 'reference'; _ref: string };
361+
}
362+
363+
const infographicRefs: SanityImageRef[] = [];
355364
const infographicUrls: string[] = [];
356-
for (const artifactId of artifactIds) {
365+
366+
for (let i = 0; i < artifactIds.length; i++) {
367+
const artifactId = artifactIds[i];
357368
try {
358-
const url = await nbClient.getInfographicUrl(notebookId, artifactId);
359-
if (url) {
360-
infographicUrls.push(url);
369+
// Step 1: Get the auth-gated URL
370+
const authUrl = await nbClient.getInfographicUrl(notebookId, artifactId);
371+
if (!authUrl) {
372+
console.warn(`[check-research] No URL for artifact ${artifactId}`);
373+
continue;
374+
}
375+
376+
// Step 2: Download PNG with NotebookLM auth cookies
377+
const cookies = nbClient.getCookieHeader();
378+
const imageResponse = await fetch(authUrl, {
379+
headers: { Cookie: cookies },
380+
redirect: 'follow',
381+
});
382+
383+
if (!imageResponse.ok) {
384+
console.warn(`[check-research] Failed to download infographic ${artifactId}: ${imageResponse.status}`);
385+
continue;
361386
}
387+
388+
const contentType = imageResponse.headers.get('content-type') || '';
389+
if (!contentType.includes('image')) {
390+
console.warn(`[check-research] Infographic ${artifactId} returned non-image: ${contentType}`);
391+
continue;
392+
}
393+
394+
const arrayBuffer = await imageResponse.arrayBuffer();
395+
const buffer = Buffer.from(arrayBuffer);
396+
console.log(`[check-research] Downloaded infographic ${i + 1}: ${buffer.length} bytes`);
397+
398+
// Step 3: Upload to Sanity assets
399+
const filename = `infographic-${doc._id}-${i}.png`;
400+
const asset = await writeClient.assets.upload('image', buffer, {
401+
filename,
402+
contentType: 'image/png',
403+
});
404+
405+
console.log(`[check-research] Uploaded to Sanity: ${asset._id}`);
406+
407+
// Step 4: Build image reference for the array field
408+
const artifact = ourArtifacts.find(a => a.id === artifactId);
409+
infographicRefs.push({
410+
_type: 'image',
411+
_key: artifactId.slice(0, 8),
412+
alt: artifact?.title || `Research infographic ${i + 1}`,
413+
asset: { _type: 'reference', _ref: asset._id },
414+
});
415+
416+
// Also store the Sanity CDN URL for researchData backward compat
417+
const cdnUrl = `https://cdn.sanity.io/images/${process.env.NEXT_PUBLIC_SANITY_PROJECT_ID}/${process.env.NEXT_PUBLIC_SANITY_DATASET}/${asset._id.replace('image-', '').replace('-png', '.png').replace('-jpg', '.jpg')}`;
418+
infographicUrls.push(cdnUrl);
419+
362420
} catch (err) {
363-
console.warn(`[check-research] Failed to get infographic URL for ${artifactId}:`, err instanceof Error ? err.message : err);
421+
console.warn(`[check-research] Failed to process infographic ${artifactId}:`, err instanceof Error ? err.message : err);
364422
}
365423
}
366424

367-
console.log(`[check-research] Collected ${infographicUrls.length} infographic URLs`);
425+
console.log(`[check-research] Processed ${infographicRefs.length} infographics (${infographicUrls.length} URLs)`);
368426

369427
// Parse existing research data and add infographic URLs
370428
let researchData: Record<string, unknown> = {};
@@ -377,15 +435,19 @@ async function stepInfographicsGenerating(
377435
}
378436
researchData.infographicUrls = infographicUrls;
379437

380-
await sanity
381-
.patch(doc._id)
382-
.set({
383-
status: 'enriching',
384-
researchData: JSON.stringify(researchData),
385-
})
386-
.commit();
438+
const patchData: Record<string, unknown> = {
439+
status: 'enriching',
440+
researchData: JSON.stringify(researchData),
441+
};
442+
443+
// Add infographic image refs if we have any
444+
if (infographicRefs.length > 0) {
445+
patchData.infographics = infographicRefs;
446+
}
447+
448+
await sanity.patch(doc._id).set(patchData).commit();
387449

388-
console.log(`[check-research] "${doc.title}" → enriching (${infographicUrls.length} infographic URLs)`);
450+
console.log(`[check-research] "${doc.title}" → enriching (${infographicRefs.length} infographics, ${infographicUrls.length} URLs)`);
389451
return { id: doc._id, title: doc.title, step: 'infographics_generating', outcome: 'enriching' };
390452
}
391453

lib/services/notebooklm/client.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,14 @@ export class NotebookLMClient {
9696
return new NotebookLMClient(auth);
9797
}
9898

99+
/**
100+
* Get the raw cookie header string for authenticated fetch calls.
101+
* Useful for downloading auth-gated resources (e.g., infographic images).
102+
*/
103+
getCookieHeader(): string {
104+
return this.auth.cookieHeader;
105+
}
106+
99107
// -------------------------------------------------------------------------
100108
// Internal RPC helper
101109
// -------------------------------------------------------------------------

sanity/schemas/documents/automatedVideo.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,32 @@ export default defineType({
288288
type: 'url',
289289
description: 'Direct URL to the short video (auto-populated from video asset)',
290290
}),
291+
defineField({
292+
name: 'infographics',
293+
title: 'Infographics',
294+
type: 'array',
295+
description: 'Research infographics from NotebookLM — reusable for blog posts and video b-roll',
296+
of: [
297+
{
298+
type: 'image',
299+
options: { hotspot: true },
300+
fields: [
301+
defineField({
302+
name: 'alt',
303+
title: 'Alt Text',
304+
type: 'string',
305+
description: 'Describe the infographic for accessibility',
306+
}),
307+
defineField({
308+
name: 'caption',
309+
title: 'Caption',
310+
type: 'string',
311+
description: 'Optional caption for display',
312+
}),
313+
],
314+
},
315+
],
316+
}),
291317
defineField({
292318
name: 'renderData',
293319
title: 'Render Data',

0 commit comments

Comments
 (0)