@tais00/api 0.7.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 +612 -0
- package/dist/api/index.d.ts +604 -0
- package/dist/base-request.d.ts +22 -0
- package/dist/enums/index.d.ts +61 -0
- package/dist/index.cjs +3837 -0
- package/dist/index.cjs.LICENSE.txt +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +3791 -0
- package/dist/index.js.LICENSE.txt +1 -0
- package/dist/types/event.d.ts +231 -0
- package/dist/types/file.d.ts +4 -0
- package/dist/types/index.d.ts +3 -0
- package/dist/types/message.d.ts +143 -0
- package/package.json +61 -0
package/README.md
ADDED
|
@@ -0,0 +1,612 @@
|
|
|
1
|
+
# @dify-chat/api
|
|
2
|
+
|
|
3
|
+
  
|
|
4
|
+
|
|
5
|
+
`@dify-chat/api` 是 [Dify Chat](https://github.com/lexmin0412/dify-chat) 项目中的一个包,它提供了一套完整的方法来操作 Dify 应用,包括获取应用信息、管理会话、发送消息等功能。
|
|
6
|
+
|
|
7
|
+
下面将介绍如何在你的应用中集成和使用它。
|
|
8
|
+
|
|
9
|
+
## 安装
|
|
10
|
+
|
|
11
|
+
通过 npm/yarn/pnpm 安装:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
# npm
|
|
15
|
+
npm install @dify-chat/api
|
|
16
|
+
|
|
17
|
+
# yarn
|
|
18
|
+
yarn add @dify-chat/api
|
|
19
|
+
|
|
20
|
+
# pnpm
|
|
21
|
+
pnpm add @dify-chat/api
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## 基本使用
|
|
25
|
+
|
|
26
|
+
```ts
|
|
27
|
+
import { createDifyApiInstance, DifyApi } from '@dify-chat/api'
|
|
28
|
+
|
|
29
|
+
// 创建实例方式1:使用工厂函数
|
|
30
|
+
const api = createDifyApiInstance({
|
|
31
|
+
user: 'user123',
|
|
32
|
+
apiBase: 'https://api.dify.ai/v1',
|
|
33
|
+
apiKey: 'app-YOUR_API_KEY',
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
// 创建实例方式2:直接实例化
|
|
37
|
+
const api2 = new DifyApi({
|
|
38
|
+
user: 'user123',
|
|
39
|
+
apiBase: 'https://api.dify.ai/v1',
|
|
40
|
+
apiKey: 'app-YOUR_API_KEY',
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
// 调用API
|
|
44
|
+
api.getAppInfo().then(appInfo => {
|
|
45
|
+
console.log(appInfo)
|
|
46
|
+
})
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## API 实例配置
|
|
50
|
+
|
|
51
|
+
实例化 `DifyApi` 时需要提供以下配置:
|
|
52
|
+
|
|
53
|
+
```ts
|
|
54
|
+
interface IDifyApiOptions {
|
|
55
|
+
/**
|
|
56
|
+
* 用户标识
|
|
57
|
+
*/
|
|
58
|
+
user: string
|
|
59
|
+
/**
|
|
60
|
+
* API 前缀,默认 https://api.dify.ai/v1
|
|
61
|
+
*/
|
|
62
|
+
apiBase: string
|
|
63
|
+
/**
|
|
64
|
+
* Dify APP API 密钥
|
|
65
|
+
*/
|
|
66
|
+
apiKey: string
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## API 方法
|
|
71
|
+
|
|
72
|
+
> 注意:开发此包的初衷是为了实现主项目 Dify Chat 的相关功能,所以并不是所有的官方 API 都会存在对应的方法。如需调用其他 API,请自行参考官方文档。
|
|
73
|
+
|
|
74
|
+
### 更新 API 配置
|
|
75
|
+
|
|
76
|
+
当需要切换应用时,可以更新 API 配置。
|
|
77
|
+
|
|
78
|
+
```ts
|
|
79
|
+
api.updateOptions({
|
|
80
|
+
user: 'newUser',
|
|
81
|
+
apiBase: 'https://api.dify.ai/v1',
|
|
82
|
+
apiKey: 'app-NEW_API_KEY',
|
|
83
|
+
})
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### 获取应用基本信息
|
|
87
|
+
|
|
88
|
+
```ts
|
|
89
|
+
const appInfo = await api.getAppInfo()
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
**返回值类型:**
|
|
93
|
+
|
|
94
|
+
```ts
|
|
95
|
+
interface IGetAppInfoResponse {
|
|
96
|
+
name: string
|
|
97
|
+
description: string
|
|
98
|
+
tags: string[]
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### 获取应用 Meta 信息
|
|
103
|
+
|
|
104
|
+
```ts
|
|
105
|
+
const appMeta = await api.getAppMeta()
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
**返回值类型:**
|
|
109
|
+
|
|
110
|
+
```ts
|
|
111
|
+
interface IGetAppMetaResponse {
|
|
112
|
+
tool_icons: {
|
|
113
|
+
dalle2: string
|
|
114
|
+
api_tool: {
|
|
115
|
+
background: string
|
|
116
|
+
content: string
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### 获取应用参数
|
|
123
|
+
|
|
124
|
+
```ts
|
|
125
|
+
const appParameters = await api.getAppParameters()
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
**返回值类型:**
|
|
129
|
+
|
|
130
|
+
```ts
|
|
131
|
+
interface IGetAppParametersResponse {
|
|
132
|
+
opening_statement?: string
|
|
133
|
+
user_input_form: IUserInputForm[]
|
|
134
|
+
suggested_questions?: string[]
|
|
135
|
+
suggested_questions_after_answer: {
|
|
136
|
+
enabled: boolean
|
|
137
|
+
}
|
|
138
|
+
file_upload: {
|
|
139
|
+
enabled: boolean
|
|
140
|
+
allowed_file_extensions: string[]
|
|
141
|
+
allowed_file_types: IFileType[]
|
|
142
|
+
allowed_file_upload_methods: Array<'remote_url' | 'local_file'>
|
|
143
|
+
fileUploadConfig: {
|
|
144
|
+
file_size_limit: number
|
|
145
|
+
batch_count_limit: number
|
|
146
|
+
image_file_size_limit: number
|
|
147
|
+
video_file_size_limit: number
|
|
148
|
+
audio_file_size_limit: number
|
|
149
|
+
workflow_file_upload_limit: number
|
|
150
|
+
}
|
|
151
|
+
image: {
|
|
152
|
+
enabled: false
|
|
153
|
+
number_limits: 3
|
|
154
|
+
transfer_methods: ['local_file', 'remote_url']
|
|
155
|
+
}
|
|
156
|
+
number_limits: number
|
|
157
|
+
}
|
|
158
|
+
text_to_speech: {
|
|
159
|
+
enabled: boolean
|
|
160
|
+
autoPlay: 'enabled' | 'disabled'
|
|
161
|
+
language: string
|
|
162
|
+
voice: string
|
|
163
|
+
}
|
|
164
|
+
speech_to_text: {
|
|
165
|
+
enabled: boolean
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
### 会话管理
|
|
171
|
+
|
|
172
|
+
#### 获取会话列表
|
|
173
|
+
|
|
174
|
+
```ts
|
|
175
|
+
const conversations = await api.listConversations({ limit: 20 })
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
**参数:**
|
|
179
|
+
|
|
180
|
+
```ts
|
|
181
|
+
interface IListConversationsRequest {
|
|
182
|
+
limit: number
|
|
183
|
+
}
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
**返回值类型:**
|
|
187
|
+
|
|
188
|
+
```ts
|
|
189
|
+
interface IGetConversationListResponse {
|
|
190
|
+
data: IConversationItem[]
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
interface IConversationItem {
|
|
194
|
+
created_at: number
|
|
195
|
+
id: string
|
|
196
|
+
inputs: Record<string, unknown>
|
|
197
|
+
introduction: string
|
|
198
|
+
name: string
|
|
199
|
+
status: 'normal'
|
|
200
|
+
updated_at: number
|
|
201
|
+
}
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
#### 重命名会话
|
|
205
|
+
|
|
206
|
+
```ts
|
|
207
|
+
await api.renameConversation({
|
|
208
|
+
conversation_id: 'conversation_id',
|
|
209
|
+
name: '新的会话名称',
|
|
210
|
+
})
|
|
211
|
+
|
|
212
|
+
// 自动生成名称
|
|
213
|
+
await api.renameConversation({
|
|
214
|
+
conversation_id: 'conversation_id',
|
|
215
|
+
auto_generate: true,
|
|
216
|
+
})
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
**参数:**
|
|
220
|
+
|
|
221
|
+
```ts
|
|
222
|
+
{
|
|
223
|
+
conversation_id: string;
|
|
224
|
+
name?: string;
|
|
225
|
+
auto_generate?: boolean;
|
|
226
|
+
}
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
#### 删除会话
|
|
230
|
+
|
|
231
|
+
```ts
|
|
232
|
+
await api.deleteConversation('conversation_id')
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
#### 获取会话历史消息
|
|
236
|
+
|
|
237
|
+
```ts
|
|
238
|
+
const history = await api.listMessages('conversation_id')
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
**返回值类型:**
|
|
242
|
+
|
|
243
|
+
```ts
|
|
244
|
+
interface IListMessagesResponse {
|
|
245
|
+
data: IMessageItem[]
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
interface IMessageItem {
|
|
249
|
+
id: string
|
|
250
|
+
conversation_id: string
|
|
251
|
+
inputs: Record<string, string>
|
|
252
|
+
query: string
|
|
253
|
+
answer: string
|
|
254
|
+
message_files: []
|
|
255
|
+
feedback?: {
|
|
256
|
+
rating: 'like' | 'dislike'
|
|
257
|
+
}
|
|
258
|
+
status: 'normal' | 'error'
|
|
259
|
+
error: string | null
|
|
260
|
+
agent_thoughts?: IAgentThought[]
|
|
261
|
+
created_at: number
|
|
262
|
+
retriever_resources?: IRetrieverResource[]
|
|
263
|
+
}
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
### 消息相关
|
|
267
|
+
|
|
268
|
+
#### 发送消息
|
|
269
|
+
|
|
270
|
+
```ts
|
|
271
|
+
const response = await api.sendMessage({
|
|
272
|
+
conversation_id: 'conversation_id', // 可选,不传则创建新会话
|
|
273
|
+
inputs: {
|
|
274
|
+
// 输入参数,键值对形式
|
|
275
|
+
param1: 'value1',
|
|
276
|
+
},
|
|
277
|
+
files: [], // 附件,可以是远程URL或本地上传的文件ID
|
|
278
|
+
user: 'user123',
|
|
279
|
+
response_mode: 'streaming',
|
|
280
|
+
query: '你好,请问...',
|
|
281
|
+
})
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
**参数:**
|
|
285
|
+
|
|
286
|
+
```ts
|
|
287
|
+
{
|
|
288
|
+
conversation_id?: string;
|
|
289
|
+
inputs: Record<string, string>;
|
|
290
|
+
files: IFile[];
|
|
291
|
+
user: string;
|
|
292
|
+
response_mode: 'streaming';
|
|
293
|
+
query: string;
|
|
294
|
+
}
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
#### 文件类型定义
|
|
298
|
+
|
|
299
|
+
```ts
|
|
300
|
+
export type IFileType = 'document' | 'image' | 'audio' | 'video' | 'custom'
|
|
301
|
+
|
|
302
|
+
export interface IFileBase {
|
|
303
|
+
type: IFileType
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
export interface IFileRemote extends IFileBase {
|
|
307
|
+
transfer_method: 'remote_url'
|
|
308
|
+
url?: string
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
export interface IFileLocal extends IFileBase {
|
|
312
|
+
transfer_method: 'local_file'
|
|
313
|
+
upload_file_id?: string
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
export type IFile = IFileRemote | IFileLocal
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
#### 停止生成
|
|
320
|
+
|
|
321
|
+
```ts
|
|
322
|
+
await api.stopTask('taskId')
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
#### 获取下一轮建议问题
|
|
326
|
+
|
|
327
|
+
```ts
|
|
328
|
+
const suggestions = await api.getNextSuggestions({
|
|
329
|
+
message_id: 'message_id',
|
|
330
|
+
})
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
**返回值类型:**
|
|
334
|
+
|
|
335
|
+
```ts
|
|
336
|
+
{
|
|
337
|
+
data: string[]
|
|
338
|
+
}
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
#### 消息反馈
|
|
342
|
+
|
|
343
|
+
```ts
|
|
344
|
+
await api.createMessageFeedback({
|
|
345
|
+
messageId: 'message_id',
|
|
346
|
+
rating: 'like', // 'like' | 'dislike' | null
|
|
347
|
+
content: '反馈内容',
|
|
348
|
+
})
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
**参数:**
|
|
352
|
+
|
|
353
|
+
```ts
|
|
354
|
+
{
|
|
355
|
+
messageId: string
|
|
356
|
+
rating: 'like' | 'dislike' | null
|
|
357
|
+
content: string
|
|
358
|
+
}
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
### 文件操作
|
|
362
|
+
|
|
363
|
+
#### 上传文件
|
|
364
|
+
|
|
365
|
+
```ts
|
|
366
|
+
const fileInfo = await api.uploadFile(file)
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
**参数:**
|
|
370
|
+
|
|
371
|
+
- `file`: 浏览器 File 对象
|
|
372
|
+
|
|
373
|
+
**返回值类型:**
|
|
374
|
+
|
|
375
|
+
```ts
|
|
376
|
+
interface IUploadFileResponse {
|
|
377
|
+
id: string
|
|
378
|
+
name: string
|
|
379
|
+
size: number
|
|
380
|
+
extension: string
|
|
381
|
+
mime_type: string
|
|
382
|
+
created_by: number
|
|
383
|
+
created_at: number
|
|
384
|
+
}
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
### 语音相关
|
|
388
|
+
|
|
389
|
+
#### 文字转语音
|
|
390
|
+
|
|
391
|
+
```ts
|
|
392
|
+
// 通过消息ID转换
|
|
393
|
+
const audioResponse = await api.text2Audio({
|
|
394
|
+
message_id: 'message_id',
|
|
395
|
+
})
|
|
396
|
+
|
|
397
|
+
// 通过文本内容转换
|
|
398
|
+
const audioResponse2 = await api.text2Audio({
|
|
399
|
+
text: '要转换的文本内容',
|
|
400
|
+
})
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
**参数:**
|
|
404
|
+
|
|
405
|
+
```ts
|
|
406
|
+
| {
|
|
407
|
+
message_id: string;
|
|
408
|
+
}
|
|
409
|
+
| {
|
|
410
|
+
text: string;
|
|
411
|
+
}
|
|
412
|
+
```
|
|
413
|
+
|
|
414
|
+
#### 语音转文字
|
|
415
|
+
|
|
416
|
+
```ts
|
|
417
|
+
const textResponse = await api.audio2Text(audioFile)
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
**参数:**
|
|
421
|
+
|
|
422
|
+
- `audioFile`: 语音文件。支持格式:['mp3', 'mp4', 'mpeg', 'mpga', 'm4a', 'wav', 'webm'] 文件大小限制:15MB
|
|
423
|
+
|
|
424
|
+
**返回值类型:**
|
|
425
|
+
|
|
426
|
+
```ts
|
|
427
|
+
interface IAudio2TextResponse {
|
|
428
|
+
text: string
|
|
429
|
+
}
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
### 工作流相关
|
|
433
|
+
|
|
434
|
+
#### 执行 workflow
|
|
435
|
+
|
|
436
|
+
```ts
|
|
437
|
+
const workflowResponse = await api.runWorkflow({
|
|
438
|
+
inputs: {
|
|
439
|
+
// 输入参数,键值对形式
|
|
440
|
+
param1: 'value1',
|
|
441
|
+
param2: [
|
|
442
|
+
/* 文件数组 */
|
|
443
|
+
],
|
|
444
|
+
},
|
|
445
|
+
})
|
|
446
|
+
```
|
|
447
|
+
|
|
448
|
+
参数:
|
|
449
|
+
|
|
450
|
+
```ts
|
|
451
|
+
{
|
|
452
|
+
inputs: Record<string, IFile[] | unknown>
|
|
453
|
+
}
|
|
454
|
+
```
|
|
455
|
+
|
|
456
|
+
#### 获取 workflow 执行情况
|
|
457
|
+
|
|
458
|
+
```ts
|
|
459
|
+
const workflowResult = await api.getWorkflowResult({
|
|
460
|
+
workflow_run_id: 'workflow_run_id',
|
|
461
|
+
})
|
|
462
|
+
```
|
|
463
|
+
|
|
464
|
+
参数:
|
|
465
|
+
|
|
466
|
+
```ts
|
|
467
|
+
{
|
|
468
|
+
workflow_run_id: string
|
|
469
|
+
}
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
响应体:
|
|
473
|
+
|
|
474
|
+
```ts
|
|
475
|
+
{
|
|
476
|
+
/** workflow 执行 ID */
|
|
477
|
+
id: string
|
|
478
|
+
/** 关联的 Workflow ID */
|
|
479
|
+
workflow_id: string
|
|
480
|
+
/** 执行状态 running / succeeded / failed / stopped */
|
|
481
|
+
status: string
|
|
482
|
+
/** 任务输入内容 */
|
|
483
|
+
inputs: object
|
|
484
|
+
/** 任务输出内容 */
|
|
485
|
+
outputs: object
|
|
486
|
+
/** 错误原因 */
|
|
487
|
+
error: string
|
|
488
|
+
/** 任务执行总步数 */
|
|
489
|
+
total_steps: number
|
|
490
|
+
/** 任务执行总 tokens */
|
|
491
|
+
total_tokens: number
|
|
492
|
+
/** 任务开始时间 */
|
|
493
|
+
created_at: number
|
|
494
|
+
/** 任务结束时间 */
|
|
495
|
+
finished_at: number
|
|
496
|
+
/** 耗时(s) */
|
|
497
|
+
elapsed_time: number
|
|
498
|
+
}
|
|
499
|
+
```
|
|
500
|
+
|
|
501
|
+
### 文本生成相关
|
|
502
|
+
|
|
503
|
+
#### 执行文本生成
|
|
504
|
+
|
|
505
|
+
```ts
|
|
506
|
+
const completionResponse = await api.completion({
|
|
507
|
+
inputs: {
|
|
508
|
+
// 输入参数,键值对形式
|
|
509
|
+
param1: 'value1',
|
|
510
|
+
param2: [
|
|
511
|
+
/* 文件数组 */
|
|
512
|
+
],
|
|
513
|
+
},
|
|
514
|
+
})
|
|
515
|
+
```
|
|
516
|
+
|
|
517
|
+
参数:
|
|
518
|
+
|
|
519
|
+
```ts
|
|
520
|
+
{
|
|
521
|
+
inputs: Record<string, IFile[] | unknown>
|
|
522
|
+
}
|
|
523
|
+
```
|
|
524
|
+
|
|
525
|
+
## 完整事件类型
|
|
526
|
+
|
|
527
|
+
API 响应中包含各种事件类型,完整定义如下:
|
|
528
|
+
|
|
529
|
+
```ts
|
|
530
|
+
export enum EventEnum {
|
|
531
|
+
MESSAGE = 'message',
|
|
532
|
+
AGENT_MESSAGE = 'agent_message',
|
|
533
|
+
AGENT_THOUGHT = 'agent_thought',
|
|
534
|
+
MESSAGE_FILE = 'message_file',
|
|
535
|
+
MESSAGE_END = 'message_end',
|
|
536
|
+
TTS_MESSAGE = 'tts_message',
|
|
537
|
+
TTS_MESSAGE_END = 'tts_message_end',
|
|
538
|
+
MESSAGE_REPLACE = 'message_replace',
|
|
539
|
+
ERROR = 'error',
|
|
540
|
+
PING = 'ping',
|
|
541
|
+
WORKFLOW_STARTED = 'workflow_started',
|
|
542
|
+
WORKFLOW_FINISHED = 'workflow_finished',
|
|
543
|
+
WORKFLOW_NODE_STARTED = 'node_started',
|
|
544
|
+
WORKFLOW_NODE_FINISHED = 'node_finished',
|
|
545
|
+
}
|
|
546
|
+
```
|
|
547
|
+
|
|
548
|
+
## 示例:完整的对话流程
|
|
549
|
+
|
|
550
|
+
```ts
|
|
551
|
+
import { createDifyApiInstance } from '@dify-chat/api'
|
|
552
|
+
|
|
553
|
+
async function chatExample() {
|
|
554
|
+
// 1. 创建API实例
|
|
555
|
+
const api = createDifyApiInstance({
|
|
556
|
+
user: 'user123',
|
|
557
|
+
apiBase: 'https://api.dify.ai/v1',
|
|
558
|
+
apiKey: 'app-YOUR_API_KEY',
|
|
559
|
+
})
|
|
560
|
+
|
|
561
|
+
// 2. 获取应用信息
|
|
562
|
+
const appInfo = await api.getAppInfo()
|
|
563
|
+
console.log('应用信息:', appInfo)
|
|
564
|
+
|
|
565
|
+
// 3. 获取应用参数
|
|
566
|
+
const appParams = await api.getAppParameters()
|
|
567
|
+
console.log('应用参数:', appParams)
|
|
568
|
+
|
|
569
|
+
// 4. 发送消息
|
|
570
|
+
const messageStream = await api.sendMessage({
|
|
571
|
+
inputs: {},
|
|
572
|
+
files: [],
|
|
573
|
+
user: 'user123',
|
|
574
|
+
response_mode: 'streaming',
|
|
575
|
+
query: '你好,请介绍一下自己',
|
|
576
|
+
})
|
|
577
|
+
|
|
578
|
+
// 5. 处理流式响应
|
|
579
|
+
const reader = messageStream.body.getReader()
|
|
580
|
+
const decoder = new TextDecoder()
|
|
581
|
+
|
|
582
|
+
while (true) {
|
|
583
|
+
const { done, value } = await reader.read()
|
|
584
|
+
if (done) break
|
|
585
|
+
|
|
586
|
+
const chunk = decoder.decode(value)
|
|
587
|
+
const lines = chunk.split('\n').filter(line => line.trim() !== '')
|
|
588
|
+
|
|
589
|
+
for (const line of lines) {
|
|
590
|
+
if (line.startsWith('data: ')) {
|
|
591
|
+
const data = JSON.parse(line.substring(6))
|
|
592
|
+
console.log('收到事件:', data.event)
|
|
593
|
+
|
|
594
|
+
if (data.event === 'message') {
|
|
595
|
+
console.log('AI回复内容:', data.answer)
|
|
596
|
+
} else if (data.event === 'error') {
|
|
597
|
+
console.error('错误:', data.message)
|
|
598
|
+
} else if (data.event === 'message_end') {
|
|
599
|
+
console.log('消息结束')
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
```
|
|
606
|
+
|
|
607
|
+
## 注意事项
|
|
608
|
+
|
|
609
|
+
1. 所有 API 方法均返回 Promise,可以使用 async/await 或 .then() 处理
|
|
610
|
+
2. 消息发送采用流式响应,需要处理 ReadableStream
|
|
611
|
+
3. API 密钥格式通常为 `app-XXXXXXXX`,需要从 Dify 控制台获取
|
|
612
|
+
4. 用户ID可以是任意字符串,用于标识用户身份,便于区分不同用户的会话
|