fix: use v1 API for Gemini 2.5+/3.x models; show real error + generateContent filter

- GeminiIntentService/VisionService: auto-select v1 for 2.5+ models, v1beta for older
- probarGemini: tries v1 then v1beta, shows actual API error message, filters model
  list to only those supporting generateContent so the user sees usable options

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Lizandro
2026-07-15 04:13:09 +00:00
co-authored by Claude Sonnet 4.6
parent aa57f64e4f
commit 54736a8742
3 changed files with 49 additions and 37 deletions
@@ -99,48 +99,57 @@ class ShowConfiguracionChat extends Component
return;
}
$url = "https://generativelanguage.googleapis.com/v1beta/models/{$model}:generateContent";
// Try v1 first (newer models), fall back to v1beta
$apiVersions = ['v1', 'v1beta'];
$lastError = '';
try {
$inicio = microtime(true);
$response = Http::timeout(15)
->withHeaders(['Content-Type' => 'application/json'])
->post("{$url}?key={$key}", [
foreach ($apiVersions as $ver) {
$url = "https://generativelanguage.googleapis.com/{$ver}/models/{$model}:generateContent";
try {
$inicio = microtime(true);
$body = [
'contents' => [['parts' => [['text' => 'Responde solo "ok"']]]],
'generationConfig' => ['maxOutputTokens' => 5, 'temperature' => 0],
...(preg_match('/gemini-(2\.5|3[\.\d]*)/', $model)
? ['thinkingConfig' => ['thinkingBudget' => 0]]
: []),
]);
$ms = (int) ((microtime(true) - $inicio) * 1000);
$data = $response->json();
if (! $response->successful() || isset($data['error'])) {
$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}";
];
if (preg_match('/gemini-(2\.5|3[\.\d]*)/', $model)) {
$body['thinkingConfig'] = ['thinkingBudget' => 0];
}
return;
$response = Http::timeout(15)
->withHeaders(['Content-Type' => 'application/json'])
->post("{$url}?key={$key}", $body);
$ms = (int) ((microtime(true) - $inicio) * 1000);
$data = $response->json();
if ($response->successful() && ! isset($data['error'])) {
$texto = $data['candidates'][0]['content']['parts'][0]['text'] ?? '(sin texto)';
$this->geminiResult = "✅ Gemini OK — modelo: {$model} ({$ver}) — {$ms}ms — respuesta: \"{$texto}\"";
return;
}
$lastError = "[{$ver}] " . ($data['error']['message'] ?? 'HTTP ' . $response->status());
} catch (\Throwable $e) {
$lastError = "[{$ver}] " . $e->getMessage();
}
}
$texto = $data['candidates'][0]['content']['parts'][0]['text'] ?? '(sin texto)';
$this->geminiResult = "✅ Gemini OK — modelo: {$model} — ({$ms}ms) — respuesta: \"{$texto}\"";
// Ambas versiones fallaron — listar modelos disponibles
$lista = Http::timeout(10)
->get("https://generativelanguage.googleapis.com/v1beta/models?key={$key}");
} catch (\Throwable $e) {
$this->geminiResult = '❌ No se pudo conectar con Gemini: ' . $e->getMessage();
if ($lista->successful()) {
$nombres = collect($lista->json('models', []))
->filter(fn ($m) => str_contains($m['name'] ?? '', 'gemini'))
->filter(fn ($m) => in_array('generateContent', $m['supportedGenerationMethods'] ?? []))
->pluck('name')
->map(fn ($n) => str_replace('models/', '', $n))
->values()->implode(', ');
$this->geminiResult = "❌ Error: {$lastError} — Modelos con generateContent: {$nombres}";
} else {
$this->geminiResult = "❌ Error: {$lastError}";
}
}
+3 -1
View File
@@ -18,7 +18,9 @@ class GeminiIntentService
{
$this->apiKey = ChatConfig::get('gemini_api_key', '');
$this->model = ChatConfig::get('gemini_model', 'gemini-2.0-flash');
$this->apiUrl = "https://generativelanguage.googleapis.com/v1beta/models/{$this->model}:generateContent";
// v1 for newer models, v1beta as fallback
$ver = preg_match('/gemini-(2\.5|3[\.\d]*)/', $this->model) ? 'v1' : 'v1beta';
$this->apiUrl = "https://generativelanguage.googleapis.com/{$ver}/models/{$this->model}:generateContent";
}
private function buildRequest(array $contents, array $genConfig = []): array
+2 -1
View File
@@ -18,7 +18,8 @@ class GeminiVisionService
{
$this->apiKey = ChatConfig::get('gemini_api_key', '');
$this->model = ChatConfig::get('gemini_model', 'gemini-2.0-flash');
$this->apiUrl = "https://generativelanguage.googleapis.com/v1beta/models/{$this->model}:generateContent";
$ver = preg_match('/gemini-(2\.5|3[\.\d]*)/', $this->model) ? 'v1' : 'v1beta';
$this->apiUrl = "https://generativelanguage.googleapis.com/{$ver}/models/{$this->model}:generateContent";
}
private function buildRequest(array $contents, array $genConfig = []): array