// Helper function to process a single PDF const processPdf = wrapTraced( async (pdfFile: { filename: string; url: string }) => { console.log(`Processing ${pdfFile.filename}...`); // Fetch and encode the PDF file from URL (with error handling) let pdfData: Buffer; let base64String: string; try { const response = await fetch(pdfFile.url); if (!response.ok) { throw new Error(`HTTP ${response.status} ${response.statusText}`); } const arrayBuffer = await response.arrayBuffer(); pdfData = Buffer.from(arrayBuffer); base64String = pdfData.toString("base64"); } catch (err: any) { console.error(`Failed to download ${pdfFile.url}:`, err); return; // Skip this PDF and continue with the next } const userPrompt = "Please analyze this earnings call transcript"; const rootSpan = currentSpan(); rootSpan.setAttributes({ name: pdfFile.filename }); const rootSpanSlug = currentSpan().export(); // Create chat completion with file data const completion = await client.chat.completions.create({ model: "gpt-4o", messages: [ { role: "system", content: SYSTEM_PROMPT, }, { role: "user", content: [ { type: "file", file: { filename: pdfFile.filename, file_data: `data:application/pdf;base64,${base64String}`, }, }, { type: "text", text: userPrompt, }, ], }, ], max_tokens: 500, }); const summary = completion.choices[0]?.message?.content; // if no summary is generated, log an error and return if (!summary) { console.warn("No summary generated"); return; } // Console log that the summary was created console.log( `\nEarnings Summary for ${pdfFile.filename}: Summary Created! View in the Braintrust UI!\n`, ); // log the output of the LLM call to the root span rootSpan.log({ output: summary, }); // Log system prompt span await logSystemPrompt(pdfFile.filename, pdfFile.url, summary, rootSpanSlug); // Log user prompt span await logUserPrompt( pdfFile.filename, pdfFile.url, userPrompt, summary, rootSpanSlug, base64String, ); }, logger, );