Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
S
saas-bi
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
EzijingWeb
saas-bi
Commits
350da781
提交
350da781
authored
3月 21, 2025
作者:
王鹏飞
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
chore: update
上级
068ee8d5
显示空白字符变更
内嵌
并排
正在显示
7 个修改的文件
包含
148 行增加
和
180 行删除
+148
-180
MarkdownRender.tsx
src/components/MarkdownRender.tsx
+6
-0
AIChat.tsx
src/components/ai/AIChat.tsx
+2
-3
useAI.ts
src/hooks/useAI.ts
+27
-18
DataReport.tsx
src/modules/data/write/my/components/DataReport.tsx
+36
-0
Index.tsx
src/modules/data/write/my/views/Index.tsx
+2
-1
ai.ts
src/stores/ai.ts
+25
-11
ai.ts
src/utils/ai.ts
+50
-147
没有找到文件。
src/components/MarkdownRender.tsx
0 → 100644
浏览文件 @
350da781
import
Markdown
from
'react-markdown'
import
remarkGfm
from
'remark-gfm'
export
default
function
MarkdownRender
(
props
:
{
children
?:
string
})
{
return
<
Markdown
remarkPlugins=
{
[
remarkGfm
]
}
>
{
props
.
children
}
</
Markdown
>
}
src/components/ai/AIChat.tsx
浏览文件 @
350da781
...
@@ -2,9 +2,8 @@ import { useState, KeyboardEvent, useEffect, useRef } from 'react'
...
@@ -2,9 +2,8 @@ import { useState, KeyboardEvent, useEffect, useRef } from 'react'
import
{
Button
,
Card
,
FloatButton
,
Input
,
Select
}
from
'antd'
import
{
Button
,
Card
,
FloatButton
,
Input
,
Select
}
from
'antd'
import
{
CircleArrowLeft
,
CircleArrowRight
}
from
'lucide-react'
import
{
CircleArrowLeft
,
CircleArrowRight
}
from
'lucide-react'
import
{
OpenAIOutlined
,
ArrowUpOutlined
}
from
'@ant-design/icons'
import
{
OpenAIOutlined
,
ArrowUpOutlined
}
from
'@ant-design/icons'
import
Markdown
from
'react-markdown'
import
remarkGfm
from
'remark-gfm'
import
{
useAIStore
,
AIMessage
}
from
'@/stores/ai'
import
{
useAIStore
,
AIMessage
}
from
'@/stores/ai'
import
MarkdownRender
from
'../MarkdownRender'
import
'./AIChat.scss'
import
'./AIChat.scss'
export
const
MessageItem
=
({
message
}:
{
message
:
AIMessage
})
=>
{
export
const
MessageItem
=
({
message
}:
{
message
:
AIMessage
})
=>
{
...
@@ -12,7 +11,7 @@ export const MessageItem = ({ message }: { message: AIMessage }) => {
...
@@ -12,7 +11,7 @@ export const MessageItem = ({ message }: { message: AIMessage }) => {
<
div
className=
{
`message-item ${message.role}`
}
>
<
div
className=
{
`message-item ${message.role}`
}
>
<
div
className=
"message-box"
>
<
div
className=
"message-box"
>
<
div
className=
"message-content"
>
<
div
className=
"message-content"
>
<
Markdown
remarkPlugins=
{
[
remarkGfm
]
}
>
{
message
.
content
}
</
Markdown
>
<
Markdown
Render
>
{
message
.
content
}
</
MarkdownRender
>
</
div
>
</
div
>
</
div
>
</
div
>
</
div
>
</
div
>
...
...
src/hooks/useAI.ts
浏览文件 @
350da781
import
{
useState
,
useEffect
,
useCallback
}
from
'react'
import
{
useState
,
useEffect
,
useCallback
}
from
'react'
import
aiService
,
{
AIMessage
,
AIData
,
AI_OPTIONS
}
from
'@/utils/ai'
import
aiService
,
{
AIMessage
,
AIData
,
AI_OPTIONS
,
InitOptions
}
from
'@/utils/ai'
export
function
useAI
()
{
export
function
useAI
(
globalOptions
?:
InitOptions
)
{
const
[
ai
,
setAI
]
=
useState
<
string
>
(
localStorage
.
getItem
(
'ai'
)
||
'qwen'
)
const
[
ai
,
setAI
]
=
useState
<
string
>
(
localStorage
.
getItem
(
'ai'
)
||
'qwen'
)
const
[
messages
,
setMessages
]
=
useState
<
AIMessage
[]
>
([])
const
[
messages
,
setMessages
]
=
useState
<
AIMessage
[]
>
([])
const
[
message
,
setMessage
]
=
useState
<
AIMessage
|
null
>
(
null
)
// 存储最新的消息
const
[
isLoading
,
setIsLoading
]
=
useState
<
boolean
>
(
false
)
const
[
isLoading
,
setIsLoading
]
=
useState
<
boolean
>
(
false
)
useEffect
(()
=>
{
useEffect
(()
=>
{
localStorage
.
setItem
(
'ai'
,
ai
)
localStorage
.
setItem
(
'ai'
,
ai
)
},
[
ai
])
},
[
ai
])
const
post
=
useCallback
(
const
post
=
useCallback
(
async
(
data
:
AIData
)
=>
{
async
(
data
:
AIData
,
options
?:
InitOptions
)
=>
{
setIsLoading
(
true
)
setIsLoading
(
true
)
setMessages
((
prevMessages
)
=>
[...
prevMessages
,
...
data
.
messages
.
filter
((
item
)
=>
item
.
role
!==
'system'
)])
try
{
// 先添加用户消息(去掉 system 角色的消息)
const
userMessages
=
data
.
messages
.
filter
((
item
)
=>
item
.
role
!==
'system'
)
setMessages
((
prevMessages
)
=>
[...
prevMessages
,
...
userMessages
])
await
aiService
.
post
(
ai
,
data
,
{
await
aiService
.
post
(
ai
,
data
,
{
onUpdat
e
:
(
response
)
=>
{
onMessag
e
:
(
response
)
=>
{
setMessages
((
prevMessages
)
=>
{
setMessages
((
prevMessages
)
=>
{
const
messageIndex
=
prevMessages
.
findIndex
((
msg
)
=>
msg
.
id
===
response
.
id
)
const
messageIndex
=
prevMessages
.
findIndex
((
msg
)
=>
msg
.
id
===
response
.
id
)
if
(
messageIndex
===
-
1
)
{
if
(
messageIndex
===
-
1
)
{
return
[...
prevMessages
,
{
id
:
response
.
id
,
role
:
'assistant'
,
content
:
response
.
content
}]
const
newMessage
:
AIMessage
=
{
id
:
response
.
id
,
role
:
'assistant'
,
content
:
response
.
content
}
setMessage
(
newMessage
)
// 更新最新消息
return
[...
prevMessages
,
newMessage
]
}
else
{
}
else
{
return
prevMessages
.
map
((
msg
)
=>
return
prevMessages
.
map
((
msg
)
=>
{
msg
.
id
===
response
.
id
?
{
...
msg
,
content
:
msg
.
content
+
response
.
content
}
:
msg
if
(
msg
.
id
===
response
.
id
)
{
)
const
updatedMessage
=
{
...
msg
,
content
:
msg
.
content
+
response
.
content
}
setMessage
(
updatedMessage
)
// 更新最新消息
return
updatedMessage
}
return
msg
})
}
}
})
})
},
},
onError
:
(
err
)
=>
{
onerror
:
()
=>
{
console
.
error
(
'AI 请求失败:'
,
err
)
setIsLoading
(
false
)
setIsLoading
(
false
)
},
},
onComplet
e
:
()
=>
{
onclos
e
:
()
=>
{
setIsLoading
(
false
)
setIsLoading
(
false
)
},
},
...
globalOptions
,
...
options
,
})
})
}
catch
(
err
)
{
console
.
error
(
'AI 请求失败:'
,
err
)
setIsLoading
(
false
)
}
},
},
[
ai
]
[
ai
]
)
)
return
{
ai
,
setAI
,
options
:
AI_OPTIONS
,
post
,
messages
,
isLoading
}
return
{
ai
,
setAI
,
options
:
AI_OPTIONS
,
post
,
messages
,
message
,
isLoading
}
}
}
src/modules/data/write/my/components/DataReport.tsx
0 → 100644
浏览文件 @
350da781
import
{
Button
,
Flex
,
Modal
,
Spin
}
from
'antd'
import
{
useEffect
,
useState
}
from
'react'
import
{
useAI
}
from
'@/hooks/useAI'
import
MarkdownRender
from
'@/components/MarkdownRender'
export
default
function
DataReport
()
{
const
[
open
,
setOpen
]
=
useState
(
false
)
const
{
post
,
isLoading
,
message
}
=
useAI
()
useEffect
(()
=>
{
if
(
open
)
{
post
({
messages
:
[
{
role
:
'user'
,
content
:
'作为数据分析师,请基于提供的数据集,生成一份结构化的数据质量分析报告。需包含字段解释、关系梳理、质量评估及改进建议。'
,
},
],
})
}
},
[
open
])
return
(
<>
<
Button
type=
"primary"
onClick=
{
()
=>
setOpen
(
true
)
}
>
数据分析报告
</
Button
>
<
Modal
title=
"数据分析报告"
open=
{
open
}
footer=
{
null
}
width=
{
1000
}
onCancel=
{
()
=>
setOpen
(
false
)
}
destroyOnClose
>
<
MarkdownRender
>
{
message
?.
content
}
</
MarkdownRender
>
<
Flex
justify=
"center"
>
<
Spin
size=
"large"
spinning=
{
isLoading
}
></
Spin
>
</
Flex
>
</
Modal
>
</>
)
}
src/modules/data/write/my/views/Index.tsx
浏览文件 @
350da781
import
{
Link
}
from
'react-router'
import
{
Link
}
from
'react-router'
import
{
Button
,
Empty
,
Flex
,
Space
}
from
'antd'
import
{
Button
,
Empty
,
Flex
,
Space
}
from
'antd'
import
DataWrap
from
'@/components/data/DataWrap'
import
DataWrap
from
'@/components/data/DataWrap'
import
DataReport
from
'../components/DataReport'
// 无数据渲染
// 无数据渲染
const
EmptyRender
=
()
=>
{
const
EmptyRender
=
()
=>
{
...
@@ -37,7 +38,7 @@ export default function DataWriteMy() {
...
@@ -37,7 +38,7 @@ export default function DataWriteMy() {
headerRender=
{
(
data
)
=>
(
headerRender=
{
(
data
)
=>
(
<
Flex
justify=
"space-between"
align=
"middle"
style=
{
{
marginBottom
:
'20px'
}
}
>
<
Flex
justify=
"space-between"
align=
"middle"
style=
{
{
marginBottom
:
'20px'
}
}
>
<
h4
>
数据集名称:
{
data
.
info
.
name
}
</
h4
>
<
h4
>
数据集名称:
{
data
.
info
.
name
}
</
h4
>
<
Button
type=
"primary"
>
数据质量分析报告
</
Button
>
<
DataReport
/
>
</
Flex
>
</
Flex
>
)
}
)
}
empty=
{
<
EmptyRender
/>
}
></
DataWrap
>
empty=
{
<
EmptyRender
/>
}
></
DataWrap
>
...
...
src/stores/ai.ts
浏览文件 @
350da781
import
{
create
}
from
'zustand'
import
{
create
}
from
'zustand'
import
aiService
,
{
AIOption
,
AIMessage
,
AIData
,
AI_OPTIONS
}
from
'@/utils/ai'
import
aiService
,
{
AIOption
,
AIMessage
,
AIData
,
AI_OPTIONS
,
InitOptions
}
from
'@/utils/ai'
interface
AIState
{
interface
AIState
{
ai
:
string
ai
:
string
options
:
AIOption
[]
options
:
AIOption
[]
message
:
AIMessage
|
null
messages
:
AIMessage
[]
messages
:
AIMessage
[]
isLoading
:
boolean
isLoading
:
boolean
collapsed
:
boolean
collapsed
:
boolean
setAI
:
(
ai
:
string
)
=>
void
setAI
:
(
ai
:
string
)
=>
void
toggleCollapsed
:
()
=>
void
toggleCollapsed
:
()
=>
void
post
:
(
data
:
AIData
)
=>
Promise
<
void
>
post
:
(
data
:
AIData
,
options
?:
InitOptions
)
=>
Promise
<
void
>
}
}
export
const
useAIStore
=
create
<
AIState
>
((
set
,
get
)
=>
({
export
const
useAIStore
=
create
<
AIState
>
((
set
,
get
)
=>
({
ai
:
localStorage
.
getItem
(
'ai'
)
||
'qwen'
,
ai
:
localStorage
.
getItem
(
'ai'
)
||
'qwen'
,
options
:
AI_OPTIONS
,
options
:
AI_OPTIONS
,
message
:
null
,
messages
:
[],
messages
:
[],
isLoading
:
false
,
isLoading
:
false
,
collapsed
:
false
,
collapsed
:
false
,
...
@@ -25,40 +27,52 @@ export const useAIStore = create<AIState>((set, get) => ({
...
@@ -25,40 +27,52 @@ export const useAIStore = create<AIState>((set, get) => ({
toggleCollapsed
:
()
=>
{
toggleCollapsed
:
()
=>
{
set
((
state
)
=>
({
collapsed
:
!
state
.
collapsed
}))
set
((
state
)
=>
({
collapsed
:
!
state
.
collapsed
}))
},
},
post
:
async
(
data
)
=>
{
post
:
async
(
data
,
options
)
=>
{
const
{
ai
,
messages
}
=
get
()
const
{
ai
,
messages
}
=
get
()
// 处理用户消息(去掉 system 角色的消息)
const
userMessages
=
data
.
messages
.
filter
((
item
)
=>
item
.
role
!==
'system'
)
set
({
set
({
collapsed
:
true
,
collapsed
:
true
,
isLoading
:
true
,
isLoading
:
true
,
messages
:
[...
messages
,
...
data
.
messages
.
filter
((
item
)
=>
item
.
role
!==
'system'
)
],
messages
:
[...
messages
,
...
userMessages
],
})
})
try
{
try
{
await
aiService
.
post
(
ai
,
data
,
{
await
aiService
.
post
(
ai
,
data
,
{
on
Updat
e
:
(
response
)
=>
{
on
Messag
e
:
(
response
)
=>
{
set
((
state
)
=>
{
set
((
state
)
=>
{
const
messageIndex
=
state
.
messages
.
findIndex
((
msg
)
=>
msg
.
id
===
response
.
id
)
const
messageIndex
=
state
.
messages
.
findIndex
((
msg
)
=>
msg
.
id
===
response
.
id
)
if
(
messageIndex
===
-
1
)
{
if
(
messageIndex
===
-
1
)
{
// 新的 AI 回复
const
newMessage
:
AIMessage
=
{
id
:
response
.
id
,
role
:
'assistant'
,
content
:
response
.
content
}
return
{
return
{
messages
:
[...
state
.
messages
,
{
id
:
response
.
id
,
role
:
'assistant'
,
content
:
response
.
content
}],
message
:
newMessage
,
// 存储最新的 AI 消息
messages
:
[...
state
.
messages
,
newMessage
],
// 追加到历史消息
}
}
}
else
{
}
else
{
return
{
// 追加内容到已有的消息
messages
:
state
.
messages
.
map
((
msg
)
=>
const
updatedMessages
=
state
.
messages
.
map
((
msg
)
=>
msg
.
id
===
response
.
id
?
{
...
msg
,
content
:
msg
.
content
+
response
.
content
}
:
msg
msg
.
id
===
response
.
id
?
{
...
msg
,
content
:
msg
.
content
+
response
.
content
}
:
msg
),
)
return
{
message
:
updatedMessages
[
messageIndex
],
// 更新最新的 AI 消息
messages
:
updatedMessages
,
}
}
}
}
})
})
},
},
on
E
rror
:
(
err
)
=>
{
on
e
rror
:
(
err
)
=>
{
console
.
error
(
'AI 请求失败:'
,
err
)
console
.
error
(
'AI 请求失败:'
,
err
)
set
({
isLoading
:
false
})
set
({
isLoading
:
false
})
},
},
on
Complet
e
:
()
=>
{
on
clos
e
:
()
=>
{
set
({
isLoading
:
false
})
set
({
isLoading
:
false
})
},
},
...
options
,
})
})
}
catch
(
err
)
{
}
catch
(
err
)
{
console
.
error
(
'AI 请求失败:'
,
err
)
console
.
error
(
'AI 请求失败:'
,
err
)
...
...
src/utils/ai.ts
浏览文件 @
350da781
import
md5
from
'blueimp-md5'
import
md5
from
'blueimp-md5'
import
axios
from
'axios'
import
axios
from
'axios'
import
{
fetchEventSource
}
from
'@fortaine/fetch-event-source'
import
{
fetchEventSource
,
FetchEventSourceInit
}
from
'@fortaine/fetch-event-source'
export
interface
AIOption
{
export
interface
AIOption
{
label
:
string
label
:
string
...
@@ -20,15 +20,12 @@ export interface AIData {
...
@@ -20,15 +20,12 @@ export interface AIData {
}
}
export
interface
AIResponse
{
export
interface
AIResponse
{
content
:
string
id
?:
string
id
?:
string
isStream
?:
boolean
content
:
string
}
}
export
interface
AIStreamHandlers
{
export
interface
InitOptions
extends
FetchEventSourceInit
{
onUpdate
:
(
response
:
AIResponse
)
=>
void
onMessage
?:
(
message
:
AIResponse
)
=>
void
onError
:
(
error
:
any
)
=>
void
onComplete
?:
()
=>
void
}
}
// Available AI options for different implementations
// Available AI options for different implementations
...
@@ -39,7 +36,6 @@ export const AI_OPTIONS: AIOption[] = [
...
@@ -39,7 +36,6 @@ export const AI_OPTIONS: AIOption[] = [
// { label: '天工', value: 'tiangong' },
// { label: '天工', value: 'tiangong' },
]
]
// Individual AI service functions
export
async
function
getYiyanAccessToken
()
{
export
async
function
getYiyanAccessToken
()
{
const
AK
=
'wY7bvMpkWeZbDVq9w3EDvpjU'
const
AK
=
'wY7bvMpkWeZbDVq9w3EDvpjU'
const
SK
=
'XJwpiJWxs5HXkOtbo6tQrvYPZFJAWdAy'
const
SK
=
'XJwpiJWxs5HXkOtbo6tQrvYPZFJAWdAy'
...
@@ -49,184 +45,113 @@ export async function getYiyanAccessToken() {
...
@@ -49,184 +45,113 @@ export async function getYiyanAccessToken() {
return
resp
.
data
.
access_token
return
resp
.
data
.
access_token
}
}
export
async
function
fetchAIEventSource
(
url
:
string
,
options
:
FetchEventSourceInit
)
{
await
fetchEventSource
(
url
,
{
method
:
'POST'
,
headers
:
{
'Content-Type'
:
'application/json'
},
async
onopen
(
response
)
{
if
(
response
.
ok
)
return
else
throw
response
},
...
options
,
})
}
// https://cloud.baidu.com/doc/WENXINWORKSHOP/s/Fm2vrveyu
// https://cloud.baidu.com/doc/WENXINWORKSHOP/s/Fm2vrveyu
export
async
function
yiyan
(
data
:
AIData
,
handlers
:
AIStreamHandler
s
):
Promise
<
void
>
{
export
async
function
yiyan
(
data
:
AIData
,
options
:
InitOption
s
):
Promise
<
void
>
{
const
accessToken
=
await
getYiyanAccessToken
()
const
accessToken
=
await
getYiyanAccessToken
()
const
params
=
{
stream
:
true
,
...
data
}
const
params
=
{
stream
:
true
,
...
data
}
await
fetchEventSource
(
await
fetch
AI
EventSource
(
`/api/qianfan/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/eb-instant?access_token=
${
accessToken
}
`
,
`/api/qianfan/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/eb-instant?access_token=
${
accessToken
}
`
,
{
{
method
:
'POST'
,
...
options
,
headers
:
{
'Content-Type'
:
'application/json'
},
body
:
JSON
.
stringify
(
params
),
body
:
JSON
.
stringify
(
params
),
async
onopen
(
response
)
{
if
(
response
.
ok
)
{
return
}
else
{
throw
response
}
},
onmessage
(
res
)
{
onmessage
(
res
)
{
if
(
res
.
data
===
'[DONE]'
)
{
handlers
.
onComplete
?.()
return
}
try
{
try
{
const
message
=
JSON
.
parse
(
res
.
data
)
const
message
=
JSON
.
parse
(
res
.
data
)
handlers
.
onUpdate
({
id
:
message
.
id
,
content
:
message
.
result
||
''
}
)
if
(
options
.
onMessage
)
options
.
onMessage
({
id
:
message
.
id
,
content
:
message
.
result
||
''
}
as
any
)
}
catch
(
error
)
{
}
catch
(
error
)
{
console
.
error
(
error
)
console
.
error
(
error
)
}
}
},
},
onerror
(
err
)
{
handlers
.
onError
(
err
)
},
onclose
()
{
if
(
handlers
.
onComplete
)
{
handlers
.
onComplete
()
}
},
}
}
)
)
}
}
// https://api-docs.deepseek.com/zh-cn/api/create-chat-completion
// https://api-docs.deepseek.com/zh-cn/api/create-chat-completion
export
async
function
deepseek
(
data
:
AIData
,
handlers
:
AIStreamHandler
s
):
Promise
<
void
>
{
export
async
function
deepseek
(
data
:
AIData
,
options
:
InitOption
s
):
Promise
<
void
>
{
const
apiKey
=
'sk-f1a6f0a7013241de8393cb2cb108e777'
const
apiKey
=
'sk-f1a6f0a7013241de8393cb2cb108e777'
const
params
=
{
model
:
'deepseek-reasoner'
,
stream
:
true
,
...
data
}
const
params
=
{
model
:
'deepseek-reasoner'
,
stream
:
true
,
...
data
}
await
fetchEventSource
(
'/api/deepseek/chat/completions'
,
{
await
fetch
AI
EventSource
(
'/api/deepseek/chat/completions'
,
{
method
:
'POST'
,
...
options
,
headers
:
{
'Content-Type'
:
'application/json'
,
Authorization
:
`Bearer
${
apiKey
}
`
},
headers
:
{
'Content-Type'
:
'application/json'
,
Authorization
:
`Bearer
${
apiKey
}
`
},
body
:
JSON
.
stringify
(
params
),
body
:
JSON
.
stringify
(
params
),
async
onopen
(
response
)
{
if
(
response
.
ok
)
{
return
}
else
{
throw
response
}
},
onmessage
(
res
)
{
onmessage
(
res
)
{
if
(
res
.
data
===
'[DONE]'
)
{
if
(
res
.
data
===
'[DONE]'
)
return
handlers
.
onComplete
?.()
return
}
try
{
try
{
const
message
=
JSON
.
parse
(
res
.
data
)
const
message
=
JSON
.
parse
(
res
.
data
)
if
(
message
.
choices
&&
message
.
choices
.
length
>
0
)
{
if
(
message
.
choices
&&
message
.
choices
.
length
>
0
&&
options
.
onMessage
)
{
handlers
.
onUpdate
({
options
.
onMessage
({
id
:
message
.
id
,
content
:
message
.
choices
[
0
].
delta
?.
content
||
''
}
as
any
)
id
:
message
.
id
,
content
:
message
.
choices
[
0
].
delta
?.
content
||
''
,
})
}
}
}
catch
(
error
)
{
}
catch
(
error
)
{
console
.
error
(
error
)
console
.
error
(
error
)
}
}
},
},
onerror
(
err
)
{
handlers
.
onError
(
err
)
},
onclose
()
{
if
(
handlers
.
onComplete
)
{
handlers
.
onComplete
()
}
},
})
})
}
}
// https://docs.siliconflow.cn/cn/api-reference/chat-completions/chat-completions
// https://docs.siliconflow.cn/cn/api-reference/chat-completions/chat-completions
export
async
function
siliconflow
(
data
:
AIData
,
handlers
:
AIStreamHandler
s
):
Promise
<
void
>
{
export
async
function
siliconflow
(
data
:
AIData
,
options
:
InitOption
s
):
Promise
<
void
>
{
const
apiKey
=
'sk-bivnwauskdbvpspvmdorrgkrpwlyfxbfcezqsfsevowzubdj'
const
apiKey
=
'sk-bivnwauskdbvpspvmdorrgkrpwlyfxbfcezqsfsevowzubdj'
const
params
=
{
model
:
'deepseek-ai/DeepSeek-R1'
,
stream
:
true
,
...
data
}
const
params
=
{
model
:
'deepseek-ai/DeepSeek-R1'
,
stream
:
true
,
...
data
}
await
fetchEventSource
(
'/api/siliconflow/v1/chat/completions'
,
{
await
fetch
AI
EventSource
(
'/api/siliconflow/v1/chat/completions'
,
{
method
:
'POST'
,
...
options
,
headers
:
{
'Content-Type'
:
'application/json'
,
Authorization
:
`Bearer
${
apiKey
}
`
},
headers
:
{
'Content-Type'
:
'application/json'
,
Authorization
:
`Bearer
${
apiKey
}
`
},
body
:
JSON
.
stringify
(
params
),
body
:
JSON
.
stringify
(
params
),
async
onopen
(
response
)
{
if
(
response
.
ok
)
{
return
}
else
{
throw
response
}
},
onmessage
(
res
)
{
onmessage
(
res
)
{
if
(
res
.
data
===
'[DONE]'
)
{
if
(
res
.
data
===
'[DONE]'
)
return
handlers
.
onComplete
?.()
return
}
try
{
try
{
const
message
=
JSON
.
parse
(
res
.
data
)
const
message
=
JSON
.
parse
(
res
.
data
)
if
(
message
.
choices
&&
message
.
choices
.
length
>
0
)
{
if
(
message
.
choices
&&
message
.
choices
.
length
>
0
&&
options
.
onMessage
)
{
handlers
.
onUpdate
({
options
.
onMessage
({
id
:
message
.
id
,
content
:
message
.
choices
[
0
].
delta
?.
content
||
''
}
as
any
)
id
:
message
.
id
,
content
:
message
.
choices
[
0
].
delta
?.
content
||
''
,
})
}
}
}
catch
(
error
)
{
}
catch
(
error
)
{
console
.
error
(
error
)
console
.
error
(
error
)
}
}
},
},
onerror
(
err
)
{
handlers
.
onError
(
err
)
},
onclose
()
{
if
(
handlers
.
onComplete
)
{
handlers
.
onComplete
()
}
},
})
})
}
}
// https://help.aliyun.com/zh/model-studio/developer-reference/use-qwen-by-calling-api
// https://help.aliyun.com/zh/model-studio/developer-reference/use-qwen-by-calling-api
export
async
function
qwen
(
data
:
AIData
,
handlers
:
AIStreamHandler
s
):
Promise
<
void
>
{
export
async
function
qwen
(
data
:
AIData
,
options
:
InitOption
s
):
Promise
<
void
>
{
const
apiKey
=
'sk-afd0fcdb53bf4058b2068b8548820150'
const
apiKey
=
'sk-afd0fcdb53bf4058b2068b8548820150'
const
params
=
{
model
:
'qwen-max-latest'
,
stream
:
true
,
...
data
}
const
params
=
{
model
:
'qwen-max-latest'
,
stream
:
true
,
...
data
}
await
fetchEventSource
(
'/api/qwen/compatible-mode/v1/chat/completions'
,
{
await
fetch
AI
EventSource
(
'/api/qwen/compatible-mode/v1/chat/completions'
,
{
method
:
'POST'
,
...
options
,
headers
:
{
'Content-Type'
:
'application/json'
,
Authorization
:
`Bearer
${
apiKey
}
`
},
headers
:
{
'Content-Type'
:
'application/json'
,
Authorization
:
`Bearer
${
apiKey
}
`
},
body
:
JSON
.
stringify
(
params
),
body
:
JSON
.
stringify
(
params
),
async
onopen
(
response
)
{
if
(
response
.
ok
)
{
return
}
else
{
throw
response
}
},
onmessage
(
res
)
{
onmessage
(
res
)
{
if
(
res
.
data
===
'[DONE]'
)
{
if
(
res
.
data
===
'[DONE]'
)
return
handlers
.
onComplete
?.()
return
}
try
{
try
{
const
message
=
JSON
.
parse
(
res
.
data
)
const
message
=
JSON
.
parse
(
res
.
data
)
if
(
message
.
choices
&&
message
.
choices
.
length
>
0
)
{
if
(
message
.
choices
&&
message
.
choices
.
length
>
0
&&
options
.
onMessage
)
{
handlers
.
onUpdate
({
options
.
onMessage
({
id
:
message
.
id
,
content
:
message
.
choices
[
0
].
delta
?.
content
||
''
}
as
any
)
id
:
message
.
id
,
content
:
message
.
choices
[
0
].
delta
?.
content
||
''
,
})
}
}
}
catch
(
error
)
{
}
catch
(
error
)
{
console
.
error
(
error
)
console
.
error
(
error
)
}
}
},
},
onerror
(
err
)
{
handlers
.
onError
(
err
)
},
onclose
()
{
if
(
handlers
.
onComplete
)
{
handlers
.
onComplete
()
}
},
})
})
}
}
export
async
function
tiangong
(
data
:
AIData
,
handlers
:
AIStreamHandler
s
):
Promise
<
void
>
{
export
async
function
tiangong
(
data
:
AIData
,
options
:
InitOption
s
):
Promise
<
void
>
{
const
appKey
=
'a8701b73637562d33a53c668a90ee3be'
const
appKey
=
'a8701b73637562d33a53c668a90ee3be'
const
appSecret
=
'e191593f486bb88a39c634f46926762dddc97b9082e192af'
const
appSecret
=
'e191593f486bb88a39c634f46926762dddc97b9082e192af'
const
timestamp
=
Math
.
floor
(
Date
.
now
()
/
1000
).
toString
()
const
timestamp
=
Math
.
floor
(
Date
.
now
()
/
1000
).
toString
()
const
sign
=
md5
(
`
${
appKey
}${
appSecret
}${
timestamp
}
`
)
const
sign
=
md5
(
`
${
appKey
}${
appSecret
}${
timestamp
}
`
)
await
fetchEventSource
(
'/api/tiangong/sky-saas-writing/api/v1/chat'
,
{
await
fetch
AI
EventSource
(
'/api/tiangong/sky-saas-writing/api/v1/chat'
,
{
method
:
'POST'
,
...
options
,
headers
:
{
headers
:
{
'Content-Type'
:
'application/json'
,
'Content-Type'
:
'application/json'
,
app_key
:
appKey
,
app_key
:
appKey
,
...
@@ -234,41 +159,19 @@ export async function tiangong(data: AIData, handlers: AIStreamHandlers): Promis
...
@@ -234,41 +159,19 @@ export async function tiangong(data: AIData, handlers: AIStreamHandlers): Promis
timestamp
,
timestamp
,
stream
:
'true'
,
stream
:
'true'
,
},
},
body
:
JSON
.
stringify
({
body
:
JSON
.
stringify
({
chat_history
:
data
.
messages
,
stream_resp_type
:
'delta'
}),
chat_history
:
data
.
messages
,
stream_resp_type
:
'delta'
,
}),
async
onopen
(
response
)
{
if
(
response
.
ok
)
{
return
}
else
{
throw
response
}
},
onmessage
(
res
)
{
onmessage
(
res
)
{
if
(
res
.
data
===
'[DONE]'
)
return
try
{
try
{
const
message
=
JSON
.
parse
(
res
.
data
)
const
message
=
JSON
.
parse
(
res
.
data
)
if
(
message
.
type
!==
1
)
return
if
(
message
.
type
!==
1
)
return
const
messageId
=
message
.
conversation_id
const
messageId
=
message
.
conversation_id
const
messageContent
=
message
?.
arguments
?.[
0
]?.
messages
?.[
0
]?.
text
||
''
const
messageContent
=
message
?.
arguments
?.[
0
]?.
messages
?.[
0
]?.
text
||
''
if
(
options
.
onMessage
)
options
.
onMessage
({
id
:
messageId
,
content
:
messageContent
}
as
any
)
handlers
.
onUpdate
({
id
:
messageId
,
content
:
messageContent
,
})
}
catch
(
error
)
{
}
catch
(
error
)
{
console
.
error
(
error
)
console
.
error
(
error
)
}
}
},
},
onerror
(
err
)
{
handlers
.
onError
(
err
)
},
onclose
()
{
if
(
handlers
.
onComplete
)
{
handlers
.
onComplete
()
}
},
})
})
}
}
...
@@ -280,7 +183,7 @@ const aiService = {
...
@@ -280,7 +183,7 @@ const aiService = {
qwen
,
qwen
,
tiangong
,
tiangong
,
async
post
(
type
:
string
,
data
:
AIData
,
handlers
:
AIStreamHandler
s
):
Promise
<
void
>
{
async
post
(
type
:
string
,
data
:
AIData
,
options
:
InitOption
s
):
Promise
<
void
>
{
const
messages
:
AIMessage
[]
=
[]
const
messages
:
AIMessage
[]
=
[]
const
dataset
=
localStorage
.
getItem
(
'dataset'
)
const
dataset
=
localStorage
.
getItem
(
'dataset'
)
if
(
dataset
)
{
if
(
dataset
)
{
...
@@ -290,19 +193,19 @@ const aiService = {
...
@@ -290,19 +193,19 @@ const aiService = {
data
.
messages
=
[...
messages
,
...
data
.
messages
]
data
.
messages
=
[...
messages
,
...
data
.
messages
]
switch
(
type
)
{
switch
(
type
)
{
case
'yiyan'
:
case
'yiyan'
:
return
yiyan
(
data
,
handler
s
)
return
yiyan
(
data
,
option
s
)
case
'deepseek'
:
case
'deepseek'
:
return
deepseek
(
data
,
handler
s
)
return
deepseek
(
data
,
option
s
)
case
'siliconflow'
:
case
'siliconflow'
:
return
siliconflow
(
data
,
handler
s
)
return
siliconflow
(
data
,
option
s
)
case
'qwen'
:
case
'qwen'
:
return
qwen
(
data
,
handler
s
)
return
qwen
(
data
,
option
s
)
case
'tiangong'
:
case
'tiangong'
:
return
tiangong
(
data
,
handler
s
)
return
tiangong
(
data
,
option
s
)
default
:
default
:
throw
new
Error
(
`未找到对应的 AI 配置:
${
type
}
`
)
throw
new
Error
(
`未找到对应的 AI 配置:
${
type
}
`
)
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论