@bowenqt/qiniu-ai-sdk 0.27.2 โ 0.28.0
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 +209 -820
- package/README.zh-CN.md +361 -0
- package/dist/ai/a2a/expert.d.ts +38 -0
- package/dist/ai/a2a/expert.d.ts.map +1 -0
- package/dist/ai/a2a/expert.js +182 -0
- package/dist/ai/a2a/expert.js.map +1 -0
- package/dist/ai/a2a/expert.mjs +178 -0
- package/dist/ai/a2a/index.d.ts +9 -0
- package/dist/ai/a2a/index.d.ts.map +1 -0
- package/dist/ai/a2a/index.js +25 -0
- package/dist/ai/a2a/index.js.map +1 -0
- package/dist/ai/a2a/index.mjs +12 -0
- package/dist/ai/a2a/rate-limiter.d.ts +62 -0
- package/dist/ai/a2a/rate-limiter.d.ts.map +1 -0
- package/dist/ai/a2a/rate-limiter.js +192 -0
- package/dist/ai/a2a/rate-limiter.js.map +1 -0
- package/dist/ai/a2a/rate-limiter.mjs +187 -0
- package/dist/ai/a2a/types.d.ts +121 -0
- package/dist/ai/a2a/types.d.ts.map +1 -0
- package/dist/ai/a2a/types.js +62 -0
- package/dist/ai/a2a/types.js.map +1 -0
- package/dist/ai/a2a/types.mjs +56 -0
- package/dist/ai/a2a/validation.d.ts +43 -0
- package/dist/ai/a2a/validation.d.ts.map +1 -0
- package/dist/ai/a2a/validation.js +178 -0
- package/dist/ai/a2a/validation.js.map +1 -0
- package/dist/ai/a2a/validation.mjs +173 -0
- package/dist/ai/create-agent.d.ts +6 -0
- package/dist/ai/create-agent.d.ts.map +1 -1
- package/dist/ai/create-agent.js +4 -0
- package/dist/ai/create-agent.js.map +1 -1
- package/dist/ai/create-agent.mjs +4 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +14 -3
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,43 +1,75 @@
|
|
|
1
1
|
# Qiniu AI SDK
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
<div align="center">
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
[](https://www.npmjs.com/package/@bowenqt/qiniu-ai-sdk)
|
|
6
|
+
[](https://opensource.org/licenses/MIT)
|
|
7
|
+
[](https://nodejs.org/)
|
|
6
8
|
|
|
7
|
-
|
|
8
|
-
- ๐ผ๏ธ **Image Generation** - Kling, Gemini models
|
|
9
|
-
- ๐ฅ **Video Generation** - Kling, Sora, Veo models
|
|
10
|
-
- ๐ **Web Search** - Real-time web search API
|
|
11
|
-
- โฑ๏ธ **Built-in Polling** - Async task management with retry and cancellation
|
|
12
|
-
- ๐ค **Agentic Layer** - Multi-step tool execution with `generateText`
|
|
13
|
-
- ๐ **JSON Mode** - Structured output with `response_format`
|
|
14
|
-
- ๐ **Vercel AI SDK Adapter** - Drop-in replacement for Vercel AI SDK
|
|
15
|
-
- ๐ฆ **TypeScript First** - Full type definitions included
|
|
16
|
-
- ๐ง **Skills** - Markdown-based agent knowledge injection
|
|
17
|
-
- ๐ **MCP Client** - Model Context Protocol stdio + HTTP transport
|
|
18
|
-
- ๐ **OAuth 2.0** - PKCE and Device Code flows for MCP HTTP
|
|
19
|
-
- ๐พ **Checkpointer** - Save/restore state: Memory, Redis, PostgreSQL
|
|
20
|
-
- ๐ **Tracing** - OpenTelemetry integration with per-node spans
|
|
9
|
+
**TypeScript SDK for Qiniu Cloud AI Services**
|
|
21
10
|
|
|
22
|
-
|
|
11
|
+
[English](./README.md) | [ไธญๆ](./README.zh-CN.md) | [COOKBOOK](./COOKBOOK.md)
|
|
23
12
|
|
|
24
|
-
|
|
13
|
+
</div>
|
|
25
14
|
|
|
26
|
-
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## โจ Features
|
|
18
|
+
|
|
19
|
+
### Core AI Modules
|
|
20
|
+
- ๐ **Chat Completions** โ OpenAI-compatible interface with streaming support
|
|
21
|
+
- ๐ผ๏ธ **Image Generation** โ Kling, Gemini models with unified sync/async API
|
|
22
|
+
- ๐ฅ **Video Generation** โ Kling, Sora, Veo models with first/last frame control
|
|
23
|
+
- ๐ **Web Search** โ Real-time web search integration
|
|
24
|
+
- ๐ **OCR** โ High-precision text recognition for images and PDFs
|
|
25
|
+
- ๐ค **ASR** โ Multi-language speech recognition (95%+ accuracy in noisy environments)
|
|
26
|
+
- ๐ **TTS** โ Text-to-speech synthesis with multiple voice options
|
|
27
|
+
- ๐ก๏ธ **Content Moderation** โ Image and video censorship with scene-based detection
|
|
28
|
+
|
|
29
|
+
### Agentic Layer
|
|
30
|
+
- ๐ค **generateText** โ Multi-step tool execution with Zod schema support
|
|
31
|
+
- ๐ **generateObject/streamObject** โ Structured JSON output with streaming
|
|
32
|
+
- ๐ง **AgentGraph** โ State machine-based graph execution
|
|
33
|
+
- ๐ญ **createAgent** โ Reusable agent factory with configurable behaviors
|
|
34
|
+
|
|
35
|
+
### Advanced Capabilities
|
|
36
|
+
- ๐ **Skills Injection** โ Markdown-based agent knowledge (Claude Skills compatible)
|
|
37
|
+
- ๐ **MCP Client** โ Model Context Protocol with stdio + HTTP + OAuth 2.0 support
|
|
38
|
+
- ๐ฅ๏ธ **MCP Server** โ Built-in Qiniu MCP server for OCR/Censor/Vframe tools
|
|
39
|
+
- ๐พ **Checkpointer** โ State persistence (Memory, Redis, PostgreSQL, Kodo)
|
|
40
|
+
- ๐ง **Memory Manager** โ Short-term + long-term memory with LLM summarization
|
|
41
|
+
- โ
**Tool Approval (HITL)** โ Human-in-the-loop for sensitive operations
|
|
42
|
+
- โธ๏ธ **Interrupt/Resume** โ Resumable execution with checkpoint-based restore
|
|
43
|
+
- ๐ **OpenTelemetry Tracing** โ Distributed tracing with per-node spans
|
|
44
|
+
- ๐ **Vercel AI SDK Adapter** โ Drop-in replacement for Vercel AI SDK
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## ๐ฆ Installation
|
|
27
49
|
|
|
28
50
|
```bash
|
|
29
51
|
npm install @bowenqt/qiniu-ai-sdk
|
|
30
52
|
```
|
|
31
53
|
|
|
32
|
-
###
|
|
33
|
-
|
|
34
|
-
The Vercel AI SDK adapter is optional. Install the peer dependencies when you use it:
|
|
54
|
+
### Optional Peer Dependencies
|
|
35
55
|
|
|
36
56
|
```bash
|
|
37
|
-
|
|
57
|
+
# For Vercel AI SDK integration
|
|
58
|
+
npm install @ai-sdk/provider ai
|
|
59
|
+
|
|
60
|
+
# For Zod schema validation
|
|
61
|
+
npm install zod
|
|
62
|
+
|
|
63
|
+
# For Redis checkpointer
|
|
64
|
+
npm install ioredis
|
|
65
|
+
|
|
66
|
+
# For PostgreSQL checkpointer
|
|
67
|
+
npm install pg
|
|
38
68
|
```
|
|
39
69
|
|
|
40
|
-
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## ๐ Quick Start
|
|
41
73
|
|
|
42
74
|
```typescript
|
|
43
75
|
import { QiniuAI } from '@bowenqt/qiniu-ai-sdk';
|
|
@@ -53,273 +85,144 @@ const chat = await client.chat.create({
|
|
|
53
85
|
});
|
|
54
86
|
console.log(chat.choices[0].message.content);
|
|
55
87
|
|
|
56
|
-
//
|
|
57
|
-
const imageResult = await client.image.generate({
|
|
58
|
-
model: 'kling-v1',
|
|
59
|
-
prompt: 'A futuristic city',
|
|
60
|
-
});
|
|
61
|
-
const imageFinal = await client.image.waitForResult(imageResult);
|
|
62
|
-
console.log(imageFinal.data?.[0].url || imageFinal.data?.[0].b64_json);
|
|
63
|
-
|
|
64
|
-
// Video generation (async)
|
|
65
|
-
const videoTask = await client.video.create({
|
|
66
|
-
model: 'kling-video-o1',
|
|
67
|
-
prompt: 'A cat walking on the beach',
|
|
68
|
-
duration: '5',
|
|
69
|
-
});
|
|
70
|
-
const videoResult = await client.video.waitForCompletion(videoTask.id);
|
|
71
|
-
console.log(videoResult.task_result?.videos[0].url);
|
|
72
|
-
|
|
73
|
-
// Web search
|
|
74
|
-
const results = await client.sys.search({
|
|
75
|
-
query: 'Latest AI news',
|
|
76
|
-
max_results: 5,
|
|
77
|
-
});
|
|
78
|
-
console.log(results);
|
|
79
|
-
|
|
80
|
-
// Streaming Chat (New!)
|
|
88
|
+
// Streaming chat
|
|
81
89
|
const stream = await client.chat.createStream({
|
|
82
90
|
model: 'gemini-2.5-flash',
|
|
83
|
-
messages: [{ role: 'user', content: 'Explain
|
|
91
|
+
messages: [{ role: 'user', content: 'Explain AI briefly' }],
|
|
84
92
|
});
|
|
85
|
-
|
|
86
93
|
for await (const chunk of stream) {
|
|
87
94
|
process.stdout.write(chunk.choices[0]?.delta?.content || '');
|
|
88
95
|
}
|
|
89
96
|
```
|
|
90
97
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
### StreamAccumulator (Manual Streaming)
|
|
94
|
-
|
|
95
|
-
```typescript
|
|
96
|
-
import { QiniuAI, createStreamAccumulator, accumulateDelta } from '@bowenqt/qiniu-ai-sdk';
|
|
97
|
-
|
|
98
|
-
const client = new QiniuAI({ apiKey: 'Sk-xxx' });
|
|
99
|
-
const stream = client.chat.createStream({
|
|
100
|
-
model: 'gemini-2.5-flash',
|
|
101
|
-
messages: [{ role: 'user', content: 'Explain streaming in one sentence.' }],
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
const acc = createStreamAccumulator();
|
|
105
|
-
for await (const chunk of stream) {
|
|
106
|
-
const delta = chunk.choices[0]?.delta;
|
|
107
|
-
if (delta) {
|
|
108
|
-
accumulateDelta(acc, delta);
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
console.log(acc.content);
|
|
112
|
-
```
|
|
113
|
-
|
|
114
|
-
### parseSSEStream (Custom SSE Parsing)
|
|
115
|
-
|
|
116
|
-
```typescript
|
|
117
|
-
import { parseSSEStream } from '@bowenqt/qiniu-ai-sdk';
|
|
118
|
-
|
|
119
|
-
const response = await fetch('https://api.qnaigc.com/v1/chat/completions', {
|
|
120
|
-
method: 'POST',
|
|
121
|
-
headers: {
|
|
122
|
-
'Content-Type': 'application/json',
|
|
123
|
-
'Authorization': `Bearer ${process.env.QINIU_API_KEY}`,
|
|
124
|
-
},
|
|
125
|
-
body: JSON.stringify({
|
|
126
|
-
model: 'gemini-2.5-flash',
|
|
127
|
-
messages: [{ role: 'user', content: 'Hello!' }],
|
|
128
|
-
stream: true,
|
|
129
|
-
}),
|
|
130
|
-
});
|
|
131
|
-
|
|
132
|
-
for await (const chunk of parseSSEStream(response)) {
|
|
133
|
-
console.log(chunk);
|
|
134
|
-
}
|
|
135
|
-
```
|
|
136
|
-
|
|
137
|
-
### createPoller (Custom Async Polling)
|
|
138
|
-
|
|
139
|
-
```typescript
|
|
140
|
-
import { createPoller } from '@bowenqt/qiniu-ai-sdk';
|
|
141
|
-
|
|
142
|
-
const poller = createPoller({
|
|
143
|
-
intervalMs: 2000,
|
|
144
|
-
timeoutMs: 60000,
|
|
145
|
-
isTerminal: (result) => result.status === 'succeed' || result.status === 'failed',
|
|
146
|
-
getStatus: (id) => client.video.get(id),
|
|
147
|
-
});
|
|
148
|
-
|
|
149
|
-
const result = await poller.poll('task-id');
|
|
150
|
-
console.log(result.result);
|
|
151
|
-
```
|
|
152
|
-
|
|
153
|
-
## Agentic Layer
|
|
98
|
+
---
|
|
154
99
|
|
|
155
|
-
|
|
100
|
+
## ๐ค Agentic Usage
|
|
156
101
|
|
|
157
|
-
###
|
|
102
|
+
### Tool Execution with generateText
|
|
158
103
|
|
|
159
104
|
```typescript
|
|
160
105
|
import { QiniuAI, generateText } from '@bowenqt/qiniu-ai-sdk';
|
|
106
|
+
import { z } from 'zod';
|
|
161
107
|
|
|
162
108
|
const client = new QiniuAI({ apiKey: process.env.QINIU_API_KEY || '' });
|
|
163
109
|
|
|
164
110
|
const result = await generateText({
|
|
165
111
|
client,
|
|
166
112
|
model: 'gemini-2.5-flash',
|
|
167
|
-
prompt: 'What is
|
|
113
|
+
prompt: 'What is 42 * 17?',
|
|
168
114
|
tools: {
|
|
169
|
-
|
|
170
|
-
description: '
|
|
171
|
-
parameters: {
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
115
|
+
calculate: {
|
|
116
|
+
description: 'Perform calculation',
|
|
117
|
+
parameters: z.object({
|
|
118
|
+
operation: z.enum(['add', 'subtract', 'multiply', 'divide']),
|
|
119
|
+
a: z.number(),
|
|
120
|
+
b: z.number(),
|
|
121
|
+
}),
|
|
122
|
+
execute: async ({ operation, a, b }) => {
|
|
123
|
+
const ops = { add: a + b, subtract: a - b, multiply: a * b, divide: a / b };
|
|
124
|
+
return ops[operation];
|
|
175
125
|
},
|
|
176
|
-
execute: async ({ city }) => ({ temperature: 25, city }),
|
|
177
126
|
},
|
|
178
127
|
},
|
|
179
128
|
maxSteps: 3,
|
|
180
129
|
});
|
|
181
130
|
|
|
182
|
-
console.log(result.text);
|
|
183
|
-
console.log(result.
|
|
184
|
-
console.log(result.toolCalls); // Tool calls from last step
|
|
131
|
+
console.log(result.text); // Final answer
|
|
132
|
+
console.log(result.toolCalls); // Tool calls made
|
|
185
133
|
```
|
|
186
134
|
|
|
187
|
-
###
|
|
188
|
-
|
|
189
|
-
The SDK auto-converts Zod schemas to JSON Schema:
|
|
135
|
+
### Structured Output
|
|
190
136
|
|
|
191
137
|
```typescript
|
|
138
|
+
import { generateObject } from '@bowenqt/qiniu-ai-sdk';
|
|
192
139
|
import { z } from 'zod';
|
|
193
140
|
|
|
194
|
-
const
|
|
195
|
-
calculate: {
|
|
196
|
-
description: 'Calculate math',
|
|
197
|
-
parameters: z.object({
|
|
198
|
-
operation: z.enum(['add', 'subtract', 'multiply']),
|
|
199
|
-
a: z.number(),
|
|
200
|
-
b: z.number(),
|
|
201
|
-
}),
|
|
202
|
-
execute: async ({ operation, a, b }) => {
|
|
203
|
-
if (operation === 'add') return a + b;
|
|
204
|
-
if (operation === 'subtract') return a - b;
|
|
205
|
-
return a * b;
|
|
206
|
-
},
|
|
207
|
-
},
|
|
208
|
-
};
|
|
209
|
-
```
|
|
210
|
-
|
|
211
|
-
### JSON Mode (Structured Output)
|
|
212
|
-
|
|
213
|
-
```typescript
|
|
214
|
-
const result = await generateText({
|
|
141
|
+
const result = await generateObject({
|
|
215
142
|
client,
|
|
216
143
|
model: 'gemini-2.5-flash',
|
|
217
|
-
prompt: '
|
|
218
|
-
|
|
219
|
-
|
|
144
|
+
prompt: 'Generate a product listing',
|
|
145
|
+
schema: z.object({
|
|
146
|
+
name: z.string(),
|
|
147
|
+
price: z.number(),
|
|
148
|
+
category: z.string(),
|
|
149
|
+
}),
|
|
220
150
|
});
|
|
221
151
|
|
|
222
|
-
|
|
152
|
+
console.log(result.object); // Typed object
|
|
223
153
|
```
|
|
224
154
|
|
|
225
|
-
|
|
155
|
+
---
|
|
156
|
+
|
|
157
|
+
## ๐ผ๏ธ Image & Video Generation
|
|
226
158
|
|
|
227
159
|
```typescript
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
prompt: 'Write a long essay...',
|
|
236
|
-
abortSignal: controller.signal,
|
|
237
|
-
});
|
|
238
|
-
} catch (error) {
|
|
239
|
-
if (error.code === 'CANCELLED') {
|
|
240
|
-
console.log('Request cancelled');
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
```
|
|
244
|
-
|
|
245
|
-
## Agent SDK (Agentic Layer)
|
|
160
|
+
// Image generation (async task)
|
|
161
|
+
const imageResult = await client.image.generate({
|
|
162
|
+
model: 'kling-v2',
|
|
163
|
+
prompt: 'A futuristic city at sunset',
|
|
164
|
+
});
|
|
165
|
+
const finalImage = await client.image.waitForResult(imageResult);
|
|
166
|
+
console.log(finalImage.data?.[0].url);
|
|
246
167
|
|
|
247
|
-
|
|
168
|
+
// Video generation with first/last frame
|
|
169
|
+
const videoTask = await client.video.create({
|
|
170
|
+
model: 'kling-video-o1',
|
|
171
|
+
prompt: 'A cat jumps from one ledge to another',
|
|
172
|
+
frames: {
|
|
173
|
+
first: { url: 'https://example.com/start.jpg' },
|
|
174
|
+
last: { url: 'https://example.com/end.jpg' },
|
|
175
|
+
},
|
|
176
|
+
duration: '5',
|
|
177
|
+
});
|
|
178
|
+
const videoResult = await client.video.waitForCompletion(videoTask.id);
|
|
179
|
+
console.log(videoResult.task_result?.videos[0].url);
|
|
180
|
+
```
|
|
248
181
|
|
|
249
|
-
|
|
182
|
+
---
|
|
250
183
|
|
|
251
|
-
|
|
184
|
+
## ๐ Vercel AI SDK Adapter
|
|
252
185
|
|
|
253
186
|
```typescript
|
|
254
|
-
import {
|
|
255
|
-
|
|
256
|
-
const client = new QiniuAI({ apiKey: process.env.QINIU_API_KEY });
|
|
257
|
-
|
|
258
|
-
// Load skills
|
|
259
|
-
const loader = new SkillLoader({ skillsDir: './skills' });
|
|
260
|
-
const skills = await loader.loadAll();
|
|
187
|
+
import { createQiniu } from '@bowenqt/qiniu-ai-sdk/adapter';
|
|
188
|
+
import { streamText } from 'ai';
|
|
261
189
|
|
|
262
|
-
const
|
|
263
|
-
|
|
264
|
-
model: 'deepseek-v3',
|
|
265
|
-
messages: [{ role: 'user', content: 'Help me with Git' }],
|
|
266
|
-
skills, // Injected into system prompt
|
|
267
|
-
maxContextTokens: 32000, // Automatic context compaction
|
|
268
|
-
onStepFinish: (step) => console.log(step.type, step.content),
|
|
269
|
-
onNodeEnter: (node) => console.log(`Entering: ${node}`),
|
|
190
|
+
const qiniu = createQiniu({
|
|
191
|
+
apiKey: process.env.QINIU_API_KEY,
|
|
270
192
|
});
|
|
271
193
|
|
|
272
|
-
|
|
273
|
-
|
|
194
|
+
const { textStream } = await streamText({
|
|
195
|
+
model: qiniu.languageModel('gemini-2.5-flash'),
|
|
196
|
+
prompt: 'Introduce Qiniu Cloud briefly.',
|
|
197
|
+
});
|
|
274
198
|
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
console.log('Dropped skills:', result.graphInfo.compaction.droppedSkills);
|
|
199
|
+
for await (const text of textStream) {
|
|
200
|
+
process.stdout.write(text);
|
|
278
201
|
}
|
|
279
202
|
```
|
|
280
203
|
|
|
281
|
-
|
|
282
|
-
- Estimates tokens using CJK-aware algorithm (1.5x weight for Chinese/Japanese/Korean)
|
|
283
|
-
- Drops low-priority skills first when context exceeds budget
|
|
284
|
-
- Preserves tool call/result pairs (never orphaned)
|
|
285
|
-
- Reports dropped content in `graphInfo.compaction`
|
|
204
|
+
---
|
|
286
205
|
|
|
287
|
-
|
|
206
|
+
## ๐ง Advanced Features
|
|
288
207
|
|
|
289
|
-
|
|
208
|
+
### Skills Injection
|
|
290
209
|
|
|
291
210
|
```typescript
|
|
292
|
-
import { SkillLoader } from '@bowenqt/qiniu-ai-sdk';
|
|
293
|
-
|
|
294
|
-
const loader = new SkillLoader({
|
|
295
|
-
skillsDir: './skills',
|
|
296
|
-
maxFileSize: 64 * 1024, // 64KB limit
|
|
297
|
-
allowedExtensions: ['.md', '.txt'],
|
|
298
|
-
});
|
|
299
|
-
|
|
300
|
-
// Load single skill
|
|
301
|
-
const skill = await loader.load('git-workflow');
|
|
302
|
-
console.log(skill.name, skill.tokenCount);
|
|
211
|
+
import { SkillLoader, generateTextWithGraph } from '@bowenqt/qiniu-ai-sdk';
|
|
303
212
|
|
|
304
|
-
|
|
305
|
-
const
|
|
306
|
-
```
|
|
307
|
-
|
|
308
|
-
Skill format (SKILL.md):
|
|
309
|
-
```markdown
|
|
310
|
-
---
|
|
311
|
-
name: git-workflow
|
|
312
|
-
description: Git best practices
|
|
313
|
-
---
|
|
314
|
-
|
|
315
|
-
# Git Workflow
|
|
213
|
+
const loader = new SkillLoader({ skillsDir: './skills' });
|
|
214
|
+
const skills = await loader.loadAll();
|
|
316
215
|
|
|
317
|
-
|
|
216
|
+
const result = await generateTextWithGraph({
|
|
217
|
+
client,
|
|
218
|
+
model: 'deepseek-v3',
|
|
219
|
+
messages: [{ role: 'user', content: 'Help me with Git' }],
|
|
220
|
+
skills,
|
|
221
|
+
maxContextTokens: 32000,
|
|
222
|
+
});
|
|
318
223
|
```
|
|
319
224
|
|
|
320
|
-
### MCP Client (stdio)
|
|
321
|
-
|
|
322
|
-
Connect to Model Context Protocol servers:
|
|
225
|
+
### MCP Client (stdio + HTTP)
|
|
323
226
|
|
|
324
227
|
```typescript
|
|
325
228
|
import { MCPClient } from '@bowenqt/qiniu-ai-sdk';
|
|
@@ -331,642 +234,128 @@ const mcpClient = new MCPClient({
|
|
|
331
234
|
transport: 'stdio',
|
|
332
235
|
command: 'npx',
|
|
333
236
|
args: ['-y', '@modelcontextprotocol/server-github'],
|
|
334
|
-
token: process.env.GITHUB_TOKEN,
|
|
237
|
+
token: process.env.GITHUB_TOKEN,
|
|
335
238
|
},
|
|
336
239
|
],
|
|
337
240
|
});
|
|
338
241
|
|
|
339
242
|
await mcpClient.connect();
|
|
340
243
|
const tools = mcpClient.getAllTools();
|
|
341
|
-
console.log(tools.map(t => t.name));
|
|
342
|
-
|
|
343
|
-
// Use tools with generateText
|
|
344
|
-
const registeredTools = adaptMCPToolsToRegistry(tools, 'github', mcpClient);
|
|
345
244
|
```
|
|
346
245
|
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
### MCP Client (HTTP + OAuth 2.0)
|
|
350
|
-
|
|
351
|
-
Connect to remote MCP servers with OAuth authentication:
|
|
246
|
+
### Checkpointer (State Persistence)
|
|
352
247
|
|
|
353
248
|
```typescript
|
|
354
|
-
import {
|
|
355
|
-
MCPClient,
|
|
356
|
-
PKCEFlow,
|
|
357
|
-
TokenManager,
|
|
358
|
-
MemoryTokenStore
|
|
359
|
-
} from '@bowenqt/qiniu-ai-sdk';
|
|
360
|
-
|
|
361
|
-
// Step 1: Obtain tokens via PKCE flow
|
|
362
|
-
const oauthConfig = {
|
|
363
|
-
clientId: 'my-app',
|
|
364
|
-
scopes: ['mcp:read', 'mcp:write'],
|
|
365
|
-
authorizationUrl: 'https://auth.example.com/authorize',
|
|
366
|
-
tokenUrl: 'https://auth.example.com/token',
|
|
367
|
-
};
|
|
368
|
-
|
|
369
|
-
const pkceFlow = new PKCEFlow(oauthConfig);
|
|
370
|
-
const state = generateState();
|
|
371
|
-
const authUrl = pkceFlow.buildAuthorizationUrl('http://localhost:3000/callback', state);
|
|
372
|
-
// Redirect user to authUrl...
|
|
373
|
-
|
|
374
|
-
// After callback:
|
|
375
|
-
const { code } = await pkceFlow.waitForCallback({ expectedState: state, timeoutMs: 300000 });
|
|
376
|
-
const tokens = await pkceFlow.exchangeCode(code, 'http://localhost:3000/callback');
|
|
377
|
-
|
|
378
|
-
// Step 2: Set up TokenManager
|
|
379
|
-
const tokenManager = new TokenManager(new MemoryTokenStore(), oauthConfig);
|
|
380
|
-
await tokenManager.setTokens(tokens);
|
|
381
|
-
|
|
382
|
-
// Step 3: Connect with tokenProvider
|
|
383
|
-
const mcpClient = new MCPClient({
|
|
384
|
-
servers: [
|
|
385
|
-
{
|
|
386
|
-
name: 'remote-server',
|
|
387
|
-
transport: 'http',
|
|
388
|
-
url: 'https://mcp.example.com/mcp',
|
|
389
|
-
tokenProvider: () => tokenManager.getAccessToken(),
|
|
390
|
-
oauth: oauthConfig, // Required: validates auth is configured
|
|
391
|
-
},
|
|
392
|
-
],
|
|
393
|
-
});
|
|
394
|
-
|
|
395
|
-
await mcpClient.connect();
|
|
396
|
-
```
|
|
397
|
-
|
|
398
|
-
> **Note**: If `oauth` is configured without `token` or `tokenProvider`, MCPClient throws an error to prevent unauthenticated connections.
|
|
399
|
-
|
|
400
|
-
### Checkpointer
|
|
249
|
+
import { MemoryCheckpointer, RedisCheckpointer, KodoCheckpointer } from '@bowenqt/qiniu-ai-sdk';
|
|
401
250
|
|
|
402
|
-
|
|
251
|
+
// In-memory (dev/testing)
|
|
252
|
+
const memoryCheckpointer = new MemoryCheckpointer({ maxItems: 100 });
|
|
403
253
|
|
|
404
|
-
|
|
405
|
-
import { MemoryCheckpointer, deserializeCheckpoint } from '@bowenqt/qiniu-ai-sdk';
|
|
406
|
-
|
|
407
|
-
const checkpointer = new MemoryCheckpointer({ maxItems: 100 });
|
|
408
|
-
|
|
409
|
-
// Save checkpoint
|
|
410
|
-
const metadata = await checkpointer.save('thread-123', agentState);
|
|
411
|
-
|
|
412
|
-
// Load latest checkpoint
|
|
413
|
-
const checkpoint = await checkpointer.load('thread-123');
|
|
414
|
-
if (checkpoint) {
|
|
415
|
-
const restored = deserializeCheckpoint(checkpoint, toolsMap);
|
|
416
|
-
// Resume from restored state
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
// List all checkpoints
|
|
420
|
-
const list = await checkpointer.list('thread-123');
|
|
421
|
-
```
|
|
422
|
-
|
|
423
|
-
### Redis/PostgreSQL Checkpointer
|
|
424
|
-
|
|
425
|
-
For production persistence:
|
|
426
|
-
|
|
427
|
-
```typescript
|
|
428
|
-
import { RedisCheckpointer, PostgresCheckpointer } from '@bowenqt/qiniu-ai-sdk';
|
|
429
|
-
|
|
430
|
-
// Redis (requires ioredis peer dependency)
|
|
254
|
+
// Redis (production)
|
|
431
255
|
const redisCheckpointer = new RedisCheckpointer(redisClient, {
|
|
432
|
-
keyPrefix: '
|
|
433
|
-
ttlSeconds: 86400,
|
|
256
|
+
keyPrefix: 'agent:',
|
|
257
|
+
ttlSeconds: 86400,
|
|
434
258
|
});
|
|
435
259
|
|
|
436
|
-
//
|
|
437
|
-
const
|
|
438
|
-
|
|
439
|
-
|
|
260
|
+
// Kodo (cloud-native/serverless)
|
|
261
|
+
const kodoCheckpointer = new KodoCheckpointer({
|
|
262
|
+
accessKey: process.env.QINIU_ACCESS_KEY!,
|
|
263
|
+
secretKey: process.env.QINIU_SECRET_KEY!,
|
|
264
|
+
bucket: 'checkpoints',
|
|
265
|
+
region: 'z0',
|
|
440
266
|
});
|
|
441
267
|
```
|
|
442
268
|
|
|
443
|
-
### Tracing
|
|
444
|
-
|
|
445
|
-
Integrate with OpenTelemetry for distributed tracing:
|
|
269
|
+
### OpenTelemetry Tracing
|
|
446
270
|
|
|
447
271
|
```typescript
|
|
448
|
-
import { setGlobalTracer, OTelTracer
|
|
449
|
-
|
|
450
|
-
// Console tracer for development
|
|
451
|
-
setGlobalTracer(new ConsoleTracer({ redactPII: true }));
|
|
452
|
-
|
|
453
|
-
// OpenTelemetry tracer for production
|
|
272
|
+
import { setGlobalTracer, OTelTracer } from '@bowenqt/qiniu-ai-sdk';
|
|
454
273
|
import { trace } from '@opentelemetry/api';
|
|
274
|
+
|
|
455
275
|
const otelTracer = new OTelTracer(trace.getTracerProvider());
|
|
456
276
|
setGlobalTracer(otelTracer);
|
|
457
277
|
|
|
458
|
-
// AgentGraph
|
|
459
|
-
// - agent_graph.invoke
|
|
460
|
-
// - agent_graph.predict
|
|
461
|
-
// - agent_graph.execute
|
|
462
|
-
```
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
## Vercel AI SDK Adapter
|
|
466
|
-
|
|
467
|
-
Use the adapter to integrate with the Vercel AI SDK (`streamText`, `generateText`).
|
|
468
|
-
|
|
469
|
-
```typescript
|
|
470
|
-
import { createQiniu } from '@bowenqt/qiniu-ai-sdk/adapter';
|
|
471
|
-
import { streamText } from 'ai';
|
|
472
|
-
|
|
473
|
-
const qiniu = createQiniu({
|
|
474
|
-
apiKey: process.env.QINIU_API_KEY || process.env.OPENAI_API_KEY,
|
|
475
|
-
});
|
|
476
|
-
|
|
477
|
-
const { textStream } = await streamText({
|
|
478
|
-
model: qiniu.languageModel('gemini-2.5-flash'),
|
|
479
|
-
prompt: 'Introduce Qiniu Cloud in one sentence.',
|
|
480
|
-
});
|
|
481
|
-
|
|
482
|
-
for await (const text of textStream) {
|
|
483
|
-
process.stdout.write(text);
|
|
484
|
-
}
|
|
485
|
-
```
|
|
486
|
-
|
|
487
|
-
Notes:
|
|
488
|
-
- If you already have a `QiniuAI` client, pass it via `createQiniu({ client })`.
|
|
489
|
-
- You can override `baseUrl` using `createQiniu({ baseUrl })` or `QINIU_BASE_URL`.
|
|
490
|
-
|
|
491
|
-
## API Reference
|
|
492
|
-
|
|
493
|
-
### Client Initialization
|
|
494
|
-
|
|
495
|
-
```typescript
|
|
496
|
-
import { QiniuAI, consoleLogger } from '@bowenqt/qiniu-ai-sdk';
|
|
497
|
-
|
|
498
|
-
const client = new QiniuAI({
|
|
499
|
-
apiKey: string; // Required: Your Qiniu AI API key
|
|
500
|
-
baseUrl?: string; // Optional: API base URL (default: https://api.qnaigc.com/v1)
|
|
501
|
-
timeout?: number; // Optional: Request timeout in ms (default: 60000)
|
|
502
|
-
logger?: Logger; // Optional: Custom logger (use consoleLogger for debug output)
|
|
503
|
-
logLevel?: LogLevel; // Optional: 'debug' | 'info' | 'warn' | 'error' | 'silent' (default: 'info')
|
|
504
|
-
});
|
|
505
|
-
```
|
|
506
|
-
|
|
507
|
-
### Logging
|
|
508
|
-
|
|
509
|
-
Enable debug logging to see request/response details:
|
|
510
|
-
|
|
511
|
-
```typescript
|
|
512
|
-
import { QiniuAI, consoleLogger } from '@bowenqt/qiniu-ai-sdk';
|
|
513
|
-
|
|
514
|
-
const client = new QiniuAI({
|
|
515
|
-
apiKey: 'Sk-xxx',
|
|
516
|
-
logger: consoleLogger,
|
|
517
|
-
logLevel: 'debug',
|
|
518
|
-
});
|
|
519
|
-
|
|
520
|
-
// Now you'll see logs like:
|
|
521
|
-
// [QiniuAI:DEBUG] HTTP Request { requestId: 'req_123...', method: 'POST', url: '...', timeout: 60000 }
|
|
522
|
-
// [QiniuAI:DEBUG] HTTP Response { requestId: 'req_123...', status: 200, duration: 1234 }
|
|
523
|
-
```
|
|
524
|
-
|
|
525
|
-
Use a custom logger (e.g., pino, winston):
|
|
526
|
-
|
|
527
|
-
```typescript
|
|
528
|
-
import { QiniuAI, Logger } from '@bowenqt/qiniu-ai-sdk';
|
|
529
|
-
import pino from 'pino';
|
|
530
|
-
|
|
531
|
-
const pinoLogger = pino();
|
|
532
|
-
|
|
533
|
-
const customLogger: Logger = {
|
|
534
|
-
debug: (msg, meta) => pinoLogger.debug(meta, msg),
|
|
535
|
-
info: (msg, meta) => pinoLogger.info(meta, msg),
|
|
536
|
-
warn: (msg, meta) => pinoLogger.warn(meta, msg),
|
|
537
|
-
error: (msg, meta) => pinoLogger.error(meta, msg),
|
|
538
|
-
};
|
|
539
|
-
|
|
540
|
-
const client = new QiniuAI({
|
|
541
|
-
apiKey: 'Sk-xxx',
|
|
542
|
-
logger: customLogger,
|
|
543
|
-
});
|
|
544
|
-
```
|
|
545
|
-
|
|
546
|
-
### Middleware
|
|
547
|
-
|
|
548
|
-
Use middleware to intercept and modify requests/responses:
|
|
549
|
-
|
|
550
|
-
```typescript
|
|
551
|
-
import { QiniuAI, Middleware, retryMiddleware, headersMiddleware } from '@bowenqt/qiniu-ai-sdk';
|
|
552
|
-
|
|
553
|
-
// Built-in retry middleware (retries on 5xx errors)
|
|
554
|
-
const retry = retryMiddleware({ maxRetries: 3, retryDelay: 1000 });
|
|
555
|
-
|
|
556
|
-
// Built-in headers middleware (adds custom headers)
|
|
557
|
-
const customHeaders = headersMiddleware({
|
|
558
|
-
'X-Custom-Header': 'my-value',
|
|
559
|
-
});
|
|
560
|
-
|
|
561
|
-
// Custom middleware
|
|
562
|
-
const loggingMiddleware: Middleware = async (request, next) => {
|
|
563
|
-
console.log('Request:', request.method, request.url);
|
|
564
|
-
const response = await next(request);
|
|
565
|
-
console.log('Response:', response.status, response.duration + 'ms');
|
|
566
|
-
return response;
|
|
567
|
-
};
|
|
568
|
-
|
|
569
|
-
const client = new QiniuAI({
|
|
570
|
-
apiKey: 'Sk-xxx',
|
|
571
|
-
middleware: [retry, customHeaders, loggingMiddleware],
|
|
572
|
-
});
|
|
573
|
-
```
|
|
574
|
-
|
|
575
|
-
### Custom HTTP Adapter
|
|
576
|
-
|
|
577
|
-
Replace the default `fetch` with a custom HTTP client:
|
|
578
|
-
|
|
579
|
-
```typescript
|
|
580
|
-
import { QiniuAI, FetchAdapter } from '@bowenqt/qiniu-ai-sdk';
|
|
581
|
-
import axios from 'axios';
|
|
582
|
-
|
|
583
|
-
const axiosAdapter: FetchAdapter = {
|
|
584
|
-
async fetch(url, init) {
|
|
585
|
-
const response = await axios({
|
|
586
|
-
url,
|
|
587
|
-
method: init.method as any,
|
|
588
|
-
headers: init.headers as Record<string, string>,
|
|
589
|
-
data: init.body,
|
|
590
|
-
signal: init.signal,
|
|
591
|
-
validateStatus: () => true, // Don't throw on non-2xx
|
|
592
|
-
});
|
|
593
|
-
|
|
594
|
-
return new Response(JSON.stringify(response.data), {
|
|
595
|
-
status: response.status,
|
|
596
|
-
headers: response.headers as any,
|
|
597
|
-
});
|
|
598
|
-
},
|
|
599
|
-
};
|
|
600
|
-
|
|
601
|
-
const client = new QiniuAI({
|
|
602
|
-
apiKey: 'Sk-xxx',
|
|
603
|
-
adapter: axiosAdapter,
|
|
604
|
-
});
|
|
605
|
-
```
|
|
606
|
-
|
|
607
|
-
### Modules
|
|
608
|
-
|
|
609
|
-
#### `client.chat`
|
|
610
|
-
|
|
611
|
-
- `create(params: ChatCompletionRequest): Promise<ChatCompletionResponse>`
|
|
612
|
-
- `createStream(params: ChatCompletionRequest): AsyncGenerator<ChatCompletionChunk>` (New!)
|
|
613
|
-
|
|
614
|
-
**Streaming Example with Function Calling & Reasoning:**
|
|
615
|
-
|
|
616
|
-
```typescript
|
|
617
|
-
const stream = await client.chat.createStream({
|
|
618
|
-
model: 'gemini-2.5-flash', // Models supporting reasoning
|
|
619
|
-
messages: [{ role: 'user', content: 'Solve this puzzle...' }],
|
|
620
|
-
});
|
|
621
|
-
|
|
622
|
-
for await (const chunk of stream) {
|
|
623
|
-
const delta = chunk.choices[0]?.delta;
|
|
624
|
-
|
|
625
|
-
// Text content
|
|
626
|
-
if (delta?.content) {
|
|
627
|
-
process.stdout.write(delta.content);
|
|
628
|
-
}
|
|
629
|
-
|
|
630
|
-
// Reasoning content (Gemini/Claude thinking process)
|
|
631
|
-
if (delta?.reasoning_content) {
|
|
632
|
-
console.log('[Thinking]:', delta.reasoning_content);
|
|
633
|
-
}
|
|
634
|
-
|
|
635
|
-
// Function calling arguments are also streamed incrementally
|
|
636
|
-
}
|
|
637
|
-
```
|
|
638
|
-
|
|
639
|
-
#### `client.image`
|
|
640
|
-
|
|
641
|
-
- `generate(params: ImageGenerationRequest): Promise<ImageCreateResult>`
|
|
642
|
-
- `waitForResult(result: ImageCreateResult, options?: WaitOptions): Promise<ImageGenerateResult>`
|
|
643
|
-
- `create(params: ImageGenerationRequest): Promise<{ task_id: string }>` (deprecated)
|
|
644
|
-
- `edit(params: ImageEditRequest): Promise<ImageEditResponse>`
|
|
645
|
-
- `get(taskId: string): Promise<ImageTaskResponse>`
|
|
646
|
-
- `waitForCompletion(taskId: string, options?: WaitOptions): Promise<ImageTaskResponse>` (deprecated)
|
|
647
|
-
|
|
648
|
-
Note: For sync models (Gemini), `waitForResult` returns `status: 'succeed'` set by the SDK when data is returned.
|
|
649
|
-
|
|
650
|
-
**Image Edit (Kling/Gemini):**
|
|
651
|
-
|
|
652
|
-
```typescript
|
|
653
|
-
// Kling multi-image edit
|
|
654
|
-
const editTask = await client.image.edit({
|
|
655
|
-
model: 'kling-v1',
|
|
656
|
-
prompt: 'Make it watercolor style',
|
|
657
|
-
image_reference: 'subject',
|
|
658
|
-
subject_image_list: [{ image: 'https://example.com/subject.jpg', image_type: 'subject' }],
|
|
659
|
-
scene_image: { image: 'https://example.com/scene.jpg', image_type: 'scene' },
|
|
660
|
-
style_image: { image: 'https://example.com/style.jpg', image_type: 'style' },
|
|
661
|
-
});
|
|
662
|
-
|
|
663
|
-
// Gemini edit
|
|
664
|
-
const geminiEdit = await client.image.edit({
|
|
665
|
-
model: 'gemini-3.0-pro-image-preview',
|
|
666
|
-
prompt: 'Add a sunset sky',
|
|
667
|
-
image_url: 'https://example.com/input.png',
|
|
668
|
-
image_config: { aspect_ratio: '16:9', image_size: '2K' },
|
|
669
|
-
mask: 'base64-mask-data',
|
|
670
|
-
});
|
|
671
|
-
```
|
|
672
|
-
|
|
673
|
-
#### `client.video`
|
|
674
|
-
|
|
675
|
-
- `create(params: VideoGenerationRequest): Promise<{ id: string }>`
|
|
676
|
-
- `get(id: string): Promise<VideoTaskResponse>`
|
|
677
|
-
- `remix(id: string, params: VideoRemixRequest): Promise<{ id: string }>`
|
|
678
|
-
- `waitForCompletion(id: string, options?: WaitOptions): Promise<VideoTaskResponse>`
|
|
679
|
-
|
|
680
|
-
**First & Last Frame Video Generation:**
|
|
681
|
-
|
|
682
|
-
The SDK provides a unified `frames` parameter that works across all models (Kling, Veo):
|
|
683
|
-
|
|
684
|
-
```typescript
|
|
685
|
-
// Kling first/last frame (multi-frame generation)
|
|
686
|
-
const klingTask = await client.video.create({
|
|
687
|
-
model: 'kling-video-o1',
|
|
688
|
-
prompt: '่ง้ข่ฟ่ดฏๅจไธ่ตท',
|
|
689
|
-
frames: {
|
|
690
|
-
first: { url: 'https://example.com/start.jpg' },
|
|
691
|
-
last: { url: 'https://example.com/end.jpg' }
|
|
692
|
-
},
|
|
693
|
-
size: '1920x1080',
|
|
694
|
-
mode: 'pro'
|
|
695
|
-
});
|
|
696
|
-
|
|
697
|
-
// Veo first/last frame
|
|
698
|
-
const veoTask = await client.video.create({
|
|
699
|
-
model: 'veo-2.0-generate-001',
|
|
700
|
-
prompt: 'A cat jumping from chair to table',
|
|
701
|
-
frames: {
|
|
702
|
-
first: { url: 'https://example.com/cat-chair.jpg' },
|
|
703
|
-
last: { url: 'https://example.com/cat-table.jpg' }
|
|
704
|
-
},
|
|
705
|
-
generate_audio: true,
|
|
706
|
-
resolution: '720p',
|
|
707
|
-
seed: 12345,
|
|
708
|
-
sample_count: 1
|
|
709
|
-
});
|
|
710
|
-
|
|
711
|
-
// Wait for completion (works with both Kling and Veo)
|
|
712
|
-
const result = await client.video.waitForCompletion(veoTask.id);
|
|
713
|
-
console.log(result.task_result?.videos[0].url);
|
|
714
|
-
```
|
|
715
|
-
|
|
716
|
-
**Video Reference Generation (Kling):**
|
|
717
|
-
|
|
718
|
-
```typescript
|
|
719
|
-
const task = await client.video.create({
|
|
720
|
-
model: 'kling-video-o1',
|
|
721
|
-
prompt: '่ๅ่ง้ข้ฃๆ ผ็ๆๆฐๅ
ๅฎน',
|
|
722
|
-
video_list: [{
|
|
723
|
-
video_url: 'https://example.com/reference.mp4',
|
|
724
|
-
refer_type: 'base',
|
|
725
|
-
keep_original_sound: 'yes'
|
|
726
|
-
}]
|
|
727
|
-
});
|
|
728
|
-
```
|
|
729
|
-
|
|
730
|
-
**Kling Native Parameters:**
|
|
731
|
-
|
|
732
|
-
For backward compatibility, you can also use Kling's native parameters directly:
|
|
733
|
-
|
|
734
|
-
```typescript
|
|
735
|
-
// Using image_list directly (kling-video-o1)
|
|
736
|
-
const task = await client.video.create({
|
|
737
|
-
model: 'kling-video-o1',
|
|
738
|
-
prompt: '...',
|
|
739
|
-
image_list: [
|
|
740
|
-
{ image: 'https://...', type: 'first_frame' },
|
|
741
|
-
{ image: 'https://...', type: 'end_frame' }
|
|
742
|
-
]
|
|
743
|
-
});
|
|
744
|
-
|
|
745
|
-
// Using image_tail (kling-v2-5-turbo)
|
|
746
|
-
const task = await client.video.create({
|
|
747
|
-
model: 'kling-v2-5-turbo',
|
|
748
|
-
prompt: '...',
|
|
749
|
-
input_reference: 'https://example.com/start.jpg',
|
|
750
|
-
image_tail: 'https://example.com/end.jpg'
|
|
751
|
-
});
|
|
752
|
-
```
|
|
753
|
-
|
|
754
|
-
**Video Remix (Sora):**
|
|
755
|
-
|
|
756
|
-
```typescript
|
|
757
|
-
const remixTask = await client.video.remix('videos-123...', {
|
|
758
|
-
prompt: 'Make it cinematic',
|
|
759
|
-
});
|
|
760
|
-
console.log(remixTask.id);
|
|
761
|
-
```
|
|
762
|
-
|
|
763
|
-
#### `client.ocr`
|
|
764
|
-
|
|
765
|
-
- `detect(params: OcrRequest): Promise<OcrResponse>`
|
|
766
|
-
|
|
767
|
-
**OCR Example:**
|
|
768
|
-
|
|
769
|
-
```typescript
|
|
770
|
-
const ocrResult = await client.ocr.detect({
|
|
771
|
-
url: 'https://static.qiniu.com/ai-inference/example-resources/ocr-example.png',
|
|
772
|
-
});
|
|
773
|
-
console.log(ocrResult.text);
|
|
774
|
-
```
|
|
775
|
-
|
|
776
|
-
#### `client.asr`
|
|
777
|
-
|
|
778
|
-
- `transcribe(params: AsrRequest): Promise<AsrResponse>`
|
|
779
|
-
|
|
780
|
-
**ASR Example:**
|
|
781
|
-
|
|
782
|
-
```typescript
|
|
783
|
-
const asrResult = await client.asr.transcribe({
|
|
784
|
-
audio: {
|
|
785
|
-
format: 'mp3',
|
|
786
|
-
url: 'https://static.qiniu.com/ai-inference/example-resources/example.mp3',
|
|
787
|
-
},
|
|
788
|
-
});
|
|
789
|
-
console.log(asrResult.text);
|
|
790
|
-
```
|
|
791
|
-
|
|
792
|
-
#### `client.account`
|
|
793
|
-
|
|
794
|
-
- `usage(params: UsageQuery): Promise<UsageResponse>`
|
|
795
|
-
|
|
796
|
-
**Account Usage Example (API Key):**
|
|
797
|
-
|
|
798
|
-
```typescript
|
|
799
|
-
const usage = await client.account.usage({
|
|
800
|
-
granularity: 'day',
|
|
801
|
-
start: '2024-01-01T00:00:00+08:00',
|
|
802
|
-
end: '2024-01-31T23:59:59+08:00',
|
|
803
|
-
});
|
|
804
|
-
console.log(usage.data.length);
|
|
805
|
-
```
|
|
806
|
-
|
|
807
|
-
**Account Usage Example (AK/SK):**
|
|
808
|
-
|
|
809
|
-
```typescript
|
|
810
|
-
const usage = await client.account.usage({
|
|
811
|
-
granularity: 'day',
|
|
812
|
-
start: '2024-01-01T00:00:00+08:00',
|
|
813
|
-
end: '2024-01-31T23:59:59+08:00',
|
|
814
|
-
auth: {
|
|
815
|
-
accessKey: 'your-ak',
|
|
816
|
-
secretKey: 'your-sk',
|
|
817
|
-
},
|
|
818
|
-
});
|
|
819
|
-
console.log(usage.data.length);
|
|
278
|
+
// AgentGraph will now emit spans:
|
|
279
|
+
// - agent_graph.invoke
|
|
280
|
+
// - agent_graph.predict
|
|
281
|
+
// - agent_graph.execute
|
|
820
282
|
```
|
|
821
283
|
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
- `search(params: WebSearchRequest): Promise<WebSearchResult[]>`
|
|
825
|
-
|
|
826
|
-
### Advanced Usage: Generic API Access
|
|
827
|
-
|
|
828
|
-
For features not yet fully wrapped in modules, use the generic `post` and `get` methods.
|
|
829
|
-
|
|
830
|
-
**OCR (Optical Character Recognition):**
|
|
831
|
-
|
|
832
|
-
```typescript
|
|
833
|
-
const response = await client.post<any>('/images/ocr', {
|
|
834
|
-
model: 'ocr',
|
|
835
|
-
url: 'https://example.com/image.png'
|
|
836
|
-
});
|
|
837
|
-
console.log(response.data.result.text);
|
|
838
|
-
```
|
|
839
|
-
|
|
840
|
-
**TTS (Text to Speech):**
|
|
841
|
-
|
|
842
|
-
```typescript
|
|
843
|
-
// Get Voice List
|
|
844
|
-
const voices = await client.get<any[]>('/voice/list');
|
|
845
|
-
|
|
846
|
-
// Synthesize Audio
|
|
847
|
-
const res = await client.post<any>('/voice/tts', {
|
|
848
|
-
request: { text: 'Hello world' },
|
|
849
|
-
audio: { voice_type: 'qiniu_zh_female_xxx' }
|
|
850
|
-
});
|
|
851
|
-
```
|
|
852
|
-
|
|
853
|
-
### Wait Options
|
|
854
|
-
|
|
855
|
-
For `waitForCompletion` and `waitForResult` methods:
|
|
856
|
-
|
|
857
|
-
```typescript
|
|
858
|
-
interface WaitOptions {
|
|
859
|
-
intervalMs?: number; // Polling interval (default: 2000 for image, 3000 for video)
|
|
860
|
-
timeoutMs?: number; // Max wait time (default: 120000 for image, 600000 for video)
|
|
861
|
-
signal?: AbortSignal; // For cancellation support
|
|
862
|
-
maxRetries?: number; // Max retries for transient errors (default: 3)
|
|
863
|
-
}
|
|
864
|
-
```
|
|
865
|
-
|
|
866
|
-
### Error Handling
|
|
284
|
+
---
|
|
867
285
|
|
|
868
|
-
|
|
869
|
-
import { QiniuAI, APIError } from '@bowenqt/qiniu-ai-sdk';
|
|
870
|
-
|
|
871
|
-
try {
|
|
872
|
-
await client.chat.create({ ... });
|
|
873
|
-
} catch (error) {
|
|
874
|
-
if (error instanceof APIError) {
|
|
875
|
-
console.log(error.status); // HTTP status code
|
|
876
|
-
console.log(error.code); // API error code (if any)
|
|
877
|
-
console.log(error.message); // Error message
|
|
878
|
-
}
|
|
879
|
-
}
|
|
880
|
-
```
|
|
286
|
+
## ๐ Supported Models
|
|
881
287
|
|
|
882
|
-
###
|
|
288
|
+
### Chat & Reasoning (66+ models)
|
|
883
289
|
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
} catch (error) {
|
|
899
|
-
if (error.message === 'Operation cancelled') {
|
|
900
|
-
console.log('Task was cancelled');
|
|
901
|
-
}
|
|
902
|
-
}
|
|
903
|
-
```
|
|
904
|
-
|
|
905
|
-
## Supported Models
|
|
906
|
-
|
|
907
|
-
### Chat & Reasoning (66 models)
|
|
290
|
+
| Provider | Models |
|
|
291
|
+
|----------|--------|
|
|
292
|
+
| **Qwen** | qwen3-235b, qwen3-max, qwen3-32b, qwen-turbo |
|
|
293
|
+
| **Claude** | claude-4.5-opus/sonnet/haiku, claude-4.0-opus/sonnet, claude-3.7-sonnet, claude-3.5-sonnet/haiku |
|
|
294
|
+
| **Gemini** | gemini-3.0-flash/pro, gemini-2.5-flash/pro, gemini-2.0-flash |
|
|
295
|
+
| **DeepSeek** | deepseek-r1, deepseek-v3/v3.1/v3.2 |
|
|
296
|
+
| **Doubao** | doubao-seed-1.6, doubao-1.5-pro |
|
|
297
|
+
| **GLM** | glm-4.5/4.6/4.7 |
|
|
298
|
+
| **Grok** | grok-4-fast, grok-4.1-fast |
|
|
299
|
+
| **OpenAI** | gpt-5/5.2, gpt-oss-20b/120b |
|
|
300
|
+
| **Kimi** | kimi-k2 |
|
|
301
|
+
| **MiniMax** | minimax-m2/m2.1 |
|
|
302
|
+
|
|
303
|
+
### Image Generation
|
|
908
304
|
|
|
909
305
|
| Provider | Models |
|
|
910
306
|
|----------|--------|
|
|
911
|
-
| **
|
|
912
|
-
| **
|
|
913
|
-
| **Gemini** | `gemini-3.0-flash-preview`, `gemini-3.0-pro-preview`, `gemini-2.5-flash-lite`, `gemini-2.5-flash`, `gemini-2.5-pro`, `gemini-2.0-flash-lite`, `gemini-2.0-flash` |
|
|
914
|
-
| **DeepSeek** | `deepseek-r1-0528`, `deepseek-r1`, `deepseek-v3`, `deepseek-v3-0324`, `deepseek-v3.1`, `deepseek/deepseek-v3.2-251201`, `deepseek/deepseek-v3.2-exp-thinking`, `deepseek/deepseek-v3.2-exp`, `deepseek/deepseek-v3.1-terminus-thinking`, `deepseek/deepseek-v3.1-terminus` |
|
|
915
|
-
| **Doubao** | `doubao-seed-1.6-thinking`, `doubao-seed-1.6-flash`, `doubao-seed-1.6`, `doubao-1.5-thinking-pro`, `doubao-1.5-pro-32k` |
|
|
916
|
-
| **GLM** | `glm-4.5`, `glm-4.5-air`, `z-ai/glm-4.7`, `z-ai/glm-4.6` |
|
|
917
|
-
| **Grok** | `x-ai/grok-4-fast-reasoning`, `x-ai/grok-4-fast-non-reasoning`, `x-ai/grok-4-fast`, `x-ai/grok-4.1-fast-non-reasoning`, `x-ai/grok-4.1-fast-reasoning`, `x-ai/grok-4.1-fast`, `x-ai/grok-code-fast-1` |
|
|
918
|
-
| **OpenAI** | `openai/gpt-5.2`, `openai/gpt-5`, `gpt-oss-20b`, `gpt-oss-120b` |
|
|
919
|
-
| **Kimi** | `moonshotai/kimi-k2-thinking`, `moonshotai/kimi-k2-0905`, `kimi-k2` |
|
|
920
|
-
| **MiniMax** | `minimax/minimax-m2`, `minimax/minimax-m2.1`, `MiniMax-M1`, `mimo-v2-flash` |
|
|
921
|
-
| **Meituan** | `meituan/longcat-flash-chat` |
|
|
922
|
-
| **StepFun** | `stepfun-ai/gelab-zero-4b-preview` |
|
|
923
|
-
| **AutoGLM** | `z-ai/autoglm-phone-9b` |
|
|
924
|
-
|
|
925
|
-
### Image Generation & Vision
|
|
926
|
-
|
|
927
|
-
| Type | Models |
|
|
928
|
-
|------|--------|
|
|
929
|
-
| **Kling** | `kling-v1`, `kling-v1-5`, `kling-v2`, `kling-v2-new`, `kling-v2-1` |
|
|
930
|
-
| **Gemini** | `gemini-3.0-pro-image-preview`, `gemini-2.5-flash-image` |
|
|
931
|
-
| **Vision** | `doubao-1.5-vision-pro`, `qwen2.5-vl-7b-instruct`, `qwen2.5-vl-72b-instruct`, `qwen-vl-max-2025-01-25` |
|
|
307
|
+
| **Kling** | kling-v1, kling-v1-5, kling-v2, kling-v2-1 |
|
|
308
|
+
| **Gemini** | gemini-3.0-pro-image, gemini-2.5-flash-image |
|
|
932
309
|
|
|
933
310
|
### Video Generation
|
|
934
311
|
|
|
935
312
|
| Provider | Models |
|
|
936
313
|
|----------|--------|
|
|
937
|
-
| **Kling** |
|
|
938
|
-
| **Sora** |
|
|
939
|
-
| **Veo** |
|
|
940
|
-
| **Other** | `minimax/minimax-m2`, `mimo-v2-flash` |
|
|
314
|
+
| **Kling** | kling-video-o1, kling-v2-1, kling-v2-5-turbo |
|
|
315
|
+
| **Sora** | sora-2 |
|
|
316
|
+
| **Veo** | veo-2.0, veo-3.0, veo-3.1 |
|
|
941
317
|
|
|
942
|
-
|
|
318
|
+
---
|
|
319
|
+
|
|
320
|
+
## ๐ Package Exports
|
|
321
|
+
|
|
322
|
+
| Entry Point | Description |
|
|
323
|
+
|-------------|-------------|
|
|
324
|
+
| `@bowenqt/qiniu-ai-sdk` | Main entry (universal) |
|
|
325
|
+
| `@bowenqt/qiniu-ai-sdk/node` | Node.js-only features (SkillLoader, MCPClient stdio) |
|
|
326
|
+
| `@bowenqt/qiniu-ai-sdk/browser` | Browser-compatible subset |
|
|
327
|
+
| `@bowenqt/qiniu-ai-sdk/adapter` | Vercel AI SDK adapter |
|
|
328
|
+
| `@bowenqt/qiniu-ai-sdk/ai-tools` | Qiniu native cloud tools (OCR/Censor/Vframe) |
|
|
329
|
+
|
|
330
|
+
---
|
|
943
331
|
|
|
944
|
-
|
|
945
|
-
|-------|-------------|
|
|
946
|
-
| `ocr` | ๅพ็/PDFๆๆกฃ้ซ็ฒพๅบฆๆๅญ่ฏๅซ๏ผๆฏๆ PNGใJPGใPDF ็ญๆ ผๅผ |
|
|
332
|
+
## ๐ ๏ธ CLI: MCP Server
|
|
947
333
|
|
|
948
|
-
|
|
334
|
+
Run the built-in Qiniu MCP Server:
|
|
949
335
|
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
336
|
+
```bash
|
|
337
|
+
npx qiniu-mcp-server
|
|
338
|
+
```
|
|
953
339
|
|
|
954
|
-
|
|
340
|
+
**Environment variables:**
|
|
341
|
+
- `QINIU_API_KEY` โ API key for OCR/Censor operations
|
|
342
|
+
- `QINIU_ACCESS_KEY` / `QINIU_SECRET_KEY` โ For Vframe/signed operations
|
|
955
343
|
|
|
956
|
-
|
|
344
|
+
---
|
|
957
345
|
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
| ... | ๆดๅค้ณ่ฒ่ฏท้่ฟ API ่ทๅ |
|
|
346
|
+
## ๐ Documentation
|
|
347
|
+
|
|
348
|
+
- **[COOKBOOK.md](./COOKBOOK.md)** โ Copy-ready code examples for all features
|
|
349
|
+
- **[Qiniu AI Developer Center](https://developer.qiniu.com/aitokenapi)** โ Full API reference & pricing
|
|
963
350
|
|
|
964
351
|
---
|
|
965
352
|
|
|
966
|
-
|
|
353
|
+
## ๐ License
|
|
967
354
|
|
|
968
|
-
|
|
355
|
+
MIT ยฉ 2024-2026
|
|
969
356
|
|
|
970
|
-
|
|
357
|
+
---
|
|
971
358
|
|
|
972
|
-
|
|
359
|
+
<div align="center">
|
|
360
|
+
<sub>Built with โค๏ธ for the Qiniu Cloud ecosystem</sub>
|
|
361
|
+
</div>
|