Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
S
skyagents
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
EzijingWeb
skyagents
Commits
a9dbe94e
提交
a9dbe94e
authored
10月 09, 2026
作者:
王鹏飞
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
chore: 更新版本号并清理无用代码
上级
917d145e
显示空白字符变更
内嵌
并排
正在显示
4 个修改的文件
包含
57 行增加
和
179 行删除
+57
-179
deploy.mjs
deploy.mjs
+3
-3
package-lock.json
package-lock.json
+2
-38
App.vue
src/App.vue
+2
-6
useAI.js
src/composables/useAI.js
+50
-132
没有找到文件。
deploy.mjs
浏览文件 @
a9dbe94e
...
...
@@ -7,9 +7,9 @@ const log = console.log
const
__dirname
=
path
.
resolve
()
const
client
=
new
OSS
({
region
:
'oss-cn-beijing'
,
accessKeyId
:
'LTAI
OTuuLTaWoGJj
'
,
accessKeySecret
:
'
dE5tTGm2lh35eItct2krW2DeH2lf2I
'
,
bucket
:
'webapp-pub'
accessKeyId
:
'LTAI
5t6yKc2m47ZUZTBbUBuP
'
,
accessKeySecret
:
'
mhuPVC43NAkzBaheHyWGjREiIrLax0
'
,
bucket
:
'webapp-pub'
,
})
async
function
uploadTarget
(
src
,
dist
)
{
...
...
package-lock.json
浏览文件 @
a9dbe94e
{
"name"
:
"skyagents"
,
"version"
:
"
0
.0.0"
,
"version"
:
"
1
.0.0"
,
"lockfileVersion"
:
3
,
"requires"
:
true
,
"packages"
:
{
""
:
{
"name"
:
"skyagents"
,
"version"
:
"
0
.0.0"
,
"version"
:
"
1
.0.0"
,
"dependencies"
:
{
"@floating-ui/vue"
:
"^1.1.6"
,
"@fortaine/fetch-event-source"
:
"^3.0.6"
,
...
...
@@ -1491,18 +1491,6 @@
"dev"
:
true
,
"license"
:
"MIT"
},
"node_modules/@types/node"
:
{
"version"
:
"22.13.1"
,
"resolved"
:
"https://registry.npmjs.org/@types/node/-/node-22.13.1.tgz"
,
"integrity"
:
"sha512-jK8uzQlrvXqEU91UxiK5J7pKHyzgnI1Qnl0QDHIgVGuolJhRb9EEl28Cj9b3rGR8B2lhFCtvIm5os8lFnO/1Ew=="
,
"dev"
:
true
,
"license"
:
"MIT"
,
"optional"
:
true
,
"peer"
:
true
,
"dependencies"
:
{
"undici-types"
:
"~6.20.0"
}
},
"node_modules/@types/web-bluetooth"
:
{
"version"
:
"0.0.20"
,
"resolved"
:
"https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.20.tgz"
,
...
...
@@ -4341,21 +4329,6 @@
"url"
:
"https://github.com/sponsors/sindresorhus"
}
},
"node_modules/typescript"
:
{
"version"
:
"5.7.3"
,
"resolved"
:
"https://registry.npmjs.org/typescript/-/typescript-5.7.3.tgz"
,
"integrity"
:
"sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw=="
,
"license"
:
"Apache-2.0"
,
"optional"
:
true
,
"peer"
:
true
,
"bin"
:
{
"tsc"
:
"bin/tsc"
,
"tsserver"
:
"bin/tsserver"
},
"engines"
:
{
"node"
:
">=14.17"
}
},
"node_modules/ufo"
:
{
"version"
:
"1.5.4"
,
"resolved"
:
"https://registry.npmjs.org/ufo/-/ufo-1.5.4.tgz"
,
...
...
@@ -4363,15 +4336,6 @@
"dev"
:
true
,
"license"
:
"MIT"
},
"node_modules/undici-types"
:
{
"version"
:
"6.20.0"
,
"resolved"
:
"https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz"
,
"integrity"
:
"sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="
,
"dev"
:
true
,
"license"
:
"MIT"
,
"optional"
:
true
,
"peer"
:
true
},
"node_modules/unescape"
:
{
"version"
:
"1.0.1"
,
"resolved"
:
"https://registry.npmjs.org/unescape/-/unescape-1.0.1.tgz"
,
...
...
src/App.vue
浏览文件 @
a9dbe94e
...
...
@@ -2,7 +2,6 @@
import
{
useTextSelection
,
watchDebounced
,
useClipboard
}
from
'@vueuse/core'
import
{
useFloating
}
from
'@floating-ui/vue'
import
{
useAI
}
from
'@/composables/useAI'
import
{
useUser
}
from
'@/composables/useUser'
const
blacklist
=
[
'saas-x.ezijing.com'
,
'172.16.3.203'
,
'172.16.3.45'
]
...
...
@@ -32,7 +31,6 @@ watchDebounced(
},
{
debounce
:
200
,
maxWait
:
1000
}
)
const
{
userName
}
=
useUser
()
const
{
ai
,
options
,
messages
,
post
,
isLoading
}
=
useAI
()
async
function
postMessage
(
content
)
{
if
(
!
userChatInput
.
value
)
return
...
...
@@ -44,10 +42,8 @@ async function postMessage(content) {
async
function
handleSearch
()
{
dialogVisible
.
value
=
true
let
content
=
userChatInput
.
value
if
(
userName
.
value
)
{
content
=
`我是
${
userName
.
value
}
,请帮我查询有关
${
userChatInput
.
value
}
的信息`
}
const
query
=
userChatInput
.
value
.
trim
().
replace
(
/
\s
+/g
,
' '
)
const
content
=
`请用通俗易懂的语言解释以下内容:\n\n
${
query
}
`
await
postMessage
(
content
)
}
async
function
handleSend
()
{
...
...
src/composables/useAI.js
浏览文件 @
a9dbe94e
import
md5
from
'blueimp-md5'
import
{
useStorage
}
from
'@vueuse/core'
import
{
fetchEventSource
}
from
'@fortaine/fetch-event-source'
import
axios
from
'axios'
export
function
useAI
()
{
// AI 配置列表
const
options
=
[
{
label
:
'文心一言'
,
value
:
'yiyan'
},
//
{ label: '文心一言', value: 'yiyan' },
{
label
:
'DeepSeek'
,
value
:
'deepseek'
},
{
label
:
'通义千问'
,
value
:
'qwen'
},
{
label
:
'天工'
,
value
:
'tiangong'
},
//
{ label: '通义千问', value: 'qwen' },
//
{ label: '天工', value: 'tiangong' },
]
const
ai
=
useStorage
(
'ai'
,
'tiangong
'
)
const
ai
=
ref
(
'deepseek
'
)
const
messages
=
ref
([])
const
isLoading
=
ref
(
false
)
async
function
post
(
data
)
{
isLoading
.
value
=
true
try
{
switch
(
ai
.
value
)
{
case
'yiyan'
:
await
yiyan
(
data
)
break
case
'deepseek'
:
await
siliconflow
(
data
)
break
case
'qwen'
:
await
qwen
(
data
)
break
case
'tiangong'
:
await
tiangong
(
data
)
break
default
:
throw
new
Error
(
'未找到对应的 AI 配置'
)
}
await
deepseek
(
data
)
}
catch
(
err
)
{
console
.
error
(
'AI 请求失败:'
,
err
)
}
finally
{
...
...
@@ -42,123 +22,61 @@ export function useAI() {
}
}
// 文心一言
async
function
yiyan
(
data
)
{
// 获取token
const
getAccessToken
=
async
()
=>
{
const
AK
=
'wY7bvMpkWeZbDVq9w3EDvpjU'
const
SK
=
'XJwpiJWxs5HXkOtbo6tQrvYPZFJAWdAy'
const
resp
=
await
axios
.
post
(
'/api/qianfan/oauth/2.0/token?grant_type=client_credentials&client_id='
+
AK
+
'&client_secret='
+
SK
)
return
resp
.
data
.
access_token
}
const
resp
=
await
axios
.
post
(
'/api/qianfan/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/eb-instant?access_token='
+
(
await
getAccessToken
()),
{
messages
:
[{
role
:
'user'
,
content
:
data
.
content
}],
}
)
messages
.
value
.
push
({
role
:
'assistant'
,
content
:
resp
.
data
.
result
.
replaceAll
(
'
\
n'
,
'<br/>'
)
})
}
// DeepSeek
async
function
deepseek
(
data
)
{
const
apiKey
=
'sk-f1a6f0a7013241de8393cb2cb108e777'
const
resp
=
await
axios
.
post
(
'/api/deepseek/chat/completions'
,
{
model
:
'deepseek-chat'
,
messages
:
[{
role
:
'user'
,
content
:
data
.
content
}],
},
{
headers
:
{
'Content-Type'
:
'application/json'
,
Authorization
:
`Bearer
${
apiKey
}
`
},
}
)
if
(
resp
.
data
)
{
const
[
choice
=
{}]
=
resp
.
data
.
choices
messages
.
value
.
push
({
role
:
'assistant'
,
content
:
choice
.
message
.
content
.
replaceAll
(
'
\
n'
,
'<br/>'
)
})
}
}
// 硅基流动
async
function
siliconflow
(
data
)
{
const
apiKey
=
'sk-bivnwauskdbvpspvmdorrgkrpwlyfxbfcezqsfsevowzubdj'
const
resp
=
await
axios
.
post
(
'/api/siliconflow/v1/chat/completions'
,
{
model
:
'deepseek-ai/DeepSeek-V3'
,
messages
:
[{
role
:
'user'
,
content
:
data
.
content
}],
},
{
const
apiKey
=
'sk-ezj-kZBEyE-OncdWaQJxRAbAy6L_ApqVlfga'
messages
.
value
.
push
({
role
:
'assistant'
,
content
:
''
})
const
messageIndex
=
messages
.
value
.
length
-
1
const
response
=
await
fetch
(
'https://node-server.ezijing.com/ai/chat/completions'
,
{
method
:
'POST'
,
headers
:
{
'Content-Type'
:
'application/json'
,
Authorization
:
`Bearer
${
apiKey
}
`
},
}
)
if
(
resp
.
data
)
{
const
[
choice
=
{}]
=
resp
.
data
.
choices
messages
.
value
.
push
({
role
:
'assistant'
,
content
:
choice
.
message
.
content
.
replaceAll
(
'
\
n'
,
'<br/>'
)
})
}
}
// 通义千问
async
function
qwen
(
data
)
{
const
apiKey
=
'sk-afd0fcdb53bf4058b2068b8548820150'
const
resp
=
await
axios
.
post
(
'/api/qwen/compatible-mode/v1/chat/completions'
,
{
model
:
'qwen-max'
,
body
:
JSON
.
stringify
({
model
:
'deepseek-v4-1-flash'
,
messages
:
[{
role
:
'user'
,
content
:
data
.
content
}],
},
{
headers
:
{
'Content-Type'
:
'application/json'
,
Authorization
:
`Bearer
${
apiKey
}
`
},
stream
:
true
,
thinking
:
{
type
:
'disabled'
},
}),
})
if
(
!
response
.
ok
)
throw
new
Error
(
`DeepSeek 请求失败:
${
response
.
status
}
`
)
if
(
!
response
.
body
)
throw
new
Error
(
'DeepSeek 响应不支持流式读取'
)
const
reader
=
response
.
body
.
getReader
()
const
decoder
=
new
TextDecoder
()
let
buffer
=
''
let
finished
=
false
while
(
!
finished
)
{
const
{
value
,
done
}
=
await
reader
.
read
()
buffer
+=
decoder
.
decode
(
value
,
{
stream
:
!
done
})
finished
=
done
let
boundary
=
buffer
.
search
(
/
\r?\n\r?\n
/
)
while
(
boundary
!==
-
1
)
{
const
frame
=
buffer
.
slice
(
0
,
boundary
)
const
separator
=
buffer
.
slice
(
boundary
).
match
(
/^
\r?\n\r?\n
/
)[
0
]
buffer
=
buffer
.
slice
(
boundary
+
separator
.
length
)
const
eventData
=
frame
.
split
(
/
\r?\n
/
)
.
filter
((
line
)
=>
line
.
startsWith
(
'data:'
))
.
map
((
line
)
=>
line
.
slice
(
5
).
replace
(
/^ /
,
''
))
.
join
(
'
\
n'
)
if
(
eventData
&&
eventData
!==
'[DONE]'
)
{
const
chunk
=
JSON
.
parse
(
eventData
)
const
content
=
chunk
.
choices
?.[
0
]?.
delta
?.
content
if
(
content
)
{
messages
.
value
[
messageIndex
]
=
{
...
messages
.
value
[
messageIndex
],
content
:
messages
.
value
[
messageIndex
].
content
+
content
.
replaceAll
(
'
\
n'
,
'<br/>'
),
}
)
if
(
resp
.
data
)
{
const
[
choice
=
{}]
=
resp
.
data
.
choices
messages
.
value
.
push
({
role
:
'assistant'
,
content
:
choice
.
message
.
content
.
replaceAll
(
'
\
n'
,
'<br/>'
)
})
await
nextTick
()
await
new
Promise
((
resolve
)
=>
requestAnimationFrame
(
resolve
))
}
}
// 天工
async
function
tiangong
(
data
)
{
const
appKey
=
'a8701b73637562d33a53c668a90ee3be'
const
appSecret
=
'e191593f486bb88a39c634f46926762dddc97b9082e192af'
const
timestamp
=
Math
.
floor
(
Date
.
now
()
/
1000
)
const
sign
=
md5
(
`
${
appKey
}${
appSecret
}${
timestamp
}
`
)
return
await
fetchEventSource
(
'/api/tiangong/sky-saas-writing/api/v1/chat'
,
{
method
:
'POST'
,
headers
:
{
'Content-Type'
:
'application/json'
,
app_key
:
appKey
,
sign
,
timestamp
,
stream
:
'true'
},
body
:
JSON
.
stringify
({
chat_history
:
[{
role
:
'user'
,
content
:
data
.
content
}],
stream_resp_type
:
'update'
,
}),
async
onopen
(
response
)
{
console
.
log
(
response
)
if
(
response
.
ok
)
{
return
response
}
else
{
throw
response
boundary
=
buffer
.
search
(
/
\r?\n\r?\n
/
)
}
},
onmessage
(
res
)
{
console
.
log
(
res
.
data
)
const
message
=
JSON
.
parse
(
res
.
data
)
if
(
message
.
type
!==
1
)
return
const
messageId
=
message
.
conversation_id
const
messageIndex
=
messages
.
value
.
findIndex
((
message
)
=>
message
.
id
===
messageId
)
const
content
=
message
?.
arguments
?.[
0
]?.
messages
?.[
0
]?.
text
||
''
if
(
messageIndex
===
-
1
)
{
messages
.
value
.
push
({
id
:
messageId
,
role
:
'assistant'
,
content
})
}
else
{
messages
.
value
[
messageIndex
].
content
=
content
}
isLoading
.
value
=
false
},
onerror
(
err
)
{
isLoading
.
value
=
false
throw
err
},
})
}
return
{
ai
,
options
,
post
,
messages
,
isLoading
}
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论