Files
sirpremiumv2/resources/views/livewire/chat/show-configuracion-chat.blade.php
T
LizandroandClaude Sonnet 4.6 75eddd16a6 feat: make Gemini model configurable + auto-list available models on error
- gemini_model is now a saved config field (default: gemini-2.0-flash)
- Config panel shows a text input to set the model name
- probarGemini() reads the configured model and on error calls ListModels
  to show exactly which model names are available for the account's API key
- GeminiIntentService and GeminiVisionService build the URL from config at runtime

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-14 20:11:32 +00:00

231 lines
15 KiB
PHP
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<div class="max-w-2xl mx-auto space-y-6">
<div>
<h2 class="text-xl font-bold text-gray-800">Configuración del Chat</h2>
<p class="text-gray-500 text-sm">Parámetros generales del chatbot y del canal Telegram.</p>
</div>
{{-- Formulario --}}
<div class="bg-white rounded-2xl shadow border border-gray-100 p-6 space-y-5">
{{-- Token Telegram --}}
<div>
<label class="block text-sm font-semibold text-gray-700 mb-1">Token del bot de Telegram</label>
<p class="text-xs text-gray-400 mb-2">Obtenlo hablando con @BotFather en Telegram. Deja vacío si no usas Telegram.</p>
<input wire:model.defer="telegram_token" type="text"
placeholder="1234567890:ABCDefGhijKlmNoPqrStUVwxYZ"
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>
{{-- Webhook URL (solo lectura) --}}
<div>
<label class="block text-sm font-semibold text-gray-700 mb-1">URL del Webhook Telegram</label>
<p class="text-xs text-gray-400 mb-2">Esta es la URL que Telegram usará para enviarte los mensajes entrantes.</p>
<div class="flex gap-2">
<input type="text" readonly value="{{ url('/chat/webhook/telegram') }}"
class="flex-1 border border-gray-200 rounded-lg px-3 py-2 text-sm bg-gray-50 text-gray-600 font-mono">
<button wire:click="registrarWebhook"
class="flex-shrink-0 px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white text-sm font-semibold rounded-lg transition">
<span wire:loading.remove wire:target="registrarWebhook">Registrar Webhook</span>
<span wire:loading wire:target="registrarWebhook">Registrando...</span>
</button>
</div>
@if($webhookResult)
<p class="mt-2 text-sm {{ str_contains($webhookResult, '✅') ? 'text-emerald-600' : 'text-red-600' }}">
{{ $webhookResult }}
</p>
@endif
</div>
<hr class="border-gray-100">
{{-- Mensaje de bienvenida --}}
<div>
<label class="block text-sm font-semibold text-gray-700 mb-1">Mensaje de bienvenida <span class="text-red-500">*</span></label>
<p class="text-xs text-gray-400 mb-2">Primer mensaje cuando el bot no tiene menú configurado o cuando el usuario escribe "hola".</p>
<textarea wire:model.defer="mensaje_bienvenida" rows="3"
class="w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:ring-2 focus:ring-emerald-500 outline-none resize-none"></textarea>
@error('mensaje_bienvenida') <span class="text-red-500 text-xs">{{ $message }}</span> @enderror
</div>
{{-- Mensaje de transferencia --}}
<div>
<label class="block text-sm font-semibold text-gray-700 mb-1">Mensaje al transferir a agente <span class="text-red-500">*</span></label>
<p class="text-xs text-gray-400 mb-2">Se envía al usuario cuando elige la opción de hablar con un agente.</p>
<textarea wire:model.defer="mensaje_transferencia" rows="3"
class="w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:ring-2 focus:ring-emerald-500 outline-none resize-none"></textarea>
@error('mensaje_transferencia') <span class="text-red-500 text-xs">{{ $message }}</span> @enderror
</div>
<hr class="border-gray-100">
{{-- Gemini IA --}}
<div>
<h3 class="text-sm font-bold text-gray-700 mb-3">Inteligencia Artificial (Gemini)</h3>
<div class="space-y-4">
<div>
<label class="block text-sm font-semibold text-gray-700 mb-1">API Key de Gemini</label>
<p class="text-xs text-gray-400 mb-2">Obtén tu clave en aistudio.google.com</p>
<input wire:model.defer="gemini_api_key" type="password" placeholder="AIza..."
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">Modelo</label>
<p class="text-xs text-gray-400 mb-2">Usa "Probar conexión" para ver los modelos disponibles en tu cuenta si no sabes cuál poner.</p>
<input wire:model.defer="gemini_model" type="text" placeholder="gemini-2.0-flash"
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="gemini_habilitado" type="checkbox" value="1"
id="gemini_hab" class="w-4 h-4 accent-emerald-600">
<label for="gemini_hab" class="text-sm text-gray-700">
Habilitar IA para interpretar texto libre del usuario
</label>
</div>
<div>
<label class="block text-sm font-semibold text-gray-700 mb-1">Contexto extra para la IA (opcional)</label>
<textarea wire:model.defer="gemini_prompt_extra" rows="2"
class="w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:ring-2 focus:ring-emerald-500 outline-none resize-none"
placeholder="Ej: Solo vendemos streaming. No ofrecemos juegos."></textarea>
</div>
<div>
<button wire:click="probarGemini"
class="flex items-center gap-2 px-4 py-2 bg-blue-600 hover:bg-blue-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="M9.813 15.904 9 18.75l-.813-2.846a4.5 4.5 0 0 0-3.09-3.09L2.25 12l2.846-.813a4.5 4.5 0 0 0 3.09-3.09L9 5.25l.813 2.846a4.5 4.5 0 0 0 3.09 3.09L15.75 12l-2.846.813a4.5 4.5 0 0 0-3.09 3.09Z" />
</svg>
<span wire:loading.remove wire:target="probarGemini">Probar conexión Gemini</span>
<span wire:loading wire:target="probarGemini">Probando...</span>
</button>
@if($geminiResult)
<p class="mt-2 text-sm {{ str_contains($geminiResult, '✅') ? 'text-emerald-600' : 'text-red-600' }}">
{{ $geminiResult }}
</p>
@endif
</div>
</div>
</div>
<hr class="border-gray-100">
{{-- Whisper STT --}}
<div>
<h3 class="text-sm font-bold text-gray-700 mb-3">Transcripción de voz (Whisper)</h3>
<p class="text-xs text-gray-400 mb-4">Cuando un usuario envíe un audio en Telegram, se transcribirá con Whisper y el texto pasará al sistema de intención como si lo hubiera escrito.</p>
<div class="space-y-4">
<div>
<label class="block text-sm font-semibold text-gray-700 mb-1">URL del servidor Whisper</label>
<input wire:model.defer="whisper_url" type="text" placeholder="https://whisper.u-s.app/asr"
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 (contraseña Basic Auth)</label>
<input wire:model.defer="whisper_token" type="password" placeholder="Token del servidor Whisper"
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="whisper_habilitado" type="checkbox" value="1"
id="whisper_hab" class="w-4 h-4 accent-emerald-600">
<label for="whisper_hab" class="text-sm text-gray-700">
Habilitar transcripción de audios en Telegram
</label>
</div>
<div>
<button wire:click="resetearWhisper"
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="resetearWhisper">Probar conexión Whisper</span>
<span wire:loading wire:target="resetearWhisper">Probando...</span>
</button>
@if($whisperResult)
<p class="mt-2 text-sm {{ str_contains($whisperResult, '✅') ? 'text-emerald-600' : 'text-red-600' }}">
{{ $whisperResult }}
</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>
<p class="text-xs text-gray-400 mb-4">La IA lee el comprobante y cruza los datos con los correos del IMAP configurado en la seccion WhatsApp.</p>
<div class="space-y-4">
<div class="flex items-center gap-3">
<input wire:model.defer="validacion_foto_habilitada" type="checkbox" value="1"
id="val_foto" class="w-4 h-4 accent-emerald-600">
<label for="val_foto" class="text-sm text-gray-700">Habilitar validacion de comprobante por foto</label>
</div>
<div>
<label class="block text-sm font-semibold text-gray-700 mb-1">Accion al confirmar pago</label>
<select wire:model.defer="validacion_accion_auto"
class="w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:ring-2 focus:ring-emerald-500 outline-none">
<option value="solo_notificar">Solo notificar al asesor (manual)</option>
<option value="recargar_saldo">Acreditar saldo automaticamente</option>
</select>
</div>
<div>
<label class="block text-sm font-semibold text-gray-700 mb-1">Tolerancia de monto ($)</label>
<input wire:model.defer="validacion_monto_tolerancia" type="number" min="0"
class="w-32 border border-gray-300 rounded-lg px-3 py-2 text-sm focus:ring-2 focus:ring-emerald-500 outline-none">
<p class="text-xs text-gray-400 mt-1">Diferencia maxima permitida entre comprobante y correo. Recomendado: 0.</p>
</div>
</div>
</div>
<hr class="border-gray-100">
{{-- Bre-B --}}
<div>
<h3 class="text-sm font-bold text-gray-700 mb-1">Pago por Bre-B</h3>
<p class="text-xs text-gray-400 mb-4">Datos que se muestran al cliente cuando elige pagar por Bre-B. Deja la llave vacía para deshabilitar esta opción.</p>
<div class="space-y-4">
<div>
<label class="block text-sm font-semibold text-gray-700 mb-1">Banco / Billetera</label>
<input wire:model.defer="recarga_banco_nombre" type="text" placeholder="Ej: Bancolombia, Nequi, Daviplata"
class="w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:ring-2 focus:ring-emerald-500 outline-none">
@error('recarga_banco_nombre') <span class="text-red-500 text-xs">{{ $message }}</span> @enderror
</div>
<div>
<label class="block text-sm font-semibold text-gray-700 mb-1">Llave Bre-B</label>
<input wire:model.defer="recarga_banco_llave" type="text" placeholder="Ej: 3001234567"
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">
@error('recarga_banco_llave') <span class="text-red-500 text-xs">{{ $message }}</span> @enderror
</div>
<div>
<label class="block text-sm font-semibold text-gray-700 mb-1">Titular de la cuenta</label>
<input wire:model.defer="recarga_banco_titular" type="text" placeholder="Nombre del titular"
class="w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:ring-2 focus:ring-emerald-500 outline-none">
@error('recarga_banco_titular') <span class="text-red-500 text-xs">{{ $message }}</span> @enderror
</div>
</div>
</div>
{{-- Guardar --}}
<div class="flex justify-end pt-2">
<button wire:click="guardar"
class="flex items-center gap-2 bg-emerald-600 hover:bg-emerald-700 text-white text-sm font-semibold px-6 py-2.5 rounded-lg transition shadow">
<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="M9 12.75 11.25 15 15 9.75M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z" />
</svg>
<span wire:loading.remove wire:target="guardar">Guardar configuracion</span>
<span wire:loading wire:target="guardar">Guardando...</span>
</button>
</div>
</div>
{{-- Info de canales --}}
<div class="bg-blue-50 border border-blue-100 rounded-2xl p-5">
<h3 class="font-semibold text-blue-800 text-sm mb-2"> Canales disponibles</h3>
<ul class="text-blue-700 text-sm space-y-1">
<li><strong>Web:</strong> Los visitantes acceden en <code class="bg-blue-100 px-1 rounded">{{ url('/chat') }}</code></li>
<li><strong>Telegram:</strong> Configurar el token y registrar el webhook para recibir mensajes de Telegram.</li>
</ul>
</div>
</div>