File size: 2,748 Bytes
7308563
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
import { useState, useRef } from 'react';
import { Volume2, Play } from 'lucide-react';

export default function PocketTTS() {
  const [text, setText] = useState('Hello, this is a test of PocketTTS integration.');
  const [audioUrl, setAudioUrl] = useState('');
  const [loading, setLoading] = useState(false);
  const audioRef = useRef(null);

  const handleSynthesize = async () => {
    if (!text.trim()) return;
    setLoading(true);
    setAudioUrl('');

    try {
      const response = await fetch('/api/tts', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ text }),
      });

      if (!response.ok) throw new Error('TTS Generation failed');

      const blob = await response.blob();
      const url = URL.createObjectURL(blob);
      setAudioUrl(url);
    } catch (err) {
      console.error(err);
    } finally {
      setLoading(false);
    }
  };

  const playAudio = () => {
    if (audioRef.current) {
      audioRef.current.play();
    }
  };

  return (
    <div className="bg-slate-800 rounded-xl p-6 shadow-xl border border-slate-700">
      <div className="flex items-center gap-2 mb-4">
        <Volume2 className="w-5 h-5 text-blue-500" />
        <h2 className="text-lg font-semibold text-white">Pocket TTS</h2>
      </div>

      <div className="space-y-4">
        <div>
          <label className="block text-sm font-medium text-slate-400 mb-1">
            Text to Speech
          </label>
          <textarea
            value={text}
            onChange={(e) => setText(e.target.value)}
            className="w-full bg-slate-900 border border-slate-600 rounded-lg p-3 text-white placeholder-slate-500 focus:ring-2 focus:ring-blue-500 focus:border-transparent outline-none transition-all resize-none h-24"
          />
        </div>

        <div className="flex gap-2">
          <button
            onClick={handleSynthesize}
            disabled={loading}
            className="flex-1 bg-blue-600 hover:bg-blue-500 text-white font-medium py-2 rounded-lg transition-colors disabled:opacity-50"
          >
            {loading ? 'Synthesizing...' : 'Generate Audio'}
          </button>
          
          {audioUrl && (
            <button
              onClick={playAudio}
              className="bg-slate-700 hover:bg-slate-600 text-white p-2 rounded-lg transition-colors"
              title="Play Audio"
            >
              <Play className="w-5 h-5 fill-current" />
            </button>
          )}
        </div>

        {audioUrl && (
          <audio 
            ref={audioRef} 
            src={audioUrl} 
            controls 
            className="w-full mt-2 h-8"
          />
        )}
      </div>
    </div>
  );
}