feat: costo OCR en dashboard, logs correctos y fix de thinking tokens
- OcrExtractionService: registra cada llamada en ai_usage_logs (servicio=ocr, costo=5 COP/foto) y ahora tambien loggea cuando SI funciona, no solo cuando falla (antes era imposible confirmar por log que el OCR corrio). - GeminiVisionService: el log decia siempre "[Gemini Vision]" sin importar si la llamada fue de imagen o de texto post-OCR, haciendo imposible distinguir cual camino se uso realmente. Ahora usa el servicio real. - GeminiVisionService: agrega thinkingConfig.thinkingBudget=0 (igual que GeminiIntentService) para que el modelo no gaste tokens narrando su razonamiento en texto plano antes del JSON final -- se estaba colando ese razonamiento en la respuesta y comiendose el presupuesto de tokens. - GeminiIntentService: resultado ya no queda forzado a 'ok'; ahora filtra bloques 'thought' igual que vision, y guarda tokens/raw en el detalle para poder diagnosticar sin acceso al servidor. - ShowAiLogs: card y filtro de costo OCR en el dashboard de consumo. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
7b21cd9773
commit
5e0c0367d9
@@ -72,8 +72,20 @@ class GeminiIntentService
|
||||
|
||||
$inputTokens = $response->json('usageMetadata.promptTokenCount', 0);
|
||||
$outputTokens = $response->json('usageMetadata.candidatesTokenCount', 0);
|
||||
$text = $response->json('candidates.0.content.parts.0.text', '');
|
||||
$resultado = $this->parseRespuesta($text);
|
||||
|
||||
// Igual que GeminiVisionService: si el modelo manda bloques de
|
||||
// "pensamiento" (thought=true), el JSON real puede no venir en la
|
||||
// parte 0. Sin este filtro, parts.0.text agarraba el pensamiento
|
||||
// y el parseo fallaba en silencio (quedaba marcado 'ok' igual).
|
||||
$parts = $response->json('candidates.0.content.parts', []);
|
||||
$text = implode("\n", array_column(
|
||||
array_filter($parts, fn ($p) => isset($p['text']) && empty($p['thought'])),
|
||||
'text'
|
||||
));
|
||||
|
||||
$resultado = $this->parseRespuesta($text);
|
||||
|
||||
Log::info('[Gemini Intent] raw response: ' . substr($text, 0, 300));
|
||||
|
||||
AiUsageLog::registrar([
|
||||
'servicio' => 'gemini_intent',
|
||||
@@ -82,8 +94,13 @@ class GeminiIntentService
|
||||
'input_tokens' => $inputTokens,
|
||||
'output_tokens'=> $outputTokens,
|
||||
'tiempo_ms' => $tiempoMs,
|
||||
'resultado' => 'ok',
|
||||
'detalle' => ['texto' => $texto, 'accion' => $resultado['action'] ?? null],
|
||||
'resultado' => $resultado ? 'ok' : 'error',
|
||||
'detalle' => [
|
||||
'texto' => $texto,
|
||||
'accion' => $resultado['action'] ?? null,
|
||||
'tokens' => "{$inputTokens}/{$outputTokens}",
|
||||
'raw' => $resultado ? null : substr($text, 0, 200),
|
||||
],
|
||||
]);
|
||||
|
||||
return $resultado;
|
||||
|
||||
Reference in New Issue
Block a user