File size: 2,717 Bytes
674994f
 
 
 
 
 
 
 
 
 
 
 
 
d4f1e7c
 
 
 
 
674994f
 
 
 
 
 
 
 
 
 
 
 
d4f1e7c
 
 
 
 
 
 
 
 
 
674994f
d4f1e7c
674994f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
/**
 * SampleClips.jsx
 * "Examples" UI โ€” lets the user click a language button to instantly load
 * a sample audio clip, replicating the Hugging Face demo UX.
 * Active selection "sticks" with highlighted styling.
 */

import { useState } from 'react';

const SAMPLES = [
  { name: 'english', label: '๐Ÿ‡บ๐Ÿ‡ธ English', file: '/samples/english.wav' },
  { name: 'chinese', label: '๐Ÿ‡จ๐Ÿ‡ณ Chinese', file: '/samples/chinese.wav' },
  { name: 'spanish', label: '๐Ÿ‡ช๐Ÿ‡ธ Spanish', file: '/samples/spanish.wav' },
  { name: 'french', label: '๐Ÿ‡ซ๐Ÿ‡ท French', file: '/samples/french.wav' },
  { name: 'german', label: '๐Ÿ‡ฉ๐Ÿ‡ช German', file: '/samples/german.wav' },
  { name: 'italian', label: '๐Ÿ‡ฎ๐Ÿ‡น Italian', file: '/samples/italian.wav' },
  { name: 'japanese', label: '๐Ÿ‡ฏ๐Ÿ‡ต Japanese', file: '/samples/japanese.wav' },
  { name: 'hindi', label: '๐Ÿ‡ฎ๐Ÿ‡ณ Hindi', file: '/samples/hindi.wav' },
];

export default function SampleClips({ onSampleSelect, disabled }) {
  const [loading, setLoading] = useState(null);
  const [selected, setSelected] = useState(null);

  async function handleClick(sample) {
    setLoading(sample.name);
    try {
      const response = await fetch(sample.file);
      if (!response.ok) throw new Error(`Failed to fetch ${sample.file}`);
      const blob = await response.blob();
      // Detect actual audio format from magic bytes (servers may return
      // application/octet-stream for .wav files, and some samples may be
      // OGG-encoded despite the .wav extension).
      const header = new Uint8Array(await blob.slice(0, 4).arrayBuffer());
      const magic = String.fromCharCode(...header);
      let mimeType = 'audio/wav';
      if (magic === 'OggS') mimeType = 'audio/ogg';
      else if (magic === 'fLaC') mimeType = 'audio/flac';
      else if (magic.startsWith('\xff\xfb') || magic.startsWith('ID3')) mimeType = 'audio/mpeg';
      const file = new File([blob], sample.file.split('/').pop(), { type: mimeType });
      setSelected(sample.name);
      onSampleSelect(file, sample.name);
    } catch (err) {
      console.error('Sample clip load failed:', err);
    } finally {
      setLoading(null);
    }
  }

  return (
    <div className="sample-clips">
      <p className="sample-clips-hint">Try one of the sample clips.</p>
      <div className="sample-clips-row">
        {SAMPLES.map((s) => (
          <button
            key={s.name}
            className={`btn ${selected === s.name ? 'btn-sample-active' : 'btn-secondary'}`}
            onClick={() => handleClick(s)}
            disabled={disabled || loading !== null}
          >
            {loading === s.name ? 'โ€ฆ' : s.label}
          </button>
        ))}
      </div>
    </div>
  );
}