chore: stt player ui

This commit is contained in:
jialin
2025-02-17 13:49:55 +08:00
parent d2a3388058
commit c60015bd09
11 changed files with 142 additions and 111 deletions
+4 -28
View File
@@ -4894,7 +4894,7 @@ packages:
dependencies: dependencies:
'@babel/core': 7.24.5 '@babel/core': 7.24.5
postcss: 7.0.39 postcss: 7.0.39
postcss-syntax: 0.36.2(postcss@7.0.39) postcss-syntax: 0.36.2(postcss@8.4.38)
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
dev: false dev: false
@@ -4935,7 +4935,7 @@ packages:
postcss-syntax: '>=0.36.2' postcss-syntax: '>=0.36.2'
dependencies: dependencies:
postcss: 7.0.39 postcss: 7.0.39
postcss-syntax: 0.36.2(postcss@7.0.39) postcss-syntax: 0.36.2(postcss@8.4.38)
remark: 13.0.0 remark: 13.0.0
unist-util-find-all-after: 3.0.2 unist-util-find-all-after: 3.0.2
transitivePeerDependencies: transitivePeerDependencies:
@@ -14301,7 +14301,7 @@ packages:
dependencies: dependencies:
htmlparser2: 3.10.1 htmlparser2: 3.10.1
postcss: 7.0.39 postcss: 7.0.39
postcss-syntax: 0.36.2(postcss@7.0.39) postcss-syntax: 0.36.2(postcss@8.4.38)
dev: false dev: false
/postcss-image-set-function@4.0.7(postcss@8.4.38): /postcss-image-set-function@4.0.7(postcss@8.4.38):
@@ -14775,30 +14775,6 @@ packages:
lodash: 4.17.21 lodash: 4.17.21
postcss: 8.4.38 postcss: 8.4.38
/postcss-syntax@0.36.2(postcss@7.0.39):
resolution: {integrity: sha512-nBRg/i7E3SOHWxF3PpF5WnJM/jQ1YpY9000OaVXlAQj6Zp/kIqJxEDWIZ67tAd7NLuk7zqN4yqe9nc0oNAOs1w==}
peerDependencies:
postcss: '>=5.0.0'
postcss-html: '*'
postcss-jsx: '*'
postcss-less: '*'
postcss-markdown: '*'
postcss-scss: '*'
peerDependenciesMeta:
postcss-html:
optional: true
postcss-jsx:
optional: true
postcss-less:
optional: true
postcss-markdown:
optional: true
postcss-scss:
optional: true
dependencies:
postcss: 7.0.39
dev: false
/postcss-syntax@0.36.2(postcss@8.4.38): /postcss-syntax@0.36.2(postcss@8.4.38):
resolution: {integrity: sha512-nBRg/i7E3SOHWxF3PpF5WnJM/jQ1YpY9000OaVXlAQj6Zp/kIqJxEDWIZ67tAd7NLuk7zqN4yqe9nc0oNAOs1w==} resolution: {integrity: sha512-nBRg/i7E3SOHWxF3PpF5WnJM/jQ1YpY9000OaVXlAQj6Zp/kIqJxEDWIZ67tAd7NLuk7zqN4yqe9nc0oNAOs1w==}
peerDependencies: peerDependencies:
@@ -18099,7 +18075,7 @@ packages:
postcss-sass: 0.4.4 postcss-sass: 0.4.4
postcss-scss: 2.1.1 postcss-scss: 2.1.1
postcss-selector-parser: 6.0.16 postcss-selector-parser: 6.0.16
postcss-syntax: 0.36.2(postcss@7.0.39) postcss-syntax: 0.36.2(postcss@8.4.38)
postcss-value-parser: 4.2.0 postcss-value-parser: 4.2.0
resolve-from: 5.0.0 resolve-from: 5.0.0
slash: 3.0.0 slash: 3.0.0
+8 -6
View File
@@ -1,7 +1,7 @@
.player-wrap { .player-wrap {
width: 100%; width: 100%;
display: flex; display: flex;
background-color: var(--ant-color-fill-quaternary); // background-color: var(--ant-color-fill-quaternary);
border-radius: 6px; border-radius: 6px;
.player-ui { .player-ui {
@@ -13,10 +13,10 @@
} }
.controls { .controls {
width: 100%;
display: flex; display: flex;
justify-content: center; justify-content: space-between;
align-items: center; align-items: center;
margin-inline: 10px;
} }
.play-btn { .play-btn {
@@ -43,7 +43,6 @@
.slider-inner { .slider-inner {
flex: 1; flex: 1;
margin-inline: 10px;
} }
} }
@@ -55,8 +54,11 @@
} }
.time { .time {
width: 52px;
text-align: right;
&.current { &.current {
margin-left: 6px; text-align: left;
} }
} }
@@ -65,7 +67,7 @@
flex: 1; flex: 1;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: center; align-items: flex-start;
justify-content: center; justify-content: center;
.slider { .slider {
+69 -55
View File
@@ -25,6 +25,7 @@ interface AudioPlayerProps {
height?: number; height?: number;
width?: number; width?: number;
duration?: number; duration?: number;
extra?: React.ReactNode;
} }
const speedOptions = [ const speedOptions = [
@@ -42,7 +43,7 @@ const speedConfig = {
const AudioPlayer: React.FC<AudioPlayerProps> = forwardRef((props, ref) => { const AudioPlayer: React.FC<AudioPlayerProps> = forwardRef((props, ref) => {
const intl = useIntl(); const intl = useIntl();
const { autoplay = false, speed: defaultSpeed = 1 } = props; const { autoplay = false, speed: defaultSpeed = 1, extra } = props;
const audioRef = React.useRef<HTMLAudioElement>(null); const audioRef = React.useRef<HTMLAudioElement>(null);
const [audioState, setAudioState] = React.useState<{ const [audioState, setAudioState] = React.useState<{
currentTime: number; currentTime: number;
@@ -206,76 +207,89 @@ const AudioPlayer: React.FC<AudioPlayerProps> = forwardRef((props, ref) => {
<div className="progress-bar"> <div className="progress-bar">
<span className="file-name">{props.name}</span> <span className="file-name">{props.name}</span>
<div className="slider"> <div className="slider">
<span className="time current"> {/* <span className="time current">
{' '} {' '}
{formatTime(audioState.currentTime)} {formatTime(audioState.currentTime)}
</span> </span> */}
<div className="slider-inner"> <div className="slider-inner">
<Slider <Slider
tooltip={{ open: false }} tooltip={{ open: false }}
min={0} min={0}
step={1} step={1}
styles={{
rail: {
// height: 6
}
}}
max={audioState.duration} max={audioState.duration}
value={audioState.currentTime} value={audioState.currentTime}
onChange={handleCurrentChange} onChange={handleCurrentChange}
/> />
</div> </div>
<span className="time">{formatTime(audioState.duration)}</span> {/* <span className="time">{formatTime(audioState.duration)}</span> */}
</div> </div>
<div className="controls"> <div className="controls">
<Tooltip <div className="audio-control flex-center">
title={intl.formatMessage({ <span className="time current">
id: 'playground.audio.button.slow' {' '}
})} {formatTime(audioState.currentTime)}
> </span>
<Button <Tooltip
type="text" title={intl.formatMessage({
size="small" id: 'playground.audio.button.slow'
className="backward" })}
disabled={
speed === speedConfig.min || speed < speedConfig.min
}
onClick={handleReduceSpeed}
> >
<FastBackwardOutlined className="font-size-20" /> <Button
</Button> type="text"
</Tooltip> size="small"
<span className="play-btn"> className="backward"
<Button disabled={
size="middle" speed === speedConfig.min || speed < speedConfig.min
type="text" }
onClick={handlePlay} onClick={handleReduceSpeed}
disabled={!audioState?.duration} >
icon={ <FastBackwardOutlined className="font-size-20" />
!playOn ? ( </Button>
<PlayCircleFilled </Tooltip>
style={{ fontSize: '22px' }} <span className="play-btn">
></PlayCircleFilled> <Button
) : ( size="middle"
<PauseCircleFilled type="text"
style={{ fontSize: '22px' }} onClick={handlePlay}
></PauseCircleFilled> disabled={!audioState?.duration}
) icon={
} !playOn ? (
></Button> <PlayCircleFilled
</span> style={{ fontSize: '22px' }}
<Tooltip ></PlayCircleFilled>
title={intl.formatMessage({ ) : (
id: 'playground.audio.button.fast' <PauseCircleFilled
})} style={{ fontSize: '22px' }}
> ></PauseCircleFilled>
<Button )
type="text" }
size="small" ></Button>
className="forward" </span>
disabled={ <Tooltip
speed === speedConfig.max || speed > speedConfig.max title={intl.formatMessage({
} id: 'playground.audio.button.fast'
onClick={handleAddSpeed} })}
> >
<FastForwardOutlined className="font-size-20" /> <Button
</Button> type="text"
</Tooltip> size="small"
className="forward"
disabled={
speed === speedConfig.max || speed > speedConfig.max
}
onClick={handleAddSpeed}
>
<FastForwardOutlined className="font-size-20" />
</Button>
</Tooltip>
<span className="time">{formatTime(audioState.duration)}</span>
</div>
{extra}
</div> </div>
</div> </div>
</div> </div>
+5 -1
View File
@@ -139,7 +139,11 @@ const LogsList: React.FC<LogsListProps> = forwardRef((props, ref) => {
<div className={classNames('content')}> <div className={classNames('content')}>
{_.map(dataList, (item: any, index: number) => { {_.map(dataList, (item: any, index: number) => {
return ( return (
<div key={item.uid} className={classNames('text')}> <div
key={item.uid}
className={classNames('text')}
data-uid={item.uid}
>
{item.content} {item.content}
</div> </div>
); );
+16 -4
View File
@@ -4,6 +4,10 @@ const removeBrackets = (str: string) => {
return str?.replace?.(/^\(…\)/, ''); return str?.replace?.(/^\(…\)/, '');
}; };
const removeBracketsFromLine = (row: string) => {
return row.startsWith('(…)') ? row.slice(3) : row;
};
class AnsiParser { class AnsiParser {
private cursorRow: number = 0; private cursorRow: number = 0;
private cursorCol: number = 0; private cursorCol: number = 0;
@@ -12,6 +16,8 @@ class AnsiParser {
private uid: number = 0; private uid: number = 0;
private isProcessing: boolean = false; private isProcessing: boolean = false;
private taskQueue: string[] = []; private taskQueue: string[] = [];
private page: number = 1;
private pageSize: number = 500;
private colorMap = { private colorMap = {
'30': 'black', '30': 'black',
'31': 'red', '31': 'red',
@@ -33,6 +39,11 @@ class AnsiParser {
this.screen = [['']]; this.screen = [['']];
this.rawDataRows = 0; this.rawDataRows = 0;
this.uid = this.uid + 1; this.uid = this.uid + 1;
this.page = 1;
}
public setPage(page: number) {
this.page = page;
} }
private setId() { private setId() {
@@ -125,9 +136,9 @@ class AnsiParser {
const remainingText = input.slice(lastIndex); const remainingText = input.slice(lastIndex);
this.handleText(remainingText); this.handleText(remainingText);
const result = this.screen.map((row) => ({ const result = this.screen.map((row, index) => ({
content: removeBrackets(row.join('')), content: removeBracketsFromLine(row.join('')),
uid: this.setId() uid: `${this.page}-${index}`
})); }));
return { return {
@@ -176,7 +187,8 @@ class AnsiParser {
const parser = new AnsiParser(); const parser = new AnsiParser();
self.onmessage = function (event) { self.onmessage = function (event) {
const { inputStr, reset } = event.data; const { inputStr, reset, page } = event.data;
parser.setPage(page);
if (reset) { if (reset) {
parser.reset(); parser.reset();
} }
@@ -133,6 +133,7 @@ const LogsViewer: React.FC<LogsViewerProps> = forwardRef((props, ref) => {
} }
logParseWorker.current.postMessage({ logParseWorker.current.postMessage({
inputStr: data, inputStr: data,
page: pageRef.current,
reset: clearScreen.current reset: clearScreen.current
}); });
clearScreen.current = false; clearScreen.current = false;
@@ -1,6 +1,5 @@
import useSetChunkRequest from '@/hooks/use-chunk-request'; import useSetChunkRequest from '@/hooks/use-chunk-request';
import { FitAddon } from '@xterm/addon-fit'; import { FitAddon } from '@xterm/addon-fit';
import { WebglAddon } from '@xterm/addon-webgl';
import { Terminal } from '@xterm/xterm'; import { Terminal } from '@xterm/xterm';
import '@xterm/xterm/css/xterm.css'; import '@xterm/xterm/css/xterm.css';
import classNames from 'classnames'; import classNames from 'classnames';
@@ -126,7 +125,6 @@ const LogsViewer: React.FC<LogsViewerProps> = forwardRef((props, ref) => {
}); });
fitAddonRef.current = new FitAddon(); fitAddonRef.current = new FitAddon();
termRef.current.loadAddon(fitAddonRef.current); termRef.current.loadAddon(fitAddonRef.current);
termRef.current.loadAddon(new WebglAddon());
termRef.current.open(termwrapRef.current); termRef.current.open(termwrapRef.current);
// add event // add event
@@ -11,6 +11,10 @@
margin-bottom: 0; margin-bottom: 0;
} }
b {
font-weight: var(--font-weight-bold);
}
h1, h1,
h2, h2,
h3, h3,
@@ -80,6 +84,10 @@
max-width: 100%; max-width: 100%;
height: auto; height: auto;
} }
img[src^="https://img.shields.io/"], img[src*="badge.svg"]
{
margin-bottom: 6px;
}
video { video {
max-width: 100%; max-width: 100%;
-4
View File
@@ -45,10 +45,6 @@ const MarkdownViewer: React.FC<MarkdownViewerProps> = ({
// 'bibtex' // 'bibtex'
]; ];
// renderer.link = ({ href, title, text }) => {
// return `<a href="${href}" title="${title || ''}" target="_blank" rel="noopener noreferrer">${text}</a>`;
// };
const isValidURL = useCallback((url: string) => { const isValidURL = useCallback((url: string) => {
const pattern = /^(https?:\/\/|\/\/)([^\s/$.?#].[^\s]*)$/; const pattern = /^(https?:\/\/|\/\/)([^\s/$.?#].[^\s]*)$/;
@@ -1 +0,0 @@
export default {};
+31 -10
View File
@@ -307,7 +307,7 @@ const GroundLeft: React.FC<MessageProps> = forwardRef((props, ref) => {
{!isRecording && ( {!isRecording && (
<UploadAudio <UploadAudio
type="default" type="default"
accept={SpeechToTextFormat.join(',')} accept={SpeechToTextFormat.join(', ')}
onChange={handleUploadChange} onChange={handleUploadChange}
></UploadAudio> ></UploadAudio>
)} )}
@@ -322,18 +322,40 @@ const GroundLeft: React.FC<MessageProps> = forwardRef((props, ref) => {
</div> </div>
{audioData ? ( {audioData ? (
<div <div className="flex-between flex-center justify-center relative">
className="flex-between flex-center justify-center relative"
style={{ paddingInline: 80 }}
>
<div style={{ width: 600 }}> <div style={{ width: 600 }}>
<AudioPlayer <AudioPlayer
url={audioData.url} url={audioData.url}
name={audioData.name} name={audioData.name}
duration={audioData.duration} duration={audioData.duration}
extra={
<Tooltip
title={
loading
? intl.formatMessage({
id: 'playground.audio.generating'
})
: intl.formatMessage({
id: 'playground.audio.button.generate'
})
}
>
{
<Button
disabled={!audioData}
loading={loading}
type="primary"
size="middle"
shape="circle"
onClick={handleOnGenerate}
icon={<SendOutlined></SendOutlined>}
></Button>
}
</Tooltip>
}
></AudioPlayer> ></AudioPlayer>
</div> </div>
<div {/* <div
style={{ style={{
padding: '16px', padding: '16px',
textAlign: 'right', textAlign: 'right',
@@ -365,7 +387,7 @@ const GroundLeft: React.FC<MessageProps> = forwardRef((props, ref) => {
></Button> ></Button>
} }
</Tooltip> </Tooltip>
</div> </div> */}
</div> </div>
) : ( ) : (
renderAniamtion() renderAniamtion()
@@ -385,15 +407,14 @@ const GroundLeft: React.FC<MessageProps> = forwardRef((props, ref) => {
className="message-list-wrap" className="message-list-wrap"
style={{ style={{
flex: 1, flex: 1,
position: 'relative', position: 'relative'
borderTop: '1px solid var(--ant-color-split)'
}} }}
> >
{messageList?.length > 0 && ( {messageList?.length > 0 && (
<span <span
style={{ style={{
position: 'absolute', position: 'absolute',
top: 0, top: 20,
right: 2 right: 2
}} }}
> >