Skip to content

Commit ad458d5

Browse files
committed
Fix merge conflict
2 parents b7d3db0 + e6c5ca9 commit ad458d5

File tree

6 files changed

+255
-54
lines changed

6 files changed

+255
-54
lines changed

src/renderer/components/Data/AudioPlayer.tsx

Lines changed: 242 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -14,64 +14,254 @@ interface AudioPlayerProps {
1414
audioData: {
1515
audio_data_url: string;
1616
};
17-
metadata: {
17+
metadata?: {
1818
path?: string;
1919
duration?: number;
2020
};
21+
transcription?: string;
22+
compact?: boolean;
2123
}
2224

23-
const AudioPlayer: React.FC<AudioPlayerProps> = ({ audioData, metadata }) => {
25+
const AudioPlayer: React.FC<AudioPlayerProps> = ({
26+
audioData,
27+
metadata,
28+
transcription,
29+
compact = false,
30+
}) => {
2431
const [wavesurfer, setWavesurfer] = React.useState<WaveSurfer | null>(null);
32+
const [isPlaying, setIsPlaying] = React.useState(false);
33+
const [isLoading, setIsLoading] = React.useState(true);
34+
const [error, setError] = React.useState<string | null>(null);
35+
const [duration, setDuration] = React.useState<number>(0);
36+
const [currentTime, setCurrentTime] = React.useState<number>(0);
2537
const waveformRef = React.useRef<HTMLDivElement>(null);
38+
const audioRef = React.useRef<HTMLAudioElement>(null);
2639
const isDestroyedRef = React.useRef(false);
2740

28-
// Initialize Wavesurfer
41+
// Compact mode handlers
42+
const handlePlayPauseCompact = () => {
43+
if (audioRef.current) {
44+
if (isPlaying) {
45+
audioRef.current.pause();
46+
} else {
47+
audioRef.current.play();
48+
}
49+
}
50+
};
51+
52+
const handleTimeUpdate = () => {
53+
if (audioRef.current) {
54+
setCurrentTime(audioRef.current.currentTime);
55+
}
56+
};
57+
58+
const handleLoadedMetadata = () => {
59+
if (audioRef.current) {
60+
setDuration(audioRef.current.duration);
61+
setIsLoading(false);
62+
}
63+
};
64+
65+
const handlePlay = () => setIsPlaying(true);
66+
const handlePause = () => setIsPlaying(false);
67+
const handleError = () => {
68+
setError('Failed to load audio');
69+
setIsLoading(false);
70+
};
71+
72+
const formatTime = (time: number) => {
73+
const minutes = Math.floor(time / 60);
74+
const seconds = Math.floor(time % 60);
75+
return `${minutes}:${seconds.toString().padStart(2, '0')}`;
76+
};
77+
78+
// Regular mode - WaveSurfer player effects
2979
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);
80+
if (
81+
!compact &&
82+
waveformRef.current &&
83+
!wavesurfer &&
84+
!isDestroyedRef.current &&
85+
audioData?.audio_data_url
86+
) {
87+
setIsLoading(true);
88+
setError(null);
89+
90+
try {
91+
const ws = WaveSurfer.create({
92+
container: waveformRef.current,
93+
waveColor: '#4f46e5',
94+
progressColor: '#7c3aed',
95+
cursorColor: 'var(--joy-palette-primary-400)',
96+
height: 60,
97+
normalize: true,
98+
barWidth: 3,
99+
barGap: 2,
100+
barRadius: 3,
101+
fillParent: true,
102+
mediaControls: false,
103+
});
104+
105+
ws.on('ready', () => {
106+
setIsLoading(false);
107+
});
108+
109+
ws.on('play', () => {
110+
setIsPlaying(true);
111+
});
112+
113+
ws.on('pause', () => {
114+
setIsPlaying(false);
115+
});
116+
117+
ws.on('error', () => {
118+
setError('Failed to load audio');
119+
setIsLoading(false);
120+
});
121+
122+
ws.load(audioData.audio_data_url);
123+
setWavesurfer(ws);
124+
125+
return () => {
126+
isDestroyedRef.current = true;
127+
if (ws) {
128+
try {
129+
ws.pause();
130+
ws.destroy();
131+
} catch (cleanupError) {
132+
// Ignore errors during cleanup
133+
}
59134
}
60-
}
61-
setWavesurfer(null);
62-
};
135+
setWavesurfer(null);
136+
setIsPlaying(false);
137+
setIsLoading(true);
138+
setError(null);
139+
};
140+
} catch (initError) {
141+
setError('Failed to initialize audio player');
142+
setIsLoading(false);
143+
}
63144
}
64-
}, [audioData.audio_data_url]);
65145

66-
// Reset destroyed flag when audio URL changes
146+
return undefined;
147+
}, [compact, audioData?.audio_data_url]);
148+
67149
React.useEffect(() => {
68150
isDestroyedRef.current = false;
69-
}, [audioData.audio_data_url]);
151+
}, [audioData?.audio_data_url]);
152+
153+
// Regular mode handlers
154+
const handlePlayPauseRegular = () => {
155+
if (wavesurfer) {
156+
if (isPlaying) {
157+
wavesurfer.pause();
158+
} else {
159+
wavesurfer.play();
160+
}
161+
}
162+
};
163+
164+
// Compact mode render
165+
if (compact) {
166+
return (
167+
<Box sx={{ minWidth: '200px', maxWidth: '300px' }}>
168+
<audio
169+
ref={audioRef}
170+
src={audioData.audio_data_url}
171+
onTimeUpdate={handleTimeUpdate}
172+
onLoadedMetadata={handleLoadedMetadata}
173+
onPlay={handlePlay}
174+
onPause={handlePause}
175+
onError={handleError}
176+
preload="metadata"
177+
>
178+
<track kind="captions" />
179+
</audio>
180+
181+
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1, mb: 1 }}>
182+
<IconButton
183+
size="sm"
184+
variant="soft"
185+
onClick={handlePlayPauseCompact}
186+
disabled={isLoading || !!error}
187+
>
188+
{isPlaying ? <Pause size={14} /> : <Play size={14} />}
189+
</IconButton>
190+
191+
<Volume2 size={12} />
192+
193+
{isLoading && (
194+
<Typography level="body-sm" sx={{ fontSize: '0.7rem' }}>
195+
Loading...
196+
</Typography>
197+
)}
198+
199+
{error && (
200+
<Typography
201+
level="body-sm"
202+
color="danger"
203+
sx={{ fontSize: '0.7rem' }}
204+
>
205+
Error
206+
</Typography>
207+
)}
208+
209+
{!isLoading && !error && (
210+
<Typography level="body-sm" sx={{ fontSize: '0.7rem' }}>
211+
{formatTime(currentTime)} / {formatTime(duration)}
212+
</Typography>
213+
)}
214+
</Box>
70215

216+
{metadata?.path && (
217+
<Typography
218+
level="body-sm"
219+
sx={{ fontSize: '0.65rem', color: 'text.secondary', mb: 0.5 }}
220+
>
221+
<strong>File:</strong> {metadata.path.split('/').pop()}
222+
</Typography>
223+
)}
224+
225+
{transcription && (
226+
<Typography
227+
level="body-sm"
228+
sx={{ fontSize: '0.65rem', color: 'text.secondary' }}
229+
>
230+
<strong>Transcription:</strong> {transcription}
231+
</Typography>
232+
)}
233+
</Box>
234+
);
235+
}
236+
237+
// Regular mode render
71238
return (
72-
<Card>
239+
<Card sx={{ minWidth: '300px' }}>
73240
<CardContent>
74241
<Stack spacing={2}>
242+
{/* Controls */}
243+
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
244+
<IconButton
245+
size="sm"
246+
variant="soft"
247+
onClick={handlePlayPauseRegular}
248+
disabled={!wavesurfer || isLoading || !!error}
249+
>
250+
{isPlaying ? <Pause size={16} /> : <Play size={16} />}
251+
</IconButton>
252+
<Volume2 size={16} />
253+
{isLoading && (
254+
<Typography level="body-sm" color="neutral">
255+
Loading...
256+
</Typography>
257+
)}
258+
{error && (
259+
<Typography level="body-sm" color="danger">
260+
{error}
261+
</Typography>
262+
)}
263+
</Box>
264+
75265
{/* Waveform */}
76266
<Box
77267
ref={waveformRef}
@@ -82,17 +272,23 @@ const AudioPlayer: React.FC<AudioPlayerProps> = ({ audioData, metadata }) => {
82272
borderColor: 'divider',
83273
borderRadius: 'sm',
84274
padding: 1,
275+
opacity: isLoading ? 0.5 : 1,
85276
}}
86277
/>
87278

88-
{/* File Path Only */}
89-
{metadata?.path && (
90-
<Box sx={{ fontSize: '0.75rem', color: 'text.secondary' }}>
91-
<div>
279+
{/* Metadata */}
280+
<Stack spacing={1}>
281+
{metadata?.path && (
282+
<Box sx={{ fontSize: '0.75rem', color: 'text.secondary' }}>
92283
<strong>File:</strong> {metadata.path}
93-
</div>
94-
</Box>
95-
)}
284+
</Box>
285+
)}
286+
{metadata?.duration && (
287+
<Box sx={{ fontSize: '0.75rem', color: 'text.secondary' }}>
288+
<strong>Duration:</strong> {metadata.duration}s
289+
</Box>
290+
)}
291+
</Stack>
96292
</Stack>
97293
</CardContent>
98294
</Card>

src/renderer/components/Data/DatasetTable.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,7 @@ const DatasetTable = ({ datasetId }: { datasetId: string }) => {
193193
audioData={cellData.array}
194194
metadata={mergedMetadata}
195195
transcription={cellData.transcription}
196+
compact
196197
/>
197198
);
198199
}
@@ -208,6 +209,7 @@ const DatasetTable = ({ datasetId }: { datasetId: string }) => {
208209
audioData={cellData}
209210
metadata={cellData.metadata}
210211
transcription={cellData.transcription}
212+
compact
211213
/>
212214
);
213215
}

src/renderer/components/Experiment/Foundation/CurrentFoundationInfo.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -264,8 +264,8 @@ export default function CurrentFoundationInfo({
264264
setCanceling(true);
265265
const response = await fetch(
266266
getAPIFullPath('jobs', ['stop'], {
267+
id: jobId,
267268
experimentId: experimentInfo?.id,
268-
jobId,
269269
}),
270270
);
271271
if (response.ok) {

src/renderer/components/Experiment/Train/ViewEvalImagesModal.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,14 +46,15 @@ export default function ViewEvalImagesModal({
4646
[key: string]: boolean;
4747
}>({});
4848

49-
const { experimentInfo } = useExperimentInfo();
49+
const { experimentId } = useExperimentInfo();
50+
5051
const {
5152
data: imagesData,
5253
error,
5354
isLoading,
5455
} = useSWR<EvalImagesResponse>(
5556
open && jobId && jobId !== -1
56-
? chatAPI.Endpoints.Jobs.GetEvalImages(experimentInfo?.id, jobId)
57+
? chatAPI.Endpoints.Jobs.GetEvalImages(experimentId, jobId)
5758
: null,
5859
fetcher,
5960
{

src/renderer/lib/api-client/allEndpoints.json

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -86,16 +86,12 @@
8686
"jobs": {
8787
"get": {
8888
"method": "GET",
89-
"path": "jobs/{id}"
89+
"path": "experiment/{experimentId}/jobs/{id}"
9090
},
9191
"stop": {
9292
"method": "GET",
9393
"path": "experiment/{experimentId}/jobs/{jobId}/stop"
9494
},
95-
"getJobsOfType": {
96-
"method": "GET",
97-
"path": "experiment/{experimentId}/jobs/list"
98-
},
9995
"getCheckpoints": {
10096
"method": "GET",
10197
"path": "experiment/{experimentId}/jobs/{jobId}/checkpoints"

0 commit comments

Comments
 (0)