Spaces:
Sleeping
Sleeping
Add OpenRouter backup key failover
Browse files- src/humeo/layout_vision.py +47 -30
src/humeo/layout_vision.py
CHANGED
|
@@ -35,11 +35,11 @@ from humeo.env import (
|
|
| 35 |
OPENROUTER_BASE_URL,
|
| 36 |
current_llm_provider,
|
| 37 |
model_name_for_provider,
|
| 38 |
-
openrouter_default_headers,
|
| 39 |
-
resolve_gemini_api_key,
|
| 40 |
-
resolve_llm_provider,
|
| 41 |
-
|
| 42 |
-
)
|
| 43 |
from humeo.gemini_generate import gemini_generate_config
|
| 44 |
|
| 45 |
logger = logging.getLogger(__name__)
|
|
@@ -1337,31 +1337,48 @@ def _call_vision_json(keyframe_path: str, model_name: str, prompt: str) -> dict[
|
|
| 1337 |
raise RuntimeError("Gemini vision returned empty response")
|
| 1338 |
return _json_object_from_vision_response(response.text)
|
| 1339 |
|
| 1340 |
-
|
| 1341 |
-
|
| 1342 |
-
|
| 1343 |
-
|
| 1344 |
-
|
| 1345 |
-
|
| 1346 |
-
|
| 1347 |
-
|
| 1348 |
-
|
| 1349 |
-
|
| 1350 |
-
|
| 1351 |
-
|
| 1352 |
-
|
| 1353 |
-
{"
|
| 1354 |
-
{
|
| 1355 |
-
|
| 1356 |
-
|
| 1357 |
-
|
| 1358 |
-
|
| 1359 |
-
|
| 1360 |
-
|
| 1361 |
-
|
| 1362 |
-
|
| 1363 |
-
|
| 1364 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1365 |
|
| 1366 |
|
| 1367 |
def _call_gemini_vision(keyframe_path: str, model_name: str) -> dict[str, Any]:
|
|
|
|
| 35 |
OPENROUTER_BASE_URL,
|
| 36 |
current_llm_provider,
|
| 37 |
model_name_for_provider,
|
| 38 |
+
openrouter_default_headers,
|
| 39 |
+
resolve_gemini_api_key,
|
| 40 |
+
resolve_llm_provider,
|
| 41 |
+
resolve_openrouter_api_keys,
|
| 42 |
+
)
|
| 43 |
from humeo.gemini_generate import gemini_generate_config
|
| 44 |
|
| 45 |
logger = logging.getLogger(__name__)
|
|
|
|
| 1337 |
raise RuntimeError("Gemini vision returned empty response")
|
| 1338 |
return _json_object_from_vision_response(response.text)
|
| 1339 |
|
| 1340 |
+
data_url = f"data:{mime};base64,{base64.b64encode(data).decode('ascii')}"
|
| 1341 |
+
keys = resolve_openrouter_api_keys()
|
| 1342 |
+
last_error: Exception | None = None
|
| 1343 |
+
for key_idx, api_key in enumerate(keys, start=1):
|
| 1344 |
+
try:
|
| 1345 |
+
client = OpenAI(
|
| 1346 |
+
api_key=api_key,
|
| 1347 |
+
base_url=OPENROUTER_BASE_URL,
|
| 1348 |
+
default_headers=openrouter_default_headers(),
|
| 1349 |
+
)
|
| 1350 |
+
response = client.chat.completions.create(
|
| 1351 |
+
model=resolved_model,
|
| 1352 |
+
messages=[
|
| 1353 |
+
{"role": "system", "content": prompt},
|
| 1354 |
+
{
|
| 1355 |
+
"role": "user",
|
| 1356 |
+
"content": [
|
| 1357 |
+
{"type": "text", "text": "Analyze this keyframe and return only JSON."},
|
| 1358 |
+
{"type": "image_url", "image_url": {"url": data_url}},
|
| 1359 |
+
],
|
| 1360 |
+
},
|
| 1361 |
+
],
|
| 1362 |
+
temperature=0.2,
|
| 1363 |
+
response_format={"type": "json_object"},
|
| 1364 |
+
)
|
| 1365 |
+
text = _openai_message_text(response.choices[0].message.content)
|
| 1366 |
+
if not text:
|
| 1367 |
+
raise RuntimeError("OpenRouter vision returned empty response")
|
| 1368 |
+
if key_idx > 1:
|
| 1369 |
+
logger.info("OpenRouter vision succeeded with fallback key %d/%d", key_idx, len(keys))
|
| 1370 |
+
return _json_object_from_vision_response(text)
|
| 1371 |
+
except Exception as exc:
|
| 1372 |
+
last_error = exc
|
| 1373 |
+
if key_idx < len(keys):
|
| 1374 |
+
logger.warning(
|
| 1375 |
+
"OpenRouter vision failed with key %d/%d: %s; trying fallback",
|
| 1376 |
+
key_idx,
|
| 1377 |
+
len(keys),
|
| 1378 |
+
exc,
|
| 1379 |
+
)
|
| 1380 |
+
assert last_error is not None
|
| 1381 |
+
raise last_error
|
| 1382 |
|
| 1383 |
|
| 1384 |
def _call_gemini_vision(keyframe_path: str, model_name: str) -> dict[str, Any]:
|