import { GoogleGenAI, FileState, createPartFromUri, createUserContent, type File } from '@google/genai'; import type { AudioTrack } from './recorder.js'; import { buildPrompt } from './prompt.js'; const ai = new GoogleGenAI({ apiKey: process.env.GEMINI_API_KEY }); const MODEL = process.env.GEMINI_MODEL || 'gemini-2.5-flash'; const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms)); async function upload(track: AudioTrack): Promise { let file = await ai.files.upload({ file: track.file, config: { mimeType: 'audio/ogg', displayName: track.name } }); while (file.state === FileState.PROCESSING) { await sleep(2000); file = await ai.files.get({ name: file.name! }); } if (file.state === FileState.FAILED) throw new Error(`Gemini no pudo procesar el audio de ${track.name}`); return file; } export async function generateNotes(tracks: AudioTrack[], startedAt: Date): Promise { const files: File[] = []; try { for (const track of tracks) files.push(await upload(track)); const parts = tracks.flatMap((track, i) => [ `Pista ${i + 1}: ${track.name}`, createPartFromUri(files[i].uri!, files[i].mimeType!), ]); const res = await ai.models.generateContent({ model: MODEL, contents: createUserContent([buildPrompt(tracks.map((t) => t.name), startedAt), ...parts]), }); const text = res.text?.trim(); if (!text) throw new Error('Gemini devolvió una respuesta vacía'); return text.replace(/^```(?:markdown|md)?\n([\s\S]*)\n```$/, '$1'); } finally { await Promise.allSettled(files.map((f) => ai.files.delete({ name: f.name! }))); } }