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>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
deb4d040c3
commit
75eddd16a6
@@ -21,6 +21,7 @@ class ShowConfiguracionChat extends Component
|
||||
|
||||
// ── Gemini IA ─────────────────────────────────────────────
|
||||
public string $gemini_api_key = '';
|
||||
public string $gemini_model = 'gemini-2.0-flash';
|
||||
public string $gemini_habilitado = '0';
|
||||
public string $gemini_prompt_extra = '';
|
||||
|
||||
@@ -43,7 +44,7 @@ class ShowConfiguracionChat extends Component
|
||||
{
|
||||
$keys = [
|
||||
'telegram_token', 'mensaje_bienvenida', 'mensaje_transferencia',
|
||||
'gemini_api_key', 'gemini_habilitado', 'gemini_prompt_extra',
|
||||
'gemini_api_key', 'gemini_model', 'gemini_habilitado', 'gemini_prompt_extra',
|
||||
'validacion_foto_habilitada', 'validacion_accion_auto', 'validacion_monto_tolerancia',
|
||||
'whisper_url', 'whisper_token', 'whisper_habilitado',
|
||||
'recarga_banco_nombre', 'recarga_banco_llave', 'recarga_banco_titular',
|
||||
@@ -54,6 +55,7 @@ class ShowConfiguracionChat extends Component
|
||||
'mensaje_transferencia' => 'Un agente se comunicara contigo en breve. Por favor espera.',
|
||||
'validacion_accion_auto' => 'solo_notificar',
|
||||
'validacion_monto_tolerancia' => '0',
|
||||
'gemini_model' => 'gemini-2.0-flash',
|
||||
];
|
||||
|
||||
foreach ($keys as $key) {
|
||||
@@ -74,7 +76,7 @@ class ShowConfiguracionChat extends Component
|
||||
|
||||
$keys = [
|
||||
'telegram_token', 'mensaje_bienvenida', 'mensaje_transferencia',
|
||||
'gemini_api_key', 'gemini_habilitado', 'gemini_prompt_extra',
|
||||
'gemini_api_key', 'gemini_model', 'gemini_habilitado', 'gemini_prompt_extra',
|
||||
'validacion_foto_habilitada', 'validacion_accion_auto', 'validacion_monto_tolerancia',
|
||||
'whisper_url', 'whisper_token', 'whisper_habilitado',
|
||||
'recarga_banco_nombre', 'recarga_banco_llave', 'recarga_banco_titular',
|
||||
@@ -89,18 +91,19 @@ class ShowConfiguracionChat extends Component
|
||||
|
||||
public function probarGemini(): void
|
||||
{
|
||||
$key = trim($this->gemini_api_key ?: \App\Models\ChatConfig::get('gemini_api_key'));
|
||||
$key = trim($this->gemini_api_key ?: \App\Models\ChatConfig::get('gemini_api_key'));
|
||||
$model = trim($this->gemini_model ?: \App\Models\ChatConfig::get('gemini_model', 'gemini-2.0-flash'));
|
||||
|
||||
if (! $key) {
|
||||
$this->geminiResult = '⚠️ La API Key de Gemini está vacía.';
|
||||
return;
|
||||
}
|
||||
|
||||
$url = 'https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent';
|
||||
$url = "https://generativelanguage.googleapis.com/v1beta/models/{$model}:generateContent";
|
||||
|
||||
try {
|
||||
$inicio = microtime(true);
|
||||
$response = Http::timeout(10)
|
||||
$response = Http::timeout(15)
|
||||
->withHeaders(['Content-Type' => 'application/json'])
|
||||
->post("{$url}?key={$key}", [
|
||||
'contents' => [['parts' => [['text' => 'Responde solo "ok"']]]],
|
||||
@@ -111,13 +114,27 @@ class ShowConfiguracionChat extends Component
|
||||
$data = $response->json();
|
||||
|
||||
if (! $response->successful() || isset($data['error'])) {
|
||||
$msg = $data['error']['message'] ?? ('HTTP ' . $response->status());
|
||||
$this->geminiResult = "❌ Gemini respondió con error: {$msg}";
|
||||
$apiMsg = $data['error']['message'] ?? ('HTTP ' . $response->status());
|
||||
|
||||
// Listar modelos disponibles para ayudar a elegir el correcto
|
||||
$lista = Http::timeout(10)
|
||||
->get("https://generativelanguage.googleapis.com/v1beta/models?key={$key}");
|
||||
|
||||
if ($lista->successful()) {
|
||||
$nombres = collect($lista->json('models', []))
|
||||
->filter(fn ($m) => str_contains($m['name'] ?? '', 'gemini'))
|
||||
->pluck('name')
|
||||
->map(fn ($n) => str_replace('models/', '', $n))
|
||||
->values()->implode(', ');
|
||||
$this->geminiResult = "❌ Modelo \"{$model}\" no disponible. Modelos en tu cuenta: {$nombres}";
|
||||
} else {
|
||||
$this->geminiResult = "❌ Error: {$apiMsg}";
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
$texto = $data['candidates'][0]['content']['parts'][0]['text'] ?? '(sin texto)';
|
||||
$this->geminiResult = "✅ Gemini OK ({$ms}ms) — respuesta: \"{$texto}\"";
|
||||
$this->geminiResult = "✅ Gemini OK — modelo: {$model} — ({$ms}ms) — respuesta: \"{$texto}\"";
|
||||
|
||||
} catch (\Throwable $e) {
|
||||
$this->geminiResult = '❌ No se pudo conectar con Gemini: ' . $e->getMessage();
|
||||
|
||||
@@ -10,11 +10,13 @@ use Illuminate\Support\Facades\Log;
|
||||
class GeminiIntentService
|
||||
{
|
||||
private string $apiKey;
|
||||
private string $apiUrl = 'https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent';
|
||||
private string $apiUrl;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->apiKey = ChatConfig::get('gemini_api_key', '');
|
||||
$model = ChatConfig::get('gemini_model', 'gemini-2.0-flash');
|
||||
$this->apiUrl = "https://generativelanguage.googleapis.com/v1beta/models/{$model}:generateContent";
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -10,11 +10,13 @@ use Illuminate\Support\Facades\Log;
|
||||
class GeminiVisionService
|
||||
{
|
||||
private string $apiKey;
|
||||
private string $apiUrl = 'https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent';
|
||||
private string $apiUrl;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->apiKey = ChatConfig::get('gemini_api_key', '');
|
||||
$model = ChatConfig::get('gemini_model', 'gemini-2.0-flash');
|
||||
$this->apiUrl = "https://generativelanguage.googleapis.com/v1beta/models/{$model}:generateContent";
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -69,6 +69,12 @@
|
||||
<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">
|
||||
|
||||
Reference in New Issue
Block a user