feat: OCR y Whisper como herramientas opcionales por canal en uMind
Cada canal (Telegram/WhatsApp) de un agente ahora puede activar, de forma independiente, que los audios entrantes se transcriban con el Whisper ASR propio y que a las imágenes entrantes se les extraiga texto con el servicio OCR propio, antes de pasarle el mensaje al agente. Antes esos mensajes se ignoraban en silencio. - UmindCanal gana usar_whisper_audio/usar_ocr_imagenes (default off). - WhatsApp: se descarga el media vía Graph API (resolución de URL + fetch con el mismo access_token del canal) y se enruta a Whisper/OCR según type. - Telegram: se descarga el archivo vía getFile + CDN de archivos del bot, mismo enrutamiento para voice/audio/photo. - Panel: checkboxes en el alta de canal y toggles inline por canal ya creado, en la tab Canales del agente. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
d493d6dee6
commit
84506a98e2
@@ -182,6 +182,7 @@ async function copiarWidget() {
|
||||
function canalVacio() {
|
||||
return {
|
||||
tipo: 'telegram', bot_token: '', phone_number_id: '', access_token: '', app_secret: '', verify_token: '',
|
||||
usar_whisper_audio: false, usar_ocr_imagenes: false,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -206,7 +207,10 @@ async function guardarCanal() {
|
||||
verify_token: canalForm.value.verify_token,
|
||||
}
|
||||
try {
|
||||
await api.post('/app/umind/canales', { agente_id: agenteIdNum.value, tipo: canalForm.value.tipo, credenciales, activo: true })
|
||||
await api.post('/app/umind/canales', {
|
||||
agente_id: agenteIdNum.value, tipo: canalForm.value.tipo, credenciales, activo: true,
|
||||
usar_whisper_audio: canalForm.value.usar_whisper_audio, usar_ocr_imagenes: canalForm.value.usar_ocr_imagenes,
|
||||
})
|
||||
showCanalForm.value = false
|
||||
await cargarCanales()
|
||||
} catch (e) {
|
||||
@@ -215,7 +219,26 @@ async function guardarCanal() {
|
||||
}
|
||||
|
||||
async function toggleCanal(c) {
|
||||
await api.put(`/app/umind/canales/${c.ID}`, { activo: !c.activo, credenciales: {} })
|
||||
await api.put(`/app/umind/canales/${c.ID}`, {
|
||||
activo: !c.activo, credenciales: {},
|
||||
usar_whisper_audio: c.usar_whisper_audio, usar_ocr_imagenes: c.usar_ocr_imagenes,
|
||||
})
|
||||
await cargarCanales()
|
||||
}
|
||||
|
||||
async function toggleCanalWhisper(c) {
|
||||
await api.put(`/app/umind/canales/${c.ID}`, {
|
||||
activo: c.activo, credenciales: {},
|
||||
usar_whisper_audio: !c.usar_whisper_audio, usar_ocr_imagenes: c.usar_ocr_imagenes,
|
||||
})
|
||||
await cargarCanales()
|
||||
}
|
||||
|
||||
async function toggleCanalOcr(c) {
|
||||
await api.put(`/app/umind/canales/${c.ID}`, {
|
||||
activo: c.activo, credenciales: {},
|
||||
usar_whisper_audio: c.usar_whisper_audio, usar_ocr_imagenes: !c.usar_ocr_imagenes,
|
||||
})
|
||||
await cargarCanales()
|
||||
}
|
||||
|
||||
@@ -497,6 +520,16 @@ onMounted(async () => {
|
||||
<button class="text-red-500 hover:text-red-700" @click="eliminarCanal(c)">Eliminar</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex gap-4 mt-2 text-xs">
|
||||
<label class="flex items-center gap-1.5 text-gray-600 dark:text-gray-300 cursor-pointer">
|
||||
<input type="checkbox" :checked="c.usar_whisper_audio" @change="toggleCanalWhisper(c)" class="rounded border-gray-300 dark:border-gray-700 text-brand focus:ring-brand" />
|
||||
Transcribir audios (Whisper)
|
||||
</label>
|
||||
<label class="flex items-center gap-1.5 text-gray-600 dark:text-gray-300 cursor-pointer">
|
||||
<input type="checkbox" :checked="c.usar_ocr_imagenes" @change="toggleCanalOcr(c)" class="rounded border-gray-300 dark:border-gray-700 text-brand focus:ring-brand" />
|
||||
Leer texto de imágenes (OCR)
|
||||
</label>
|
||||
</div>
|
||||
<p class="text-xs text-gray-500 dark:text-gray-400 mt-1 break-all">
|
||||
Webhook: <code class="bg-gray-100 dark:bg-gray-800 px-1 rounded">{{ c.webhook_url }}</code>
|
||||
</p>
|
||||
@@ -542,6 +575,16 @@ onMounted(async () => {
|
||||
<input v-model="canalForm.verify_token" required class="w-full border border-gray-300 dark:border-gray-700 bg-white dark:bg-gray-800 text-gray-800 dark:text-gray-100 rounded-lg px-3 py-2 text-sm" />
|
||||
</div>
|
||||
</template>
|
||||
<div class="flex flex-col gap-2 pt-1">
|
||||
<label class="flex items-center gap-2 text-sm text-gray-600 dark:text-gray-300 cursor-pointer">
|
||||
<input type="checkbox" v-model="canalForm.usar_whisper_audio" class="rounded border-gray-300 dark:border-gray-700 text-brand focus:ring-brand" />
|
||||
Transcribir audios con Whisper
|
||||
</label>
|
||||
<label class="flex items-center gap-2 text-sm text-gray-600 dark:text-gray-300 cursor-pointer">
|
||||
<input type="checkbox" v-model="canalForm.usar_ocr_imagenes" class="rounded border-gray-300 dark:border-gray-700 text-brand focus:ring-brand" />
|
||||
Leer texto de imágenes con OCR
|
||||
</label>
|
||||
</div>
|
||||
<div class="flex justify-end gap-2 pt-2">
|
||||
<button type="button" class="px-4 py-2 text-sm text-gray-500 dark:text-gray-400" @click="showCanalForm = false">Cancelar</button>
|
||||
<button type="submit" class="bg-brand hover:bg-brand-dark text-white text-sm font-medium px-4 py-2 rounded-lg">Guardar</button>
|
||||
|
||||
Reference in New Issue
Block a user