Spaces:
Running
Running
| import { useState } from 'react'; | |
| import { textToSpeech } from '../services/api'; | |
| import languageVoices from '../data/languageVoices'; // Adjust the path as needed | |
| function TextToSpeech() { | |
| const [text, setText] = useState(''); | |
| const [languageCode, setLanguageCode] = useState('en-US'); | |
| const [ssmlGender, setSsmlGender] = useState('NEUTRAL'); | |
| const [name, setName] = useState('en-US-Standard-C'); | |
| const [pitch, setPitch] = useState(0.0); | |
| const [speakingRate, setSpeakingRate] = useState(1.0); | |
| const [volumeGainDb, setVolumeGainDb] = useState(0.0); | |
| const [audioUrl, setAudioUrl] = useState(null); | |
| // Ensure you have VITE_API_URL set in your .env file | |
| const API_URL = import.meta.env.VITE_API_URL; | |
| const handleTextToSpeech = async () => { | |
| // Call text-to-speech service | |
| try { | |
| const response = await textToSpeech(text, languageCode, ssmlGender, name, pitch, speakingRate, volumeGainDb); | |
| const baseUrl = new URL(API_URL); | |
| const audioUrl = `${baseUrl.origin}/static/storage/exported/${response}`; | |
| console.log(audioUrl) | |
| setAudioUrl(audioUrl); | |
| } catch (error) { | |
| console.error('Text-to-Speech failed:', error); | |
| } | |
| }; | |
| const handleDeleteAudio = () => { | |
| setAudioUrl(null); | |
| }; | |
| return ( | |
| <div className="flex justify-center items-center min-h-screen bg-gray-100 p-4"> | |
| <div className="w-full max-w-3xl p-6 bg-white rounded-lg shadow-md"> | |
| <h2 className="text-3xl font-bold mb-6 text-center text-blue-500">Text-to-Speech AI</h2> | |
| <div className="mb-6"> | |
| <textarea | |
| value={text} | |
| onChange={(e) => setText(e.target.value)} | |
| className="w-full h-32 p-3 border rounded" | |
| placeholder="Enter some text here..." | |
| /> | |
| </div> | |
| <div className="mb-4"> | |
| <label className="block text-gray-700 font-bold mb-2">Volume</label> | |
| <input | |
| type="range" | |
| min="-96.0" | |
| max="16.0" | |
| step="0.1" | |
| value={volumeGainDb} | |
| onChange={(e) => setVolumeGainDb(parseFloat(e.target.value))} | |
| className="w-full" | |
| /> | |
| <span className="block text-right text-gray-600">{volumeGainDb.toFixed(1)}</span> | |
| </div> | |
| <div className="mb-4"> | |
| <label className="block text-gray-700 font-bold mb-2">Rate</label> | |
| <input | |
| type="range" | |
| min="0.25" | |
| max="4.0" | |
| step="0.01" | |
| value={speakingRate} | |
| onChange={(e) => setSpeakingRate(parseFloat(e.target.value))} | |
| className="w-full" | |
| /> | |
| <span className="block text-right text-gray-600">{speakingRate.toFixed(2)}</span> | |
| </div> | |
| <div className="mb-4"> | |
| <label className="block text-gray-700 font-bold mb-2">Pitch</label> | |
| <input | |
| type="range" | |
| min="-20.0" | |
| max="20.0" | |
| step="0.1" | |
| value={pitch} | |
| onChange={(e) => setPitch(parseFloat(e.target.value))} | |
| className="w-full" | |
| /> | |
| <span className="block text-right text-gray-600">{pitch.toFixed(1)}</span> | |
| </div> | |
| <div className="mb-4"> | |
| <label className="block text-gray-700 font-bold mb-2">Language</label> | |
| <select | |
| value={languageCode} | |
| onChange={(e) => { | |
| setLanguageCode(e.target.value); | |
| setName(languageVoices[e.target.value][0].name); // Set default voice for selected language | |
| }} | |
| className="w-full p-2 border rounded" | |
| > | |
| {Object.keys(languageVoices).map((lang) => ( | |
| <option key={lang} value={lang}> | |
| {lang} | |
| </option> | |
| ))} | |
| </select> | |
| </div> | |
| <div className="mb-4"> | |
| <label className="block text-gray-700 font-bold mb-2">Voice</label> | |
| <select | |
| value={name} | |
| onChange={(e) => setName(e.target.value)} | |
| className="w-full p-2 border rounded" | |
| > | |
| {languageVoices[languageCode].map((voice) => ( | |
| <option key={voice.name} value={voice.name}> | |
| {voice.label} | |
| </option> | |
| ))} | |
| </select> | |
| </div> | |
| <div className="flex justify-between mt-6"> | |
| <button | |
| onClick={handleTextToSpeech} // Stop button handler | |
| className="w-fit px-4 py-2 bg-blue-500 text-white rounded hover:shadow-lg hover:bg-blue-700 transition duration-200" | |
| > | |
| Generate | |
| </button> | |
| </div> | |
| {audioUrl && ( | |
| <div className="mt-6"> | |
| <div className="flex items-center"> | |
| <audio controls src={audioUrl} className="w-full"> | |
| Your browser does not support the audio element. | |
| </audio> | |
| <button | |
| onClick={handleDeleteAudio} | |
| className="ml-4 px-4 py-2 bg-red-500 text-white rounded hover:bg-red-700 transition duration-200" | |
| > | |
| Delete | |
| </button> | |
| </div> | |
| </div> | |
| )} | |
| </div> | |
| </div> | |
| ); | |
| } | |
| export default TextToSpeech; | |