Primeiro Commit

This commit is contained in:
luisfepsale
2025-10-22 12:52:23 -03:00
parent 27820254e7
commit 235fb538e1
19 changed files with 2132 additions and 426 deletions
+74 -67
View File
@@ -14,6 +14,7 @@ import {
SelectValue,
} from "@/components/ui/select";
import { useToast } from "@/hooks/use-toast";
import { audioGenerationService, VOICE_OPTIONS, VoiceType } from "@/services/audioGeneration";
interface GeneratedAudio {
id: string;
@@ -24,49 +25,10 @@ interface GeneratedAudio {
timestamp: Date;
}
const VOICE_OPTIONS = {
alloy: {
label: "Alloy",
gender: "Masculina",
style: "Neutra, equilibrada, tom corporativo",
description: "Boa para tutoriais e comunicações institucionais."
},
echo: {
label: "Echo",
gender: "Masculina",
style: "Forte e profissional, mais grave",
description: "Ideal para voz de autoridade ou locução firme."
},
fable: {
label: "Fable",
gender: "Feminina",
style: "Narrativa, calorosa e envolvente",
description: "Ótima para storytelling e áudios empáticos."
},
onyx: {
label: "Onyx",
gender: "Masculina",
style: "Grave, autoritária, impactante",
description: "Excelente para trailers, mensagens sérias ou institucionais."
},
nova: {
label: "Nova",
gender: "Feminina",
style: "Brilhante, animada, energética",
description: "Boa para vídeos curtos, marketing ou conteúdos leves."
},
shimmer: {
label: "Shimmer",
gender: "Feminina",
style: "Suave, otimista, clara",
description: "Boa para mensagens acolhedoras, explicações e IA conversacional."
}
};
export const GenerationView = () => {
const [textToSpeech, setTextToSpeech] = useState("");
const [isProcessing, setIsProcessing] = useState(false);
const [selectedVoice, setSelectedVoice] = useState<keyof typeof VOICE_OPTIONS>("alloy");
const [selectedVoice, setSelectedVoice] = useState<VoiceType>("alloy");
const [generatedAudio, setGeneratedAudio] = useState<GeneratedAudio | null>(null);
const [audioHistory, setAudioHistory] = useState<GeneratedAudio[]>([]);
const [audioSearchQuery, setAudioSearchQuery] = useState("");
@@ -79,32 +41,67 @@ export const GenerationView = () => {
}
}, []);
const handleGenerateAudio = () => {
setIsProcessing(true);
setTimeout(() => {
const audio: GeneratedAudio = {
id: Date.now().toString(),
text: textToSpeech,
voice: selectedVoice,
voiceLabel: VOICE_OPTIONS[selectedVoice].label,
audioUrl: "data:audio/mp3;base64,//sample",
timestamp: new Date(),
};
setGeneratedAudio(audio);
const newHistory = [audio, ...audioHistory].slice(0, 10);
setAudioHistory(newHistory);
localStorage.setItem('audioHistory', JSON.stringify(newHistory));
setIsProcessing(false);
const handleGenerateAudio = async () => {
// Valida o texto antes de enviar
const validation = audioGenerationService.validateText(textToSpeech);
if (!validation.valid) {
toast({
title: "Áudio gerado com sucesso",
description: `Voz: ${VOICE_OPTIONS[selectedVoice].label}`,
title: "Texto inválido",
description: validation.error,
variant: "destructive",
});
}, 2000);
return;
}
setIsProcessing(true);
try {
// Chama o serviço de geração de áudio
const response = await audioGenerationService.generateAudio({
message: textToSpeech,
voice: selectedVoice,
});
// Verifica se a geração foi bem-sucedida
if (response.success) {
console.log('URL do áudio gerado:', response.audio_url);
const audio: GeneratedAudio = {
id: response.audio_generation_id,
text: response.message,
voice: selectedVoice,
voiceLabel: VOICE_OPTIONS[selectedVoice].label,
audioUrl: response.audio_url,
timestamp: new Date(),
};
setGeneratedAudio(audio);
const newHistory = [audio, ...audioHistory].slice(0, 10);
setAudioHistory(newHistory);
localStorage.setItem('audioHistory', JSON.stringify(newHistory));
toast({
title: "Áudio gerado com sucesso",
description: `Voz: ${VOICE_OPTIONS[selectedVoice].label}`,
});
// Limpa o campo de texto após sucesso
setTextToSpeech("");
} else {
throw new Error('Erro ao gerar áudio');
}
} catch (error: any) {
console.error('Erro na geração de áudio:', error);
toast({
title: "Erro na geração",
description: error.message || "Não foi possível gerar o áudio. Tente novamente.",
variant: "destructive",
});
} finally {
setIsProcessing(false);
}
};
const handleDownloadAudio = (audio: GeneratedAudio) => {
@@ -177,7 +174,7 @@ export const GenerationView = () => {
<div className="space-y-4">
<div className="space-y-2">
<label className="text-sm font-medium">Tipo de Voz</label>
<Select value={selectedVoice} onValueChange={(value) => setSelectedVoice(value as keyof typeof VOICE_OPTIONS)}>
<Select value={selectedVoice} onValueChange={(value) => setSelectedVoice(value as VoiceType)}>
<SelectTrigger>
<SelectValue />
</SelectTrigger>
@@ -258,7 +255,12 @@ export const GenerationView = () => {
<div className="bg-muted/30 rounded-lg p-4">
<p className="text-sm mb-3">{generatedAudio.text}</p>
<audio controls className="w-full">
<audio
key={generatedAudio.id}
controls
className="w-full"
preload="metadata"
>
<source src={generatedAudio.audioUrl} type="audio/mpeg" />
Seu navegador não suporta o elemento de áudio.
</audio>
@@ -325,7 +327,12 @@ export const GenerationView = () => {
<p className="text-sm text-muted-foreground line-clamp-2">
{audio.text}
</p>
<audio controls className="w-full">
<audio
key={audio.id}
controls
className="w-full"
preload="metadata"
>
<source src={audio.audioUrl} type="audio/mpeg" />
</audio>
</div>