add vitepress docs

This commit is contained in:
Timi
2026-09-21 16:05:14 +08:00
parent b435bf992e
commit 37cf38fe27
73 changed files with 7003 additions and 802 deletions
+93
View File
@@ -0,0 +1,93 @@
/**
* 演示专用的假 SSE 流。
*
* `useAiChat` 要求 `request` 返回一个 `Response`,真实的实现由后端提供。
* 这里用 ReadableStream 按内置协议逐条吐出事件,让文档站无需后端也能跑通
* 流式对话的完整链路。
*
* 内置协议的事件名与载荷字段(见 `parseDefaultEvent` / `extractText` 等):
* - `thinking` 载荷取 `thought` / `thinking` / `reasoning`
* - `answer` 载荷取 `answer` / `text` / `content`
* - `tool-status` 载荷取 `text` / `message` / `status`
* - `citation` 载荷为引用对象
* - `done` 载荷可带 `conversationId` 与 `duration`
*/
/** 单条 SSE 事件。 */
interface MockEvent {
event: string;
data: Record<string, unknown>;
}
/** 每个事件之间的间隔,模拟真实的流式节奏。 */
const STEP_DELAY = 420;
function buildEvents(question: string): MockEvent[] {
return [
{ event: "thinking", data: { thought: `先理解问题:「${question}」` } },
{ event: "thinking", data: { thought: "然后确认需要的数据口径与时间范围。" } },
{ event: "tool-status", data: { text: "正在查询数据" } },
{ event: "answer", data: { text: "根据当前口径," } },
{ event: "answer", data: { text: `关于「${question}」的结论如下:` } },
{ event: "answer", data: { text: "\n\n- 近 30 天整体**环比上升 12%**" } },
{ event: "answer", data: { text: "\n- 其中移动端贡献了主要增量" } },
{ event: "citation", data: { source: "分析中心", dataDomain: "订单域", timeRange: "近 30 天" } },
{ event: "done", data: { conversationId: "demo-conversation", duration: STEP_DELAY * 9 } }
];
}
function sleep(ms: number): Promise<void> {
return new Promise(resolve => setTimeout(resolve, ms));
}
/**
* 生成一段假的流式回复。
*
* @param question 用户提问,会回显在回答里
* @param signal 取消信号,用户点「停止」时中断
*/
export function createMockReply(question: string, signal?: AbortSignal): Response {
const encoder = new TextEncoder();
const events = buildEvents(question);
let index = 0;
const stream = new ReadableStream<Uint8Array>({
async pull(controller) {
if (signal?.aborted) {
controller.error(new DOMException("已停止生成", "AbortError"));
return;
}
if (index >= events.length) {
controller.close();
return;
}
const item = events[index];
index += 1;
controller.enqueue(encoder.encode(`event: ${item.event}\ndata: ${JSON.stringify(item.data)}\n\n`));
await sleep(STEP_DELAY);
}
});
return new Response(stream, {
headers: { "Content-Type": "text/event-stream" }
});
}
/** 构造一条用于静态展示的消息。 */
export function createMessage(
id: number,
role: "user" | "assistant",
content: string,
extra: Partial<{ thinkingList: Array<{ id: number; content: string }>; citationList: unknown[] }> = {}
) {
return {
id,
role,
content,
thinkingList: extra.thinkingList ?? [],
citationList: extra.citationList ?? [],
createdAt: Date.now() - (10 - id) * 60_000,
statusText: "",
duration: role === "assistant" ? 2400 : undefined
};
}