Skip to content

Commit 71b4f1f

Browse files
authored
Merge pull request transformerlab#709 from transformerlab/add/audio-dataset-support
Add support for downloading audio datasets from HF
2 parents d88868a + 40f6051 commit 71b4f1f

File tree

2 files changed

+154
-32
lines changed

2 files changed

+154
-32
lines changed
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import React from 'react';
2+
import {
3+
Box,
4+
Typography,
5+
Card,
6+
CardContent,
7+
Stack,
8+
IconButton,
9+
} from '@mui/joy';
10+
import { Play, Pause, Volume2 } from 'lucide-react';
11+
12+
interface AudioPlayerProps {
13+
audioData: {
14+
audio_data_url: string;
15+
};
16+
metadata: {
17+
path?: string;
18+
duration?: number;
19+
};
20+
}
21+
22+
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));
25+
26+
const togglePlay = () => {
27+
if (isPlaying) {
28+
audio.pause();
29+
setIsPlaying(false);
30+
} else {
31+
audio.play();
32+
setIsPlaying(true);
33+
}
34+
};
35+
36+
// Handle audio ended event
37+
React.useEffect(() => {
38+
const handleEnded = () => setIsPlaying(false);
39+
audio.addEventListener('ended', handleEnded);
40+
return () => audio.removeEventListener('ended', handleEnded);
41+
}, [audio]);
42+
43+
return (
44+
<Card variant="outlined" sx={{ maxWidth: 400 }}>
45+
<CardContent>
46+
<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>
64+
65+
{/* File Path Only */}
66+
{metadata?.path && (
67+
<Box sx={{ fontSize: '0.75rem', color: 'text.secondary' }}>
68+
<div>
69+
<strong>File:</strong> {metadata.path}
70+
</div>
71+
</Box>
72+
)}
73+
</Stack>
74+
</CardContent>
75+
</Card>
76+
);
77+
};
78+
79+
export default AudioPlayer;

src/renderer/components/Data/DatasetTable.tsx

Lines changed: 75 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -2,41 +2,40 @@ import { useEffect, useState } from 'react';
22
import {
33
Button,
44
Table,
5-
CircularProgress,
65
Box,
76
IconButton,
87
iconButtonClasses,
98
Alert,
109
Select,
1110
Option,
1211
FormControl,
13-
FormLabel,
14-
LinearProgress,
1512
Typography,
1613
Skeleton,
1714
Tooltip,
1815
} from '@mui/joy';
1916

20-
import * as chatAPI from '../../lib/transformerlab-api-sdk';
2117
import { ChevronLeftIcon, ChevronRightIcon } from 'lucide-react';
2218
import useSWR from 'swr';
23-
const fetcher = (url) =>
19+
import * as chatAPI from '../../lib/transformerlab-api-sdk';
20+
import AudioPlayer from './AudioPlayer';
21+
22+
const fetcher = (url: string) =>
2423
fetch(url)
2524
.then((res) => res.json())
2625
.then((data) => data);
2726

28-
const DatasetTable = ({ datasetId }) => {
27+
const DatasetTable = ({ datasetId }: { datasetId: string }) => {
2928
const [pageNumber, setPageNumber] = useState(1);
3029
const [numOfPages, setNumOfPages] = useState(1);
31-
const [datasetLen, setDatasetLen] = useState(null);
30+
const [datasetLen, setDatasetLen] = useState<number | null>(null);
3231
let pageSize = 10; //Set the number of rows per page
3332
const offset = (pageNumber - 1) * pageSize; //Calculate current row number to start from
3433

35-
const [split, setSplit] = useState(''); //Set the default split to display
34+
const [split, setSplit] = useState(''); // Set the default split to display
3635
const [showingSplit, setShowingSplit] = useState(''); // We use this to show the user what split is shown without triggering a re-call of the data
3736

38-
//Set the pagination for the dataset
39-
const setPagination = (totalRows, rowsPerPage) => {
37+
// Set the pagination for the dataset
38+
const setPagination = (totalRows: number, rowsPerPage: number) => {
4039
const totalPages = Math.ceil(totalRows / rowsPerPage);
4140
setNumOfPages(totalPages);
4241
};
@@ -173,28 +172,72 @@ const DatasetTable = ({ datasetId }) => {
173172
textOverflow: 'ellipsis',
174173
}}
175174
>
176-
{typeof data.data['columns'][key][rowIndex] ===
177-
'string' &&
178-
data.data['columns'][key][rowIndex].startsWith(
179-
'data:image/',
180-
) ? (
181-
<img
182-
src={data.data['columns'][key][rowIndex]}
183-
alt="preview"
184-
style={{
185-
maxWidth: 120,
186-
maxHeight: 120,
187-
display: 'block',
188-
}}
189-
/>
190-
) : typeof data.data['columns'][key][rowIndex] ===
191-
'string' ? (
192-
data.data['columns'][key][rowIndex]
193-
) : (
194-
JSON.stringify(
195-
data.data['columns'][key][rowIndex],
196-
)
197-
)}
175+
{(() => {
176+
const cellData =
177+
data.data['columns'][key][rowIndex];
178+
179+
// Handle audio data with nested structure
180+
if (
181+
typeof cellData === 'object' &&
182+
cellData !== null &&
183+
cellData.array?.audio_data_url
184+
) {
185+
// Merge metadata from both array.metadata and root level
186+
const mergedMetadata = {
187+
...cellData.array.metadata,
188+
path: cellData.path,
189+
};
190+
191+
return (
192+
<AudioPlayer
193+
audioData={cellData.array}
194+
metadata={mergedMetadata}
195+
transcription={cellData.transcription}
196+
/>
197+
);
198+
}
199+
200+
// Handle audio data (object with audio_data_url at root level)
201+
if (
202+
typeof cellData === 'object' &&
203+
cellData !== null &&
204+
cellData.audio_data_url
205+
) {
206+
return (
207+
<AudioPlayer
208+
audioData={cellData}
209+
metadata={cellData.metadata}
210+
transcription={cellData.transcription}
211+
/>
212+
);
213+
}
214+
215+
// Handle image data (string starting with data:image/)
216+
if (
217+
typeof cellData === 'string' &&
218+
cellData.startsWith('data:image/')
219+
) {
220+
return (
221+
<img
222+
src={cellData}
223+
alt="preview"
224+
style={{
225+
maxWidth: 120,
226+
maxHeight: 120,
227+
display: 'block',
228+
}}
229+
/>
230+
);
231+
}
232+
233+
// Handle regular strings
234+
if (typeof cellData === 'string') {
235+
return cellData;
236+
}
237+
238+
// Handle other data types
239+
return JSON.stringify(cellData);
240+
})()}
198241
</div>
199242
</Tooltip>
200243
</td>

0 commit comments

Comments
 (0)