vision-agent / lib /utils /content.ts
MingruiZhang's picture
feat: Code result image display (#76)
ae074fc unverified
raw
history blame
4.85 kB
import toast from 'react-hot-toast';
const ANSWERS_PREFIX = 'answers';
export const generateAnswersImageMarkdown = (index: number, url: string) => {
return `![${ANSWERS_PREFIX}-${index}](${url})`;
};
export const cleanInputMessage = (content: string) => {
return content
.replace(/!\[input-.*?\)/g, '')
.replace(/<video[^>]*>.*?<\/video>/g, '');
};
export const cleanAnswerMessage = (content: string) => {
return content.replace(/!\[answers.*?\.png\)/g, '');
};
type PlansBody =
| {
type: 'plans';
status: 'started';
}
| {
type: 'plans';
status: 'completed';
payload: Array<Record<string, string>>;
};
type ToolsBody =
| {
type: 'tools';
status: 'started';
}
| {
type: 'tools';
status: 'completed';
payload: Array<Record<string, string>>;
};
type CodeBody =
| {
type: 'code';
status: 'started';
}
| {
type: 'code';
status: 'running';
payload: {
code: string;
test: string;
};
}
| {
type: 'code';
status: 'completed' | 'failed';
payload: {
code: string;
test: string;
result: string;
};
};
// this will return if self_reflection flag is true
type ReflectionBody =
| {
type: 'self_reflection';
status: 'started';
}
| {
type: 'self_reflection';
status: 'completed' | 'failed';
payload: { feedback: string; success: boolean };
};
type MessageBody =
| PlansBody
| ToolsBody
| CodeBody
| ReflectionBody
| PrismaJson.FinalChatResult;
const getMessageTitle = (json: MessageBody) => {
switch (json.type) {
case 'plans':
if (json.status === 'started') {
return '🎬 Start generating plans...\n';
} else {
return 'βœ… Going to run the following plan(s) in sequence:\n';
}
case 'tools':
if (json.status === 'started') {
return '🎬 Start retrieving tools...\n';
} else {
return 'βœ… Tools retrieved:\n';
}
case 'code':
if (json.status === 'started') {
return '🎬 Start generating code...\n';
} else if (json.status === 'running') {
return '🎬 Code generated, start execution... ';
} else if (json.status === 'completed') {
return 'βœ… Code executed successfully. ';
} else {
return '❌ Code execution failed. ';
}
case 'self_reflection':
if (json.status === 'started') {
return '🎬 Start self reflection...\n';
} else if (json.status === 'completed') {
return 'βœ… Self reflection completed: \n';
} else {
return '❌ Self reflection failed: \n';
}
case 'final_code':
if (json.status === 'completed') {
return 'βœ… The vision agent has concluded the chat, the last execution is successful. \n';
} else {
return '❌ The vision agent has concluded the chat, the last execution is failed. \n';
}
default:
throw 'Not supported type';
}
};
export type CodeResult = {
code: string;
test: string;
result: string;
};
export type ChunkBody =
| {
type: 'plans' | 'tools' | 'code' | 'final_code';
status: 'started' | 'completed' | 'failed' | 'running';
payload:
| Array<Record<string, string>> // PlansBody | ToolsBody
| CodeResult; // CodeBody
}
| PrismaJson.FinalChatResult;
/**
* Formats the stream logs and returns an array of grouped sections.
*
* @param content - The content of the stream logs.
* @returns An array of grouped sections and an optional final code result.
*/
export const formatStreamLogs = (
content: string | null | undefined,
): [ChunkBody[], CodeResult?] => {
if (!content) return [[], undefined];
const streamLogs = content.split('\n').filter(log => !!log);
const buffer = streamLogs.pop();
const parsedStreamLogs: ChunkBody[] = [];
try {
streamLogs.forEach(streamLog =>
parsedStreamLogs.push(JSON.parse(streamLog)),
);
} catch {
toast.error('Error parsing stream logs');
return [[], undefined];
}
if (buffer) {
try {
const lastLog = JSON.parse(buffer);
parsedStreamLogs.push(lastLog);
} catch {
console.log(buffer);
}
}
// Merge consecutive logs of the same type to the latest status
const groupedSections = parsedStreamLogs.reduce((acc, curr) => {
if (
acc.length > 0 &&
acc[acc.length - 1].type === curr.type &&
curr.status !== 'started'
) {
acc[acc.length - 1] = curr;
} else {
acc.push(curr);
}
return acc;
}, [] as ChunkBody[]);
return [
groupedSections.filter(section => section.type !== 'final_code'),
groupedSections.find(section => section.type === 'final_code')
?.payload as CodeResult,
];
};