Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
C
center-book
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
EzijingWeb
center-book
Commits
5aa3bc6d
提交
5aa3bc6d
authored
6月 12, 2024
作者:
王鹏飞
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
chore: update
上级
e5337a88
隐藏空白字符变更
内嵌
并排
正在显示
7 个修改的文件
包含
150 行增加
和
123 行删除
+150
-123
.env.development
.env.development
+1
-1
ai.js
src/api/ai.js
+10
-5
aiWrite.jsx
src/common/wangeditor-customer/components/aiWrite.jsx
+34
-39
useAI.js
src/hooks/useAI.js
+36
-36
useBaiduAI.js
src/hooks/useBaiduAI.js
+25
-0
useFetchEventSource.js
src/hooks/useFetchEventSource.js
+40
-31
fetchEventSource.js
src/utils/fetchEventSource.js
+4
-11
没有找到文件。
.env.development
浏览文件 @
5aa3bc6d
VITE_API_URL_WORD = https://zijingebook.ezijing.com/api
#
VITE_API_URL_WORD = https://zijingebook.ezijing.com/api
VITE_API_URL_WORD = https://book-admin-web.ezijing.com/api
VITE_API_URL_WORD = https://book-admin-web.ezijing.com/api
# VITE_API_URL_WORD = http://ebook-pc.ezijing.com:7419
# VITE_API_URL_WORD = http://ebook-pc.ezijing.com:7419
VITE_API_BASE_API_PREFFIX = /api
VITE_API_BASE_API_PREFFIX = /api
...
...
src/api/ai.js
浏览文件 @
5aa3bc6d
import
axios
from
'@/utils/axios'
;
import
axios
from
'@/utils/axios'
import
fetchEventSource
from
'@/utils/fetchEventSource'
;
import
fetchEventSource
from
'@/utils/fetchEventSource'
// 流式编辑接口
// 流式编辑接口
export
function
aiEdit
(
options
)
{
export
function
aiEdit
(
options
)
{
return
fetchEventSource
(
'/api/ai/sky3/edit'
,
options
)
;
return
fetchEventSource
(
'/api/ai/sky3/edit'
,
options
)
}
}
// 流式对话接口
// 流式对话接口
export
function
aiChat
(
data
)
{
export
function
aiChat
(
data
)
{
return
axios
.
post
(
'/api/ai/sky3/chat'
,
data
)
;
return
axios
.
post
(
'/api/ai/sky3/chat'
,
data
)
}
}
// 文本生成图片接口
// 文本生成图片接口
export
function
aiGenerateImage
(
data
)
{
export
function
aiGenerateImage
(
data
)
{
return
axios
.
post
(
'/api/ai/sky3/generateImage'
,
data
);
return
axios
.
post
(
'/api/ai/sky3/generateImage'
,
data
)
}
// 百度聊天接口
export
function
baiduAIChat
(
data
)
{
return
axios
.
post
(
'/api/ai/baidubce/chat'
,
data
)
}
}
src/common/wangeditor-customer/components/aiWrite.jsx
浏览文件 @
5aa3bc6d
import
{
useEffect
,
useState
}
from
'react'
;
import
{
useEffect
,
useState
}
from
'react'
import
{
Modal
,
Input
,
Button
,
Flex
,
Spin
}
from
'antd'
;
import
{
Modal
,
Input
,
Button
,
Flex
,
Spin
}
from
'antd'
import
{
useAIEdit
}
from
'@/hooks/use
AI'
;
import
{
useAIEdit
}
from
'@/hooks/use
BaiduAI'
const
{
TextArea
}
=
Input
;
const
{
TextArea
}
=
Input
const
actionMap
=
{
const
actionMap
=
{
rewrite
:
'改写'
,
rewrite
:
{
name
:
'改写'
,
prompt
:
'帮我改写以下文字内容:'
}
,
expand
:
'扩写'
,
expand
:
{
name
:
'扩写'
,
prompt
:
'帮我在以下文字内容基础上进行扩写:'
}
,
abbreviate
:
'缩写'
,
abbreviate
:
{
name
:
'缩写'
,
prompt
:
'帮我缩写以下文字内容:'
}
,
summary
:
'总结'
,
summary
:
{
name
:
'缩写'
,
prompt
:
'帮我总结以下文字内容:'
}
}
;
}
export
default
function
AIWrite
({
editor
,
docAction
,
...
rest
})
{
export
default
function
AIWrite
({
editor
,
docAction
,
...
rest
})
{
const
[
content
,
setContent
]
=
useState
(
''
)
;
const
[
content
,
setContent
]
=
useState
(
''
)
const
{
text
,
fetch
,
isLoading
}
=
useAIEdit
()
;
const
{
text
,
fetch
,
isLoading
}
=
useAIEdit
()
const
actionText
=
actionMap
[
docAction
]
;
const
actionText
=
actionMap
[
docAction
]
?.
name
const
[
selectionText
,
setSelectionText
]
=
useState
(
''
)
;
const
[
selectionText
,
setSelectionText
]
=
useState
(
''
)
useEffect
(()
=>
{
useEffect
(()
=>
{
if
(
rest
.
open
)
{
if
(
rest
.
open
)
{
const
selection
=
editor
.
getSelectionText
()
;
const
selection
=
editor
.
getSelectionText
()
if
(
selection
)
{
if
(
selection
)
{
setSelectionText
(
selection
)
;
setSelectionText
(
selection
)
setContent
(
selection
)
;
setContent
(
selection
)
fetch
({
content
:
selection
,
doc_action
:
docAction
,
full_text
:
false
});
fetch
({
messages
:
[{
role
:
'user'
,
content
:
actionMap
[
docAction
].
prompt
+
selection
}]
})
}
}
}
}
},
[
rest
.
open
])
;
},
[
rest
.
open
])
useEffect
(()
=>
{
useEffect
(()
=>
{
setContent
(
text
)
;
setContent
(
text
)
},
[
text
])
;
},
[
text
])
const
handleFetch
=
()
=>
{
const
handleFetch
=
()
=>
{
fetch
({
content
:
selectionText
,
doc_action
:
docAction
,
full_text
:
false
});
fetch
({
messages
:
[{
role
:
'user'
,
content
:
actionMap
[
docAction
].
prompt
+
selectionText
}]
})
}
;
}
const
handlePrimary
=
()
=>
{
const
handlePrimary
=
()
=>
{
editor
.
restoreSelection
()
;
editor
.
restoreSelection
()
editor
.
insertText
(
text
)
;
editor
.
insertText
(
text
)
rest
.
onCancel
()
;
rest
.
onCancel
()
}
;
}
return
(
return
(
<
Modal
<
Modal
...
@@ -48,28 +48,23 @@ export default function AIWrite({ editor, docAction, ...rest }) {
...
@@ -48,28 +48,23 @@ export default function AIWrite({ editor, docAction, ...rest }) {
classNames=
{
{
classNames=
{
{
header
:
'editor-header-customer'
,
header
:
'editor-header-customer'
,
body
:
'editor-body-customer'
,
body
:
'editor-body-customer'
,
wrapper
:
'editor-wrapper-customer'
,
wrapper
:
'editor-wrapper-customer'
}
}
}
}
>
>
<
Spin
spinning=
{
isLoading
}
>
<
Spin
spinning=
{
isLoading
}
>
<
TextArea
<
TextArea
autoSize=
{
{
minRows
:
4
}
}
value=
{
content
}
onChange=
{
e
=>
setContent
(
e
.
target
.
value
)
}
/>
autoSize=
{
{
minRows
:
4
}
}
value=
{
content
}
onChange=
{
(
e
)
=>
setContent
(
e
.
target
.
value
)
}
/>
</
Spin
>
</
Spin
>
<
br
/>
<
br
/>
<
Flex
gap=
'small'
justify=
'center'
>
<
Flex
gap=
"small"
justify=
"center"
>
<
Button
type=
'primary'
onClick=
{
handlePrimary
}
>
<
Button
type=
"primary"
onClick=
{
handlePrimary
}
>
替换内容
替换内容
</
Button
>
</
Button
>
<
Button
type=
'primary'
onClick=
{
handleFetch
}
>
<
Button
type=
"primary"
onClick=
{
handleFetch
}
>
重新
{
actionText
}
重新
{
actionText
}
</
Button
>
</
Button
>
<
Button
type=
'primary'
onClick=
{
rest
.
onCancel
}
>
<
Button
type=
"primary"
onClick=
{
rest
.
onCancel
}
>
取消
取消
</
Button
>
</
Button
>
</
Flex
>
</
Flex
>
</
Modal
>
</
Modal
>
)
;
)
}
}
src/hooks/useAI.js
浏览文件 @
5aa3bc6d
import
{
useState
}
from
'react'
;
import
{
useState
}
from
'react'
import
{
aiEdit
,
aiChat
,
aiGenerateImage
}
from
'@/api/ai'
;
import
{
aiEdit
,
aiChat
,
aiGenerateImage
}
from
'@/api/ai'
export
function
useAIEdit
()
{
export
function
useAIEdit
()
{
const
[
messages
,
setMessages
]
=
useState
([])
;
const
[
messages
,
setMessages
]
=
useState
([])
const
[
isLoading
,
setIsLoading
]
=
useState
(
false
)
;
const
[
isLoading
,
setIsLoading
]
=
useState
(
false
)
const
latestMessage
=
messages
[
messages
.
length
-
1
]
||
{}
;
const
latestMessage
=
messages
[
messages
.
length
-
1
]
||
{}
const
{
text
=
''
}
=
latestMessage
;
const
{
text
=
''
}
=
latestMessage
const
fetch
=
async
(
params
)
=>
{
const
fetch
=
async
params
=>
{
setIsLoading
(
true
)
;
setIsLoading
(
true
)
try
{
try
{
const
res
=
await
aiEdit
({
const
res
=
await
aiEdit
({
body
:
JSON
.
stringify
({
params
}),
body
:
JSON
.
stringify
({
params
}),
onmessage
:
(
res
)
=>
{
onmessage
:
res
=>
{
let
message
=
JSON
.
parse
(
res
.
data
)
;
let
message
=
JSON
.
parse
(
res
.
data
)
message
=
{
...
message
.
data
,
request_id
:
message
.
request_id
}
;
message
=
{
...
message
.
data
,
request_id
:
message
.
request_id
}
setMessages
(
(
prevMessages
)
=>
{
setMessages
(
prevMessages
=>
{
const
messageIndex
=
prevMessages
.
findIndex
(
(
m
)
=>
m
.
request_id
===
message
.
request_id
);
const
messageIndex
=
prevMessages
.
findIndex
(
m
=>
m
.
request_id
===
message
.
request_id
)
if
(
messageIndex
===
-
1
)
{
if
(
messageIndex
===
-
1
)
{
return
[...
prevMessages
,
message
]
;
return
[...
prevMessages
,
message
]
}
else
{
}
else
{
return
prevMessages
.
map
(
(
m
)
=>
(
m
.
request_id
===
message
.
request_id
?
message
:
m
));
return
prevMessages
.
map
(
m
=>
(
m
.
request_id
===
message
.
request_id
?
message
:
m
))
}
}
})
;
})
}
,
}
})
;
})
}
catch
(
error
)
{
}
catch
(
error
)
{
console
.
error
(
'Error fetching AI edit:'
,
error
)
;
console
.
error
(
'Error fetching AI edit:'
,
error
)
}
finally
{
}
finally
{
setIsLoading
(
false
)
;
setIsLoading
(
false
)
}
}
}
;
}
return
{
messages
,
text
,
setMessages
,
fetch
,
isLoading
}
;
return
{
messages
,
text
,
setMessages
,
fetch
,
isLoading
}
}
}
export
function
useAIChat
()
{
export
function
useAIChat
()
{
const
[
messages
,
setMessages
]
=
useState
([])
;
const
[
messages
,
setMessages
]
=
useState
([])
const
fetch
=
async
(
params
)
=>
{
const
fetch
=
async
params
=>
{
const
res
=
await
aiChat
({
const
res
=
await
aiChat
({
body
:
JSON
.
stringify
({
params
}),
body
:
JSON
.
stringify
({
params
}),
onmessage
:
(
res
)
=>
{
onmessage
:
res
=>
{
const
message
=
JSON
.
parse
(
res
.
data
)
;
const
message
=
JSON
.
parse
(
res
.
data
)
console
.
log
(
message
)
;
console
.
log
(
message
)
setMessages
(
(
messages
)
=>
[...
messages
,
message
]);
setMessages
(
messages
=>
[...
messages
,
message
])
}
,
}
})
;
})
}
;
}
}
}
export
function
useAIGenerateImage
()
{
export
function
useAIGenerateImage
()
{
const
[
messages
,
setMessages
]
=
useState
([])
;
const
[
messages
,
setMessages
]
=
useState
([])
const
fetch
=
async
(
params
)
=>
{
const
fetch
=
async
params
=>
{
const
res
=
await
aiGenerateImage
(
params
)
;
const
res
=
await
aiGenerateImage
(
params
)
setMessages
(
res
)
;
setMessages
(
res
)
}
;
}
}
}
src/hooks/useBaiduAI.js
0 → 100644
浏览文件 @
5aa3bc6d
import
{
useState
,
useCallback
}
from
'react'
import
{
baiduAIChat
}
from
'@/api/ai'
export
function
useAIEdit
()
{
const
[
messages
,
setMessages
]
=
useState
([])
const
[
isLoading
,
setIsLoading
]
=
useState
(
false
)
const
latestMessage
=
messages
[
messages
.
length
-
1
]
||
{}
const
text
=
latestMessage
?.
content
||
''
const
fetch
=
useCallback
(
async
params
=>
{
setIsLoading
(
true
)
try
{
const
defaultParams
=
{
ernie_name
:
'ERNIE-4.0-8K'
,
stream
:
false
}
const
res
=
await
baiduAIChat
({
...
defaultParams
,
params
})
const
message
=
{
role
:
'assistant'
,
content
:
res
.
data
.
result
}
setMessages
(
prevMessages
=>
[...
prevMessages
,
message
])
}
catch
(
error
)
{
console
.
error
(
'Error fetching data:'
,
error
)
}
finally
{
setIsLoading
(
false
)
}
},
[])
return
{
text
,
messages
,
isLoading
,
fetch
}
}
src/hooks/useFetchEventSource.js
浏览文件 @
5aa3bc6d
import
{
useEffect
,
useState
}
from
'react'
;
import
{
useEffect
,
useState
,
useCallback
}
from
'react'
import
{
fetchEventSource
}
from
'@fortaine/fetch-event-source'
;
import
{
fetchEventSource
}
from
'@fortaine/fetch-event-source'
// 获取本地存储中的令牌
function
getToken
()
{
function
getToken
()
{
return
window
.
localStorage
.
getItem
(
'kiwi.token'
)
||
''
;
return
window
.
localStorage
.
getItem
(
'kiwi.token'
)
||
''
}
}
// 生成请求头部信息
const
getHeaders
=
()
=>
{
const
getHeaders
=
()
=>
{
const
token
=
getToken
()
;
const
token
=
getToken
()
const
appId
=
'TzEU5jPk2tu80266'
;
const
appId
=
'TzEU5jPk2tu80266'
const
appSecret
=
'0a006048a4480481b18fef1405120b83'
;
const
appSecret
=
'0a006048a4480481b18fef1405120b83'
const
timestamp
=
Math
.
floor
(
Date
.
now
()
/
1000
)
;
const
timestamp
=
Math
.
floor
(
Date
.
now
()
/
1000
)
return
{
return
{
Authorization
:
token
,
Authorization
:
token
,
AppId
:
appId
,
AppId
:
appId
,
AppSecret
:
appSecret
,
AppSecret
:
appSecret
,
Timestamp
:
timestamp
,
Timestamp
:
timestamp
,
'Content-Type'
:
'application/json'
,
'Content-Type'
:
'application/json'
}
;
}
}
;
}
const
defaultOnOpen
=
async
(
response
)
=>
{
// 默认的响应打开处理函数
const
defaultOnOpen
=
async
response
=>
{
if
(
!
response
.
ok
)
{
if
(
!
response
.
ok
)
{
throw
response
;
throw
response
}
}
return
response
;
return
response
}
;
}
const
defaultOnMessage
=
(
setMessages
)
=>
(
res
)
=>
{
// 默认的消息处理函数
const
message
=
JSON
.
parse
(
res
.
data
);
const
defaultOnMessage
=
setMessages
=>
res
=>
{
setMessages
((
prevMessages
)
=>
[...
prevMessages
,
message
]);
const
message
=
JSON
.
parse
(
res
.
data
)
};
setMessages
(
prevMessages
=>
[...
prevMessages
,
message
])
}
// 自定义 Hook,用于使用 Fetch 事件源
export
function
useFetchEventSource
(
url
,
options
=
{})
{
export
function
useFetchEventSource
(
url
,
options
=
{})
{
const
[
isLoading
,
setLoading
]
=
useState
(
false
)
;
const
[
isLoading
,
setLoading
]
=
useState
(
false
)
const
[
messages
,
setMessages
]
=
useState
([])
;
const
[
messages
,
setMessages
]
=
useState
([])
const
[
error
,
setError
]
=
useState
(
null
)
;
const
[
error
,
setError
]
=
useState
(
null
)
const
fetch
=
()
=>
{
// 定义 fetch 函数
setLoading
(
true
);
const
fetch
=
useCallback
(()
=>
{
const
headers
=
getHeaders
();
setLoading
(
true
)
const
headers
=
getHeaders
()
const
defaultOptions
=
{
const
defaultOptions
=
{
method
:
'POST'
,
method
:
'POST'
,
headers
,
headers
,
onopen
:
defaultOnOpen
,
onopen
:
defaultOnOpen
,
onmessage
:
defaultOnMessage
(
setMessages
),
onmessage
:
defaultOnMessage
(
setMessages
),
onerror
:
(
err
)
=>
setError
(
err
),
onerror
:
err
=>
setError
(
err
)
}
;
}
fetchEventSource
(
url
,
{
...
defaultOptions
,
...
options
}).
finally
(()
=>
setLoading
(
false
));
fetchEventSource
(
url
,
{
...
defaultOptions
,
...
options
})
};
.
catch
(
err
=>
setError
(
err
))
.
finally
(()
=>
setLoading
(
false
))
},
[
url
,
options
])
// 在组件挂载时执行 fetch 函数
useEffect
(()
=>
{
useEffect
(()
=>
{
fetch
()
;
fetch
()
},
[
url
,
options
]);
},
[
fetch
])
return
{
isLoading
,
error
,
messages
};
return
{
isLoading
,
error
,
messages
,
fetch
}
}
}
src/utils/fetchEventSource.js
浏览文件 @
5aa3bc6d
...
@@ -18,22 +18,15 @@ export default async function fetchEventSourceFn(url, options) {
...
@@ -18,22 +18,15 @@ export default async function fetchEventSourceFn(url, options) {
Timestamp
:
timestamp
,
Timestamp
:
timestamp
,
'Content-Type'
:
'application/json'
'Content-Type'
:
'application/json'
}
}
const
messages
=
[]
const
defaultOptions
=
{
const
defaultOptions
=
{
method
:
'POST'
,
method
:
'POST'
,
headers
:
{
...
defaultHeaders
},
headers
:
{
...
defaultHeaders
},
async
onopen
(
response
)
{
if
(
response
.
ok
)
{
return
response
}
else
{
throw
response
}
},
onmessage
(
res
)
{
onmessage
(
res
)
{
const
message
=
JSON
.
parse
(
res
.
data
)
const
message
=
JSON
.
parse
(
res
.
data
)
messages
.
push
(
message
)
console
.
log
(
res
.
data
)
}
}
}
}
await
fetchEventSource
(
url
,
{
...
defaultOptions
,
...
options
})
return
await
fetchEventSource
(
url
,
{
...
defaultOptions
,
...
options
}).
then
(()
=>
messages
)
}
}
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论