mirror of
https://github.com/langgenius/dify.git
synced 2026-05-04 09:28:04 +08:00
Merge branch 'main' into feat/workflow
This commit is contained in:
@ -40,6 +40,7 @@ const TextToSpeech: FC = () => {
|
||||
{ languageInfo?.example && (
|
||||
<AudioBtn
|
||||
value={languageInfo?.example}
|
||||
voice={voiceItem?.value}
|
||||
isAudition={true}
|
||||
/>
|
||||
)}
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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);
|
||||
}
|
||||
@ -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'
|
||||
/>
|
||||
)}
|
||||
|
||||
@ -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) => {
|
||||
|
||||
@ -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 |
@ -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 |
@ -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>
|
||||
|
||||
|
||||
@ -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>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user