feat: leer comprobantes via OCR externo + Gemini solo-texto
Antes, si Gemini Vision fallaba (cuota/API), el 100% de los comprobantes del chat web quedaban sin poder leerse. Ahora el job intenta primero un servicio OCR externo configurable (imagen -> texto) y le pasa el texto a Gemini para que solo lo estructure en JSON, más barato y sin la cuota de visión. Si el OCR no está habilitado o falla, cae al método anterior (Gemini leyendo la imagen directamente) sin romper nada. Agrega configuración en el panel (URL/token/habilitado + probar conexión) y la spec del servicio OCR a desplegar en docs/ocr-service-spec.md. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
7f4053ea62
commit
7afd22d581
@@ -150,6 +150,48 @@
|
||||
|
||||
<hr class="border-gray-100">
|
||||
|
||||
{{-- OCR de comprobantes --}}
|
||||
<div>
|
||||
<h3 class="text-sm font-bold text-gray-700 mb-1">OCR de comprobantes (antes de la IA)</h3>
|
||||
<p class="text-xs text-gray-400 mb-4">Si está habilitado, la imagen del comprobante se manda primero a este servicio para extraer el texto, y luego ese texto (no la imagen) se le pasa a Gemini para estructurarlo. Si el servicio falla o está deshabilitado, se usa el método anterior (Gemini lee la imagen directamente).</p>
|
||||
<div class="space-y-4">
|
||||
<div>
|
||||
<label class="block text-sm font-semibold text-gray-700 mb-1">URL del servicio OCR</label>
|
||||
<input wire:model.defer="ocr_url" type="text" placeholder="https://ocr.tu-dominio.com"
|
||||
class="w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:ring-2 focus:ring-emerald-500 outline-none font-mono">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-semibold text-gray-700 mb-1">Token (Authorization: Bearer)</label>
|
||||
<input wire:model.defer="ocr_token" type="password" placeholder="Token del servicio OCR"
|
||||
class="w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:ring-2 focus:ring-emerald-500 outline-none font-mono">
|
||||
</div>
|
||||
<div class="flex items-center gap-3">
|
||||
<input wire:model.defer="ocr_habilitado" type="checkbox" value="1"
|
||||
id="ocr_hab" class="w-4 h-4 accent-emerald-600">
|
||||
<label for="ocr_hab" class="text-sm text-gray-700">
|
||||
Habilitar OCR antes de enviar a la IA
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<button wire:click="probarOcr"
|
||||
class="flex items-center gap-2 px-4 py-2 bg-purple-600 hover:bg-purple-700 text-white text-sm font-semibold rounded-lg transition">
|
||||
<svg class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M16.023 9.348h4.992v-.001M2.985 19.644v-4.992m0 0h4.992m-4.993 0 3.181 3.183a8.25 8.25 0 0 0 13.803-3.7M4.031 9.865a8.25 8.25 0 0 1 13.803-3.7l3.181 3.182m0-4.991v4.99" />
|
||||
</svg>
|
||||
<span wire:loading.remove wire:target="probarOcr">Probar conexión OCR</span>
|
||||
<span wire:loading wire:target="probarOcr">Probando...</span>
|
||||
</button>
|
||||
@if($ocrResult)
|
||||
<p class="mt-2 text-sm {{ str_contains($ocrResult, '✅') ? 'text-emerald-600' : 'text-red-600' }}">
|
||||
{{ $ocrResult }}
|
||||
</p>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr class="border-gray-100">
|
||||
|
||||
{{-- Validacion de pagos --}}
|
||||
<div>
|
||||
<h3 class="text-sm font-bold text-gray-700 mb-1">Validacion de pagos por foto + correo IMAP</h3>
|
||||
|
||||
Reference in New Issue
Block a user