indicate 0.7.0__tar.gz → 0.7.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of indicate might be problematic. Click here for more details.

Files changed (35) hide show
  1. indicate-0.7.1/.gitignore +34 -0
  2. indicate-0.7.1/.pre-commit-config.yaml +40 -0
  3. indicate-0.7.1/CHANGELOG.md +63 -0
  4. indicate-0.7.1/CITATION.cff +11 -0
  5. indicate-0.7.1/CLAUDE.md +77 -0
  6. indicate-0.7.1/LICENSE +21 -0
  7. indicate-0.7.1/Makefile +56 -0
  8. {indicate-0.7.0 → indicate-0.7.1}/PKG-INFO +12 -12
  9. indicate-0.7.1/dist/.gitignore +1 -0
  10. indicate-0.7.1/images/h2e_ed.png +0 -0
  11. indicate-0.7.1/images/pa2e_ed.png +0 -0
  12. {indicate-0.7.0 → indicate-0.7.1}/indicate/__init__.py +7 -3
  13. {indicate-0.7.0 → indicate-0.7.1}/indicate/batch.py +29 -13
  14. {indicate-0.7.0 → indicate-0.7.1}/indicate/cli.py +67 -55
  15. {indicate-0.7.0 → indicate-0.7.1}/indicate/decoder.py +1 -1
  16. {indicate-0.7.0 → indicate-0.7.1}/indicate/file_utils.py +15 -19
  17. {indicate-0.7.0 → indicate-0.7.1}/indicate/indic_utils.py +12 -20
  18. {indicate-0.7.0 → indicate-0.7.1}/indicate/llm_indic.py +32 -30
  19. indicate-0.7.1/indicate/py.typed +0 -0
  20. {indicate-0.7.0 → indicate-0.7.1}/indicate/transliterator.py +12 -15
  21. {indicate-0.7.0 → indicate-0.7.1}/indicate/utils.py +4 -178
  22. {indicate-0.7.0 → indicate-0.7.1}/pyproject.toml +54 -90
  23. indicate-0.7.1/uv.lock +3050 -0
  24. indicate-0.7.0/indicate/transliterate.py +0 -18
  25. {indicate-0.7.0 → indicate-0.7.1}/README.md +0 -0
  26. {indicate-0.7.0 → indicate-0.7.1}/indicate/data/hindi_to_english/english_tokens.json +0 -0
  27. {indicate-0.7.0 → indicate-0.7.1}/indicate/data/hindi_to_english/hindi_tokens.json +0 -0
  28. {indicate-0.7.0 → indicate-0.7.1}/indicate/data/llm_examples.json +0 -0
  29. {indicate-0.7.0 → indicate-0.7.1}/indicate/data/punjabi_to_english/english_tokens.json +0 -0
  30. {indicate-0.7.0 → indicate-0.7.1}/indicate/data/punjabi_to_english/punjabi_tokens.json +0 -0
  31. {indicate-0.7.0 → indicate-0.7.1}/indicate/encoder.py +0 -0
  32. {indicate-0.7.0 → indicate-0.7.1}/indicate/hindi2english.py +0 -0
  33. {indicate-0.7.0 → indicate-0.7.1}/indicate/logging.py +0 -0
  34. {indicate-0.7.0 → indicate-0.7.1}/indicate/punjabi2english.py +0 -0
  35. {indicate-0.7.0 → indicate-0.7.1}/indicate/rerank.py +0 -0
@@ -0,0 +1,34 @@
1
+ .*
2
+ !.github
3
+ !.gitignore
4
+ !.gitattributes
5
+ !.travis.yml
6
+ !.pre-commit-config.yaml
7
+ *.pyc
8
+ *.log
9
+ ./data
10
+ build/
11
+ lit/
12
+ dist/
13
+ .ipynb_checkpoints
14
+ */.ipynb_checkpoints/*
15
+ past/
16
+ .venv
17
+ *.egg-info*
18
+ coverage.xml
19
+ htmlcov/
20
+ /test_install_tf220
21
+ /test_tf219
22
+ # Dakshina benchmark dataset (downloaded locally for training/eval.py)
23
+ *.tar
24
+ dakshina_dataset_v1.0/
25
+ data/dakshina/
26
+ # Large/raw Punjabi source data (silver, electoral-roll PII); committed data is data/punjabi.csv
27
+ data/punjab_transliteration_subset.parquet
28
+ training/IMPROVEMENTS.md
29
+ # v2 (Aksharantar) — external download, derived training corpora, built eval sets
30
+ data/aksharantar/
31
+ data/eval/
32
+ data/*_train_v2.csv.gz
33
+ # Model weights are hosted on HF and lazy-downloaded; tokenizer JSONs stay tracked
34
+ indicate/data/*/saved_weights/
@@ -0,0 +1,40 @@
1
+ repos:
2
+ - repo: https://github.com/astral-sh/ruff-pre-commit
3
+ rev: v0.8.7
4
+ hooks:
5
+ - id: ruff
6
+ args: [--fix]
7
+ - id: ruff-format
8
+
9
+ - repo: https://github.com/pre-commit/mirrors-mypy
10
+ rev: v1.12.1
11
+ hooks:
12
+ - id: mypy
13
+ additional_dependencies:
14
+ - types-requests
15
+ args: [--ignore-missing-imports]
16
+
17
+ - repo: https://github.com/pre-commit/pre-commit-hooks
18
+ rev: v5.0.0
19
+ hooks:
20
+ - id: trailing-whitespace
21
+ - id: end-of-file-fixer
22
+ - id: check-yaml
23
+ - id: check-toml
24
+ - id: check-merge-conflict
25
+ - id: check-case-conflict
26
+ - id: check-docstring-first
27
+ - id: debug-statements
28
+ - id: check-added-large-files
29
+
30
+ - repo: https://github.com/jsh9/pydoclint
31
+ rev: 0.8.6
32
+ hooks:
33
+ - id: pydoclint
34
+
35
+ - repo: https://github.com/pycqa/bandit
36
+ rev: 1.8.0
37
+ hooks:
38
+ - id: bandit
39
+ args: [-r, ., -ll]
40
+ exclude: ^tests/
@@ -0,0 +1,63 @@
1
+ # Changelog
2
+
3
+ ## 0.7.0
4
+
5
+ ### Added
6
+ - **Data-scaled v2 models** — both Hindi and Punjabi retrained on the public
7
+ **Aksharantar** corpus (AI4Bharat) merged with our own data: Hindi ~1.5M pairs,
8
+ Punjabi ~773k. A strict **leakage filter** drops every eval word from training.
9
+ - **Batched inference** — `transliterate_batch(list[str])` is the decode engine
10
+ (batched greedy + beam); `transliterate(str)` is a thin wrapper. The CLI
11
+ `--batch` mode and bulk eval use it (≫ faster than one-at-a-time).
12
+ - **Top-k / n-best** — `transliterate(text, n=k)` returns up to `k` ranked
13
+ candidates (a `list[str]`); `n=1` (default) still returns a `str`.
14
+
15
+ ### Changed
16
+ - **Model weights hosted on Hugging Face** (`soodoku/indicate`, tag `v0.7.0`) and
17
+ lazy-downloaded (cached) on first use, so the wheel is ~50 KB instead of ~107 MB
18
+ (PyPI's 100 MB limit). Tokenizer JSONs still ship in the package; a local copy of
19
+ the weights, if present, is used in preference to the download. Weights are fp32
20
+ (`safetensors`) — fp16 was tried and rejected (it perturbed ~0.05% of outputs for
21
+ no size benefit worth keeping, since hosting solves the size problem).
22
+ - **Input-adaptive decode cap** (`min(max_length_output, 2·len(input)+8)`).
23
+ - Removed `func_timeout` (the decoder is hard-bounded, so the wall-clock guard
24
+ was dead weight — and a perf/flakiness drag); dropped the dependency.
25
+ - Coverage reports to the terminal only (no `htmlcov`/`coverage.xml`).
26
+
27
+ ### Accuracy (Dakshina test, exact-match; vs AI4Bharat IndicXlit, same direction/data)
28
+ | Model | Dakshina (gold) | Held-out-own names |
29
+ |-------|-----------------|--------------------|
30
+ | Hindi v2 | **74.4%** (IndicXlit 73.2%) | **52.8%** (IndicXlit 49.7%) |
31
+ | Punjabi v2 | 71.9% (IndicXlit 73.2%) | **56.9%** (IndicXlit 53.5%) |
32
+
33
+ v2 matches/edges SOTA IndicXlit on the gold benchmark and **beats it on the
34
+ deployment domain** (names IndicXlit never trained on). Eval is leakage-filtered;
35
+ see `training/IMPROVEMENTS.md` and `training/compare.py`.
36
+
37
+ ## 0.6.0
38
+
39
+ ### Added
40
+ - **Punjabi (Gurmukhi → English) transliteration model** — new `PunjabiToEnglish`
41
+ class, `indicate.punjabi2english(...)` API, and `indicate punjabi2english` CLI
42
+ command. Distilled from GPT-4o-labelled Punjab data
43
+ (`training/extract_punjabi.py` → `data/punjabi.csv.gz`).
44
+ - **Beam-search decoding** (length-normalized, width 5) is now the default for
45
+ both models — +1.5 pts exact-match on the Hindi Dakshina test set vs greedy.
46
+ - Evaluation tooling: `training/eval.py` (gold Dakshina), `training/oos_eval.py`
47
+ (held-out), and `training/metrics.py` reporting exact-match accuracy, CER, and
48
+ Acc@≤1 with edit-distance histograms.
49
+
50
+ ### Changed
51
+ - **Migrated the modeling stack from TensorFlow to PyTorch** and the package to
52
+ **Python 3.13-only**. Weights now ship as `safetensors`.
53
+ - Refactored the per-language logic into a shared `Seq2SeqTransliterator` base.
54
+
55
+ ### Accuracy (Google Dakshina test, exact-match / Acc@≤1 / CER)
56
+ - Hindi → English: **77.32% / 91.16% / 5.65%**
57
+ - Punjabi → English: **71.24% / 91.56% / 6.42%**
58
+
59
+ ### Notes
60
+ - Char-LM beam re-ranking and attention padding masks are implemented but gated
61
+ off (no measured win for the name-heavy, native→Latin case); see
62
+ `training/IMPROVEMENTS.md`. The next milestone is a data-scale retrain on the
63
+ public Aksharantar corpus.
@@ -0,0 +1,11 @@
1
+ cff-version: 1.2.0
2
+ message: "If you use this software, please cite it as below."
3
+ authors:
4
+ - family-names: "Chintalapati"
5
+ given-names: "Rajashekar"
6
+ - family-names: "Sood"
7
+ given-names: "Gaurav"
8
+ title: "Indicate: Transliterate Indic Languages to English"
9
+ version: 0.1.0
10
+ date-released: 2022-08-21
11
+ url: "https://github.com/in-rolls/indicate"
@@ -0,0 +1,77 @@
1
+ # CLAUDE.md
2
+
3
+ This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4
+
5
+ ## Project Overview
6
+
7
+ Indicate is a Python package for transliterating Indic text to English using PyTorch-based encoder-decoder models with attention. It ships local models for **Hindi** (Devanagari) and **Punjabi** (Gurmukhi), plus an LLM backend for other languages. The local models are custom-trained neural networks with pre-trained weights.
8
+
9
+ ## Development Commands
10
+
11
+ ### Testing
12
+ ```bash
13
+ python -m unittest tests.test_010_hindi_translate
14
+ python -m unittest discover tests/
15
+ ```
16
+
17
+ ### Build and Installation
18
+ ```bash
19
+ uv sync # Install dependencies with uv (recommended)
20
+ uv build # Build package
21
+ pip install -e . # Install in development mode (alternative)
22
+ ```
23
+
24
+ ### CLI Usage
25
+ ```bash
26
+ # Modern Click-based CLI
27
+ indicate hindi2english "राजशेखर चिंतालपति"
28
+ indicate hindi2english --input file.txt --output result.txt
29
+ indicate info
30
+ ```
31
+
32
+ ### Documentation (Sphinx)
33
+ ```bash
34
+ cd docs/
35
+ make html # Build HTML documentation
36
+ make clean # Clean build artifacts
37
+ ```
38
+
39
+ ## Architecture
40
+
41
+ ### Core Components
42
+
43
+ 1. **Seq2SeqTransliterator** (`indicate/transliterator.py`) - Base lazy-loaded singleton holding the load + greedy `transliterate()` logic, parameterized by class attrs (vocab/weights paths, max lengths)
44
+ 2. **HindiToEnglish** (`indicate/hindi2english.py`) / **PunjabiToEnglish** (`indicate/punjabi2english.py`) - Thin subclasses pointing at each language's tokenizers + safetensors
45
+ 3. **Encoder** (`indicate/encoder.py`) - `nn.Module` LSTM encoder
46
+ 4. **Decoder** (`indicate/decoder.py`) - `nn.Module` LSTM decoder with Luong (dot-product) attention
47
+ 5. **Utils** (`indicate/utils.py`) - Tokenizer loading (`load_tokenizer`) and greedy decoding (`translate`)
48
+
49
+ ### Model Architecture
50
+ - Encoder-decoder with Luong attention mechanism
51
+ - Embedding dimension: 256, LSTM units: 1024
52
+ - Per-language safetensors weights + tokenizer JSONs under
53
+ `indicate/data/{hindi,punjabi}_to_english/`
54
+
55
+ ### Training
56
+ - PyTorch training/extraction/eval scripts live in `training/` (see `training/README.md`)
57
+ - Hindi corpus `data/hindi.csv.gz` and Punjabi corpus `data/punjabi.csv.gz` are committed
58
+ (Punjabi is extracted from the Dataverse-hosted parquet via `training/extract_punjabi.py`)
59
+ - Raw/large source data and the Dakshina benchmark live on Dataverse (see `data/README.md`)
60
+
61
+ ### Data Pipeline
62
+ - Training data from ESPN Cricinfo, election affidavits, Google Dakshina dataset, and IIT Bombay corpus
63
+ - Character-level tokenization with special start (^) and end ($) tokens
64
+ - Decoding is hard-bounded by an input-adaptive step cap (no wall-clock timeout)
65
+
66
+ ### Key Entry Points
67
+ - CLI: `indicate` command (Click group) with `hindi2english` / `punjabi2english` subcommands
68
+ - API: `indicate.hindi2english(text)` and `indicate.punjabi2english(text)` functions
69
+ - Main module: `indicate/__init__.py` exposes both transliteration functions
70
+
71
+ ## Dependencies
72
+ - Python 3.13+ (modern Python with enhanced type hints)
73
+ - Click 8.0+ (modern CLI framework)
74
+ - PyTorch 2.6+ (core ML framework)
75
+ - safetensors 0.4+ (model weight serialization)
76
+ - func-timeout 4.3.0+ (prevents hanging translations)
77
+ - tqdm 4.60.0+ (progress bars)
indicate-0.7.1/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2021 Rajasekhar Chintalapati and Gaurav Sood
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,56 @@
1
+ .PHONY: help clean install test test-cov lint format type-check docs docs-serve build upload dev-install
2
+
3
+ help: ## Show this help message
4
+ @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}'
5
+
6
+ clean: ## Clean build artifacts
7
+ rm -rf build/
8
+ rm -rf dist/
9
+ rm -rf *.egg-info/
10
+ rm -rf .pytest_cache/
11
+ rm -rf .coverage
12
+ rm -rf htmlcov/
13
+ rm -rf docs/_build/
14
+ find . -type d -name __pycache__ -delete
15
+ find . -type f -name "*.pyc" -delete
16
+
17
+ install: ## Install package
18
+ uv pip install -e .
19
+
20
+ dev-install: ## Install package with development dependencies
21
+ uv sync --dev
22
+ pre-commit install
23
+
24
+ test: ## Run tests
25
+ pytest
26
+
27
+ test-cov: ## Run tests with coverage
28
+ pytest --cov=indicate --cov-report=html --cov-report=term
29
+
30
+ lint: ## Run linter
31
+ ruff check .
32
+
33
+ format: ## Format code
34
+ ruff format .
35
+ ruff check --fix .
36
+
37
+ type-check: ## Run type checker
38
+ mypy indicate/
39
+
40
+ docs: ## Build documentation
41
+ cd docs && make clean && make html
42
+
43
+ docs-serve: ## Serve documentation locally
44
+ cd docs/build/html && python -m http.server 8000
45
+
46
+ build: ## Build package
47
+ uv build
48
+
49
+ upload: ## Upload to PyPI
50
+ uv publish
51
+
52
+ ci: lint type-check test ## Run CI checks
53
+
54
+ # Legacy aliases for compatibility
55
+ install-dev: dev-install ## Legacy alias for dev-install
56
+ typecheck: type-check ## Legacy alias for type-check
@@ -1,28 +1,28 @@
1
- Metadata-Version: 2.3
1
+ Metadata-Version: 2.4
2
2
  Name: indicate
3
- Version: 0.7.0
3
+ Version: 0.7.1
4
4
  Summary: Transliterations to/from Indian languages
5
- Keywords: transliterate,indic,hindi,english
6
- Author: Rajashekar Chintalapati, Gaurav Sood
5
+ Project-URL: Homepage, https://github.com/in-rolls/indicate
6
+ Project-URL: Repository, https://github.com/in-rolls/indicate
7
7
  Author-email: Rajashekar Chintalapati <rajshekar.ch@gmail.com>, Gaurav Sood <gsood07@gmail.com>
8
8
  License: MIT
9
+ License-File: LICENSE
10
+ Keywords: english,hindi,indic,transliterate
9
11
  Classifier: Development Status :: 3 - Alpha
10
12
  Classifier: Intended Audience :: Developers
11
13
  Classifier: Programming Language :: Python :: 3.13
12
14
  Classifier: Topic :: Scientific/Engineering :: Information Analysis
13
15
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
14
16
  Classifier: Topic :: Utilities
17
+ Requires-Python: >=3.13
15
18
  Requires-Dist: click>=8.0.0
16
- Requires-Dist: tqdm>=4.60.0
17
- Requires-Dist: numpy>=1.26
18
- Requires-Dist: torch>=2.6.0
19
- Requires-Dist: safetensors>=0.4.0
19
+ Requires-Dist: google-genai>=1.0
20
20
  Requires-Dist: huggingface-hub>=0.23
21
21
  Requires-Dist: litellm>=1.0.0
22
- Requires-Dist: google-genai>=1.0
23
- Requires-Python: >=3.13
24
- Project-URL: Homepage, https://github.com/in-rolls/indicate
25
- Project-URL: Repository, https://github.com/in-rolls/indicate
22
+ Requires-Dist: numpy>=1.26
23
+ Requires-Dist: safetensors>=0.4.0
24
+ Requires-Dist: torch>=2.6.0
25
+ Requires-Dist: tqdm>=4.60.0
26
26
  Description-Content-Type: text/markdown
27
27
 
28
28
  # Indicate: Transliterate Indic Languages with PyTorch and LLMs
@@ -0,0 +1 @@
1
+ *
Binary file
Binary file
@@ -1,11 +1,15 @@
1
+ from .hindi2english import HindiToEnglish
1
2
  from .indic_utils import detect_indic_script, detect_language_from_script
2
3
  from .llm_indic import IndicLLMTransliterator
3
- from .transliterate import hindi2english, punjabi2english
4
+ from .punjabi2english import PunjabiToEnglish
5
+
6
+ hindi2english = HindiToEnglish.transliterate
7
+ punjabi2english = PunjabiToEnglish.transliterate
4
8
 
5
9
  __all__ = [
6
- "hindi2english",
7
- "punjabi2english",
8
10
  "IndicLLMTransliterator",
9
11
  "detect_indic_script",
10
12
  "detect_language_from_script",
13
+ "hindi2english",
14
+ "punjabi2english",
11
15
  ]
@@ -30,6 +30,7 @@ import tempfile
30
30
  import time
31
31
  from dataclasses import asdict, dataclass, field
32
32
  from pathlib import Path
33
+ from typing import Any, cast
33
34
 
34
35
  import litellm
35
36
 
@@ -175,8 +176,8 @@ def _content_to_text(content) -> str:
175
176
  def _parse_output_jsonl(content) -> dict[str, str]:
176
177
  """Map each request's ``custom_id`` to the model's text output.
177
178
 
178
- Output lines follow the OpenAI batch schema:
179
- ``{"custom_id", "response": {"body": {"choices": [{"message": {"content"}}]}}, "error"}``.
179
+ Output lines follow the OpenAI batch schema (``custom_id``,
180
+ ``response.body.choices[0].message.content``, ``error``).
180
181
  """
181
182
  results: dict[str, str] = {}
182
183
  for line in _content_to_text(content).splitlines():
@@ -257,7 +258,7 @@ def _parse_gemini_jsonl(content) -> dict[str, str]:
257
258
 
258
259
 
259
260
  def _write_jsonl(records: list[dict]) -> str:
260
- tmp = tempfile.NamedTemporaryFile(
261
+ tmp = tempfile.NamedTemporaryFile( # noqa: SIM115 - delete=False, path returned
261
262
  "w", suffix=".jsonl", delete=False, encoding="utf-8"
262
263
  )
263
264
  for record in records:
@@ -294,14 +295,21 @@ def _submit_openai_jobs(
294
295
  path = _write_jsonl(request_chunk)
295
296
  try:
296
297
  with open(path, "rb") as handle:
297
- file_obj = litellm.create_file(
298
- file=handle, purpose="batch", custom_llm_provider=state.provider
298
+ # litellm types the sync variants as possibly-Coroutine
299
+ file_obj = cast(
300
+ Any,
301
+ litellm.create_file(
302
+ file=handle, purpose="batch", custom_llm_provider=state.provider
303
+ ),
299
304
  )
300
- batch = litellm.create_batch(
301
- completion_window=completion_window,
302
- endpoint=BATCH_ENDPOINT,
303
- input_file_id=file_obj.id,
304
- custom_llm_provider=state.provider,
305
+ batch = cast(
306
+ Any,
307
+ litellm.create_batch(
308
+ completion_window=completion_window,
309
+ endpoint=BATCH_ENDPOINT,
310
+ input_file_id=file_obj.id,
311
+ custom_llm_provider=state.provider,
312
+ ),
305
313
  )
306
314
  finally:
307
315
  os.unlink(path)
@@ -347,7 +355,11 @@ def _submit_gemini_jobs(
347
355
  uploaded = client.files.upload(
348
356
  file=path, config=types.UploadFileConfig(mime_type="jsonl")
349
357
  )
358
+ if not uploaded.name:
359
+ raise RuntimeError("Gemini file upload returned no name")
350
360
  job = client.batches.create(model=gmodel, src=uploaded.name)
361
+ if not job.name:
362
+ raise RuntimeError("Gemini batch create returned no name")
351
363
  finally:
352
364
  os.unlink(path)
353
365
  chunk_map = {r["key"]: custom_id_to_tokens[r["key"]] for r in request_chunk}
@@ -364,7 +376,10 @@ def _submit_gemini_jobs(
364
376
 
365
377
 
366
378
  def _poll_job(job: BatchJob, provider: str) -> tuple[str, dict[str, str]]:
367
- """Poll one job. Returns (status, by_custom_id); status in completed/running/failed."""
379
+ """Poll one job.
380
+
381
+ Returns (status, by_custom_id); status in completed/running/failed.
382
+ """
368
383
  if provider in _GEMINI_PROVIDERS:
369
384
  client = _gemini_client() # keep a ref for the whole call (httpx lifecycle)
370
385
  info = client.batches.get(name=job.batch_id)
@@ -384,7 +399,7 @@ def _poll_job(job: BatchJob, provider: str) -> tuple[str, dict[str, str]]:
384
399
  return "running", {}
385
400
 
386
401
  retrieved = litellm.retrieve_batch(
387
- batch_id=job.batch_id, custom_llm_provider=provider
402
+ batch_id=job.batch_id, custom_llm_provider=cast(Any, provider)
388
403
  )
389
404
  status = getattr(retrieved, "status", None)
390
405
  output_file_id = getattr(retrieved, "output_file_id", None)
@@ -535,7 +550,8 @@ def collect_transliteration_batches(
535
550
  parsed = transliterator._parse_batch_response(text, len(group))
536
551
  if len(raw_lines) != len(group) or any(not p for p in parsed):
537
552
  logger.warning(
538
- "Batch %s group %s: %d output line(s) for %d tokens; requeueing",
553
+ "Batch %s group %s: %d output line(s) for %d tokens; "
554
+ "requeueing",
539
555
  job.batch_id,
540
556
  custom_id,
541
557
  len(raw_lines),