@alicloud/appflow-chat 0.0.4-alpha.2 → 0.0.4-alpha.4

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.
@@ -124,7 +124,7 @@ export declare interface ChatSenderProps {
124
124
  placeholder?: string;
125
125
  /** 提交方式:'enter' 回车发送 | 'shiftEnter' Shift+回车发送 */
126
126
  submitType?: 'enter' | 'shiftEnter';
127
- /** 可用模型列表 */
127
+ /** 可用模型列表,传入且长度>1时显示模型选择下拉框 */
128
128
  models?: ModelInfo[];
129
129
  /** 当前选中的模型ID */
130
130
  modelId?: string;
@@ -134,15 +134,13 @@ export declare interface ChatSenderProps {
134
134
  onModelChange?: (modelId: string) => void;
135
135
  /**
136
136
  * 模型能力配置,控制功能按钮的显隐
137
- * 如果不传,所有功能按钮都显示
137
+ * 不传时默认所有功能关闭
138
138
  */
139
139
  capabilities?: ModelCapabilities;
140
140
  /** 提交消息回调 */
141
141
  onSubmit?: (data: ChatSenderSubmitData) => void;
142
142
  /** 取消当前请求 */
143
143
  onCancel?: () => void;
144
- /** 清除会话回调 */
145
- onClear?: () => void;
146
144
  /** 文件上传方法,返回下载URL */
147
145
  onUpload?: (file: File) => Promise<string>;
148
146
  /** 自定义类名 */
@@ -157,8 +155,13 @@ export declare interface ChatSenderSubmitData {
157
155
  text: string;
158
156
  /** 图片URL列表 */
159
157
  images: string[];
160
- /** 文件URL列表 */
161
- files: string[];
158
+ /** 文件列表(包含文件名和URL */
159
+ files: {
160
+ name: string;
161
+ url: string;
162
+ }[];
163
+ /** 语音文件URL(录音上传后的下载地址) */
164
+ audio?: string;
162
165
  /** 选中的模型ID */
163
166
  modelId?: string;
164
167
  /** 是否启用联网搜索 */
@@ -613,6 +616,13 @@ export declare interface MessageBubbleProps {
613
616
  status?: 'Running' | 'Success' | 'Error';
614
617
  /** 参考资料列表 */
615
618
  references?: DocReferenceItem[];
619
+ /** 图片URL列表(用户消息中上传的图片) */
620
+ images?: string[];
621
+ /** 文件列表(用户消息中上传的文件) */
622
+ files?: {
623
+ name: string;
624
+ url: string;
625
+ }[];
616
626
  /** 自定义类名 */
617
627
  className?: string;
618
628
  /** 自定义样式 */
@@ -649,6 +659,7 @@ export declare interface ModelInfo {
649
659
  config?: {
650
660
  image?: boolean;
651
661
  file?: boolean;
662
+ audio?: boolean;
652
663
  webSearch?: boolean;
653
664
  fileConfig?: string;
654
665
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alicloud/appflow-chat",
3
- "version": "0.0.4-alpha.2",
3
+ "version": "0.0.4-alpha.4",
4
4
  "description": "Appflow-Chat AI聊天机器人组件库,提供聊天服务和UI组件",
5
5
  "type": "module",
6
6
  "main": "./dist/appflow-chat.cjs.js",
package/src/App.tsx ADDED
@@ -0,0 +1,182 @@
1
+ import { useState } from 'react';
2
+ import { ConfigProvider } from 'antd';
3
+ import { ChatSender } from './components/ChatSender';
4
+ import { MessageBubble } from './components/MessageBubble';
5
+ import type { ChatSenderSubmitData } from './components/ChatSender';
6
+ import type { ModelInfo, ModelCapabilities } from './services/ChatService';
7
+
8
+ // 模拟模型列表
9
+ const mockModels: ModelInfo[] = [
10
+ { id: 'model-1', name: '通义千问-VL', config: { image: true, file: true, webSearch: true , audio: true } },
11
+ { id: 'model-2', name: '通义千问-Max', config: { image: false, file: false, webSearch: true } },
12
+ { id: 'model-3', name: 'DeepSeek-R1', config: { image: false, file: false, webSearch: false } },
13
+ ];
14
+
15
+ // 模拟上传
16
+ const mockUpload = async (file: File): Promise<string> => {
17
+ return new Promise((resolve) => {
18
+ setTimeout(() => {
19
+ resolve(`https://example.com/files/${file.name}`);
20
+ }, 1500);
21
+ });
22
+ };
23
+
24
+ function App() {
25
+ const [loading, setLoading] = useState(false);
26
+ const [selectedModelId, setSelectedModelId] = useState(mockModels[0].id);
27
+ const [logs, setLogs] = useState<string[]>([]);
28
+
29
+ // 根据选中模型计算能力
30
+ const currentModel = mockModels.find(m => m.id === selectedModelId) || mockModels[0];
31
+ const capabilities: ModelCapabilities = {
32
+ image: currentModel.config?.image ?? false,
33
+ file: currentModel.config?.file ?? false,
34
+ audio: currentModel.config?.audio ?? false,
35
+ webSearch: currentModel.config?.webSearch ?? false,
36
+ };
37
+
38
+ const addLog = (message: string) => {
39
+ setLogs(prev => [`[${new Date().toLocaleTimeString()}] ${message}`, ...prev].slice(0, 50));
40
+ };
41
+
42
+ // 消息列表
43
+ interface Message {
44
+ id: string;
45
+ role: 'user' | 'bot';
46
+ content: string;
47
+ status: 'Running' | 'Success' | 'Error';
48
+ images?: string[];
49
+ files?: { name: string; url: string }[];
50
+ }
51
+
52
+ const [messages, setMessages] = useState<Message[]>([]);
53
+
54
+ const handleSubmit = (data: ChatSenderSubmitData) => {
55
+ addLog(`发送消息: text="${data.text}", model=${data.modelId}, images=${data.images.length}, files=${data.files.length}, audio=${data.audio || 'none'}, webSearch=${data.webSearch}`);
56
+
57
+ // 构建用户消息(包含图片和文件)
58
+ const userMsg: Message = {
59
+ id: `msg-${Date.now()}`,
60
+ role: 'user',
61
+ content: data.text,
62
+ status: 'Success',
63
+ images: data.images.length > 0 ? data.images : undefined,
64
+ files: data.files.length > 0 ? data.files : undefined,
65
+ };
66
+
67
+ // 构建 bot 占位消息
68
+ const botMsg: Message = {
69
+ id: `msg-${Date.now() + 1}`,
70
+ role: 'bot',
71
+ content: '',
72
+ status: 'Running',
73
+ };
74
+
75
+ setMessages(prev => [...prev, userMsg, botMsg]);
76
+ setLoading(true);
77
+
78
+ // 模拟 AI 回复
79
+ setTimeout(() => {
80
+ setMessages(prev => prev.map(m =>
81
+ m.id === botMsg.id
82
+ ? { ...m, content: '收到你的消息!这是一条模拟的 AI 回复。', status: 'Success' as const }
83
+ : m
84
+ ));
85
+ setLoading(false);
86
+ addLog('AI 回复完成');
87
+ }, 2000);
88
+ };
89
+
90
+ const handleCancel = () => {
91
+ setLoading(false);
92
+ addLog('取消请求');
93
+ };
94
+
95
+ // 切换能力的控制面板
96
+ const [showUpload, setShowUpload] = useState(true);
97
+ const [showAudio, setShowAudio] = useState(false);
98
+
99
+ const adjustedCapabilities: ModelCapabilities = {
100
+ ...capabilities,
101
+ image: showUpload && capabilities.image,
102
+ file: showUpload && capabilities.file,
103
+ audio: showAudio,
104
+ };
105
+
106
+ return (
107
+ <ConfigProvider>
108
+ <div style={{ maxWidth: 800, margin: '40px auto', padding: '0 20px', fontFamily: '-apple-system, BlinkMacSystemFont, sans-serif' }}>
109
+ <h2 style={{ marginBottom: 24, color: '#333' }}>ChatSender 组件预览</h2>
110
+
111
+ {/* 控制面板 */}
112
+ <div style={{ marginBottom: 24, padding: 16, background: '#f5f5f5', borderRadius: 8 }}>
113
+ <h4 style={{ margin: '0 0 12px 0', color: '#666' }}>功能开关(模拟 capabilities 控制)</h4>
114
+ <div style={{ display: 'flex', gap: 16, flexWrap: 'wrap' }}>
115
+ <label style={{ display: 'flex', alignItems: 'center', gap: 4, cursor: 'pointer' }}>
116
+ <input type="checkbox" checked={showUpload} onChange={e => setShowUpload(e.target.checked)} />
117
+ 文件/图片上传
118
+ </label>
119
+ <label style={{ display: 'flex', alignItems: 'center', gap: 4, cursor: 'pointer' }}>
120
+ <input type="checkbox" checked={showAudio} onChange={e => setShowAudio(e.target.checked)} />
121
+ 语音输入
122
+ </label>
123
+ <span style={{ color: '#999', fontSize: 13 }}>
124
+ 当前模型: <strong>{currentModel.name}</strong>
125
+ {capabilities.image && ' | 支持图片'}
126
+ {capabilities.file && ' | 支持文件'}
127
+ </span>
128
+ </div>
129
+ </div>
130
+
131
+ {/* 消息列表 */}
132
+ <div style={{ marginBottom: 24, padding: 16, background: '#fff', borderRadius: 8, minHeight: 200, maxHeight: 500, overflow: 'auto', border: '1px solid #f0f0f0' }}>
133
+ {messages.length === 0 && (
134
+ <div style={{ color: '#999', textAlign: 'center', padding: 40 }}>
135
+ 发送消息后,消息气泡将在此展示(支持图片和文件)
136
+ </div>
137
+ )}
138
+ <div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
139
+ {messages.map(msg => (
140
+ <MessageBubble
141
+ key={msg.id}
142
+ content={msg.content}
143
+ role={msg.role}
144
+ status={msg.status}
145
+ images={msg.images}
146
+ files={msg.files}
147
+ />
148
+ ))}
149
+ </div>
150
+ </div>
151
+
152
+ {/* ChatSender 组件 */}
153
+ <div style={{ marginBottom: 24 }}>
154
+ <ChatSender
155
+ loading={loading}
156
+ models={mockModels}
157
+ modelId={selectedModelId}
158
+ onModelChange={setSelectedModelId}
159
+ capabilities={adjustedCapabilities}
160
+ placeholder="输入消息,按 Enter 发送..."
161
+ onSubmit={handleSubmit}
162
+ onCancel={handleCancel}
163
+ onUpload={mockUpload}
164
+ />
165
+ </div>
166
+
167
+ {/* 日志区域 */}
168
+ <div style={{ padding: 16, background: '#1e1e1e', borderRadius: 8, maxHeight: 300, overflow: 'auto' }}>
169
+ <h4 style={{ margin: '0 0 8px 0', color: '#888', fontSize: 13 }}>事件日志</h4>
170
+ {logs.length === 0 && <div style={{ color: '#666', fontSize: 13 }}>暂无日志,尝试发送消息或上传文件...</div>}
171
+ {logs.map((log, index) => (
172
+ <div key={index} style={{ color: '#4ec9b0', fontSize: 13, lineHeight: 1.6, fontFamily: 'monospace' }}>
173
+ {log}
174
+ </div>
175
+ ))}
176
+ </div>
177
+ </div>
178
+ </ConfigProvider>
179
+ );
180
+ }
181
+
182
+ export default App;