This commit is contained in:
Nico Albanese committed 2024-10-10 08:56:38 +01:00
1 parent 3602e229ec
commit 9a941df84f
3 files changed
+6 -183

No files matched your search

+1 -169
View File
@@ -138,35 +138,7 @@ export const explainQuery = async (input: string, sqlQuery: string) => {
}
};
export const generateAChart = async (results: Result[], userQuery: string) => {
"use server";
try {
const result = await generateObject({
model: openai("gpt-4o"),
system: `You are a data visualization expert. Your job is to suggest the best chart type to represent the given data and provide the necessary information for rendering the chart. Consider the number of data points, the types of variables, and the relationships between them.`,
prompt: `Given the following data from a SQL query result, suggest the best chart type to visualize this information. Provide the columns to use, labels for the chart, and the relevant data points. Also, give a brief explanation for your choice.
Use the right chart type for the user query. For example, if the data is about which country has the most unicorns, you might suggest a pie chart. Or for growth rate, you might suggest a line chart. Show multiple lines where necessary.
In your description, be sure to explain the biggest takeaway from the chart. You can refactor the data and format to fit the chart type and desired takeaway.
You can take liberty with long tail of data if it is not relevant to the chart type. For example, if the user asks for a pie chart of the top 5 countries with the most unicorns, you can ignore the rest of the data.
User Query:
${userQuery}
Data:
${JSON.stringify(results, null, 2)}`,
schema: z.object({ generation: chartGenerationSchema }),
output: "object",
});
return result.object;
} catch (e) {
// @ts-expect-error e
console.error(e.message);
throw new Error("Failed to generate chart suggestion");
}
};
export const generateChart = async (results: Result[], userQuery: string) => {
export const generateChartConfig = async (results: Result[], userQuery: string) => {
"use server";
const system = `You are a data visualization expert. `;
@@ -211,143 +183,3 @@ export const generateChart = async (results: Result[], userQuery: string) => {
throw new Error("Failed to generate chart suggestion");
}
};
export const streamChartData = async (
config: Config,
results: Unicorn[],
userQuery: string,
) => {
const stream = createStreamableValue<string[]>([]);
try {
(async () => {
const { object: dataObj, elementStream } = await streamObject({
model: openai("gpt-4o"),
system: `You are a data visualization expert.`,
prompt: `Given the following available data from a SQL query result, generate the datapoints (in csv format) that best visualises the data and answers the users query.
Here is an example complete data:
month,sales,profit,expenses
January,1000,200,800
February,1200,250,950
March,1500,300,1200
April,1800,350,1450
May,2000,400,1600
June,2200,450,1750
User Query:
${userQuery}
Available Data:
${JSON.stringify(results, null, 2)}
Chart Config to Use to Guide Data Generation:
${JSON.stringify(config)}
Return only the data.
`,
schema: z
.string()
.describe("CSV formatted data points for a chart with a header row"),
output: "array",
});
let items = [];
for await (const el of elementStream) {
items.push(el);
stream.update(items);
}
stream.done(items);
})();
return stream.value;
} catch (e) {
console.error(e);
throw Error();
}
};
export const generateChartData = async (
config: Config,
results: Unicorn[],
userQuery: string,
) => {
try {
const { object: dataObj } = await generateObject({
model: openai("gpt-4o-mini"),
system: `You are a data visualization expert.`,
prompt: `Given the following available data from a SQL query result, generate the datapoints (in csv format) that best visualises the data and answers the users query.
Here is an example complete data:
month,sales,profit,expenses
January,1000,200,800
February,1200,250,950
March,1500,300,1200
April,1800,350,1450
May,2000,400,1600
June,2200,450,1750
User Query:
${userQuery}
Available Data:
${JSON.stringify(results, null, 2)}
Chart Config to Use to Guide Data Generation:
${JSON.stringify(config)}
Return only the data.
`,
schema: z
.object({ data: z.string() })
.describe("CSV formatted data points for a chart with a header row"),
});
return dataObj;
} catch (e) {
console.error(e);
throw Error();
}
};
export const generateChartConfig = async (results: Result[], userQuery: string) => {
"use server";
const system = `You are a SQL and data visualization expert.`;
try {
const { object: config } = await generateObject({
model: openai("gpt-4o"),
system,
prompt: `Given the following data from a SQL query result, generate the chart config that could visualises the data and answers the users query without any data modification.
For multiple groups use multi-lines.
Here is an example complete config:
export const chartConfig = {
type: "pie",
xKey: "month",
yKeys: ["sales", "profit", "expenses"],
colors: {
sales: "#4CAF50", // Green for sales
profit: "#2196F3", // Blue for profit
expenses: "#F44336" // Red for expenses
},
legend: true
}
User Query:
${userQuery}
Data:
${JSON.stringify(results, null, 2)}`,
schema: configSchema,
});
const colors: Record<string, string> = {};
config.yKeys.forEach((key, index) => {
colors[key] = `hsl(var(--chart-${index+1}))`;
});
const updatedConfig: Config = { ...config, colors };
return { config: updatedConfig };
} catch (e) {
// @ts-expect-errore
console.error(e.message);
throw new Error("Failed to generate chart suggestion");
}
};
+4 -7
View File
@@ -14,14 +14,11 @@ import {
} from "@/components/ui/table";
import {
explainQuery,
generateAChart,
generateChart,
generateChartData,
generateChartConfig,
generateQuery,
getCompanies,
streamChartData,
} from "./actions";
import { Config, Data, QueryExplanation, Unicorn } from "@/lib/types";
import { Config, QueryExplanation, Unicorn } from "@/lib/types";
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
import { Info, X, Search, Sparkles, Loader2, BarChart2 } from "lucide-react";
import Link from "next/link";
@@ -105,7 +102,7 @@ export default function Component() {
setResults(companies);
setColumns(columns);
setLoading(false);
const generation = await generateChart(companies, inputValue);
const generation = await generateChartConfig(companies, inputValue);
setChartConfig(generation.config);
};
@@ -167,7 +164,7 @@ export default function Component() {
const handleGenerateChart = async () => {
setIsGeneratingChart(true);
try {
const generation = await generateChart(results, inputValue);
const generation = await generateChartConfig(results, inputValue);
setChartConfig(generation.config);
setIsChartModalOpen(true);
} catch (error) {
+1 -7
View File
@@ -14,20 +14,14 @@ import {
XAxis,
YAxis,
CartesianGrid,
Tooltip,
Legend,
ResponsiveContainer,
} from "recharts";
import {
ChartContainer,
ChartTooltip,
ChartTooltipContent,
} from "@/components/ui/chart";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Loader2 } from "lucide-react";
import { generateChart } from "@/app/actions";
import { Config, Data, Unicorn } from "@/lib/types";
import { Config, Data } from "@/lib/types";
import { Label } from "recharts";
import { transformDataForMultiLineChart } from "@/lib/rechart-format";