|
@@ -3,14 +3,14 @@
|
|
|
<!-- 左侧对话列表 -->
|
|
|
<div class="sidebar">
|
|
|
<div class="logo">
|
|
|
- <img src="https://mdn.alipayobjects.com/huamei_iwk9zp/afts/img/A*eco6RrQhxbMAAAAAAAAAAAAADgCCAQ/original"
|
|
|
+ <img src="../assets/logos.JPG"
|
|
|
alt="logo" class="logo-img" />
|
|
|
- <span class="logo-text">Ant Design X Vue</span>
|
|
|
+ <span class="logo-text">瑞赢旷世</span>
|
|
|
</div>
|
|
|
|
|
|
<Button @click="onAddConversation" type="link" class="new-chat-btn">
|
|
|
<PlusOutlined />
|
|
|
- New Conversation
|
|
|
+ 新建会话
|
|
|
</Button>
|
|
|
|
|
|
<Conversations :items="conversationItems" :defaultActiveKey="activeConversation" :style="sidebarStyle"
|
|
@@ -55,7 +55,7 @@
|
|
|
</template>
|
|
|
</Welcome>
|
|
|
|
|
|
- <Prompts v-if="placeholderPromptsItems.length" title="Do you want?" :items="placeholderPromptsItems"
|
|
|
+ <Prompts v-if="placeholderPromptsItems.length" title="你有什么问题?" :items="placeholderPromptsItems"
|
|
|
:styles="promptsStyles" @itemClick="onPromptsItemClick" />
|
|
|
</div>
|
|
|
<!-- 底部输入区域 -->
|
|
@@ -131,30 +131,30 @@ const headerOpen = ref(false)
|
|
|
const inputContent = ref('')
|
|
|
const attachedFiles = ref([])
|
|
|
const activeConversation = ref('')
|
|
|
-const API_BASE_URL = 'http://192.168.66.187:8082'
|
|
|
+const API_BASE_URL = 'http://192.168.100.187:8082'//'http://121.36.251.245:8082'
|
|
|
// 对话列表数据
|
|
|
const conversationItems = ref([
|
|
|
{
|
|
|
key: 'chat1',
|
|
|
- label: 'What is Ant Design X?',
|
|
|
+ label: '当前窗口',
|
|
|
}
|
|
|
])
|
|
|
/* 对话列表菜单 */
|
|
|
const menuConfig: ConversationsProps['menu'] = (conversation) => ({
|
|
|
items: [
|
|
|
{
|
|
|
- label: 'Operation 1',
|
|
|
+ label: '操作 1',
|
|
|
key: 'operation1',
|
|
|
icon: h(EditOutlined),
|
|
|
},
|
|
|
{
|
|
|
- label: 'Operation 2',
|
|
|
+ label: '操作 2',
|
|
|
key: 'operation2',
|
|
|
icon: h(StopOutlined),
|
|
|
disabled: true,
|
|
|
},
|
|
|
{
|
|
|
- label: 'Operation 3',
|
|
|
+ label: '操作 3',
|
|
|
key: 'operation3',
|
|
|
icon: h(DeleteOutlined),
|
|
|
danger: true,
|
|
@@ -183,24 +183,24 @@ const roles = {
|
|
|
const placeholderPromptsItems = ref([
|
|
|
{
|
|
|
key: '1',
|
|
|
- label: 'Hot Topics',
|
|
|
- icon: '',//markRaw(FireOutlined),
|
|
|
- description: 'What are you interested in?',
|
|
|
+ label: '热门话题',
|
|
|
+ icon: '',
|
|
|
+ description: '你对什么感兴趣?',
|
|
|
children: [
|
|
|
- { key: '1-1', description: `What's new in X?` },
|
|
|
- { key: '1-2', description: `What's AGI?` },
|
|
|
- { key: '1-3', description: `Where is the doc?` },
|
|
|
+ { key: '1-1', description: 'X的新特性是什么?' },
|
|
|
+ { key: '1-2', description: '什么是AGI?' },
|
|
|
+ { key: '1-3', description: '在哪里可以找到文档?' },
|
|
|
],
|
|
|
},
|
|
|
{
|
|
|
- key: '2',
|
|
|
- label: 'Design Guide',
|
|
|
- icon: '',//markRaw(ReadOutlined),
|
|
|
- description: 'How to design a good product?',
|
|
|
+ key: '2',
|
|
|
+ label: '设计指南',
|
|
|
+ icon: '',
|
|
|
+ description: '如何设计一个好产品?',
|
|
|
children: [
|
|
|
- { key: '2-1', icon: '', description: 'Know the well' },//markRaw(HeartOutlined)
|
|
|
- { key: '2-2', icon: '', description: 'Set the AI role' },//markRaw(SmileOutlined)
|
|
|
- { key: '2-3', icon: '', description: 'Express the feeling' },//markRaw(CommentOutlined)
|
|
|
+ { key: '2-1', icon: '', description: '了解基础' },
|
|
|
+ { key: '2-2', icon: '', description: '设置AI角色' },
|
|
|
+ { key: '2-3', icon: '', description: '表达感受' },
|
|
|
],
|
|
|
},
|
|
|
])
|
|
@@ -208,13 +208,13 @@ const placeholderPromptsItems = ref([
|
|
|
const senderPromptsItems = ref([
|
|
|
{
|
|
|
key: '1',
|
|
|
- description: 'Hot Topics',
|
|
|
- icon: ''//markRaw(FireOutlined),
|
|
|
+ description: '热门话题',
|
|
|
+ icon: ''
|
|
|
},
|
|
|
{
|
|
|
key: '2',
|
|
|
- description: 'Design Guide',
|
|
|
- icon: '',//markRaw(ReadOutlined),
|
|
|
+ description: '设计指南',
|
|
|
+ icon: ''
|
|
|
},
|
|
|
])
|
|
|
|
|
@@ -242,22 +242,20 @@ const { messages, onRequest, setMessages } = useXChat({
|
|
|
request: async ({ message, attachments }, { onSuccess, onError }) => {
|
|
|
try {
|
|
|
loading.value = true
|
|
|
- console.log('messages', messages.value)
|
|
|
- // 保存当前消息状态
|
|
|
- const currentMessages = [...messages.value]
|
|
|
+
|
|
|
+ // 保存发送请求前的消息状态
|
|
|
+ const previousMessages = [...messages.value]
|
|
|
|
|
|
// 构建请求数据
|
|
|
const formData = new FormData()
|
|
|
formData.append('message', message)
|
|
|
|
|
|
- // 添加附件
|
|
|
if (attachments?.length) {
|
|
|
attachments.forEach(file => {
|
|
|
formData.append('files', file)
|
|
|
})
|
|
|
}
|
|
|
|
|
|
- // 发送请求到后端API
|
|
|
const response = await fetch('/api/chat', {
|
|
|
method: 'POST',
|
|
|
body: formData
|
|
@@ -268,9 +266,12 @@ const { messages, onRequest, setMessages } = useXChat({
|
|
|
}
|
|
|
|
|
|
const data = await response.json()
|
|
|
- // 确保在成功回调前不会清空消息
|
|
|
- setMessages(currentMessages)
|
|
|
- onSuccess(data.message)
|
|
|
+
|
|
|
+ // 在调用 onSuccess 之前,确保恢复之前的消息
|
|
|
+ nextTick(() => {
|
|
|
+ setMessages(previousMessages)
|
|
|
+ onSuccess(data.message)
|
|
|
+ })
|
|
|
|
|
|
} catch (error) {
|
|
|
onError(error)
|
|
@@ -280,9 +281,9 @@ const { messages, onRequest, setMessages } = useXChat({
|
|
|
}
|
|
|
}
|
|
|
})[0],
|
|
|
- initialMessages: [], // 添加初始空数组
|
|
|
- // 添加配置以防止自动清空消息
|
|
|
- preserveMessages: true
|
|
|
+ initialMessages: [],
|
|
|
+ preserveMessages: true,
|
|
|
+ clearOnRequest: false
|
|
|
})
|
|
|
|
|
|
// 添加消息状态监听
|
|
@@ -301,8 +302,8 @@ watch(messages, (newMessages) => {
|
|
|
// 监听会话切换
|
|
|
watch(activeConversation, () => {
|
|
|
if (activeConversation.value !== undefined) {
|
|
|
- // 切换会话时清空消息
|
|
|
- setMessages([])
|
|
|
+ // 切换会话时清空消息 会导致第一条记录置空
|
|
|
+ /* setMessages([]) */
|
|
|
}
|
|
|
}, { immediate: true })
|
|
|
|
|
@@ -524,27 +525,41 @@ const handleFocus = () => {
|
|
|
// 修改消息处理部分
|
|
|
const handleSubmit = async () => {
|
|
|
const content = inputContent.value.trim()
|
|
|
- if (!content && !items.value.length) return
|
|
|
+ if (!content && !items.value.length && imageUrls.value.length === 0 && documentUrls.value.length === 0) return
|
|
|
|
|
|
try {
|
|
|
loading.value = true
|
|
|
const userMessageId = `user-${Date.now()}`
|
|
|
|
|
|
- // 保存当前消息状态
|
|
|
- const currentMessages = [...messages.value]
|
|
|
+ // 创建新的消息数组,包含用户消息
|
|
|
+ const newMessages = [
|
|
|
+ ...messages.value,
|
|
|
+ {
|
|
|
+ id: userMessageId,
|
|
|
+ role: 'local',
|
|
|
+ message: content,
|
|
|
+ status: 'success'
|
|
|
+ }
|
|
|
+ ]
|
|
|
|
|
|
- // 添加用户消息
|
|
|
- const newMessages = [...currentMessages, {
|
|
|
- id: userMessageId,
|
|
|
- role: 'local',
|
|
|
+ // 使用函数形式更新消息,确保获取最新状态
|
|
|
+ setMessages(() => newMessages)
|
|
|
+
|
|
|
+
|
|
|
+ const requestData = {
|
|
|
message: content,
|
|
|
- status: 'success'
|
|
|
- }]
|
|
|
+ chat_config_id: "17",
|
|
|
+ user_id: 4,
|
|
|
+ session_id: activeConversation.value,
|
|
|
+ source: "pc",
|
|
|
+ image_urls: imageUrls.value,
|
|
|
+ documents: documentUrls.value,
|
|
|
+ merchant_id: "3",
|
|
|
+ model_type: selectedModelInfo.value.type,
|
|
|
+ model_name: selectedModelInfo.value.name
|
|
|
+ }
|
|
|
|
|
|
- // 更新消息数组
|
|
|
- setMessages(newMessages)
|
|
|
-
|
|
|
- // 清理输入
|
|
|
+ // 清理输入(移到这里,确保在发送请求前清理)
|
|
|
await nextTick(() => {
|
|
|
inputContent.value = ''
|
|
|
items.value = []
|
|
@@ -552,24 +567,12 @@ const handleSubmit = async () => {
|
|
|
documentUrls.value = []
|
|
|
})
|
|
|
|
|
|
- // API 请求
|
|
|
const response = await fetch(`${API_BASE_URL}/api/chat/online/multimodal`, {
|
|
|
method: 'POST',
|
|
|
headers: {
|
|
|
'Content-Type': 'application/json'
|
|
|
},
|
|
|
- body: JSON.stringify({
|
|
|
- message: content,
|
|
|
- chat_config_id: "17",
|
|
|
- user_id: 4,
|
|
|
- session_id: activeConversation.value,
|
|
|
- source: "pc",
|
|
|
- image_urls: imageUrls.value,
|
|
|
- documents: documentUrls.value,
|
|
|
- merchant_id: "3",
|
|
|
- model_type: selectedModelInfo.value.type,
|
|
|
- model_name: selectedModelInfo.value.name
|
|
|
- })
|
|
|
+ body: JSON.stringify(requestData)
|
|
|
})
|
|
|
|
|
|
if (!response.ok) {
|
|
@@ -580,23 +583,24 @@ const handleSubmit = async () => {
|
|
|
if (result.code !== 2000) {
|
|
|
throw new Error(`API returned error code: ${result.code}`)
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
activeConversation.value = result.session_id
|
|
|
+
|
|
|
if (result.choices?.[0]?.message?.content) {
|
|
|
const aiMessageId = `ai-${Date.now()}`
|
|
|
const fullMessage = result.choices[0].message.content
|
|
|
|
|
|
- // 使用最新的消息数组
|
|
|
- const latestMessages = [...messages.value]
|
|
|
- const updatedMessages = [...latestMessages, {
|
|
|
- id: aiMessageId,
|
|
|
- role: 'ai',
|
|
|
- message: '',
|
|
|
- status: 'loading'
|
|
|
- }]
|
|
|
- setMessages(updatedMessages)
|
|
|
-
|
|
|
- // 逐字显示
|
|
|
+ // 使用函数形式更新消息,确保基于最新状态
|
|
|
+ setMessages(currentMessages => [
|
|
|
+ ...currentMessages,
|
|
|
+ {
|
|
|
+ id: aiMessageId,
|
|
|
+ role: 'ai',
|
|
|
+ message: '',
|
|
|
+ status: 'loading'
|
|
|
+ }
|
|
|
+ ])
|
|
|
+
|
|
|
let currentText = ''
|
|
|
const chars = fullMessage.split('')
|
|
|
|
|
@@ -604,21 +608,24 @@ const handleSubmit = async () => {
|
|
|
await new Promise(resolve => setTimeout(resolve, 50))
|
|
|
currentText += chars[i]
|
|
|
|
|
|
- const progressMessages = messages.value.map(msg =>
|
|
|
- msg.id === aiMessageId
|
|
|
- ? { ...msg, message: currentText }
|
|
|
- : msg
|
|
|
+ // 使用函数形式更新消息
|
|
|
+ setMessages(currentMessages =>
|
|
|
+ currentMessages.map(msg =>
|
|
|
+ msg.id === aiMessageId
|
|
|
+ ? { ...msg, message: currentText }
|
|
|
+ : msg
|
|
|
+ )
|
|
|
)
|
|
|
- setMessages(progressMessages)
|
|
|
}
|
|
|
|
|
|
- // 确保最终状态使用最新的消息数组
|
|
|
- const finalMessages = messages.value.map(msg =>
|
|
|
- msg.id === aiMessageId
|
|
|
- ? { ...msg, message: fullMessage, status: 'success' }
|
|
|
- : msg
|
|
|
+ // 最终更新使用函数形式
|
|
|
+ setMessages(currentMessages =>
|
|
|
+ currentMessages.map(msg =>
|
|
|
+ msg.id === aiMessageId
|
|
|
+ ? { ...msg, message: fullMessage, status: 'success' }
|
|
|
+ : msg
|
|
|
+ )
|
|
|
)
|
|
|
- setMessages(finalMessages)
|
|
|
}
|
|
|
|
|
|
} catch (error) {
|
|
@@ -629,13 +636,13 @@ const handleSubmit = async () => {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-// 添加文件上传函数
|
|
|
+// 修改文件上传函数
|
|
|
const uploadFile = async (file: File) => {
|
|
|
const formData = new FormData()
|
|
|
formData.append('file', file)
|
|
|
|
|
|
try {
|
|
|
- const response = await fetch('http://your-api/upload/file', {
|
|
|
+ const response = await fetch(`${API_BASE_URL}/upload/file`, {
|
|
|
method: 'POST',
|
|
|
body: formData
|
|
|
})
|
|
@@ -650,8 +657,10 @@ const uploadFile = async (file: File) => {
|
|
|
const fileUrl = result.data.fileUrl
|
|
|
if (file.type.startsWith('image/')) {
|
|
|
imageUrls.value.push(fileUrl)
|
|
|
+ console.log('Added image URL:', fileUrl, 'Current images:', imageUrls.value)
|
|
|
} else {
|
|
|
documentUrls.value.push(fileUrl)
|
|
|
+ console.log('Added document URL:', fileUrl, 'Current documents:', documentUrls.value)
|
|
|
}
|
|
|
|
|
|
return fileUrl
|
|
@@ -682,7 +691,7 @@ const onPromptsItemClick = async (info: any) => {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-// 添加文件处理函数
|
|
|
+// 修改文件处理函数
|
|
|
const handleFileChange = (info: any) => {
|
|
|
const { fileList } = info
|
|
|
attachedFiles.value = fileList.map((file: any) => ({
|
|
@@ -698,10 +707,12 @@ const handleFileChange = (info: any) => {
|
|
|
if (file.type?.startsWith('image/')) {
|
|
|
if (!imageUrls.value.includes(fileUrl)) {
|
|
|
imageUrls.value.push(fileUrl)
|
|
|
+ console.log('Added image from fileList:', fileUrl)
|
|
|
}
|
|
|
} else {
|
|
|
if (!documentUrls.value.includes(fileUrl)) {
|
|
|
documentUrls.value.push(fileUrl)
|
|
|
+ console.log('Added document from fileList:', fileUrl)
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@@ -732,7 +743,7 @@ const attachmentsNode = computed(() =>
|
|
|
|
|
|
// 添加欢迎页面的计算属性
|
|
|
const welcomeTitle = computed(() => ({
|
|
|
- content: 'Hello, I\'m Ant Design X',
|
|
|
+ content: '你好,我是AI助手',
|
|
|
style: {
|
|
|
fontSize: '24px',
|
|
|
fontWeight: 'bold',
|
|
@@ -740,7 +751,7 @@ const welcomeTitle = computed(() => ({
|
|
|
}
|
|
|
}))
|
|
|
|
|
|
-const welcomeDescription = ref('Base on Ant Design, AGI product interface solution, create a better intelligent vision~')
|
|
|
+const welcomeDescription = ref('')
|
|
|
|
|
|
const [message, contextHolder] = messageAnt.useMessage();
|
|
|
|
|
@@ -767,11 +778,11 @@ const triggerOpen = () => {
|
|
|
}
|
|
|
|
|
|
const senderSubmit = () => {
|
|
|
- message.success('Send message successfully!');
|
|
|
+ message.success('消息发送成功!');
|
|
|
}
|
|
|
|
|
|
const selectFileClick = () => {
|
|
|
- message.info('Mock select file');
|
|
|
+ message.info('选择文件');
|
|
|
}
|
|
|
|
|
|
// 确保所有响应式数据都有初始值
|
|
@@ -786,7 +797,7 @@ const selectRef = ref()
|
|
|
|
|
|
const senderHeader = computed(() =>
|
|
|
h(Sender.Header, {
|
|
|
- title: "Attachments",
|
|
|
+ title: "附件",
|
|
|
styles: {
|
|
|
content: {
|
|
|
padding: 0,
|
|
@@ -818,11 +829,11 @@ const senderHeader = computed(() =>
|
|
|
}
|
|
|
},
|
|
|
placeholder: (type: string) => type === 'drop'
|
|
|
- ? { title: 'Drop file here' }
|
|
|
+ ? { title: '将文件拖放到此处' }
|
|
|
: {
|
|
|
icon: h(CloudUploadOutlined),
|
|
|
- title: 'Upload files',
|
|
|
- description: 'Click or drag files to this area to upload',
|
|
|
+ title: '上传文件',
|
|
|
+ description: '点击或将文件拖拽到此区域上传',
|
|
|
},
|
|
|
getDropContainer: () => senderRef.value?.nativeElement
|
|
|
})
|
|
@@ -843,11 +854,26 @@ const handleInputChange = (value: string) => {
|
|
|
inputContent.value = value
|
|
|
}
|
|
|
|
|
|
-// 添加清理文件的函数
|
|
|
+// 修改清理文件的函数
|
|
|
const clearFiles = () => {
|
|
|
+ // 清空文件数组
|
|
|
attachedFiles.value = []
|
|
|
imageUrls.value = []
|
|
|
documentUrls.value = []
|
|
|
+
|
|
|
+ // 重置Attachments组件的状态
|
|
|
+ if (senderRef.value) {
|
|
|
+ // 尝试访问Attachments组件并重置其状态
|
|
|
+ const attachmentsComponent = senderRef.value.$refs?.attachmentsRef
|
|
|
+ if (attachmentsComponent) {
|
|
|
+ attachmentsComponent.fileList = []
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 重置header的打开状态
|
|
|
+ open.value = false
|
|
|
+
|
|
|
+ console.log('Files cleared')
|
|
|
}
|
|
|
|
|
|
// 在 script setup 中添加滚动逻辑
|