import { parsePartialJson } from '@ai-sdk/ui-utils' import { z } from 'zod' export type DeepPartial = T extends object ? T extends Array ? T : { [P in keyof T]?: DeepPartial } : T export function removeJsonMarkdown(text: string) { if (text.startsWith('```json')) { text = text.slice(7) } else if (text.startsWith('json')) { text = text.slice(4) } else if (text.startsWith('```')) { text = text.slice(3) } if (text.endsWith('```')) { text = text.slice(0, -3) } return text } /** * 解析流式的 JSON 数据 * @param textStream 字符串流 * @param _schema zod schema 用于类型验证 * @param isValid 自定义验证函数,用于判断解析出的 JSON 是否有效 * @returns 异步生成器,yield 解析后的数据 */ export async function* parseStreamingJson( textStream: AsyncIterable, _schema: T, isValid: (value: DeepPartial>) => boolean, ): AsyncGenerator>> { let rawText = '' let isParseSuccessful = false for await (const chunk of textStream) { rawText += chunk const parsed = parsePartialJson(removeJsonMarkdown(rawText)) isParseSuccessful = parsed.state === 'repaired-parse' || parsed.state === 'successful-parse' if (isParseSuccessful && isValid(parsed.value as any)) { yield parsed.value as DeepPartial> } else { console.debug(`Failed to parse JSON:`, rawText) } } return { isSuccessful: isParseSuccessful } }