Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
S
saas-lab
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
EzijingWeb
saas-lab
Commits
620daf75
提交
620daf75
authored
8月 14, 2024
作者:
王鹏飞
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
chore: 修改AI数据分析
上级
7e659cdd
隐藏空白字符变更
内嵌
并排
正在显示
5 个修改的文件
包含
84 行增加
和
53 行删除
+84
-53
api.ts
src/modules/ai/api.ts
+5
-0
Upload.vue
src/modules/ai/components/Upload.vue
+3
-3
useChat.js
src/modules/ai/composabels/useChat.js
+68
-44
Index.vue
src/modules/ai/views/Index.vue
+8
-5
axios.ts
src/utils/axios.ts
+0
-1
没有找到文件。
src/modules/ai/api.ts
浏览文件 @
620daf75
...
...
@@ -4,3 +4,8 @@ import httpRequest from '@/utils/axios'
export
function
qwenChat
(
data
:
any
)
{
return
httpRequest
.
post
(
'/api/lab/v1/experiment/qwen/chat'
,
data
,
{
headers
:
{
'Content-Type'
:
'application/json'
}
})
}
// 聊天(流式响应)
export
function
aiChat
(
data
:
any
)
{
return
httpRequest
.
post
(
'/api/ai/api/chat/data-analysis/generate-chart'
,
data
,
{
headers
:
{
'Content-Type'
:
'application/json'
}
})
}
src/modules/ai/components/Upload.vue
浏览文件 @
620daf75
...
...
@@ -3,7 +3,7 @@ const emit = defineEmits(['success'])
const
file
=
ref
()
const
onSuccess
=
res
=>
{
file
.
value
=
res
.
data
.
detail
file
.
value
=
res
.
data
emit
(
'success'
,
file
.
value
)
}
</
script
>
...
...
@@ -12,13 +12,13 @@ const onSuccess = res => {
<el-upload
class=
"ai-upload"
drag
action=
"/api/
lab/v1/experiment/qwen
/upload-file"
action=
"/api/
ai/api
/upload-file"
accept=
".csv, .xls, .xlsx, text/csv, application/csv,text/comma-separated-values, application/csv, application/excel,application/vnd.msexcel, text/anytext, application/vnd. ms-excel,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
:data=
"
{ purpose: 'file-extract' }"
:show-file-list="false"
:on-success="onSuccess">
<ul
class=
"ai-upload-list"
v-if=
"file"
>
<li>
{{
file
.
filename
}}
</li>
<li>
{{
file
.
file
_
name
}}
</li>
</ul>
<div
class=
"ai-upload-box"
>
<img
src=
"@/assets/images/ai_plus.png"
height=
"40"
/>
...
...
src/modules/ai/composabels/useChat.js
浏览文件 @
620daf75
import
{
fetchEventSource
}
from
'@microsoft/fetch-event-source'
import
{
ElMessage
}
from
'element-plus'
// import { fetchEventSource } from '@microsoft/fetch-event-source'
// import { ElMessage } from 'element-plus'
// export function useChat() {
// const messages = ref([])
// const isLoading = ref(false)
// async function post() {
// isLoading.value = true
// await fetchEventSource('/api/lab/v1/experiment/qwen/chat', {
// method: 'POST',
// headers: { 'Content-Type': 'application/json' },
// body: JSON.stringify({ model: 'qwen-long', messages: messages.value }),
// async onopen(response) {
// if (response.ok) {
// return response
// } else {
// throw response
// }
// },
// onmessage(res) {
// console.log(res.data)
// try {
// const message = JSON.parse(res.data)
// if (message.error) {
// ElMessage.error(message.error.message)
// return
// }
// const id = message.id
// const messageIndex = messages.value.findIndex(session => session.id === id)
// let content = message?.choices[0]?.delta.content || ''
// content = content.replaceAll('\n', '<br/>')
// if (messageIndex === -1) {
// messages.value.push({ id, role: 'assistant', content })
// } else {
// messages.value[messageIndex].content = messages.value[messageIndex].content + content
// }
// isLoading.value = false
// } catch (error) {
// console.log(error)
// isLoading.value = false
// }
// },
// onerror(err) {
// isLoading.value = false
// throw err
// }
// })
// }
// return { messages, post, isLoading }
// }
import
{
aiChat
}
from
'../api'
export
function
useChat
()
{
const
messages
=
ref
([])
const
isLoading
=
ref
(
false
)
async
function
post
()
{
async
function
post
(
data
)
{
isLoading
.
value
=
true
await
fetchEventSource
(
'/api/lab/v1/experiment/qwen/chat'
,
{
method
:
'POST'
,
headers
:
{
'Content-Type'
:
'application/json'
},
body
:
JSON
.
stringify
({
model
:
'qwen-long'
,
messages
:
messages
.
value
}),
async
onopen
(
response
)
{
if
(
response
.
ok
)
{
return
response
}
else
{
throw
response
}
},
onmessage
(
res
)
{
console
.
log
(
res
.
data
)
try
{
const
message
=
JSON
.
parse
(
res
.
data
)
if
(
message
.
error
)
{
ElMessage
.
error
(
message
.
error
.
message
)
return
}
const
id
=
message
.
id
const
messageIndex
=
messages
.
value
.
findIndex
(
session
=>
session
.
id
===
id
)
let
content
=
message
?.
choices
[
0
]?.
delta
.
content
||
''
content
=
content
.
replaceAll
(
'
\
n'
,
'<br/>'
)
if
(
messageIndex
===
-
1
)
{
messages
.
value
.
push
({
id
,
role
:
'assistant'
,
content
})
}
else
{
messages
.
value
[
messageIndex
].
content
=
messages
.
value
[
messageIndex
].
content
+
content
}
isLoading
.
value
=
false
}
catch
(
error
)
{
console
.
log
(
error
)
isLoading
.
value
=
false
}
},
onerror
(
err
)
{
isLoading
.
value
=
false
throw
err
}
})
try
{
const
response
=
await
aiChat
(
data
)
const
items
=
response
.
data
.
items
||
[]
items
.
filter
(
item
=>
item
.
type
===
'text'
||
item
.
type
===
'html'
)
.
forEach
(
item
=>
{
messages
.
value
.
push
({
role
:
'assistant'
,
content
:
item
.
content
,
type
:
item
.
type
})
})
}
catch
(
error
)
{
isLoading
.
value
=
false
throw
error
}
finally
{
isLoading
.
value
=
false
}
}
return
{
messages
,
post
,
isLoading
}
}
src/modules/ai/views/Index.vue
浏览文件 @
620daf75
...
...
@@ -5,16 +5,16 @@ const { messages, post, isLoading } = useChat()
const
chatInput
=
ref
(
''
)
const
file
=
ref
(
null
)
const
onUploadSuccess
=
res
=>
{
const
message
=
{
role
:
'system'
,
content
:
`fileid://
${
res
.
id
}
`
}
messages
.
value
.
push
(
message
)
file
.
value
=
res
}
async
function
postMessage
()
{
if
(
!
chatInput
.
value
)
return
const
message
=
{
role
:
'user'
,
content
:
chatInput
.
value
}
messages
.
value
.
push
(
message
)
post
(
message
)
post
(
{
file_path
:
file
.
value
?.
file_path
,
file_name
:
file
.
value
?.
file_name
,
chart_content
:
chatInput
.
value
}
)
chatInput
.
value
=
''
}
const
chatRef
=
ref
()
...
...
@@ -43,7 +43,10 @@ watch(messages.value, () => nextTick(() => scrollToBottom()))
<template
v-for=
"(item, index) in messages"
:key=
"index"
>
<div
class=
"ai-message-item"
:class=
"item.role"
v-if=
"item.role !== 'system'"
>
<div
class=
"ai-message__avatar"
><img
:src=
"item.role === 'assistant' ? '/images/ai_avatar_bot.png' : '/images/ai_avatar_user.png'"
/></div>
<div
class=
"ai-message__content"
v-html=
"item.content"
></div>
<div
class=
"ai-message__content"
>
<iframe
:srcdoc=
"item.content"
frameborder=
"0"
v-if=
"item.type === 'html'"
width=
"900"
height=
"500"
></iframe>
<div
v-html=
"item.content"
v-else
></div>
</div>
</div>
</
template
>
<div
class=
"ai-message-item"
v-if=
"isLoading"
>
...
...
@@ -76,7 +79,7 @@ watch(messages.value, () => nextTick(() => scrollToBottom()))
flex
:
none
;
}
.el-upload-dragger
{
padding
:
80px
0
;
padding
:
80px
20px
;
}
}
}
...
...
src/utils/axios.ts
浏览文件 @
620daf75
...
...
@@ -5,7 +5,6 @@ import { useAppConfig } from '@/composables/useAppConfig'
const
appConfig
=
useAppConfig
()
const
httpRequest
=
axios
.
create
({
timeout
:
60000
,
withCredentials
:
true
,
headers
:
{
'Content-Type'
:
'application/x-www-form-urlencoded'
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论