Skip to content

Instantly share code, notes, and snippets.

@patrickloeber
Last active August 5, 2025 07:48
Show Gist options
  • Select an option

  • Save patrickloeber/87a4c7ff615a9f3bb8874a332cceca90 to your computer and use it in GitHub Desktop.

Select an option

Save patrickloeber/87a4c7ff615a9f3bb8874a332cceca90 to your computer and use it in GitHub Desktop.
AI SDK + Gemini market researcher example
import { google } from "@ai-sdk/google";
import { z } from "zod";
import { generateText, generateObject } from "ai";
import "dotenv/config";
import puppeteer from "puppeteer";
import { ChartConfiguration } from "chart.js";
function createChartConfig({labels, data, label, type, colors,}: {
labels: string[];
data: number[];
label: string;
type: "bar" | "line";
colors: string[];
}): ChartConfiguration {
return {
type: type,
data: {
labels: labels,
datasets: [
{
label: label,
data: data,
borderWidth: 1,
...(type === "bar" && { backgroundColor: colors }),
...(type === "line" && colors.length > 0 && { borderColor: colors[0] }),
},
],
},
options: {
animation: { duration: 0 },
},
};
}
async function main() {
// Step 1: Search market trends
const { text: marketTrends } = await generateText({
model: google("gemini-2.5-flash"),
tools: {
google_search: google.tools.googleSearch({}),
},
prompt: `Search the web for market trends for plant-based milk in North America for 2024-2025.
I need to know the market size, key players and their market share, and primary consumer drivers.
`,
});
console.log(marketTrends);
// Step 2: Extract chart data
const { object } = await generateObject({
model: google("gemini-2.5-flash"),
schema: z.object({
chartConfigurations: z
.array(
z.object({
type: z.enum(["bar", "line"]).describe('The type of chart to generate. Either "bar" or "line"',),
labels: z.array(z.string()).describe("A list of chart labels"),
data: z.array(z.number()).describe("A list of the chart data"),
label: z.string().describe("A label for the chart"),
colors: z.array(z.string()).describe('A list of colors to use for the chart, e.g. "rgba(255, 99, 132, 0.8)"',),
}),
)
.describe("A list of chart configurations"),
}),
prompt: `Given the following market trends text, come up with a list of 1-3 meaningful bar or line charts
and generate chart data.
Market Trends:
${marketTrends}
`,
});
// Step 3: Create chart configs
const chartConfigs = object.chartConfigurations.map((config) =>
createChartConfig(config),
);
// Step 4: Write final HTML report
const { text: html } = await generateText({
model: google("gemini-2.5-flash"),
prompt: `You are an expert report writer. Combine the market trends and the chart data into one HTML report.
Below is an example HTML code needed to generate one example graph. Use this snippet to create the charts:
<!DOCTYPE html>
<html>
<head>
<title>Chart</title>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<body>
<div style="width: 800px; height: 600px;">
<canvas id="myChart"></canvas>
</div>
<script>
const ctx = document.getElementById('myChart').getContext('2d');
new Chart(ctx, configuration);
</script>
</body>
</html>
Market Trends:
${marketTrends}
Chart configurations:
${JSON.stringify(chartConfigs)}
Return only the HTML code.`,
});
// Step 5: Save report to PDF
let finalHtml = html;
if (finalHtml.startsWith("```html")) {
finalHtml = finalHtml.substring(7);
}
if (finalHtml.endsWith("```")) {
finalHtml = finalHtml.slice(0, -3);
}
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.setContent(finalHtml);
await page.pdf({ path: "report.pdf", format: "A4" });
await browser.close();
}
main().catch(console.error);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment