vite-plugin-ai-mock 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +30 -2
- package/README.zh-CN.md +23 -1
- package/mock/ai/claude.json +116 -0
- package/mock/ai/deepseek-reasoner.json +79 -0
- package/mock/ai/deepseek.json +69 -0
- package/mock/ai/default.json +7 -0
- package/mock/ai/doubao.json +69 -0
- package/mock/ai/gemini.json +61 -0
- package/mock/ai/openai.json +69 -0
- package/mock/ai/qwen-thinking.json +79 -0
- package/mock/ai/qwen.json +69 -0
- package/package.json +10 -1
package/README.md
CHANGED
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
> English | [中文](./README.zh-CN.md)
|
|
4
4
|
|
|
5
|
+
[](https://www.npmjs.com/package/vite-plugin-ai-mock)
|
|
6
|
+
[](https://nodejs.org)
|
|
7
|
+
[](https://vitejs.dev)
|
|
8
|
+
[](https://github.com/quanzhiyuan/vite-plugin-ai-mock/actions)
|
|
9
|
+
[](./LICENSE)
|
|
10
|
+
|
|
5
11
|
A standalone Vite plugin for AI scene mocking. Returns streaming data in JSON format, simulating various AI scenarios.
|
|
6
12
|
|
|
7
13
|
- Reads mock files from `mock/ai/*.json`
|
|
@@ -63,6 +69,17 @@ Append parameters directly to the request URL, useful for debugging a single end
|
|
|
63
69
|
/api/ai/mock/default?firstChunkDelayMs=1000&errorAt=3
|
|
64
70
|
```
|
|
65
71
|
|
|
72
|
+
```ts
|
|
73
|
+
const response = await fetch("/api/ai/mock/default?firstChunkDelayMs=4800", {
|
|
74
|
+
method: "POST",
|
|
75
|
+
headers: {
|
|
76
|
+
"Content-Type": "application/json",
|
|
77
|
+
Accept: "text/event-stream",
|
|
78
|
+
},
|
|
79
|
+
body: JSON.stringify({}),
|
|
80
|
+
});
|
|
81
|
+
```
|
|
82
|
+
|
|
66
83
|
**2. Plugin option `defaultScenario` (global)**
|
|
67
84
|
|
|
68
85
|
Configure in `vite.config.ts` to apply to all mock requests. URL parameters take precedence and override this:
|
|
@@ -70,7 +87,7 @@ Configure in `vite.config.ts` to apply to all mock requests. URL parameters take
|
|
|
70
87
|
```ts
|
|
71
88
|
aiMockPlugin({
|
|
72
89
|
defaultScenario: {
|
|
73
|
-
scenario: "jitter",
|
|
90
|
+
scenario: "jitter", // Use a preset scenario name
|
|
74
91
|
// Individual options override the preset's corresponding values:
|
|
75
92
|
firstChunkDelayMs: 500,
|
|
76
93
|
minIntervalMs: 100,
|
|
@@ -108,7 +125,18 @@ Each file is a JSON object with a `chunks` array. Every chunk maps to one SSE ev
|
|
|
108
125
|
|
|
109
126
|
### Real-world format examples
|
|
110
127
|
|
|
111
|
-
The `data` field can mirror any real API response.
|
|
128
|
+
The `data` field can mirror any real API response. The package ships with ready-to-use examples in `mock/ai/` — copy them into your project as a starting point:
|
|
129
|
+
|
|
130
|
+
| File | Provider |
|
|
131
|
+
| --- | --- |
|
|
132
|
+
| `mock/ai/openai.json` | OpenAI / compatible |
|
|
133
|
+
| `mock/ai/claude.json` | Anthropic Claude |
|
|
134
|
+
| `mock/ai/gemini.json` | Google Gemini |
|
|
135
|
+
| `mock/ai/deepseek.json` | DeepSeek |
|
|
136
|
+
| `mock/ai/deepseek-reasoner.json` | DeepSeek Reasoner |
|
|
137
|
+
| `mock/ai/qwen.json` | Qwen (Alibaba) |
|
|
138
|
+
| `mock/ai/qwen-thinking.json` | Qwen Thinking |
|
|
139
|
+
| `mock/ai/doubao.json` | Doubao (ByteDance) |
|
|
112
140
|
|
|
113
141
|
**OpenAI / compatible** (`openai.json`) — `data` ends with `"[DONE]"` string:
|
|
114
142
|
|
package/README.zh-CN.md
CHANGED
|
@@ -63,6 +63,17 @@ export default defineConfig({
|
|
|
63
63
|
/api/ai/mock/default?firstChunkDelayMs=1000&errorAt=3
|
|
64
64
|
```
|
|
65
65
|
|
|
66
|
+
```ts
|
|
67
|
+
const response = await fetch("/api/ai/mock/default?firstChunkDelayMs=4800", {
|
|
68
|
+
method: "POST",
|
|
69
|
+
headers: {
|
|
70
|
+
"Content-Type": "application/json",
|
|
71
|
+
Accept: "text/event-stream",
|
|
72
|
+
},
|
|
73
|
+
body: JSON.stringify({}),
|
|
74
|
+
});
|
|
75
|
+
```
|
|
76
|
+
|
|
66
77
|
**2. 插件选项 `defaultScenario`(全局生效)**
|
|
67
78
|
|
|
68
79
|
在 `vite.config.ts` 中配置,对所有 mock 请求生效,可被 URL 参数覆盖:
|
|
@@ -108,7 +119,18 @@ aiMockPlugin({
|
|
|
108
119
|
|
|
109
120
|
### 主流格式示例
|
|
110
121
|
|
|
111
|
-
`data` 字段可以完整模拟真实 API
|
|
122
|
+
`data` 字段可以完整模拟真实 API 的响应结构。npm 包内置了以下示例文件(位于 `mock/ai/`),可直接复制到项目中使用:
|
|
123
|
+
|
|
124
|
+
| 文件 | 提供商 |
|
|
125
|
+
| --- | --- |
|
|
126
|
+
| `mock/ai/openai.json` | OpenAI / 兼容格式 |
|
|
127
|
+
| `mock/ai/claude.json` | Anthropic Claude |
|
|
128
|
+
| `mock/ai/gemini.json` | Google Gemini |
|
|
129
|
+
| `mock/ai/deepseek.json` | DeepSeek |
|
|
130
|
+
| `mock/ai/deepseek-reasoner.json` | DeepSeek Reasoner |
|
|
131
|
+
| `mock/ai/qwen.json` | 通义千问(阿里) |
|
|
132
|
+
| `mock/ai/qwen-thinking.json` | 通义千问 Thinking |
|
|
133
|
+
| `mock/ai/doubao.json` | 豆包(字节跳动) |
|
|
112
134
|
|
|
113
135
|
**OpenAI / 兼容格式**(`openai.json`)——最后一条 `data` 为字符串 `"[DONE]"`:
|
|
114
136
|
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
{
|
|
2
|
+
"chunks": [
|
|
3
|
+
{
|
|
4
|
+
"id": "1",
|
|
5
|
+
"event": "message_start",
|
|
6
|
+
"data": {
|
|
7
|
+
"type": "message_start",
|
|
8
|
+
"message": {
|
|
9
|
+
"id": "msg_001",
|
|
10
|
+
"type": "message",
|
|
11
|
+
"role": "assistant",
|
|
12
|
+
"model": "claude-opus-4-5",
|
|
13
|
+
"content": [],
|
|
14
|
+
"stop_reason": null,
|
|
15
|
+
"usage": { "input_tokens": 25, "output_tokens": 0 }
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"id": "2",
|
|
21
|
+
"event": "content_block_start",
|
|
22
|
+
"data": {
|
|
23
|
+
"type": "content_block_start",
|
|
24
|
+
"index": 0,
|
|
25
|
+
"content_block": { "type": "thinking", "thinking": "" }
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
"id": "3",
|
|
30
|
+
"event": "content_block_delta",
|
|
31
|
+
"data": {
|
|
32
|
+
"type": "content_block_delta",
|
|
33
|
+
"index": 0,
|
|
34
|
+
"delta": { "type": "thinking_delta", "thinking": "The user is asking about React hooks. I should explain useState and useEffect with clear code examples and markdown formatting." }
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
"id": "4",
|
|
39
|
+
"event": "content_block_stop",
|
|
40
|
+
"data": { "type": "content_block_stop", "index": 0 }
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
"id": "5",
|
|
44
|
+
"event": "content_block_start",
|
|
45
|
+
"data": {
|
|
46
|
+
"type": "content_block_start",
|
|
47
|
+
"index": 1,
|
|
48
|
+
"content_block": { "type": "text", "text": "" }
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
"id": "6",
|
|
53
|
+
"event": "content_block_delta",
|
|
54
|
+
"data": {
|
|
55
|
+
"type": "content_block_delta",
|
|
56
|
+
"index": 1,
|
|
57
|
+
"delta": { "type": "text_delta", "text": "## React Hooks Guide\n\n" }
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
"id": "7",
|
|
62
|
+
"event": "content_block_delta",
|
|
63
|
+
"data": {
|
|
64
|
+
"type": "content_block_delta",
|
|
65
|
+
"index": 1,
|
|
66
|
+
"delta": { "type": "text_delta", "text": "Hooks let function components have state and side effects without writing classes.\n\n### `useState`\n\n" }
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
"id": "8",
|
|
71
|
+
"event": "content_block_delta",
|
|
72
|
+
"data": {
|
|
73
|
+
"type": "content_block_delta",
|
|
74
|
+
"index": 1,
|
|
75
|
+
"delta": { "type": "text_delta", "text": "```tsx\nconst [count, setCount] = useState(0);\n// Read: count\n// Update: setCount(count + 1)\n```\n\n" }
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
"id": "9",
|
|
80
|
+
"event": "content_block_delta",
|
|
81
|
+
"data": {
|
|
82
|
+
"type": "content_block_delta",
|
|
83
|
+
"index": 1,
|
|
84
|
+
"delta": { "type": "text_delta", "text": "### `useEffect`\n\n```tsx\nuseEffect(() => {\n document.title = `Count: ${count}`;\n return () => { /* cleanup */ };\n}, [count]); // Dependency array\n```\n\n" }
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
"id": "10",
|
|
89
|
+
"event": "content_block_delta",
|
|
90
|
+
"data": {
|
|
91
|
+
"type": "content_block_delta",
|
|
92
|
+
"index": 1,
|
|
93
|
+
"delta": { "type": "text_delta", "text": "| Hook | Purpose |\n|------|---------|\n| `useState` | Local state |\n| `useEffect` | Side effects (fetch, subscriptions) |\n| `useRef` | DOM references / values across renders |\n| `useMemo` | Cache computed results |" }
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
"id": "11",
|
|
98
|
+
"event": "content_block_stop",
|
|
99
|
+
"data": { "type": "content_block_stop", "index": 1 }
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
"id": "12",
|
|
103
|
+
"event": "message_delta",
|
|
104
|
+
"data": {
|
|
105
|
+
"type": "message_delta",
|
|
106
|
+
"delta": { "stop_reason": "end_turn", "stop_sequence": null },
|
|
107
|
+
"usage": { "output_tokens": 120 }
|
|
108
|
+
}
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
"id": "13",
|
|
112
|
+
"event": "message_stop",
|
|
113
|
+
"data": { "type": "message_stop" }
|
|
114
|
+
}
|
|
115
|
+
]
|
|
116
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
{
|
|
2
|
+
"chunks": [
|
|
3
|
+
{
|
|
4
|
+
"id": "1",
|
|
5
|
+
"event": "message",
|
|
6
|
+
"data": {
|
|
7
|
+
"id": "chatcmpl-dsr-001",
|
|
8
|
+
"object": "chat.completion.chunk",
|
|
9
|
+
"model": "deepseek-reasoner",
|
|
10
|
+
"choices": [{ "index": 0, "delta": { "role": "assistant", "content": "", "reasoning_content": null }, "finish_reason": null }]
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"id": "2",
|
|
15
|
+
"event": "message",
|
|
16
|
+
"data": {
|
|
17
|
+
"id": "chatcmpl-dsr-001",
|
|
18
|
+
"object": "chat.completion.chunk",
|
|
19
|
+
"model": "deepseek-reasoner",
|
|
20
|
+
"choices": [{ "index": 0, "delta": { "reasoning_content": "The user wants to know the time complexity of bubble sort. Let me think through this carefully." }, "finish_reason": null }]
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"id": "3",
|
|
25
|
+
"event": "message",
|
|
26
|
+
"data": {
|
|
27
|
+
"id": "chatcmpl-dsr-001",
|
|
28
|
+
"object": "chat.completion.chunk",
|
|
29
|
+
"model": "deepseek-reasoner",
|
|
30
|
+
"choices": [{ "index": 0, "delta": { "reasoning_content": " Bubble sort has two nested loops, each running up to n iterations, giving O(n²) in the worst case. Best case with early termination is O(n)." }, "finish_reason": null }]
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"id": "4",
|
|
35
|
+
"event": "message",
|
|
36
|
+
"data": {
|
|
37
|
+
"id": "chatcmpl-dsr-001",
|
|
38
|
+
"object": "chat.completion.chunk",
|
|
39
|
+
"model": "deepseek-reasoner",
|
|
40
|
+
"choices": [{ "index": 0, "delta": { "content": "## Bubble Sort Complexity\n\n" }, "finish_reason": null }]
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
"id": "5",
|
|
45
|
+
"event": "message",
|
|
46
|
+
"data": {
|
|
47
|
+
"id": "chatcmpl-dsr-001",
|
|
48
|
+
"object": "chat.completion.chunk",
|
|
49
|
+
"model": "deepseek-reasoner",
|
|
50
|
+
"choices": [{ "index": 0, "delta": { "content": "Bubble sort repeatedly swaps adjacent elements that are in the wrong order.\n\n" }, "finish_reason": null }]
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
"id": "6",
|
|
55
|
+
"event": "message",
|
|
56
|
+
"data": {
|
|
57
|
+
"id": "chatcmpl-dsr-001",
|
|
58
|
+
"object": "chat.completion.chunk",
|
|
59
|
+
"model": "deepseek-reasoner",
|
|
60
|
+
"choices": [{ "index": 0, "delta": { "content": "| Case | Time | Space |\n|------|------|-------|\n| Best | O(n) | O(1) |\n| Average | O(n²) | O(1) |\n| Worst | O(n²) | O(1) |\n\n> **Note:** Best case requires an early-exit flag to detect an already-sorted array." }, "finish_reason": null }]
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
"id": "7",
|
|
65
|
+
"event": "message",
|
|
66
|
+
"data": {
|
|
67
|
+
"id": "chatcmpl-dsr-001",
|
|
68
|
+
"object": "chat.completion.chunk",
|
|
69
|
+
"model": "deepseek-reasoner",
|
|
70
|
+
"choices": [{ "index": 0, "delta": {}, "finish_reason": "stop" }]
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
"id": "8",
|
|
75
|
+
"event": "message",
|
|
76
|
+
"data": "[DONE]"
|
|
77
|
+
}
|
|
78
|
+
]
|
|
79
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
{
|
|
2
|
+
"chunks": [
|
|
3
|
+
{
|
|
4
|
+
"id": "1",
|
|
5
|
+
"event": "message",
|
|
6
|
+
"data": {
|
|
7
|
+
"id": "chatcmpl-ds-001",
|
|
8
|
+
"object": "chat.completion.chunk",
|
|
9
|
+
"model": "deepseek-chat",
|
|
10
|
+
"choices": [{ "index": 0, "delta": { "role": "assistant", "content": "" }, "finish_reason": null }]
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"id": "2",
|
|
15
|
+
"event": "message",
|
|
16
|
+
"data": {
|
|
17
|
+
"id": "chatcmpl-ds-001",
|
|
18
|
+
"object": "chat.completion.chunk",
|
|
19
|
+
"model": "deepseek-chat",
|
|
20
|
+
"choices": [{ "index": 0, "delta": { "content": "## Quick Sort\n\n" }, "finish_reason": null }]
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"id": "3",
|
|
25
|
+
"event": "message",
|
|
26
|
+
"data": {
|
|
27
|
+
"id": "chatcmpl-ds-001",
|
|
28
|
+
"object": "chat.completion.chunk",
|
|
29
|
+
"model": "deepseek-chat",
|
|
30
|
+
"choices": [{ "index": 0, "delta": { "content": "Quick sort works by selecting a **pivot** element and partitioning the array:\n\n" }, "finish_reason": null }]
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"id": "4",
|
|
35
|
+
"event": "message",
|
|
36
|
+
"data": {
|
|
37
|
+
"id": "chatcmpl-ds-001",
|
|
38
|
+
"object": "chat.completion.chunk",
|
|
39
|
+
"model": "deepseek-chat",
|
|
40
|
+
"choices": [{ "index": 0, "delta": { "content": "```python\ndef quick_sort(arr):\n if len(arr) <= 1:\n return arr\n pivot = arr[len(arr) // 2]\n left = [x for x in arr if x < pivot]\n mid = [x for x in arr if x == pivot]\n right= [x for x in arr if x > pivot]\n return quick_sort(left) + mid + quick_sort(right)\n```\n\n" }, "finish_reason": null }]
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
"id": "5",
|
|
45
|
+
"event": "message",
|
|
46
|
+
"data": {
|
|
47
|
+
"id": "chatcmpl-ds-001",
|
|
48
|
+
"object": "chat.completion.chunk",
|
|
49
|
+
"model": "deepseek-chat",
|
|
50
|
+
"choices": [{ "index": 0, "delta": { "content": "| Case | Time Complexity |\n|------|-----------------|\n| Best | O(n log n) |\n| Average | O(n log n) |\n| Worst | O(n²) |" }, "finish_reason": null }]
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
"id": "6",
|
|
55
|
+
"event": "message",
|
|
56
|
+
"data": {
|
|
57
|
+
"id": "chatcmpl-ds-001",
|
|
58
|
+
"object": "chat.completion.chunk",
|
|
59
|
+
"model": "deepseek-chat",
|
|
60
|
+
"choices": [{ "index": 0, "delta": {}, "finish_reason": "stop" }]
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
"id": "7",
|
|
65
|
+
"event": "message",
|
|
66
|
+
"data": "[DONE]"
|
|
67
|
+
}
|
|
68
|
+
]
|
|
69
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
{
|
|
2
|
+
"chunks": [
|
|
3
|
+
{
|
|
4
|
+
"id": "1",
|
|
5
|
+
"event": "message",
|
|
6
|
+
"data": {
|
|
7
|
+
"id": "chatcmpl-db-001",
|
|
8
|
+
"object": "chat.completion.chunk",
|
|
9
|
+
"model": "doubao-pro-32k",
|
|
10
|
+
"choices": [{ "index": 0, "delta": { "role": "assistant", "content": "" }, "finish_reason": null }]
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"id": "2",
|
|
15
|
+
"event": "message",
|
|
16
|
+
"data": {
|
|
17
|
+
"id": "chatcmpl-db-001",
|
|
18
|
+
"object": "chat.completion.chunk",
|
|
19
|
+
"model": "doubao-pro-32k",
|
|
20
|
+
"choices": [{ "index": 0, "delta": { "content": "## CSS Grid Layout Guide\n\n" }, "finish_reason": null }]
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"id": "3",
|
|
25
|
+
"event": "message",
|
|
26
|
+
"data": {
|
|
27
|
+
"id": "chatcmpl-db-001",
|
|
28
|
+
"object": "chat.completion.chunk",
|
|
29
|
+
"model": "doubao-pro-32k",
|
|
30
|
+
"choices": [{ "index": 0, "delta": { "content": "CSS Grid is a two-dimensional layout system that controls both **rows** and **columns**, ideal for complex page structures.\n\n" }, "finish_reason": null }]
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"id": "4",
|
|
35
|
+
"event": "message",
|
|
36
|
+
"data": {
|
|
37
|
+
"id": "chatcmpl-db-001",
|
|
38
|
+
"object": "chat.completion.chunk",
|
|
39
|
+
"model": "doubao-pro-32k",
|
|
40
|
+
"choices": [{ "index": 0, "delta": { "content": "### Basic Usage\n\n```css\n.container {\n display: grid;\n grid-template-columns: repeat(3, 1fr);\n grid-template-rows: auto;\n gap: 16px;\n}\n```\n\n" }, "finish_reason": null }]
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
"id": "5",
|
|
45
|
+
"event": "message",
|
|
46
|
+
"data": {
|
|
47
|
+
"id": "chatcmpl-db-001",
|
|
48
|
+
"object": "chat.completion.chunk",
|
|
49
|
+
"model": "doubao-pro-32k",
|
|
50
|
+
"choices": [{ "index": 0, "delta": { "content": "### Common Properties\n\n| Property | Function |\n|----------|----------|\n| `grid-template-columns` | Define columns count and width |\n| `grid-template-rows` | Define rows count and height |\n| `gap` | Row and column spacing |\n| `grid-area` | Child element area placement |\n\n> Tip: Works best with Flexbox: Grid for overall layout, Flex for local alignment." }, "finish_reason": null }]
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
"id": "6",
|
|
55
|
+
"event": "message",
|
|
56
|
+
"data": {
|
|
57
|
+
"id": "chatcmpl-db-001",
|
|
58
|
+
"object": "chat.completion.chunk",
|
|
59
|
+
"model": "doubao-pro-32k",
|
|
60
|
+
"choices": [{ "index": 0, "delta": {}, "finish_reason": "stop" }]
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
"id": "7",
|
|
65
|
+
"event": "message",
|
|
66
|
+
"data": "[DONE]"
|
|
67
|
+
}
|
|
68
|
+
]
|
|
69
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
{
|
|
2
|
+
"chunks": [
|
|
3
|
+
{
|
|
4
|
+
"id": "1",
|
|
5
|
+
"event": "message",
|
|
6
|
+
"data": {
|
|
7
|
+
"candidates": [
|
|
8
|
+
{
|
|
9
|
+
"content": { "parts": [{ "text": "## Async/Await in JavaScript\n\n" }], "role": "model" },
|
|
10
|
+
"finishReason": null,
|
|
11
|
+
"index": 0
|
|
12
|
+
}
|
|
13
|
+
],
|
|
14
|
+
"modelVersion": "gemini-2.0-flash"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"id": "2",
|
|
19
|
+
"event": "message",
|
|
20
|
+
"data": {
|
|
21
|
+
"candidates": [
|
|
22
|
+
{
|
|
23
|
+
"content": { "parts": [{ "text": "`async/await` is syntactic sugar over Promises, making asynchronous code read like synchronous code.\n\n" }], "role": "model" },
|
|
24
|
+
"finishReason": null,
|
|
25
|
+
"index": 0
|
|
26
|
+
}
|
|
27
|
+
],
|
|
28
|
+
"modelVersion": "gemini-2.0-flash"
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
"id": "3",
|
|
33
|
+
"event": "message",
|
|
34
|
+
"data": {
|
|
35
|
+
"candidates": [
|
|
36
|
+
{
|
|
37
|
+
"content": { "parts": [{ "text": "```js\nasync function fetchUser(id) {\n try {\n const res = await fetch(`/api/users/${id}`);\n if (!res.ok) throw new Error(`HTTP ${res.status}`);\n return await res.json();\n } catch (err) {\n console.error('Failed:', err);\n }\n}\n```\n\n" }], "role": "model" },
|
|
38
|
+
"finishReason": null,
|
|
39
|
+
"index": 0
|
|
40
|
+
}
|
|
41
|
+
],
|
|
42
|
+
"modelVersion": "gemini-2.0-flash"
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
"id": "4",
|
|
47
|
+
"event": "message",
|
|
48
|
+
"data": {
|
|
49
|
+
"candidates": [
|
|
50
|
+
{
|
|
51
|
+
"content": { "parts": [{ "text": "### Key Rules\n\n- `await` can only be used inside an `async` function\n- `await` pauses execution **within the function only**\n- Errors propagate via `try/catch` or `.catch()` on the returned Promise\n\n| Pattern | Use when |\n|---------|----------|\n| `await` sequentially | Each call depends on the previous |\n| `Promise.all([...])` | Independent parallel calls |" }], "role": "model" },
|
|
52
|
+
"finishReason": "STOP",
|
|
53
|
+
"index": 0
|
|
54
|
+
}
|
|
55
|
+
],
|
|
56
|
+
"usageMetadata": { "promptTokenCount": 18, "candidatesTokenCount": 110, "totalTokenCount": 128 },
|
|
57
|
+
"modelVersion": "gemini-2.0-flash"
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
]
|
|
61
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
{
|
|
2
|
+
"chunks": [
|
|
3
|
+
{
|
|
4
|
+
"id": "1",
|
|
5
|
+
"event": "message",
|
|
6
|
+
"data": {
|
|
7
|
+
"id": "chatcmpl-001",
|
|
8
|
+
"object": "chat.completion.chunk",
|
|
9
|
+
"model": "gpt-4o",
|
|
10
|
+
"choices": [{ "index": 0, "delta": { "role": "assistant", "content": "" }, "finish_reason": null }]
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"id": "2",
|
|
15
|
+
"event": "message",
|
|
16
|
+
"data": {
|
|
17
|
+
"id": "chatcmpl-001",
|
|
18
|
+
"object": "chat.completion.chunk",
|
|
19
|
+
"model": "gpt-4o",
|
|
20
|
+
"choices": [{ "index": 0, "delta": { "content": "## TypeScript Generics\n\n" }, "finish_reason": null }]
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"id": "3",
|
|
25
|
+
"event": "message",
|
|
26
|
+
"data": {
|
|
27
|
+
"id": "chatcmpl-001",
|
|
28
|
+
"object": "chat.completion.chunk",
|
|
29
|
+
"model": "gpt-4o",
|
|
30
|
+
"choices": [{ "index": 0, "delta": { "content": "Generics allow you to write **reusable, type-safe** functions and classes.\n\n" }, "finish_reason": null }]
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"id": "4",
|
|
35
|
+
"event": "message",
|
|
36
|
+
"data": {
|
|
37
|
+
"id": "chatcmpl-001",
|
|
38
|
+
"object": "chat.completion.chunk",
|
|
39
|
+
"model": "gpt-4o",
|
|
40
|
+
"choices": [{ "index": 0, "delta": { "content": "```ts\nfunction identity<T>(value: T): T {\n return value;\n}\n\n// Usage\nconst num = identity<number>(42); // T = number\nconst str = identity(\"hello\"); // T inferred as string\n```\n\n" }, "finish_reason": null }]
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
"id": "5",
|
|
45
|
+
"event": "message",
|
|
46
|
+
"data": {
|
|
47
|
+
"id": "chatcmpl-001",
|
|
48
|
+
"object": "chat.completion.chunk",
|
|
49
|
+
"model": "gpt-4o",
|
|
50
|
+
"choices": [{ "index": 0, "delta": { "content": "### Constraints\n\n```ts\nfunction getLength<T extends { length: number }>(arg: T): number {\n return arg.length;\n}\n```\n\n> Use `extends` to restrict `T` to types that have specific properties." }, "finish_reason": null }]
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
"id": "6",
|
|
55
|
+
"event": "message",
|
|
56
|
+
"data": {
|
|
57
|
+
"id": "chatcmpl-001",
|
|
58
|
+
"object": "chat.completion.chunk",
|
|
59
|
+
"model": "gpt-4o",
|
|
60
|
+
"choices": [{ "index": 0, "delta": {}, "finish_reason": "stop" }]
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
"id": "7",
|
|
65
|
+
"event": "message",
|
|
66
|
+
"data": "[DONE]"
|
|
67
|
+
}
|
|
68
|
+
]
|
|
69
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
{
|
|
2
|
+
"chunks": [
|
|
3
|
+
{
|
|
4
|
+
"id": "1",
|
|
5
|
+
"event": "message",
|
|
6
|
+
"data": {
|
|
7
|
+
"id": "chatcmpl-qwt-001",
|
|
8
|
+
"object": "chat.completion.chunk",
|
|
9
|
+
"model": "qwq-plus",
|
|
10
|
+
"choices": [{ "index": 0, "delta": { "role": "assistant", "content": "", "reasoning_content": null }, "finish_reason": null }]
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"id": "2",
|
|
15
|
+
"event": "message",
|
|
16
|
+
"data": {
|
|
17
|
+
"id": "chatcmpl-qwt-001",
|
|
18
|
+
"object": "chat.completion.chunk",
|
|
19
|
+
"model": "qwq-plus",
|
|
20
|
+
"choices": [{ "index": 0, "delta": { "reasoning_content": "The user is asking about the Fibonacci recurrence formula. This is a basic math problem." }, "finish_reason": null }]
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"id": "3",
|
|
25
|
+
"event": "message",
|
|
26
|
+
"data": {
|
|
27
|
+
"id": "chatcmpl-qwt-001",
|
|
28
|
+
"object": "chat.completion.chunk",
|
|
29
|
+
"model": "qwq-plus",
|
|
30
|
+
"choices": [{ "index": 0, "delta": { "reasoning_content": " F(n) = F(n-1) + F(n-2), with base cases F(0)=0, F(1)=1. I should provide the definition, formula, and a short code example." }, "finish_reason": null }]
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"id": "4",
|
|
35
|
+
"event": "message",
|
|
36
|
+
"data": {
|
|
37
|
+
"id": "chatcmpl-qwt-001",
|
|
38
|
+
"object": "chat.completion.chunk",
|
|
39
|
+
"model": "qwq-plus",
|
|
40
|
+
"choices": [{ "index": 0, "delta": { "content": "## Fibonacci Sequence\n\n" }, "finish_reason": null }]
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
"id": "5",
|
|
45
|
+
"event": "message",
|
|
46
|
+
"data": {
|
|
47
|
+
"id": "chatcmpl-qwt-001",
|
|
48
|
+
"object": "chat.completion.chunk",
|
|
49
|
+
"model": "qwq-plus",
|
|
50
|
+
"choices": [{ "index": 0, "delta": { "content": "**Recurrence Formula:**\n\n$$F(n) = F(n-1) + F(n-2), \\quad F(0)=0,\\ F(1)=1$$\n\n" }, "finish_reason": null }]
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
"id": "6",
|
|
55
|
+
"event": "message",
|
|
56
|
+
"data": {
|
|
57
|
+
"id": "chatcmpl-qwt-001",
|
|
58
|
+
"object": "chat.completion.chunk",
|
|
59
|
+
"model": "qwq-plus",
|
|
60
|
+
"choices": [{ "index": 0, "delta": { "content": "First 10 terms: `0, 1, 1, 2, 3, 5, 8, 13, 21, 34`\n\n```python\ndef fib(n):\n a, b = 0, 1\n for _ in range(n):\n a, b = b, a + b\n return a\n```" }, "finish_reason": null }]
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
"id": "7",
|
|
65
|
+
"event": "message",
|
|
66
|
+
"data": {
|
|
67
|
+
"id": "chatcmpl-qwt-001",
|
|
68
|
+
"object": "chat.completion.chunk",
|
|
69
|
+
"model": "qwq-plus",
|
|
70
|
+
"choices": [{ "index": 0, "delta": {}, "finish_reason": "stop" }]
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
"id": "8",
|
|
75
|
+
"event": "message",
|
|
76
|
+
"data": "[DONE]"
|
|
77
|
+
}
|
|
78
|
+
]
|
|
79
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
{
|
|
2
|
+
"chunks": [
|
|
3
|
+
{
|
|
4
|
+
"id": "1",
|
|
5
|
+
"event": "message",
|
|
6
|
+
"data": {
|
|
7
|
+
"id": "chatcmpl-qw-001",
|
|
8
|
+
"object": "chat.completion.chunk",
|
|
9
|
+
"model": "qwen-plus",
|
|
10
|
+
"choices": [{ "index": 0, "delta": { "role": "assistant", "content": "" }, "finish_reason": null }]
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"id": "2",
|
|
15
|
+
"event": "message",
|
|
16
|
+
"data": {
|
|
17
|
+
"id": "chatcmpl-qw-001",
|
|
18
|
+
"object": "chat.completion.chunk",
|
|
19
|
+
"model": "qwen-plus",
|
|
20
|
+
"choices": [{ "index": 0, "delta": { "content": "## What is Transformer?\n\n" }, "finish_reason": null }]
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"id": "3",
|
|
25
|
+
"event": "message",
|
|
26
|
+
"data": {
|
|
27
|
+
"id": "chatcmpl-qw-001",
|
|
28
|
+
"object": "chat.completion.chunk",
|
|
29
|
+
"model": "qwen-plus",
|
|
30
|
+
"choices": [{ "index": 0, "delta": { "content": "Transformer is a neural network architecture based on the **Self-Attention** mechanism, proposed by Google in the 2017 paper *Attention Is All You Need*.\n\n" }, "finish_reason": null }]
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"id": "4",
|
|
35
|
+
"event": "message",
|
|
36
|
+
"data": {
|
|
37
|
+
"id": "chatcmpl-qw-001",
|
|
38
|
+
"object": "chat.completion.chunk",
|
|
39
|
+
"model": "qwen-plus",
|
|
40
|
+
"choices": [{ "index": 0, "delta": { "content": "### Core Components\n\n1. **Multi-Head Attention** — Captures dependencies across different subspaces in parallel\n2. **Feed-Forward Network** — Applies non-linear transformations independently at each position\n3. **Positional Encoding** — Injects position information into the sequence\n\n" }, "finish_reason": null }]
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
"id": "5",
|
|
45
|
+
"event": "message",
|
|
46
|
+
"data": {
|
|
47
|
+
"id": "chatcmpl-qw-001",
|
|
48
|
+
"object": "chat.completion.chunk",
|
|
49
|
+
"model": "qwen-plus",
|
|
50
|
+
"choices": [{ "index": 0, "delta": { "content": "```\nInput → Embedding + Positional Encoding\n → N × (Multi-Head Attention → Add&Norm → FFN → Add&Norm)\n → Output\n```" }, "finish_reason": null }]
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
"id": "6",
|
|
55
|
+
"event": "message",
|
|
56
|
+
"data": {
|
|
57
|
+
"id": "chatcmpl-qw-001",
|
|
58
|
+
"object": "chat.completion.chunk",
|
|
59
|
+
"model": "qwen-plus",
|
|
60
|
+
"choices": [{ "index": 0, "delta": {}, "finish_reason": "stop" }]
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
"id": "7",
|
|
65
|
+
"event": "message",
|
|
66
|
+
"data": "[DONE]"
|
|
67
|
+
}
|
|
68
|
+
]
|
|
69
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vite-plugin-ai-mock",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "A Vite plugin for AI streaming mock (SSE/JSON) with configurable scenarios.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
},
|
|
17
17
|
"files": [
|
|
18
18
|
"dist",
|
|
19
|
+
"mock",
|
|
19
20
|
"README.md",
|
|
20
21
|
"README.zh-CN.md",
|
|
21
22
|
"LICENSE"
|
|
@@ -27,6 +28,14 @@
|
|
|
27
28
|
"sse",
|
|
28
29
|
"ai"
|
|
29
30
|
],
|
|
31
|
+
"repository": {
|
|
32
|
+
"type": "git",
|
|
33
|
+
"url": "https://github.com/quanzhiyuan/vite-plugin-ai-mock"
|
|
34
|
+
},
|
|
35
|
+
"homepage": "https://github.com/quanzhiyuan/vite-plugin-ai-mock#readme",
|
|
36
|
+
"bugs": {
|
|
37
|
+
"url": "https://github.com/quanzhiyuan/vite-plugin-ai-mock/issues"
|
|
38
|
+
},
|
|
30
39
|
"engines": {
|
|
31
40
|
"node": ">=18"
|
|
32
41
|
},
|