62 lines
2.1 KiB
TypeScript
62 lines
2.1 KiB
TypeScript
import type { ActionFunctionArgs } from '@remix-run/node';
|
||
import { generateId } from 'ai';
|
||
import { readFile } from 'fs/promises';
|
||
import { join } from 'path';
|
||
import { createScopedLogger } from '~/utils/logger';
|
||
|
||
const logger = createScopedLogger('api.chat.mock-chat');
|
||
|
||
/**
|
||
* 处理 mock 数据的流式输出,通常用于开发环境下使用。
|
||
*/
|
||
export async function mockChat(_args: ActionFunctionArgs, filePath: string = 'mock_stream_text_1.txt') {
|
||
try {
|
||
const id = generateId();
|
||
// 读取 mock 数据文件
|
||
const mockFilePath = join(process.cwd(), 'mock', filePath);
|
||
const fileContent = await readFile(mockFilePath, 'utf-8');
|
||
const lines = fileContent.split('\n').map((line) => {
|
||
// 替换 messageId 为生成 id,data: {"type":"start","messageId":"uoLyIATGAm28y7rP"}
|
||
if (line.includes('messageId')) {
|
||
const startData = JSON.parse(line.replace('data: ', ''));
|
||
startData.messageId = id;
|
||
return `data: ${JSON.stringify(startData)}`;
|
||
}
|
||
return line;
|
||
});
|
||
|
||
// 创建一个 ReadableStream 来按行输出内容
|
||
const encoder = new TextEncoder();
|
||
const stream = new ReadableStream({
|
||
async start(controller) {
|
||
// 按行输出内容,每行之间添加延迟
|
||
for (const line of lines) {
|
||
if (line.trim() !== '') {
|
||
controller.enqueue(encoder.encode(`${line}\n\n`));
|
||
// 添加小延迟,模拟真实的流式输出
|
||
await new Promise((resolve) => setTimeout(resolve, 10));
|
||
}
|
||
}
|
||
controller.close();
|
||
},
|
||
});
|
||
|
||
// 返回 Response 对象
|
||
return new Response(stream, {
|
||
status: 200,
|
||
headers: {
|
||
'Content-Type': 'text/event-stream; charset=utf-8',
|
||
Connection: 'keep-alive',
|
||
'Cache-Control': 'no-cache, no-transform',
|
||
'X-Accel-Buffering': 'no',
|
||
},
|
||
});
|
||
} catch (error: any) {
|
||
logger.error(`Mock 数据流式输出错误: ${error}`);
|
||
throw new Response(`Mock 数据流式输出错误: ${error.message}`, {
|
||
status: 500,
|
||
statusText: 'Internal Server Error',
|
||
});
|
||
}
|
||
}
|