import {PromptTemplate} from '@langchain/core/prompts';
import {IVisualizer} from '../types';
import {AiIntegrationBindings} from '../../../keys';
import {LLMProvider} from '../../../types';
import {inject} from '@loopback/core';
import {AnyObject} from '@loopback/repository';
import {VisualizationGraphState} from '../state';
import z from 'zod';
import {RunnableSequence} from '@langchain/core/runnables';
import {visualizer} from '../decorators/visualizer.decorator';
@visualizer()
export class PieVisualizer implements IVisualizer {
name = 'pie';
description = `Renders the data in a pie chart format. Best for visualizing proportions and percentages among categories.`;
renderPrompt = PromptTemplate.fromTemplate(`
You are an expert data visualization assistant. Your task is to create a pie chart config based on the provided SQL query, it's description and user prompt. Follow these steps:
1. Analyze the SQL query results to understand the data structure.
2. Identify the key categories and their corresponding values for the pie chart.
3. Create a configuration object for the pie chart using the identified categories and values.
4. Return the pie chart configuration object.
{sql}
{description}
{userPrompt}
`);
context?: string | undefined =
`A pie chart requires data with at least two columns: one for the labels (categories) and one for the values (numerical data). Ensure that the values are non-negative and represent parts of a whole, as pie charts are used to visualize proportions and percentages among different categories.`;
schema = z.object({
labelColumn: z
.string()
.describe('Column to be used for labels in the pie chart'),
valueColumn: z
.string()
.describe('Column to be used for values in the pie chart'),
}) as z.AnyZodObject;
constructor(
@inject(AiIntegrationBindings.CheapLLM)
private readonly llm: LLMProvider,
) {}
async getConfig(state: VisualizationGraphState): Promise {
if (!state.sql || !state.queryDescription || !state.prompt) {
throw new Error('Invalid State');
}
const llmWithStructuredOutput = this.llm.withStructuredOutput(
this.schema,
);
const chain = RunnableSequence.from([
this.renderPrompt,
llmWithStructuredOutput,
]);
const settings = await chain.invoke({
sql: state.sql!,
description: state.queryDescription!,
userPrompt: state.prompt!,
});
return settings;
}
}