@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.
@@ -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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alicloud/appflow-chat",
3
- "version": "0.0.4-alpha.10",
3
+ "version": "0.0.4-alpha.12",
4
4
  "description": "Appflow-Chat AI聊天机器人组件库,提供聊天服务和UI组件",
5
5
  "type": "module",
6
6
  "main": "./dist/appflow-chat.cjs.js",
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.audio ? '' : data.text,
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
- <Attachments
433
- ref={attachmentsRef as any}
434
- items={attachmentItems as AttachmentsProps['items']}
435
- accept={acceptTypes}
436
- multiple
437
- customRequest={({ file }) => {
438
- if (file instanceof File) {
439
- handleFileUpload(file);
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
- return updated;
449
- });
450
- }}
451
- placeholder={{
452
- icon: <CloudUploadOutlined />,
453
- title: '拖拽文件到此处',
454
- description: '支持图片和文件',
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
- if (this.config?.models?.length) {
502
- requestBody.chatbotModelId = this.config.models[0]?.id || '';
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);