Merge branch 'main' into feat/workflow

This commit is contained in:
StyleZhang
2024-03-06 19:05:21 +08:00
62 changed files with 1095 additions and 269 deletions

View File

@ -40,6 +40,7 @@ const TextToSpeech: FC = () => {
{ languageInfo?.example && (
<AudioBtn
value={languageInfo?.example}
voice={voiceItem?.value}
isAudition={true}
/>
)}

View File

@ -9,12 +9,14 @@ import { textToAudio } from '@/service/share'
type AudioBtnProps = {
value: string
voice?: string
className?: string
isAudition?: boolean
}
const AudioBtn = ({
value,
voice,
className,
isAudition,
}: AudioBtnProps) => {
@ -27,13 +29,16 @@ const AudioBtn = ({
const pathname = usePathname()
const removeCodeBlocks = (inputText: any) => {
const codeBlockRegex = /```[\s\S]*?```/g
return inputText.replace(codeBlockRegex, '')
if (inputText)
return inputText.replace(codeBlockRegex, '')
return ''
}
const playAudio = async () => {
const formData = new FormData()
if (value !== '') {
formData.append('text', removeCodeBlocks(value))
formData.append('voice', removeCodeBlocks(voice))
let url = ''
let isPublic = false
@ -56,13 +61,14 @@ const AudioBtn = ({
const audioUrl = URL.createObjectURL(blob)
const audio = new Audio(audioUrl)
audioRef.current = audio
audio.play().then(() => {
setIsPlaying(true)
}).catch(() => {
audio.play().then(() => {}).catch(() => {
setIsPlaying(false)
URL.revokeObjectURL(audioUrl)
})
audio.onended = () => setHasEnded(true)
audio.onended = () => {
setHasEnded(true)
setIsPlaying(false)
}
}
catch (error) {
setIsPlaying(false)
@ -70,24 +76,34 @@ const AudioBtn = ({
}
}
}
const togglePlayPause = () => {
if (audioRef.current) {
if (isPlaying) {
setPause(true)
audioRef.current.pause()
}
else if (!hasEnded) {
setPause(false)
audioRef.current.play()
if (!hasEnded) {
setPause(false)
audioRef.current.play()
}
if (!isPause) {
setPause(true)
audioRef.current.pause()
}
}
else if (!isPlaying) {
playAudio().then()
if (isPause) {
setPause(false)
audioRef.current.play()
}
else {
setHasEnded(false)
playAudio().then()
}
}
setIsPlaying(prevIsPlaying => !prevIsPlaying)
}
else {
playAudio().then()
setIsPlaying(true)
if (!isPlaying)
playAudio().then()
}
}
@ -102,7 +118,7 @@ const AudioBtn = ({
className={`box-border p-0.5 flex items-center justify-center cursor-pointer ${isAudition || 'rounded-md bg-white'}`}
style={{ boxShadow: !isAudition ? '0px 4px 8px -2px rgba(16, 24, 40, 0.1), 0px 2px 4px -2px rgba(16, 24, 40, 0.06)' : '' }}
onClick={togglePlayPause}>
<div className={`w-6 h-6 rounded-md ${!isAudition ? 'hover:bg-gray-200' : 'hover:bg-gray-50'} ${!isPause ? ((isPlaying && !hasEnded) ? s.playIcon : s.stopIcon) : s.pauseIcon}`}></div>
<div className={`w-6 h-6 rounded-md ${!isAudition ? 'hover:bg-gray-200' : 'hover:bg-gray-50'} ${(isPlaying && !hasEnded) ? s.pauseIcon : s.playIcon}`}></div>
</div>
</Tooltip>
</div>

View File

@ -8,9 +8,3 @@
background-position: center;
background-repeat: no-repeat;
}
.stopIcon {
background-position: center;
background-repeat: no-repeat;
background-image: url(~@/app/components/develop/secret-key/assets/stop.svg);
}

View File

@ -77,6 +77,7 @@ const Operation: FC<OperationProps> = ({
{(!isOpeningStatement && config?.text_to_speech?.enabled) && (
<AudioBtn
value={content}
voice={config?.text_to_speech?.voice}
className='hidden group-hover:block'
/>
)}

View File

@ -9,6 +9,7 @@ import {
} from 'react'
import { useTranslation } from 'react-i18next'
import { useThrottleEffect } from 'ahooks'
import { debounce } from 'lodash-es'
import type {
ChatConfig,
ChatItem,
@ -81,16 +82,24 @@ const Chat: FC<ChatProps> = ({
chatContainerRef.current.scrollTop = chatContainerRef.current.scrollHeight
}
useThrottleEffect(() => {
handleScrolltoBottom()
const handleWindowResize = () => {
if (chatContainerRef.current && chatFooterRef.current)
chatFooterRef.current.style.width = `${chatContainerRef.current.clientWidth}px`
if (chatContainerInnerRef.current && chatFooterInnerRef.current)
chatFooterInnerRef.current.style.width = `${chatContainerInnerRef.current.clientWidth}px`
}
useThrottleEffect(() => {
handleScrolltoBottom()
handleWindowResize()
}, [chatList], { wait: 500 })
useEffect(() => {
window.addEventListener('resize', debounce(handleWindowResize))
return () => window.removeEventListener('resize', handleWindowResize)
}, [])
useEffect(() => {
if (chatFooterRef.current && chatContainerRef.current) {
const resizeObserver = new ResizeObserver((entries) => {

View File

@ -1,7 +1,7 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_129_107)">
<path d="M7.99991 14.6666C11.6819 14.6666 14.6666 11.6819 14.6666 7.99998C14.6666 4.31808 11.6819 1.33331 7.99998 1.33331C4.31808 1.33331 1.33331 4.31808 1.33331 7.99998C1.33331 11.6819 4.31808 14.6666 7.99998 14.6666Z" stroke="#155EEF" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M6.66665 5.33331L10.6666 7.99998L6.66665 10.6666V5.33331Z" stroke="#155EEF" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M7.99998 14.6666C11.6819 14.6666 14.6666 11.6819 14.6666 7.99998C14.6666 4.31808 11.6819 1.33331 7.99998 1.33331C4.31808 1.33331 1.33331 4.31808 1.33331 7.99998C1.33331 11.6819 4.31808 14.6666 7.99998 14.6666Z" stroke="#667085" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M6.66665 5.33331L10.6666 7.99998L6.66665 10.6666V5.33331Z" stroke="#667085" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
</g>
<defs>
<clipPath id="clip0_129_107">

Before

Width:  |  Height:  |  Size: 703 B

After

Width:  |  Height:  |  Size: 703 B

View File

@ -1,11 +0,0 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_129_107)">
<path d="M7.99998 14.6666C11.6819 14.6666 14.6666 11.6819 14.6666 7.99998C14.6666 4.31808 11.6819 1.33331 7.99998 1.33331C4.31808 1.33331 1.33331 4.31808 1.33331 7.99998C1.33331 11.6819 4.31808 14.6666 7.99998 14.6666Z" stroke="#667085" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M6.66665 5.33331L10.6666 7.99998L6.66665 10.6666V5.33331Z" stroke="#667085" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
</g>
<defs>
<clipPath id="clip0_129_107">
<rect width="16" height="16" fill="white"/>
</clipPath>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 703 B

View File

@ -71,8 +71,8 @@ Chat applications support session persistence, allowing previous chat history to
- `upload_file_id` (string) Uploaded file ID, which must be obtained by uploading through the File Upload API in advance (when the transfer method is `local_file`)
</Property>
<Property name='auto_generate_name' type='bool' key='auto_generate_name'>
Auto-generate title, default is `false`.
Can achieve async title generation by calling the conversation rename API and setting `auto_generate` to true.
Auto-generate title, default is `true`.
If set to `false`, can achieve async title generation by calling the conversation rename API and setting `auto_generate` to `true`.
</Property>
</Properties>

View File

@ -71,7 +71,7 @@ import { Row, Col, Properties, Property, Heading, SubProperty } from '../md.tsx'
- `upload_file_id` 上传文件 ID。仅当传递方式为 `local_file `时)。
</Property>
<Property name='auto_generate_name' type='bool' key='auto_generate_name'>
(选填)自动生成标题,默认 `false`可通过调用会话重命名接口并设置 `auto_generate` 为 `true` 实现异步生成标题。
(选填)自动生成标题,默认 `true`。 若设置为 `false`,则可通过调用会话重命名接口并设置 `auto_generate` 为 `true` 实现异步生成标题。
</Property>
</Properties>