mirror of
https://github.com/enricoros/big-AGI.git
synced 2026-05-11 14:10:15 -07:00
Charts: User Fix.
This commit is contained in:
@@ -22,21 +22,21 @@ const CodeFixes: Record<string, CodeFix> = {
|
||||
|
||||
// See `RenderCodeChartJS`
|
||||
'chartjs-issue': {
|
||||
description: 'Provides the corrected ChartJS configuration code.',
|
||||
systemMessage: `You are an AI assistant that helps fix invalid ChartJS configuration JSON code.
|
||||
When provided with invalid ChartJS code, you analyze it, identify errors, and output a corrected version in valid JSON format.
|
||||
description: 'Provides the corrected Chart.js configuration code.',
|
||||
systemMessage: `You are an AI assistant that helps fix invalid Chart.js configuration JSON code.
|
||||
When provided with invalid Chart.js code, you analyze it, identify errors, and output a corrected version in valid JSON format.
|
||||
Respond only by calling the \`{{functionName}}\` function.`,
|
||||
userInstructionTemplate: `The following ChartJS configuration code is invalid and cannot be parsed:
|
||||
userInstructionTemplate: `The following Chart.js configuration code is invalid and cannot be parsed:
|
||||
\`\`\`json
|
||||
{{codeToFix}}
|
||||
\`\`\`
|
||||
|
||||
{{errorMessageSection}}
|
||||
Please analyze the code, correct any errors, and provide a valid JSON configuration that can be parsed by ChartJS.
|
||||
Please analyze the code, correct any errors, and provide a valid JSON configuration that can be parsed by Chart.js.
|
||||
Call the function \`{{functionName}}\` once, providing the corrected code.`,
|
||||
functionName: 'provide_corrected_chartjs_code',
|
||||
outputSchema: z.object({
|
||||
corrected_code: z.string().describe('The corrected ChartJS configuration code in valid JSON format.'),
|
||||
corrected_code: z.string().describe('The corrected Chart.js configuration code in valid JSON format.'),
|
||||
}),
|
||||
},
|
||||
|
||||
|
||||
@@ -70,13 +70,13 @@ export function aixRequireSingleFunctionCallInvocation(fragments: DMessageConten
|
||||
if (!Array.isArray(fragments) || fragments.length !== 1) {
|
||||
if (AIX_DEBUG_CLIENT_TOOLS)
|
||||
console.error('[DEV] single-function-call: invalid fragments:', fragments, 'for', debugLabel);
|
||||
throw new Error('AIX: Unexpected response for ' + debugLabel);
|
||||
throw new Error('AIX: Unexpected response.');
|
||||
}
|
||||
|
||||
if (!isContentFragment(fragments[0]) || fragments[0].part.pt !== 'tool_invocation') {
|
||||
if (AIX_DEBUG_CLIENT_TOOLS)
|
||||
console.error('[DEV] single-function-call: invalid fragment part:', fragments[0].part, 'for', debugLabel);
|
||||
throw new Error('AIX: Missing tool invocation for ' + debugLabel);
|
||||
throw new Error('AIX: Missing tool invocation.');
|
||||
}
|
||||
|
||||
const { invocation } = fragments[0].part;
|
||||
@@ -84,7 +84,7 @@ export function aixRequireSingleFunctionCallInvocation(fragments: DMessageConten
|
||||
if (invocation.type !== 'function_call' || invocation.name !== expectedFunctionName) {
|
||||
if (AIX_DEBUG_CLIENT_TOOLS)
|
||||
console.error('[DEV] single-function-call: invalid invocation:', invocation, 'for', debugLabel);
|
||||
throw new Error('AIX: Expected a function call to ' + expectedFunctionName + ' for ' + debugLabel);
|
||||
throw new Error('AIX: Expected a function call.');
|
||||
}
|
||||
|
||||
if (!invocation.args) {
|
||||
|
||||
@@ -146,7 +146,7 @@ export function AutoBlocksRenderer(props: {
|
||||
let enhancedStartCollapsed = false;
|
||||
if (bkInput.title === BLOCK_CODE_VND_AGI_CHARTJS) {
|
||||
disableEnhancedRender = false;
|
||||
// For ChartJS charts, at the moment, we use the 'unwanted' refresh at the end of the message to start (that block) without collapse
|
||||
// For Chart.js charts, at the moment, we use the 'unwanted' refresh at the end of the message to start (that block) without collapse
|
||||
enhancedStartCollapsed = bkInput.isPartial;
|
||||
}
|
||||
|
||||
|
||||
@@ -269,7 +269,7 @@ function RenderCodeImpl(props: RenderCodeBaseProps & {
|
||||
</OverlayButton>
|
||||
)}
|
||||
|
||||
{/* SVG, ChartJS, Mermaid, PlantUML -- including a max-out button */}
|
||||
{/* SVG, Chart.js, Mermaid, PlantUML -- including a max-out button */}
|
||||
{(isSVGCode || isChartJSCode || isMermaidCode || isPlantUMLCode) && (
|
||||
<ButtonGroup aria-label='Diagram' sx={overlayGroupWithShadowSx}>
|
||||
{/* Toggle rendering */}
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
import * as React from 'react';
|
||||
|
||||
import type { SxProps } from '@mui/joy/styles/types';
|
||||
import { Box, Typography } from '@mui/joy';
|
||||
import { Box, Button, Typography } from '@mui/joy';
|
||||
import AutoAwesomeIcon from '@mui/icons-material/AutoAwesome';
|
||||
|
||||
import { useAgiFixupCode } from '~/modules/aifn/agicodefixup/useAgiFixupCode';
|
||||
|
||||
import { ChartConstructorType, fixupChartJSObject, useDynamicChartJS } from './useDynamicChartJS';
|
||||
|
||||
@@ -29,6 +32,7 @@ export function RenderCodeChartJS(props: {
|
||||
|
||||
// state
|
||||
const [renderError, setRenderError] = React.useState<string | null>(null);
|
||||
const [fixupError, setFixupError] = React.useState<string | null>(null);
|
||||
const canvasRef = React.useRef<HTMLCanvasElement>(null);
|
||||
const chartInstanceRef = React.useRef<ChartConstructorType | null>(null);
|
||||
|
||||
@@ -43,10 +47,13 @@ export function RenderCodeChartJS(props: {
|
||||
fixupChartJSObject(config);
|
||||
return { chartConfig: config, parseError: null };
|
||||
} catch (error: any) {
|
||||
return { chartConfig: null, parseError: 'Invalid Chart.js input: ' + (error.message || 'Unknown error.') };
|
||||
return { chartConfig: null, parseError: error.message as string || 'Unknown error.' };
|
||||
}
|
||||
}, [props.chartJSCode]);
|
||||
|
||||
// AI functions
|
||||
const { isFetching, refetch } = useAgiFixupCode('chartjs-issue', false, props.chartJSCode, parseResult.parseError);
|
||||
|
||||
|
||||
// Rendering
|
||||
React.useEffect(() => {
|
||||
@@ -72,6 +79,24 @@ export function RenderCodeChartJS(props: {
|
||||
}, [chartJS, parseResult.chartConfig]);
|
||||
|
||||
|
||||
// handlers
|
||||
|
||||
const { onReplaceInCode } = props;
|
||||
|
||||
const handleChartRegenerate = React.useCallback(async () => {
|
||||
if (!onReplaceInCode) return;
|
||||
setFixupError(null);
|
||||
refetch().then((result) => {
|
||||
if (result.data)
|
||||
onReplaceInCode(props.chartJSCode, result.data);
|
||||
else if (result.error)
|
||||
setFixupError(result.error.message || 'Unknown error.');
|
||||
else
|
||||
setFixupError('Unknown Fixup error.');
|
||||
});
|
||||
}, [onReplaceInCode, props.chartJSCode, refetch]);
|
||||
|
||||
|
||||
// Handle all the non-chart states
|
||||
switch (true) {
|
||||
case isLibraryLoading:
|
||||
@@ -80,8 +105,38 @@ export function RenderCodeChartJS(props: {
|
||||
return null;
|
||||
case !!loadingError:
|
||||
return <Typography level='body-sm' color='danger'>{loadingError}</Typography>;
|
||||
case !!parseResult.parseError:
|
||||
return <Typography level='body-sm' color='warning'>{parseResult.parseError}</Typography>;
|
||||
case !!parseResult.parseError || !!fixupError:
|
||||
return (
|
||||
<Box sx={{ display: 'grid', gap: 1, justifyItems: 'start' }}>
|
||||
{props.onReplaceInCode && (
|
||||
<Button
|
||||
size='sm'
|
||||
variant='outlined'
|
||||
color='success'
|
||||
onClick={handleChartRegenerate}
|
||||
loading={isFetching}
|
||||
loadingPosition='end'
|
||||
sx={{
|
||||
minWidth: 160,
|
||||
backgroundColor: 'background.surface',
|
||||
boxShadow: 'xs',
|
||||
}}
|
||||
endDecorator={<AutoAwesomeIcon />}
|
||||
>
|
||||
{isFetching ? 'Fixing Chart...' : 'Fix Chart'}
|
||||
</Button>
|
||||
)}
|
||||
{fixupError ? (
|
||||
<Typography level='body-sm' color='danger'>
|
||||
Error fixing chart: {fixupError}
|
||||
</Typography>
|
||||
) : (parseResult.parseError && !isFetching) && (
|
||||
<Typography level='body-xs'>
|
||||
Invalid Chart.js input: {parseResult.parseError}
|
||||
</Typography>
|
||||
)}
|
||||
</Box>
|
||||
);
|
||||
case !!renderError:
|
||||
return <Typography level='body-sm' color='warning' variant='plain'>{renderError}</Typography>;
|
||||
}
|
||||
|
||||
@@ -84,10 +84,10 @@ export function bareBonesPromptMixer(_template: string, assistantLlmId: DLLMId |
|
||||
mixed = mixed.replace('{{PreferTables}}', 'Data presentation: prefer tables (auto-columns)');
|
||||
// {{Render...}}
|
||||
mixed = mixed.replace('{{RenderChartJS}}', `
|
||||
When presenting data that would be better visualized as a chart, output a ChartJS configuration object in this format:
|
||||
When presenting data that would be better visualized as a chart, output a Chart.js configuration object in this format:
|
||||
\`\`\`chartjs
|
||||
{
|
||||
// Valid and complete ChartJS configuration JSON (DO NOT USE FUNCTIONS)
|
||||
// Valid and complete Chart.js configuration JSON (DO NOT USE FUNCTIONS)
|
||||
}
|
||||
\`\`\`
|
||||
Choose the most suitable chart type based on the data and context. Include only the JSON configuration, without any explanatory text. Ensure the JSON is valid and complete.
|
||||
|
||||
Reference in New Issue
Block a user