Files
nucleoWhisper/nuxt4/app/composables/useWhisper.ts
josedario87 6439ff8f60
Some checks failed
build-and-deploy / build (push) Failing after 5s
build-and-deploy / deploy (push) Has been skipped
Implementación inicial de Nucleo Whisper
- Configurado proyecto Nuxt 4 con PWA
- Integrado OpenAI Whisper API para transcripción de audio
- Implementada captura de audio desde navegador
- Creada UI con grabación y visualización de transcripciones
- Configurado Authentik Proxy para autenticación
- Setup de Docker y Gitea Actions para despliegue
2025-10-13 14:33:04 -06:00

138 lines
3.7 KiB
TypeScript

export const useWhisper = () => {
const isRecording = useState<boolean>('whisper_isRecording', () => false)
const isTranscribing = useState<boolean>('whisper_isTranscribing', () => false)
const transcription = useState<string>('whisper_transcription', () => '')
const error = useState<string | null>('whisper_error', () => null)
let mediaRecorder: MediaRecorder | null = null
let audioChunks: Blob[] = []
const startRecording = async () => {
try {
error.value = null
// Solicitar permisos de micrófono
const stream = await navigator.mediaDevices.getUserMedia({
audio: {
echoCancellation: true,
noiseSuppression: true,
sampleRate: 16000
}
})
// Crear MediaRecorder
const mimeType = MediaRecorder.isTypeSupported('audio/webm')
? 'audio/webm'
: 'audio/mp4'
mediaRecorder = new MediaRecorder(stream, {
mimeType
})
audioChunks = []
mediaRecorder.ondataavailable = (event) => {
if (event.data.size > 0) {
audioChunks.push(event.data)
}
}
mediaRecorder.onstop = async () => {
// Detener todos los tracks del stream
stream.getTracks().forEach(track => track.stop())
// Procesar la transcripción
await processTranscription()
}
mediaRecorder.start()
isRecording.value = true
console.log('[Whisper] Grabación iniciada')
} catch (err: any) {
console.error('[Whisper] Error al iniciar grabación:', err)
error.value = err.message || 'Error al acceder al micrófono'
}
}
const stopRecording = () => {
if (mediaRecorder && isRecording.value) {
mediaRecorder.stop()
isRecording.value = false
console.log('[Whisper] Grabación detenida')
}
}
const processTranscription = async () => {
try {
isTranscribing.value = true
error.value = null
// Crear blob del audio
const audioBlob = new Blob(audioChunks, { type: 'audio/webm' })
console.log('[Whisper] Enviando audio para transcripción:', {
size: audioBlob.size,
type: audioBlob.type
})
// Crear FormData
const formData = new FormData()
formData.append('file', audioBlob, 'recording.webm')
formData.append('language', 'es')
// Enviar al backend
const response = await $fetch('/api/whisper/transcribe', {
method: 'POST',
body: formData
})
if (response.success) {
transcription.value = response.transcription
console.log('[Whisper] Transcripción exitosa:', response.transcription)
// Copiar al clipboard automáticamente
if (navigator.clipboard) {
await navigator.clipboard.writeText(response.transcription)
console.log('[Whisper] Copiado al clipboard')
}
}
} catch (err: any) {
console.error('[Whisper] Error en transcripción:', err)
error.value = err.message || 'Error al procesar la transcripción'
} finally {
isTranscribing.value = false
audioChunks = []
}
}
const clearTranscription = () => {
transcription.value = ''
error.value = null
}
const copyToClipboard = async () => {
if (transcription.value && navigator.clipboard) {
try {
await navigator.clipboard.writeText(transcription.value)
return true
} catch (err) {
console.error('[Whisper] Error al copiar:', err)
return false
}
}
return false
}
return {
isRecording: readonly(isRecording),
isTranscribing: readonly(isTranscribing),
transcription: readonly(transcription),
error: readonly(error),
startRecording,
stopRecording,
clearTranscription,
copyToClipboard
}
}