@alicloud/appflow-chat 0.0.4-alpha.10 → 0.0.4-alpha.12
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/dist/appflow-chat.cjs.js +17 -17
- package/dist/appflow-chat.esm.js +3167 -3165
- package/dist/types/index.d.ts +2 -2
- package/package.json +1 -1
- package/src/App.tsx +3 -6
- package/src/components/ChatSender.tsx +32 -30
- package/src/services/ChatService.ts +9 -7
package/dist/types/index.d.ts
CHANGED
|
@@ -148,7 +148,7 @@ export declare interface ChatSenderProps {
|
|
|
148
148
|
/** 取消当前请求 */
|
|
149
149
|
onCancel?: () => void;
|
|
150
150
|
/** 文件上传方法,返回下载URL和可选的fileId */
|
|
151
|
-
onUpload?: (file: File) => Promise<{
|
|
151
|
+
onUpload?: (file: File, modelId?: string) => Promise<{
|
|
152
152
|
downloadUrl: string;
|
|
153
153
|
fileId?: string;
|
|
154
154
|
}>;
|
|
@@ -221,7 +221,7 @@ export declare class ChatService {
|
|
|
221
221
|
* 非图片文件会额外获取 fileId(用于服务端文件关联)
|
|
222
222
|
* @returns 上传结果,包含 downloadUrl 和可选的 fileId
|
|
223
223
|
*/
|
|
224
|
-
upload(file: File): Promise<UploadResult>;
|
|
224
|
+
upload(file: File, modelId?: string): Promise<UploadResult>;
|
|
225
225
|
/**
|
|
226
226
|
* 清除会话
|
|
227
227
|
*/
|
package/package.json
CHANGED
package/src/App.tsx
CHANGED
|
@@ -13,7 +13,7 @@ const mockModels: ModelInfo[] = [
|
|
|
13
13
|
];
|
|
14
14
|
|
|
15
15
|
// 模拟上传
|
|
16
|
-
const mockUpload = async (file: File): Promise<{ downloadUrl: string; fileId?: string }> => {
|
|
16
|
+
const mockUpload = async (file: File, _modelId?: string): Promise<{ downloadUrl: string; fileId?: string }> => {
|
|
17
17
|
return new Promise((resolve) => {
|
|
18
18
|
setTimeout(() => {
|
|
19
19
|
// 音频文件返回 blob URL,以便本地测试播放
|
|
@@ -55,7 +55,6 @@ function App() {
|
|
|
55
55
|
status: 'Running' | 'Success' | 'Error';
|
|
56
56
|
images?: string[];
|
|
57
57
|
files?: { name: string; url: string }[];
|
|
58
|
-
audio?: string;
|
|
59
58
|
}
|
|
60
59
|
|
|
61
60
|
const [messages, setMessages] = useState<Message[]>([]);
|
|
@@ -63,15 +62,14 @@ function App() {
|
|
|
63
62
|
const handleSubmit = (data: ChatSenderSubmitData) => {
|
|
64
63
|
addLog(`发送消息: text="${data.text}", model=${data.modelId}, images=${data.images.length}, files=${data.files.length}, audio=${data.audio || 'none'}, webSearch=${data.webSearch}`);
|
|
65
64
|
|
|
66
|
-
//
|
|
65
|
+
// 构建用户消息(包含图片和文件)
|
|
67
66
|
const userMsg: Message = {
|
|
68
67
|
id: `msg-${Date.now()}`,
|
|
69
68
|
role: 'user',
|
|
70
|
-
content: data.
|
|
69
|
+
content: data.text,
|
|
71
70
|
status: 'Success',
|
|
72
71
|
images: data.images.length > 0 ? data.images : undefined,
|
|
73
72
|
files: data.files.length > 0 ? data.files : undefined,
|
|
74
|
-
audio: data.audio || undefined,
|
|
75
73
|
};
|
|
76
74
|
|
|
77
75
|
// 构建 bot 占位消息
|
|
@@ -154,7 +152,6 @@ function App() {
|
|
|
154
152
|
status={msg.status}
|
|
155
153
|
images={msg.images}
|
|
156
154
|
files={msg.files}
|
|
157
|
-
audio={msg.audio}
|
|
158
155
|
/>
|
|
159
156
|
))}
|
|
160
157
|
</div>
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import React, { useState, useRef, useCallback, useMemo, useEffect } from 'react';
|
|
6
6
|
import { Sender, Attachments } from '@ant-design/x';
|
|
7
7
|
import type { AttachmentsProps } from '@ant-design/x';
|
|
8
|
-
import { Select, Switch, Button, Tooltip } from 'antd';
|
|
8
|
+
import { Select, Switch, Button, Tooltip, Spin } from 'antd';
|
|
9
9
|
import {
|
|
10
10
|
PaperClipOutlined,
|
|
11
11
|
PictureOutlined,
|
|
@@ -105,7 +105,7 @@ export interface ChatSenderProps {
|
|
|
105
105
|
/** 取消当前请求 */
|
|
106
106
|
onCancel?: () => void;
|
|
107
107
|
/** 文件上传方法,返回下载URL和可选的fileId */
|
|
108
|
-
onUpload?: (file: File) => Promise<{ downloadUrl: string; fileId?: string }>;
|
|
108
|
+
onUpload?: (file: File, modelId?: string) => Promise<{ downloadUrl: string; fileId?: string }>;
|
|
109
109
|
|
|
110
110
|
// ==================== 样式 ====================
|
|
111
111
|
|
|
@@ -332,7 +332,7 @@ export const ChatSender: React.FC<ChatSenderProps> = ({
|
|
|
332
332
|
setHeaderOpen(true);
|
|
333
333
|
|
|
334
334
|
try {
|
|
335
|
-
const result = await onUpload(file);
|
|
335
|
+
const result = await onUpload(file, currentModelId);
|
|
336
336
|
setAttachments(prev =>
|
|
337
337
|
prev.map(a => a.uid === uid ? { ...a, status: 'done' as const, url: result.downloadUrl, fileId: result.fileId } : a)
|
|
338
338
|
);
|
|
@@ -341,7 +341,7 @@ export const ChatSender: React.FC<ChatSenderProps> = ({
|
|
|
341
341
|
prev.map(a => a.uid === uid ? { ...a, status: 'error' as const } : a)
|
|
342
342
|
);
|
|
343
343
|
}
|
|
344
|
-
}, [onUpload, hasImageCapability, hasFileCapability]);
|
|
344
|
+
}, [onUpload, hasImageCapability, hasFileCapability, currentModelId]);
|
|
345
345
|
|
|
346
346
|
// ==================== 提交处理 ====================
|
|
347
347
|
|
|
@@ -429,34 +429,36 @@ export const ChatSender: React.FC<ChatSenderProps> = ({
|
|
|
429
429
|
content: { padding: 4 },
|
|
430
430
|
}}
|
|
431
431
|
>
|
|
432
|
-
<
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
}}
|
|
442
|
-
onRemove={(file) => {
|
|
443
|
-
setAttachments(prev => {
|
|
444
|
-
const updated = prev.filter(a => a.uid !== file.uid);
|
|
445
|
-
if (updated.length === 0) {
|
|
446
|
-
setHeaderOpen(false);
|
|
432
|
+
<Spin spinning={isUploading} tip="文件上传中,请稍候...">
|
|
433
|
+
<Attachments
|
|
434
|
+
ref={attachmentsRef as any}
|
|
435
|
+
items={attachmentItems as AttachmentsProps['items']}
|
|
436
|
+
accept={acceptTypes}
|
|
437
|
+
multiple
|
|
438
|
+
customRequest={({ file }) => {
|
|
439
|
+
if (file instanceof File) {
|
|
440
|
+
handleFileUpload(file);
|
|
447
441
|
}
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
442
|
+
}}
|
|
443
|
+
onRemove={(file) => {
|
|
444
|
+
setAttachments(prev => {
|
|
445
|
+
const updated = prev.filter(a => a.uid !== file.uid);
|
|
446
|
+
if (updated.length === 0) {
|
|
447
|
+
setHeaderOpen(false);
|
|
448
|
+
}
|
|
449
|
+
return updated;
|
|
450
|
+
});
|
|
451
|
+
}}
|
|
452
|
+
placeholder={{
|
|
453
|
+
icon: <CloudUploadOutlined />,
|
|
454
|
+
title: '拖拽文件到此处',
|
|
455
|
+
description: '支持图片和文件',
|
|
456
|
+
}}
|
|
457
|
+
/>
|
|
458
|
+
</Spin>
|
|
457
459
|
</Sender.Header>
|
|
458
460
|
);
|
|
459
|
-
}, [hasUploadCapability, headerOpen, attachmentItems]);
|
|
461
|
+
}, [hasUploadCapability, headerOpen, attachmentItems, isUploading]);
|
|
460
462
|
|
|
461
463
|
// ==================== 触发文件选择 ====================
|
|
462
464
|
|
|
@@ -520,7 +522,7 @@ export const ChatSender: React.FC<ChatSenderProps> = ({
|
|
|
520
522
|
|
|
521
523
|
try {
|
|
522
524
|
// 上传音频文件
|
|
523
|
-
const result = await onUpload(audioFile);
|
|
525
|
+
const result = await onUpload(audioFile, currentModelId);
|
|
524
526
|
|
|
525
527
|
// 发送语音消息(audio 优先级最高,服务端会忽略 text/images/files)
|
|
526
528
|
onSubmit?.({
|
|
@@ -474,7 +474,8 @@ class ChatService {
|
|
|
474
474
|
private async sendUploadEvent(
|
|
475
475
|
eventType: 'uploadToken' | 'uploadFile',
|
|
476
476
|
fileName: string,
|
|
477
|
-
extraData?: Record<string, any
|
|
477
|
+
extraData?: Record<string, any>,
|
|
478
|
+
modelId?: string
|
|
478
479
|
): Promise<any> {
|
|
479
480
|
const domain = this.setupConfig?.domain || '';
|
|
480
481
|
const integrateId = this.config?.integrateId || '';
|
|
@@ -494,12 +495,13 @@ class ChatService {
|
|
|
494
495
|
}
|
|
495
496
|
};
|
|
496
497
|
|
|
497
|
-
// 携带 sessionId 和 chatbotModelId
|
|
498
|
+
// 携带 sessionId 和 chatbotModelId(优先使用传入的 modelId,否则使用第一个模型)
|
|
498
499
|
if (this.sessionId) {
|
|
499
500
|
requestBody.sessionId = this.sessionId;
|
|
500
501
|
}
|
|
501
|
-
|
|
502
|
-
|
|
502
|
+
const resolvedModelId = modelId || this.config?.models[0]?.id;
|
|
503
|
+
if (resolvedModelId) {
|
|
504
|
+
requestBody.chatbotModelId = resolvedModelId;
|
|
503
505
|
}
|
|
504
506
|
|
|
505
507
|
const response = await fetch(`${domain}/webhook/chatbot/chat/${integrateId}`, {
|
|
@@ -578,14 +580,14 @@ class ChatService {
|
|
|
578
580
|
* 非图片文件会额外获取 fileId(用于服务端文件关联)
|
|
579
581
|
* @returns 上传结果,包含 downloadUrl 和可选的 fileId
|
|
580
582
|
*/
|
|
581
|
-
async upload(file: File): Promise<UploadResult> {
|
|
583
|
+
async upload(file: File, modelId?: string): Promise<UploadResult> {
|
|
582
584
|
if (!this.isInitialized) {
|
|
583
585
|
throw new Error('请先调用 setup() 初始化SDK');
|
|
584
586
|
}
|
|
585
587
|
|
|
586
588
|
try {
|
|
587
589
|
// 1. 获取上传预签名URL
|
|
588
|
-
const uploadInfo = await this.sendUploadEvent('uploadToken', file.name);
|
|
590
|
+
const uploadInfo = await this.sendUploadEvent('uploadToken', file.name, undefined, modelId);
|
|
589
591
|
|
|
590
592
|
if (!uploadInfo?.uploadUrl) {
|
|
591
593
|
console.error('获取上传URL失败,uploadInfo:', uploadInfo);
|
|
@@ -609,7 +611,7 @@ class ChatService {
|
|
|
609
611
|
try {
|
|
610
612
|
const fileIdResult = await this.sendUploadEvent('uploadFile', file.name, {
|
|
611
613
|
fileUrl: uploadInfo.downloadUrl,
|
|
612
|
-
});
|
|
614
|
+
}, modelId);
|
|
613
615
|
fileId = fileIdResult?.fileId;
|
|
614
616
|
} catch (e) {
|
|
615
617
|
console.warn('获取fileId失败,将继续使用downloadUrl:', e);
|