import { Artifact } from '@/components/create-artifact'; import { CodeEditor } from '@/components/code-editor'; import { CopyIcon, LogsIcon, MessageIcon, PlayIcon, RedoIcon, UndoIcon, } from '@/components/icons'; import { toast } from 'sonner'; import { generateUUID } from '@/lib/utils'; import { Console, type ConsoleOutput, type ConsoleOutputContent, } from '@/components/console'; const OUTPUT_HANDLERS = { matplotlib: ` import io import base64 from matplotlib import pyplot as plt # Clear any existing plots plt.clf() plt.close('all') # Switch to agg backend plt.switch_backend('agg') def setup_matplotlib_output(): def custom_show(): if plt.gcf().get_size_inches().prod() * plt.gcf().dpi ** 2 > 25_000_000: print("Warning: Plot size too large, reducing quality") plt.gcf().set_dpi(100) png_buf = io.BytesIO() plt.savefig(png_buf, format='png') png_buf.seek(0) png_base64 = base64.b64encode(png_buf.read()).decode('utf-8') print(f'data:image/png;base64,{png_base64}') png_buf.close() plt.clf() plt.close('all') plt.show = custom_show `, basic: ` # Basic output capture setup `, }; function detectRequiredHandlers(code: string): string[] { const handlers: string[] = ['basic']; if (code.includes('matplotlib') || code.includes('plt.')) { handlers.push('matplotlib'); } return handlers; } interface Metadata { outputs: Array; } export const codeArtifact = new Artifact<'code', Metadata>({ kind: 'code', description: 'Useful for code generation; Code execution is only available for python code.', initialize: async ({ setMetadata }) => { setMetadata({ outputs: [], }); }, onStreamPart: ({ streamPart, setArtifact }) => { if (streamPart.type === 'data-codeDelta') { setArtifact((draftArtifact) => ({ ...draftArtifact, content: streamPart.data, isVisible: draftArtifact.status === 'streaming' && draftArtifact.content.length > 300 && draftArtifact.content.length < 310 ? true : draftArtifact.isVisible, status: 'streaming', })); } }, content: ({ metadata, setMetadata, ...props }) => { return ( <>
{metadata?.outputs && ( { setMetadata({ ...metadata, outputs: [], }); }} /> )} ); }, actions: [ { icon: , label: 'Run', description: 'Execute code', onClick: async ({ content, setMetadata }) => { const runId = generateUUID(); const outputContent: Array = []; setMetadata((metadata) => ({ ...metadata, outputs: [ ...metadata.outputs, { id: runId, contents: [], status: 'in_progress', }, ], })); try { // @ts-expect-error - loadPyodide is not defined const currentPyodideInstance = await globalThis.loadPyodide({ indexURL: 'https://cdn.jsdelivr.net/pyodide/v0.23.4/full/', }); currentPyodideInstance.setStdout({ batched: (output: string) => { outputContent.push({ type: output.startsWith('data:image/png;base64') ? 'image' : 'text', value: output, }); }, }); await currentPyodideInstance.loadPackagesFromImports(content, { messageCallback: (message: string) => { setMetadata((metadata) => ({ ...metadata, outputs: [ ...metadata.outputs.filter((output) => output.id !== runId), { id: runId, contents: [{ type: 'text', value: message }], status: 'loading_packages', }, ], })); }, }); const requiredHandlers = detectRequiredHandlers(content); for (const handler of requiredHandlers) { if (OUTPUT_HANDLERS[handler as keyof typeof OUTPUT_HANDLERS]) { await currentPyodideInstance.runPythonAsync( OUTPUT_HANDLERS[handler as keyof typeof OUTPUT_HANDLERS], ); if (handler === 'matplotlib') { await currentPyodideInstance.runPythonAsync( 'setup_matplotlib_output()', ); } } } await currentPyodideInstance.runPythonAsync(content); setMetadata((metadata) => ({ ...metadata, outputs: [ ...metadata.outputs.filter((output) => output.id !== runId), { id: runId, contents: outputContent, status: 'completed', }, ], })); } catch (error: any) { setMetadata((metadata) => ({ ...metadata, outputs: [ ...metadata.outputs.filter((output) => output.id !== runId), { id: runId, contents: [{ type: 'text', value: error.message }], status: 'failed', }, ], })); } }, }, { icon: , description: 'View Previous version', onClick: ({ handleVersionChange }) => { handleVersionChange('prev'); }, isDisabled: ({ currentVersionIndex }) => { if (currentVersionIndex === 0) { return true; } return false; }, }, { icon: , description: 'View Next version', onClick: ({ handleVersionChange }) => { handleVersionChange('next'); }, isDisabled: ({ isCurrentVersion }) => { if (isCurrentVersion) { return true; } return false; }, }, { icon: , description: 'Copy code to clipboard', onClick: ({ content }) => { navigator.clipboard.writeText(content); toast.success('Copied to clipboard!'); }, }, ], toolbar: [ { icon: , description: 'Add comments', onClick: ({ sendMessage }) => { sendMessage({ role: 'user', parts: [ { type: 'text', text: 'Add comments to the code snippet for understanding', }, ], }); }, }, { icon: , description: 'Add logs', onClick: ({ sendMessage }) => { sendMessage({ role: 'user', parts: [ { type: 'text', text: 'Add logs to the code snippet for debugging', }, ], }); }, }, ], });