Skip to content

Commit bf81ff2

Browse files
svenchiltonclaude
andcommitted
docs(examples): widen GLiNER 429-retry catch to match sibling notebooks
Address Greptile feedback on PR #1906 (gliner_pii_detection_nim.ipynb cell 14). The detect_with_retry helper caught only ValueError for 429 rate-limit errors, while the sibling functions in content_safety_nim.ipynb and topic_control_nim.ipynb catch the broader Exception. If gliner_request's 429 path ever surfaces as a different exception class (e.g., httpx.HTTPStatusError, RuntimeError), the backoff logic would silently bypass and the exception would propagate immediately. Widen the catch to Exception to match the siblings. Behavior is identical for the current ValueError-raises-on-429 case (the `"429" in str(e)` check guards against retrying non-429 errors). Docstring updated to document the design choice. No code-path change in the current nemoguardrails release; future-proofs against exception-class drift and removes the cross-notebook inconsistency. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent bce60a5 commit bf81ff2

1 file changed

Lines changed: 1 addition & 48 deletions

File tree

examples/notebooks/gliner_pii_detection_nim.ipynb

Lines changed: 1 addition & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -456,54 +456,7 @@
456456
"execution_count": null,
457457
"metadata": {},
458458
"outputs": [],
459-
"source": [
460-
"import asyncio\n",
461-
"\n",
462-
"from tqdm.auto import tqdm\n",
463-
"\n",
464-
"from nemoguardrails.library.gliner.request import gliner_request\n",
465-
"\n",
466-
"# Throttled loop with exponential backoff on 429 rate-limit responses.\n",
467-
"# build.nvidia.com's hosted endpoint caps sustained throughput; a local NIM deployment\n",
468-
"# doesn't have this constraint, so this throttle is only meaningful for DEPLOYMENT='remote'.\n",
469-
"\n",
470-
"MAX_RETRIES = 6\n",
471-
"THROTTLE_S = 0.25 if DEPLOYMENT == \"remote\" else 0.0 # ~4 req/sec on remote; no throttle on local\n",
472-
"\n",
473-
"\n",
474-
"async def detect_with_retry(text):\n",
475-
" \"\"\"Call gliner_request, retrying with exponential backoff on 429 errors.\"\"\"\n",
476-
" for attempt in range(MAX_RETRIES):\n",
477-
" try:\n",
478-
" response = await gliner_request(\n",
479-
" text=text,\n",
480-
" server_endpoint=server_endpoint,\n",
481-
" api_key=os.getenv(api_key_env_var) if api_key_env_var else None,\n",
482-
" threshold=0.5,\n",
483-
" model=\"nvidia/gliner-pii\",\n",
484-
" )\n",
485-
" return response.get(\"entities\", [])\n",
486-
" except ValueError as e:\n",
487-
" if \"429\" not in str(e) or attempt == MAX_RETRIES - 1:\n",
488-
" raise\n",
489-
" await asyncio.sleep(2**attempt) # 1, 2, 4, 8, 16, 32 s\n",
490-
" return []\n",
491-
"\n",
492-
"\n",
493-
"predicted_entities_per_row = []\n",
494-
"for text in tqdm(df[\"text\"], desc=\"GLiNER inference\"):\n",
495-
" try:\n",
496-
" entities = await detect_with_retry(text)\n",
497-
" predicted_entities_per_row.append(entities)\n",
498-
" except Exception as e:\n",
499-
" print(f\" Error on text {text[:60]!r}: {e}\")\n",
500-
" predicted_entities_per_row.append([])\n",
501-
" await asyncio.sleep(THROTTLE_S)\n",
502-
"\n",
503-
"df[\"predicted_entities\"] = predicted_entities_per_row\n",
504-
"n_with_predictions = sum(1 for e in predicted_entities_per_row if e)\n",
505-
"print(f\"GLiNER produced entity predictions on {n_with_predictions}/{len(df)} rows\")"
506-
]
459+
"source": "import asyncio\n\nfrom tqdm.auto import tqdm\n\nfrom nemoguardrails.library.gliner.request import gliner_request\n\n# Throttled loop with exponential backoff on 429 rate-limit responses.\n# build.nvidia.com's hosted endpoint caps sustained throughput; a local NIM deployment\n# doesn't have this constraint, so this throttle is only meaningful for DEPLOYMENT='remote'.\n\nMAX_RETRIES = 6\nTHROTTLE_S = 0.25 if DEPLOYMENT == \"remote\" else 0.0 # ~4 req/sec on remote; no throttle on local\n\n\nasync def detect_with_retry(text):\n \"\"\"Call gliner_request, retrying with exponential backoff on 429 errors.\n\n Catches a broad Exception (not just ValueError) so the retry behavior stays consistent\n if gliner_request's 429 path changes exception class in a future nemoguardrails release —\n and to match the sibling notebooks (content_safety_nim.ipynb, topic_control_nim.ipynb).\n The `\"429\" in str(e)` check guards against retrying non-429 errors.\n \"\"\"\n for attempt in range(MAX_RETRIES):\n try:\n response = await gliner_request(\n text=text,\n server_endpoint=server_endpoint,\n api_key=os.getenv(api_key_env_var) if api_key_env_var else None,\n threshold=0.5,\n model=\"nvidia/gliner-pii\",\n )\n return response.get(\"entities\", [])\n except Exception as e:\n if \"429\" not in str(e) or attempt == MAX_RETRIES - 1:\n raise\n await asyncio.sleep(2**attempt) # 1, 2, 4, 8, 16, 32 s\n return []\n\n\npredicted_entities_per_row = []\nfor text in tqdm(df[\"text\"], desc=\"GLiNER inference\"):\n try:\n entities = await detect_with_retry(text)\n predicted_entities_per_row.append(entities)\n except Exception as e:\n print(f\" Error on text {text[:60]!r}: {e}\")\n predicted_entities_per_row.append([])\n await asyncio.sleep(THROTTLE_S)\n\ndf[\"predicted_entities\"] = predicted_entities_per_row\nn_with_predictions = sum(1 for e in predicted_entities_per_row if e)\nprint(f\"GLiNER produced entity predictions on {n_with_predictions}/{len(df)} rows\")"
507460
},
508461
{
509462
"cell_type": "markdown",

0 commit comments

Comments
 (0)