feat: add Gemini connection test button in config panel

probarGemini() sends a minimal prompt to gemini-1.5-flash and reports
latency + trimmed response text, or the error message from the API.
Mirrors the existing Whisper test button pattern.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Lizandro
2026-07-14 19:35:16 +00:00
co-authored by Claude Sonnet 4.6
parent 30fc8c0f1b
commit 13386f5b49
2 changed files with 53 additions and 0 deletions
@@ -17,6 +17,7 @@ class ShowConfiguracionChat extends Component
public string $mensaje_transferencia = '';
public string $webhookResult = '';
public string $whisperResult = '';
public string $geminiResult = '';
// ── Gemini IA ─────────────────────────────────────────────
public string $gemini_api_key = '';
@@ -86,6 +87,43 @@ class ShowConfiguracionChat extends Component
$this->alert('success', 'Configuracion guardada correctamente.');
}
public function probarGemini(): void
{
$key = trim($this->gemini_api_key ?: \App\Models\ChatConfig::get('gemini_api_key'));
if (! $key) {
$this->geminiResult = '⚠️ La API Key de Gemini está vacía.';
return;
}
$url = 'https://generativelanguage.googleapis.com/v1beta/models/gemini-1.5-flash:generateContent';
try {
$inicio = microtime(true);
$response = Http::timeout(10)
->withHeaders(['Content-Type' => 'application/json'])
->post("{$url}?key={$key}", [
'contents' => [['parts' => [['text' => 'Responde solo "ok"']]]],
'generationConfig' => ['maxOutputTokens' => 5, 'temperature' => 0],
]);
$ms = (int) ((microtime(true) - $inicio) * 1000);
$data = $response->json();
if (! $response->successful() || isset($data['error'])) {
$msg = $data['error']['message'] ?? ('HTTP ' . $response->status());
$this->geminiResult = "❌ Gemini respondió con error: {$msg}";
return;
}
$texto = $data['candidates'][0]['content']['parts'][0]['text'] ?? '(sin texto)';
$this->geminiResult = "✅ Gemini OK ({$ms}ms) — respuesta: \"{$texto}\"";
} catch (\Throwable $e) {
$this->geminiResult = '❌ No se pudo conectar con Gemini: ' . $e->getMessage();
}
}
public function resetearWhisper(): void
{
$url = trim($this->whisper_url ?: ChatConfig::get('whisper_url'));
@@ -82,6 +82,21 @@
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>