Spaces:
Sleeping
Sleeping
import toast from 'react-hot-toast'; | |
import { ResultPayload } from '../types'; | |
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, ''); | |
}; | |
export type CodeResult = { | |
code: string; | |
test: string; | |
result: string; | |
}; | |
const WIPLogTypes = ['plans', 'tools', 'code']; | |
const AllLogTypes = [ | |
'plans', | |
'tools', | |
'code', | |
'final_code', | |
'final_error', | |
] as const; | |
export type ChunkBody = { | |
type: (typeof AllLogTypes)[number]; | |
status: 'started' | 'completed' | 'failed' | 'running'; | |
timestamp?: string; | |
payload: | |
| Array<Record<string, string>> // PlansBody | ToolsBody | |
| CodeResult // CodeBody | |
| ResultPayload['error']; // ErrorBody | |
}; | |
export type WIPChunkBodyGroup = ChunkBody & { | |
duration?: number; | |
}; | |
/** | |
* 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, | |
): [WIPChunkBodyGroup[], CodeResult?, ResultPayload['error']?] => { | |
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) => { | |
const lastGroup = acc[acc.length - 1]; | |
if ( | |
acc.length > 0 && | |
lastGroup.type === curr.type && | |
curr.status !== 'started' | |
) { | |
acc[acc.length - 1] = { | |
...curr, | |
// always use the timestamp of the first log | |
timestamp: lastGroup?.timestamp, | |
// duration is the difference between the last log and the first log | |
duration: | |
lastGroup?.timestamp && curr.timestamp | |
? Date.parse(curr.timestamp) - Date.parse(lastGroup.timestamp) | |
: undefined, | |
}; | |
} else { | |
acc.push(curr); | |
} | |
return acc; | |
}, [] as WIPChunkBodyGroup[]); | |
return [ | |
groupedSections.filter(section => WIPLogTypes.includes(section.type)), | |
groupedSections.find(section => section.type === 'final_code') | |
?.payload as CodeResult, | |
groupedSections.find(section => section.type === 'final_error') | |
?.payload as ResultPayload['error'], | |
]; | |
}; | |