提交 5aa3bc6d authored 作者: 王鹏飞's avatar 王鹏飞

chore: update

上级 e5337a88
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
......
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)
} }
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/useAI'; import { useAIEdit } from '@/hooks/useBaiduAI'
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>
); )
} }
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)
}; }
} }
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 }
}
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 }
} }
...@@ -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 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论