mirror of
https://github.com/wassname/chatGPTBox.git
synced 2026-07-13 17:42:45 +08:00
feat: added a ReadButton to convert the text output from GPT into voice and read it out loud
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import { useState } from 'react'
|
||||
import { ChevronDownIcon, XCircleIcon, SyncIcon } from '@primer/octicons-react'
|
||||
import CopyButton from '../CopyButton'
|
||||
import ReadButton from '../ReadButton'
|
||||
import PropTypes from 'prop-types'
|
||||
import MarkdownRender from '../MarkdownRender/markdown.jsx'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
@@ -73,6 +74,9 @@ export function ConversationItem({ type, content, session, done, port, onRetry }
|
||||
{session && (
|
||||
<CopyButton contentFn={() => content.replace(/\n<hr\/>$/, '')} size={14} />
|
||||
)}
|
||||
{session && (
|
||||
<ReadButton contentFn={() => content.replace(/\n<hr\/>$/, '')} size={14} />
|
||||
)}
|
||||
{!collapsed ? (
|
||||
<span
|
||||
title={t('Collapse')}
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
import { useState } from 'react'
|
||||
import { UnmuteIcon, MuteIcon } from '@primer/octicons-react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
|
||||
ReadButton.propTypes = {
|
||||
contentFn: PropTypes.func.isRequired,
|
||||
size: PropTypes.number.isRequired,
|
||||
className: PropTypes.string,
|
||||
}
|
||||
|
||||
function ReadButton({ className, contentFn, size }) {
|
||||
const { t } = useTranslation()
|
||||
const [speaking, setSpeaking] = useState(false)
|
||||
|
||||
const startSpeak = () => {
|
||||
speechSynthesis.cancel()
|
||||
|
||||
let text = contentFn()
|
||||
|
||||
const utterance = new SpeechSynthesisUtterance(text)
|
||||
Object.assign(utterance, {
|
||||
// lang: 'zh-CN',
|
||||
rate: 0.9,
|
||||
volume: 1,
|
||||
onend: () => setSpeaking(false),
|
||||
onerror: () => setSpeaking(false),
|
||||
})
|
||||
|
||||
let supportedVoices = speechSynthesis.getVoices()
|
||||
for (let i = 0; i < supportedVoices.length; i++) {
|
||||
if (supportedVoices[i].lang.indexOf(text[0]) >= 0) {
|
||||
utterance.voice = supportedVoices[i]
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
speechSynthesis.speak(utterance)
|
||||
setSpeaking(true)
|
||||
}
|
||||
|
||||
const stopSpeak = () => {
|
||||
speechSynthesis.cancel()
|
||||
setSpeaking(false)
|
||||
}
|
||||
|
||||
return (
|
||||
<span
|
||||
title={t('Read')}
|
||||
className={`gpt-util-icon ${className ? className : ''}`}
|
||||
onClick={speaking ? stopSpeak : startSpeak}
|
||||
>
|
||||
{speaking ? <MuteIcon size={size} /> : <UnmuteIcon size={size} />}
|
||||
</span>
|
||||
)
|
||||
}
|
||||
|
||||
export default ReadButton
|
||||
@@ -7,3 +7,4 @@ export * from './DeleteButton'
|
||||
export * from './FeedbackForChatGPTWeb'
|
||||
export * from './FloatingToolbar'
|
||||
export * from './InputBox'
|
||||
export * from './ReadButton'
|
||||
|
||||
Reference in New Issue
Block a user