import AlertInfo from '@/components/alert-info'; import AudioAnimation from '@/components/audio-animation'; import AudioPlayer from '@/components/audio-player'; import CopyButton from '@/components/copy-button'; import IconFont from '@/components/icon-font'; import UploadAudio from '@/components/upload-audio'; import useOverlayScroller from '@/hooks/use-overlay-scroller'; import { readAudioFile } from '@/utils/load-audio-file'; import { SendOutlined } from '@ant-design/icons'; import { useIntl, useSearchParams } from '@umijs/max'; import { Button, Spin, Tooltip } from 'antd'; import classNames from 'classnames'; import 'overlayscrollbars/overlayscrollbars.css'; import { forwardRef, memo, useCallback, useEffect, useImperativeHandle, useRef, useState } from 'react'; import { speechToText } from '../apis'; import { RealtimeParamsConfig as paramsConfig } from '../config/params-config'; import '../style/ground-left.less'; import '../style/speech-to-text.less'; import '../style/system-message-wrap.less'; import AudioInput from './audio-input'; import DynamicParams from './dynamic-params'; import ViewCodeModal from './view-code-modal'; interface MessageProps { modelList: Global.BaseOption[]; loaded?: boolean; ref?: any; } const initialValues = { language: 'auto' }; const GroundLeft: React.FC = forwardRef((props, ref) => { const intl = useIntl(); const { modelList } = props; const messageId = useRef(0); const [messageList, setMessageList] = useState< { uid: number; content: string }[] >([]); const [searchParams] = useSearchParams(); const modelType = searchParams.get('type') || ''; const selectModel = searchParams.get('model') ? modelType === 'stt' && searchParams.get('model') : ''; const [parameters, setParams] = useState({}); const [show, setShow] = useState(false); const [loading, setLoading] = useState(false); const [tokenResult, setTokenResult] = useState(null); const [collapse, setCollapse] = useState(false); const controllerRef = useRef(null); const scroller = useRef(null); const paramsRef = useRef(null); const [audioPermissionOn, setAudioPermissionOn] = useState(true); const [audioData, setAudioData] = useState(null); const [audioChunks, setAudioChunks] = useState({ data: [], analyser: null }); const [isRecording, setIsRecording] = useState(false); const formRef = useRef(null); const { initialize, updateScrollerPosition } = useOverlayScroller(); const { initialize: innitializeParams } = useOverlayScroller(); useImperativeHandle(ref, () => { return { viewCode() { setShow(true); }, setCollapse() { setCollapse(!collapse); }, collapse: collapse }; }); const setMessageId = () => { messageId.current = messageId.current + 1; }; const handleStopConversation = () => { controllerRef.current?.abort?.(); setLoading(false); }; const submitMessage = async () => { await formRef.current?.form.validateFields(); if (!parameters.model) return; try { setLoading(true); setMessageId(); setTokenResult(null); setMessageList([]); controllerRef.current?.abort?.(); controllerRef.current = new AbortController(); const signal = controllerRef.current.signal; const params = { ...parameters, file: new File([audioData.data], audioData.name, { type: audioData.type }) }; const result: any = await speechToText({ data: params }); if (result?.error) { setTokenResult({ error: true, errorMessage: result?.data?.error?.message || result?.data?.message || result?.detail || '' }); return; } setMessageList([ { content: result.text, uid: messageId.current } ]); } catch (error: any) { console.log('error:', error); const res = error?.response?.data; if (res?.error) { setTokenResult({ error: true, errorMessage: res?.error?.message || res?.data?.error || res?.detail || '' }); } } finally { setLoading(false); setIsRecording(false); } }; const handleClear = () => { if (!messageList.length) { return; } setMessageId(); setMessageList([]); setTokenResult(null); }; const handleCloseViewCode = () => { setShow(false); }; const handleOnAudioData = useCallback( (data: { chunks: Blob[]; url: string; name: string; duration: number; type: string; }) => { setAudioData(() => { return { url: data.url, name: data.name, data: data.chunks, type: data.type, duration: data.duration }; }); }, [] ); const handleOnAudioPermission = useCallback((permission: boolean) => { setAudioPermissionOn(permission); }, []); const handleUploadChange = useCallback( async (data: { file: any; fileList: any }) => { const res = await readAudioFile(data.file); setAudioData(res); setTokenResult(null); }, [] ); const handleOnAnalyse = useCallback((data: any, analyser: any) => { setAudioChunks((pre: any) => { return { data: data, analyser: analyser }; }); }, []); const handleOnRecord = useCallback((val: boolean) => { setIsRecording(val); setAudioData(null); setTokenResult(null); console.log('data===', val); }, []); const handleOnGenerate = async () => { submitMessage(); }; const renderAniamtion = () => { if (!audioPermissionOn) { return (
{intl.formatMessage({ id: 'playground.audio.enablemic' })}
); } if (isRecording) { return ( ); } return (
{intl.formatMessage({ id: 'playground.audio.speechtotext.tips' })}
); }; useEffect(() => { console.log('parameters:', parameters); }, [parameters]); useEffect(() => { if (scroller.current) { initialize(scroller.current); } }, [scroller.current, initialize]); useEffect(() => { if (paramsRef.current) { innitializeParams(paramsRef.current); } }, [paramsRef.current, innitializeParams]); useEffect(() => { if (loading) { updateScrollerPosition(); } }, [messageList, loading]); return (
{!isRecording && ( )}
{audioData ? (
) : ( renderAniamtion() )}
{messageList?.length > 0 && ( )}
<> {!tokenResult && (
{messageList.length ? ( messageList[0]?.content ) : ( {intl.formatMessage({ id: 'playground.audio.generating.tips' })} )}
)} {tokenResult && (
)}
{loading && (
)}
); }); export default memo(GroundLeft);