Skip to content

Commit 3268247

Browse files
committed
Merge branch 'main' of https://github.com/transformerlab/transformerlab-app into add/move-job-to-experiment
2 parents 9710eb2 + 7e81096 commit 3268247

File tree

11 files changed

+711
-73
lines changed

11 files changed

+711
-73
lines changed

package-lock.json

Lines changed: 10 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
"url": "https://github.com/dadmobile"
2626
}
2727
],
28-
"version": "0.20.7",
28+
"version": "0.21.1",
2929
"main": "./src/main/main.ts",
3030
"scripts": {
3131
"build": "concurrently \"npm run build:main\" \"npm run build:renderer\" \"npm run build:cloud\"",
@@ -147,7 +147,8 @@
147147
"three": "^0.175.0",
148148
"tree-kill": "^1.2.2",
149149
"use-debounce": "^9.0.4",
150-
"validator": "^13.7.0"
150+
"validator": "^13.7.0",
151+
"wavesurfer.js": "^7.10.1"
151152
},
152153
"devDependencies": {
153154
"@electron/notarize": "^2.1.0",

release/app/package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

release/app/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "transformerlab",
3-
"version": "0.20.7",
3+
"version": "0.21.1",
44
"description": "A tool to play with and train LLMs",
55
"license": "AGPL-3.0",
66
"author": {

src/renderer/components/Data/AudioPlayer.tsx

Lines changed: 56 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
IconButton,
99
} from '@mui/joy';
1010
import { Play, Pause, Volume2 } from 'lucide-react';
11+
import WaveSurfer from 'wavesurfer.js';
1112

1213
interface AudioPlayerProps {
1314
audioData: {
@@ -20,47 +21,69 @@ interface AudioPlayerProps {
2021
}
2122

2223
const AudioPlayer: React.FC<AudioPlayerProps> = ({ audioData, metadata }) => {
23-
const [isPlaying, setIsPlaying] = React.useState(false);
24-
const [audio] = React.useState(new Audio(audioData.audio_data_url));
24+
const [wavesurfer, setWavesurfer] = React.useState<WaveSurfer | null>(null);
25+
const waveformRef = React.useRef<HTMLDivElement>(null);
26+
const isDestroyedRef = React.useRef(false);
2527

26-
const togglePlay = () => {
27-
if (isPlaying) {
28-
audio.pause();
29-
setIsPlaying(false);
30-
} else {
31-
audio.play();
32-
setIsPlaying(true);
28+
// Initialize Wavesurfer
29+
React.useEffect(() => {
30+
if (waveformRef.current && !wavesurfer && !isDestroyedRef.current) {
31+
const ws = WaveSurfer.create({
32+
container: waveformRef.current,
33+
waveColor: '#4f46e5',
34+
// progressColor: '#7c3aed',
35+
cursorColor: 'var(--joy-palette-primary-400)',
36+
height: 60,
37+
normalize: true,
38+
barWidth: 3,
39+
barGap: 2,
40+
barRadius: 3,
41+
fillParent: true,
42+
pixelRatio: 1,
43+
mediaControls: true,
44+
});
45+
46+
ws.load(audioData.audio_data_url);
47+
48+
setWavesurfer(ws);
49+
50+
return () => {
51+
isDestroyedRef.current = true;
52+
if (ws && !ws.isDestroyed) {
53+
try {
54+
ws.pause();
55+
ws.destroy();
56+
} catch (error) {
57+
// Ignore errors during cleanup
58+
console.warn('Error destroying wavesurfer:', error);
59+
}
60+
}
61+
setWavesurfer(null);
62+
};
3363
}
34-
};
64+
}, [audioData.audio_data_url]);
3565

36-
// Handle audio ended event
66+
// Reset destroyed flag when audio URL changes
3767
React.useEffect(() => {
38-
const handleEnded = () => setIsPlaying(false);
39-
audio.addEventListener('ended', handleEnded);
40-
return () => audio.removeEventListener('ended', handleEnded);
41-
}, [audio]);
68+
isDestroyedRef.current = false;
69+
}, [audioData.audio_data_url]);
4270

4371
return (
44-
<Card variant="outlined" sx={{ maxWidth: 400 }}>
72+
<Card>
4573
<CardContent>
4674
<Stack spacing={2}>
47-
{/* Audio Controls */}
48-
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
49-
<IconButton
50-
size="sm"
51-
variant="solid"
52-
color="primary"
53-
onClick={togglePlay}
54-
>
55-
{isPlaying ? <Pause size={16} /> : <Play size={16} />}
56-
</IconButton>
57-
<Volume2 size={16} />
58-
<Typography level="body-sm">
59-
{metadata?.duration
60-
? `${metadata.duration.toFixed(1)}s`
61-
: 'Audio'}
62-
</Typography>
63-
</Box>
75+
{/* Waveform */}
76+
<Box
77+
ref={waveformRef}
78+
sx={{
79+
width: '100%',
80+
minHeight: '60px',
81+
border: '1px solid',
82+
borderColor: 'divider',
83+
borderRadius: 'sm',
84+
padding: 1,
85+
}}
86+
/>
6487

6588
{/* File Path Only */}
6689
{metadata?.path && (

0 commit comments

Comments
 (0)