diff --git a/src/assets/images/img_01.png b/src/assets/images/img_01.png new file mode 100644 index 00000000..90d4b078 Binary files /dev/null and b/src/assets/images/img_01.png differ diff --git a/src/assets/images/img_02.png b/src/assets/images/img_02.png new file mode 100644 index 00000000..35a52339 Binary files /dev/null and b/src/assets/images/img_02.png differ diff --git a/src/components/audio-animation/index.less b/src/components/audio-animation/index.less index c16c3d32..a2e3b5f5 100644 --- a/src/components/audio-animation/index.less +++ b/src/components/audio-animation/index.less @@ -3,9 +3,11 @@ justify-content: center; align-items: center; text-align: center; + width: 100%; canvas { display: block; + width: 100%; image-rendering: crisp-edges; } } diff --git a/src/components/audio-animation/index.tsx b/src/components/audio-animation/index.tsx index 469734af..a9a48da4 100644 --- a/src/components/audio-animation/index.tsx +++ b/src/components/audio-animation/index.tsx @@ -1,3 +1,4 @@ +import useResizeObserver from '@/components/logs-viewer/use-size'; import React, { useEffect } from 'react'; import './index.less'; @@ -5,24 +6,31 @@ interface AudioAnimationProps { width: number; height: number; scaleFactor?: number; + maxBarCount?: number; analyserData: { data: Uint8Array; analyser: any; }; } -const AudioAnimation: React.FC = ({ - width, - height, - scaleFactor = 1.2, - analyserData -}) => { +const AudioAnimation: React.FC = (props) => { + const { + scaleFactor = 1.2, + maxBarCount = 128, + analyserData, + width, + height + } = props; const canvasRef = React.useRef(null); const animationId = React.useRef(0); const isScaled = React.useRef(false); const oscillationOffset = React.useRef(0); const direction = React.useRef(1); - const maxBarCount = 128; + // const [width, setWidth] = useState(props.width); + // const [height, setHeight] = useState(props.height); + const containerRef = React.useRef(null); + + const size = useResizeObserver(containerRef); const calculateJitter = ( i: number, @@ -120,7 +128,29 @@ const AudioAnimation: React.FC = ({ draw(performance.now()); }; + // const handleResizeThrottle = React.useCallback( + // throttle(() => { + // console.log('size:', size); + // if (size.width && size.width !== width) { + // setWidth(size.width); + // } + // if (size.height && size.height !== height) { + // setHeight(size.height); + // } + // }, 100), + // [size, width, height] + // ); + + // useEffect(() => { + // handleResizeThrottle(); + // window.addEventListener('resize', handleResizeThrottle); + // return () => { + // handleResizeThrottle.cancel(); + // }; + // }, [size, width, height]); + useEffect(() => { + if (!canvasRef.current) return; const clearCanvas = () => { if (canvasRef.current) { const ctx = canvasRef.current.getContext('2d'); @@ -145,6 +175,7 @@ const AudioAnimation: React.FC = ({ return (
{ + setWidth(w || 0); + }, [w]); + return ( = (props) => { const [color, setColor] = React.useState({}); const imgWrapper = React.useRef(null); + const [imgSize, setImgSize] = React.useState({ + width: width, + height: height + }); const thumImgWrapStyle = React.useMemo(() => { - return loading ? { width: width, height: height } : {}; - }, [loading, width, height]); + return loading ? { width: '100%', height: '100%' } : {}; + }, [loading, imgSize]); const handleOnLoad = React.useCallback(async () => { if (!autoBgColor) { @@ -73,76 +78,114 @@ const SingleImage: React.FC = (props) => { }); }, []); + const handleResize = React.useCallback( + (size: { width: number; height: number }) => { + if (!autoSize) return; + + const { width: containerWidth, height: containerHeight } = size; + const { width: originalWidth, height: originalHeight } = props; + + if (!originalWidth || !originalHeight) return; + + const imageAspectRatio = originalWidth / originalHeight; + const containerAspectRatio = containerWidth / containerHeight; + + let newWidth, newHeight; + + if (containerAspectRatio > imageAspectRatio) { + newHeight = containerHeight; + newWidth = containerHeight * imageAspectRatio; + } else { + newWidth = containerWidth; + newHeight = containerWidth / imageAspectRatio; + } + + setImgSize({ + width: newWidth, + height: newHeight + }); + }, + [autoSize, props] + ); + return ( -
- {autoBgColor && ( -
+
+ {autoBgColor && ( +
+ )} +
- )} - - <> - {loading ? ( - - {progress}%} - trailColor="var(--ant-color-fill-secondary)" - /> - - ) : ( - - + ref={imgWrapper} + > + <> + {loading ? ( + + ( + {progress}% + )} + trailColor="var(--ant-color-fill-secondary)" + /> + + ) : ( + + + + )} + + + {editable && ( + handleOnDelete(uid)}> + )} - - - {editable && ( - handleOnDelete(uid)}> - - - )} - -
+ +
+ ); }; diff --git a/src/components/logs-viewer/use-size.ts b/src/components/logs-viewer/use-size.ts index df93a8fd..f3efd067 100644 --- a/src/components/logs-viewer/use-size.ts +++ b/src/components/logs-viewer/use-size.ts @@ -1,13 +1,27 @@ -import useResizeObserver from '@react-hook/resize-observer'; -import React from 'react'; +import { useEffect, useState } from 'react'; -export default function useSize(target: any) { - const [size, setSize] = React.useState(); +const useResizeObserver = (ref: React.RefObject) => { + const [size, setSize] = useState({ width: 0, height: 0 }); - React.useLayoutEffect(() => { - setSize(target.current?.getBoundingClientRect()); - }, [target]); + useEffect(() => { + const element = ref.current; + if (!element) return; + + const observer = new ResizeObserver((entries) => { + if (entries[0]) { + const { width, height } = entries[0].contentRect; + setSize({ width, height }); + } + }); + + observer.observe(element); + + return () => { + observer.disconnect(); + }; + }, [ref]); - useResizeObserver(target, (entry: any) => setSize(entry?.contentRect)); return size; -} +}; + +export default useResizeObserver; diff --git a/src/components/speech-content/audio-player.tsx b/src/components/speech-content/audio-player.tsx index f6b6822e..3afb4dfa 100644 --- a/src/components/speech-content/audio-player.tsx +++ b/src/components/speech-content/audio-player.tsx @@ -14,10 +14,11 @@ interface AudioPlayerProps { ref?: any; height?: number; width?: number; - onReady?: () => void; + onReady?: (duration: number) => void; onClick?: (value: number) => void; onFinish?: () => void; onAnalyse?: (analyseData: any, frequencyBinCount: any) => void; + onAudioprocess?: (current: number) => void; } const AudioPlayer: React.FC< @@ -29,7 +30,6 @@ const AudioPlayer: React.FC< const audioContext = useRef(null); const analyser = useRef(null); const dataArray = useRef(null); - const audioStream = useRef(null); const mediaElement = useRef(null); const initAudioContext = useCallback(() => { @@ -50,8 +50,8 @@ const AudioPlayer: React.FC< }, []); const listenEvents = () => { - wavesurfer.current?.on('ready', () => { - props.onReady?.(); + wavesurfer.current?.on('ready', (duration: number) => { + props.onReady?.(duration); }); wavesurfer.current?.on('click', (value) => { @@ -60,9 +60,13 @@ const AudioPlayer: React.FC< wavesurfer.current?.on('finish', () => { props.onFinish?.(); }); + wavesurfer.current?.on('audioprocess', (current: number) => { + console.log('audioprocess==========:', current); + props.onAudioprocess?.(current); + }); wavesurfer.current?.on('play', () => { - // analyser.current?.getByteFrequencyData(dataArray.current); - // props.onAnalyse?.(dataArray.current, analyser); + analyser.current?.getByteFrequencyData(dataArray.current); + props.onAnalyse?.(dataArray.current, analyser); }); }; diff --git a/src/components/speech-content/speech-item.tsx b/src/components/speech-content/speech-item.tsx index 466eb947..80530c48 100644 --- a/src/components/speech-content/speech-item.tsx +++ b/src/components/speech-content/speech-item.tsx @@ -1,5 +1,4 @@ -import IconFont from '@/components/icon-font'; -import { formatTime } from '@/utils/index'; +import useResizeObserver from '@/components/logs-viewer/use-size'; import { DownloadOutlined, PauseCircleOutlined, @@ -8,7 +7,8 @@ import { import { useIntl } from '@umijs/max'; import { Button, Tooltip } from 'antd'; import dayjs from 'dayjs'; -import React, { useRef, useState } from 'react'; +import _ from 'lodash'; +import React, { useCallback, useEffect, useRef, useState } from 'react'; import AudioPlayer from './audio-player'; import './styles/index.less'; @@ -36,16 +36,19 @@ interface SpeechContentProps { } const SpeechItem: React.FC = (props) => { const intl = useIntl(); - const [collapsed, setCollapsed] = useState(false); const [isPlay, setIsPlay] = useState(props.autoplay); const [duration, setDuration] = useState(0); + const [animationSize, setAnimationSize] = useState({ width: 900, height: 0 }); const [currentTime, setCurrentTime] = useState(0); const [audioChunks, setAudioChunks] = useState({ - data: [], + data: new Uint8Array(128), analyser: null }); + const wrapper = useRef(null); const ref = useRef(null); + const size = useResizeObserver(wrapper); + const handlePlay = () => { if (isPlay) { ref.current?.pause(); @@ -56,24 +59,44 @@ const SpeechItem: React.FC = (props) => { setIsPlay(true); }; - const handleOnAnalyse = (data: any, analyser: any) => { + const handleOnAnalyse = useCallback((data: any, analyser: any) => { setAudioChunks((pre: any) => { return { data: data, analyser: analyser }; }); - }; + }, []); - const handleReay = () => { - const duration = ref.current?.duration?.(); - setDuration(duration < 1 ? 1 : duration); - }; + const handleOnFinish = useCallback(() => { + setIsPlay(false); + }, []); + + const handleOnAudioprocess = useCallback((current: number) => { + setCurrentTime(() => current); + console.log('current:', current, duration); + }, []); + + const handleReay = useCallback((duration: number) => { + setIsPlay(props.autoplay); + setDuration(duration); + }, []); - const handleOnClick = (value: number) => { + const handleOnClick = useCallback((value: number) => { console.log('current:', value); - }; + }, []); + + const handleAnimationResize = useCallback((size: any) => { + console.log('size:=======', size); + setAnimationSize({ + width: size.width, + height: size.height + }); + }, []); + useEffect(() => { + console.log('width:', size); + }, [size]); const onDownload = () => { const url = props.audioUrl || ''; const filename = `audio-${dayjs().format('YYYYMMDDHHmmss')}.${props.format}`; @@ -89,33 +112,37 @@ const SpeechItem: React.FC = (props) => { return (
- {/* {isPlay && ( - - )} */} -
- -
-
+
setIsPlay(false)} + onFinish={handleOnFinish} onAnalyse={handleOnAnalyse} + onAudioprocess={handleOnAudioprocess} ref={ref} > + {/* {isPlay && ( + + )} */}
+ {/* */}
{props.format} - {formatTime(duration)} + {_.round(duration, 2)}
= forwardRef((props, ref) => { const progress = _.round(item.progress, 0); newImageList[item.index] = { dataUrl: imgItem.dataUrl, - height: '100%', - width: '100%', + height: imgSize[1], + width: imgSize[0], maxHeight: `${imgSize[1]}px`, maxWidth: `${imgSize[0]}px`, uid: imgItem.uid, diff --git a/src/pages/playground/components/ground-tts.tsx b/src/pages/playground/components/ground-tts.tsx index 2c08e495..a6a0355d 100644 --- a/src/pages/playground/components/ground-tts.tsx +++ b/src/pages/playground/components/ground-tts.tsx @@ -212,7 +212,6 @@ const GroundLeft: React.FC = forwardRef((props, ref) => { const res = await queryModelVoices({ model: value }); - console.log('res:', res); if (res?.error) { setVoiceError({ error: true, @@ -235,6 +234,7 @@ const GroundLeft: React.FC = forwardRef((props, ref) => { const newList = sortVoiceList(locale, list); setVoiceList(newList); + setVoiceError(null); setParams((pre: any) => { return { ...pre, diff --git a/src/pages/playground/components/thumb-img.tsx b/src/pages/playground/components/thumb-img.tsx index 47fda620..d46c55c4 100644 --- a/src/pages/playground/components/thumb-img.tsx +++ b/src/pages/playground/components/thumb-img.tsx @@ -1,7 +1,5 @@ -import AutoImage from '@/components/auto-image'; import SingleImage from '@/components/auto-image/single-image'; -import { CloseCircleOutlined } from '@ant-design/icons'; -import { Col, Progress, Row } from 'antd'; +import { Col, Row } from 'antd'; import _ from 'lodash'; import React, { useCallback } from 'react'; import '../style/thumb-img.less'; @@ -38,57 +36,6 @@ const ThumbImg: React.FC<{ return null; } - const renderImageItem = (item: any) => { - const thumImgWrapStyle = item.loading - ? { width: item.width, height: item.height } - : {}; - return ( - - <> - {item.loading ? ( - - - - ) : ( - - - - )} - - - {editable && ( - handleOnDelete(item.uid)}> - - - )} - - ); - }; - return ( <> { @@ -147,6 +94,7 @@ const ThumbImg: React.FC<{ > { // generate a random number between 0 and 64 bit export const generateRandomNumber = () => { - // 0x100000000 - return Math.floor(Math.random() * Number.MAX_SAFE_INTEGER); + // 16: 0x1000;32:0x100000000 + return Math.floor(Math.random() * 0x100000000); };