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
This commit is contained in:
137
nuxt4/app/composables/useWhisper.ts
Normal file
137
nuxt4/app/composables/useWhisper.ts
Normal file
@@ -0,0 +1,137 @@
|
||||
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
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user