story-generator/src/components/demo/AudioRecorderDemo.tsx
2024-12-20 10:06:24 -03:00

154 lines
4.8 KiB
TypeScript

import React, { useState, useRef } from 'react';
import { Mic, Square, Loader, Play, RotateCcw } from 'lucide-react';
interface AudioRecorderDemoProps {
onAnalysisComplete: (result: {
fluency: number;
accuracy: number;
confidence: number;
feedback: string;
}) => void;
}
export function AudioRecorderDemo({ onAnalysisComplete }: AudioRecorderDemoProps) {
const [isRecording, setIsRecording] = useState(false);
const [audioBlob, setAudioBlob] = useState<Blob | null>(null);
const [isAnalyzing, setIsAnalyzing] = useState(false);
const [error, setError] = useState<string | null>(null);
const mediaRecorderRef = useRef<MediaRecorder | null>(null);
const chunksRef = useRef<Blob[]>([]);
const startRecording = async () => {
try {
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
mediaRecorderRef.current = new MediaRecorder(stream);
chunksRef.current = [];
mediaRecorderRef.current.ondataavailable = (e) => {
chunksRef.current.push(e.data);
};
mediaRecorderRef.current.onstop = () => {
const audioBlob = new Blob(chunksRef.current, { type: 'audio/webm' });
setAudioBlob(audioBlob);
};
mediaRecorderRef.current.start();
setIsRecording(true);
setError(null);
} catch (err) {
setError('Erro ao acessar microfone. Verifique as permissões.');
console.error('Erro ao iniciar gravação:', err);
}
};
const stopRecording = () => {
if (mediaRecorderRef.current && isRecording) {
mediaRecorderRef.current.stop();
setIsRecording(false);
mediaRecorderRef.current.stream.getTracks().forEach(track => track.stop());
}
};
const analyzeAudio = async () => {
if (!audioBlob) return;
setIsAnalyzing(true);
setError(null);
try {
// Simulação de análise para demo
await new Promise(resolve => setTimeout(resolve, 2000));
// Resultados simulados para demonstração
onAnalysisComplete({
fluency: Math.floor(Math.random() * 20) + 80, // 80-100
accuracy: Math.floor(Math.random() * 15) + 85, // 85-100
confidence: Math.floor(Math.random() * 25) + 75, // 75-100
feedback: "Excelente leitura! Sua fluência está muito boa e você demonstra confiança na pronúncia. Continue praticando para melhorar ainda mais."
});
} catch (err) {
setError('Erro ao analisar áudio. Tente novamente.');
console.error('Erro na análise:', err);
} finally {
setIsAnalyzing(false);
}
};
const resetRecording = () => {
setAudioBlob(null);
setError(null);
};
return (
<div className="p-6 bg-gray-50 rounded-xl">
<div className="flex flex-wrap items-center gap-4 justify-center">
{!isRecording && !audioBlob && (
<button
onClick={startRecording}
className="flex items-center gap-2 px-6 py-3 bg-red-600 text-white rounded-xl hover:bg-red-700 transition"
>
<Mic className="w-5 h-5" />
Iniciar Gravação
</button>
)}
{isRecording && (
<button
onClick={stopRecording}
className="flex items-center gap-2 px-6 py-3 bg-gray-600 text-white rounded-xl hover:bg-gray-700 transition"
>
<Square className="w-5 h-5" />
Parar Gravação
</button>
)}
{audioBlob && !isAnalyzing && (
<>
<button
onClick={() => {
const url = URL.createObjectURL(audioBlob);
const audio = new Audio(url);
audio.play();
}}
className="flex items-center gap-2 px-6 py-3 bg-purple-600 text-white rounded-xl hover:bg-purple-700 transition"
>
<Play className="w-5 h-5" />
Ouvir
</button>
<button
onClick={analyzeAudio}
className="flex items-center gap-2 px-6 py-3 bg-green-600 text-white rounded-xl hover:bg-green-700 transition"
>
Analisar Leitura
</button>
<button
onClick={resetRecording}
className="flex items-center gap-2 px-6 py-3 bg-gray-200 text-gray-600 rounded-xl hover:bg-gray-300 transition"
>
<RotateCcw className="w-5 h-5" />
Recomeçar
</button>
</>
)}
{isAnalyzing && (
<div className="flex items-center gap-2 text-gray-600">
<Loader className="w-5 h-5 animate-spin" />
Analisando sua leitura...
</div>
)}
</div>
{error && (
<div className="mt-4 text-red-600 text-sm text-center">
{error}
</div>
)}
</div>
);
}