ThomsenDrake commited on
Commit
8172529
·
verified ·
1 Parent(s): 45df764

Wire Parakeet ASR into ZeroGPU Space

Browse files
README.md CHANGED
@@ -10,6 +10,7 @@ pinned: false
10
  python_version: 3.12.12
11
  preload_from_hub:
12
  - build-small-hackathon/figment-finetuned-model-archive figment_sft_v14p/figment-sft-v14p-lora-merged-bf16/chat_template.jinja,figment_sft_v14p/figment-sft-v14p-lora-merged-bf16/config.json,figment_sft_v14p/figment-sft-v14p-lora-merged-bf16/configuration_nemotron_h.py,figment_sft_v14p/figment-sft-v14p-lora-merged-bf16/generation_config.json,figment_sft_v14p/figment-sft-v14p-lora-merged-bf16/model-00001-of-00002.safetensors,figment_sft_v14p/figment-sft-v14p-lora-merged-bf16/model-00002-of-00002.safetensors,figment_sft_v14p/figment-sft-v14p-lora-merged-bf16/model.safetensors.index.json,figment_sft_v14p/figment-sft-v14p-lora-merged-bf16/modeling_nemotron_h.py,figment_sft_v14p/figment-sft-v14p-lora-merged-bf16/special_tokens_map.json,figment_sft_v14p/figment-sft-v14p-lora-merged-bf16/tokenizer.json,figment_sft_v14p/figment-sft-v14p-lora-merged-bf16/tokenizer_config.json
 
13
  ---
14
 
15
  # Figment
@@ -24,7 +25,7 @@ Figment turns messy field intake into a card-cited protocol workflow: confirm th
24
 
25
  | Surface | Current evidence | What it means | Boundary |
26
  | --- | --- | --- | --- |
27
- | Public Space | [build-small-hackathon/figment](https://huggingface.co/spaces/build-small-hackathon/figment) was `RUNNING` on `zero-a10g` at Space commit `e06aaf664bb7a848dd5c1958050779ef3a9feb03` on 2026-06-15. A synthetic `/run_navigator` call returned `raw_route=hf_zerogpu`, `fallback_tier=configured`, `final_route=model_with_deterministic_patches`, and `validator.passed=true` in 36.16 seconds. | The public Space reaches the published v14p BF16 model archive through HF ZeroGPU and the validator passed on the returned response. | This is one live synthetic route check. Deterministic patches still contributed, so it is live serving proof, not pure model-only competence proof. |
28
  | Hosted Omni eval | `31/50` whole-output competence, `8/50` full fallback, `480/650` model-retained fields, `170/650` deterministic patches, and `50/50` final validation. | Hosted Omni can carry bounded fields, and the app can keep outputs inside the safety contract. | `50/50` final validation is app safety after validation, repair, and fallback. It is not pure model performance. |
29
  | 4B LoRA system eval | v14p repair-union on the corrected 150-case field-workflow holdout: `150/150` competence, `150/150` expected labels, `150/150` final validation, `0` deterministic patches, `0` fallback. Raw first-pass success is `146/150`; `4/150` cases close through focused model repair. | The strongest documented small-model result is model-owned output plus model repair on a synthetic/de-identified holdout. | This is not clinical validation, target-user validation, local ASR proof, or proof that raw first-pass output solved every case. |
30
  | Public artifacts | [model archive](https://huggingface.co/build-small-hackathon/figment-finetuned-model-archive) and [eval/training dataset](https://huggingface.co/datasets/build-small-hackathon/figment-eval-traces). | Versioned BF16/GGUF model artifacts, synthetic corpora, eval traces, and summaries are inspectable outside this checkout. | Generated `traces/`, `data/finetune/`, weights, and checkpoint folders are intentionally not part of a clean clone. |
@@ -95,12 +96,12 @@ Figment supports four runtime routes:
95
  | --- | --- | --- |
96
  | Canned fallback | `MODEL_BACKEND=canned` | No-secret app smoke, UI development, honest fallback traces. |
97
  | Hosted Omni | `MODEL_BACKEND=hosted_omni` with `NVIDIA_API_KEY` | Live hosted demo and hosted eval path using `nvidia/nemotron-3-nano-omni-30b-a3b-reasoning`. |
98
- | HF ZeroGPU v14p | `MODEL_BACKEND=hf_zerogpu` with `ZEROGPU_MODEL_REPO` / `ZEROGPU_MODEL_SUBFOLDER` | Public Space route using the published v14p BF16 merged model on Hugging Face ZeroGPU. |
99
  | Local OpenAI-compatible | `MODEL_BACKEND=llama_cpp` with `LLAMA_BASE_URL` | Local text-navigation route for the 4B BF16/GGUF artifacts and local evidence bundles. |
100
 
101
  The Build Small constraint is <=32B total parameters. The hosted Omni path is tracked with a parameter-count caveat: the NVIDIA model-card body reports 31B total parameters, while sidebar counts have differed. The 4B BF16 base model, `nvidia/NVIDIA-Nemotron-3-Nano-4B-BF16`, is the local text-navigation training target.
102
 
103
- Parakeet ASR remains a gated local-audio path. Artifact presence alone is not enough; local ASR needs provider-output evidence before any local-audio claim is upgraded.
104
 
105
  ## Evaluation
106
 
 
10
  python_version: 3.12.12
11
  preload_from_hub:
12
  - build-small-hackathon/figment-finetuned-model-archive figment_sft_v14p/figment-sft-v14p-lora-merged-bf16/chat_template.jinja,figment_sft_v14p/figment-sft-v14p-lora-merged-bf16/config.json,figment_sft_v14p/figment-sft-v14p-lora-merged-bf16/configuration_nemotron_h.py,figment_sft_v14p/figment-sft-v14p-lora-merged-bf16/generation_config.json,figment_sft_v14p/figment-sft-v14p-lora-merged-bf16/model-00001-of-00002.safetensors,figment_sft_v14p/figment-sft-v14p-lora-merged-bf16/model-00002-of-00002.safetensors,figment_sft_v14p/figment-sft-v14p-lora-merged-bf16/model.safetensors.index.json,figment_sft_v14p/figment-sft-v14p-lora-merged-bf16/modeling_nemotron_h.py,figment_sft_v14p/figment-sft-v14p-lora-merged-bf16/special_tokens_map.json,figment_sft_v14p/figment-sft-v14p-lora-merged-bf16/tokenizer.json,figment_sft_v14p/figment-sft-v14p-lora-merged-bf16/tokenizer_config.json
13
+ - nvidia/parakeet-ctc-1.1b config.json,model.safetensors,preprocessor_config.json,special_tokens_map.json,tokenizer.json,tokenizer_config.json,vocab.json
14
  ---
15
 
16
  # Figment
 
25
 
26
  | Surface | Current evidence | What it means | Boundary |
27
  | --- | --- | --- | --- |
28
+ | Public Space | [build-small-hackathon/figment](https://huggingface.co/spaces/build-small-hackathon/figment) was `RUNNING` on `zero-a10g` at Space commit `45df7643e9e592f8496214c436532a3ade3cfdfc` on 2026-06-15. A synthetic `/run_navigator` call returned `raw_route=hf_zerogpu`, `fallback_tier=configured`, `field_level_fallback_used=true`, `final_route=model_with_deterministic_patches`, and `validation_status=passed` in 41.87 seconds. | The public Space reaches the published v14p BF16 model archive through HF ZeroGPU and the validator passed on the returned response. | This is one live synthetic route check. Deterministic patches still contributed, so it is live serving proof, not pure model-only competence proof. |
29
  | Hosted Omni eval | `31/50` whole-output competence, `8/50` full fallback, `480/650` model-retained fields, `170/650` deterministic patches, and `50/50` final validation. | Hosted Omni can carry bounded fields, and the app can keep outputs inside the safety contract. | `50/50` final validation is app safety after validation, repair, and fallback. It is not pure model performance. |
30
  | 4B LoRA system eval | v14p repair-union on the corrected 150-case field-workflow holdout: `150/150` competence, `150/150` expected labels, `150/150` final validation, `0` deterministic patches, `0` fallback. Raw first-pass success is `146/150`; `4/150` cases close through focused model repair. | The strongest documented small-model result is model-owned output plus model repair on a synthetic/de-identified holdout. | This is not clinical validation, target-user validation, local ASR proof, or proof that raw first-pass output solved every case. |
31
  | Public artifacts | [model archive](https://huggingface.co/build-small-hackathon/figment-finetuned-model-archive) and [eval/training dataset](https://huggingface.co/datasets/build-small-hackathon/figment-eval-traces). | Versioned BF16/GGUF model artifacts, synthetic corpora, eval traces, and summaries are inspectable outside this checkout. | Generated `traces/`, `data/finetune/`, weights, and checkpoint folders are intentionally not part of a clean clone. |
 
96
  | --- | --- | --- |
97
  | Canned fallback | `MODEL_BACKEND=canned` | No-secret app smoke, UI development, honest fallback traces. |
98
  | Hosted Omni | `MODEL_BACKEND=hosted_omni` with `NVIDIA_API_KEY` | Live hosted demo and hosted eval path using `nvidia/nemotron-3-nano-omni-30b-a3b-reasoning`. |
99
+ | HF ZeroGPU v14p + Parakeet ASR | `MODEL_BACKEND=hf_zerogpu`, `AUDIO_BACKEND=parakeet_nemo`, and `ALLOW_LOCAL_ASR=true` | Public Space route using the published v14p BF16 merged model plus gated Parakeet ASR draft intake on Hugging Face ZeroGPU. |
100
  | Local OpenAI-compatible | `MODEL_BACKEND=llama_cpp` with `LLAMA_BASE_URL` | Local text-navigation route for the 4B BF16/GGUF artifacts and local evidence bundles. |
101
 
102
  The Build Small constraint is <=32B total parameters. The hosted Omni path is tracked with a parameter-count caveat: the NVIDIA model-card body reports 31B total parameters, while sidebar counts have differed. The 4B BF16 base model, `nvidia/NVIDIA-Nemotron-3-Nano-4B-BF16`, is the local text-navigation training target.
103
 
104
+ Parakeet ASR remains evidence-gated. A Space route can use the Transformers-native `nvidia/parakeet-ctc-1.1b` Parakeet model for live audio draft intake; the original local/offline proof path still requires a real provider-output evidence bundle before any no-cloud/local-ASR claim is upgraded.
105
 
106
  ## Evaluation
107
 
app.py CHANGED
@@ -14,6 +14,12 @@ from figment.audio_intake import draft_audio_intake as _draft_audio_intake
14
  from figment.config import FigmentConfig, load_config
15
  from figment.model_client import ModelClient, ModelClientError, hosted_audio_limits_text, validate_hosted_audio_file
16
  from figment.navigator import run_navigation
 
 
 
 
 
 
17
  from figment.retrieval import load_protocol_cards, query_from_intake, retrieval_source_summary, search_protocol_cards
18
  from figment.rules import evaluate_rules, run_red_flag_checks
19
  from figment.sbar import render_sbar
@@ -158,6 +164,16 @@ def draft_audio_intake(
158
  provider_payload = ModelClient(config).generate_audio_draft(audio_file)
159
  except ModelClientError as exc:
160
  provider_error = f"Hosted Omni audio draft failed; typed transcript or canned fallback required. {exc}"
 
 
 
 
 
 
 
 
 
 
161
  draft = _draft_audio_intake(
162
  transcript=transcript,
163
  config=config,
@@ -176,6 +192,11 @@ def draft_audio_intake(
176
  hosted_disclosure = _hosted_audio_disclosure_text()
177
  draft["hosted_audio_disclosure"] = hosted_disclosure
178
  retention_note = f"{retention_note} {hosted_disclosure}"
 
 
 
 
 
179
  draft["audio_retention_note"] = retention_note
180
  if provider_error and draft.get("audio_intake_path") == "audio_received_needs_transcript_or_model":
181
  draft["processing_status"] = provider_error
@@ -1635,6 +1656,15 @@ def _should_use_hosted_omni_audio(config: FigmentConfig) -> bool:
1635
  )
1636
 
1637
 
 
 
 
 
 
 
 
 
 
1638
  def _hosted_audio_disclosure_text() -> str:
1639
  return (
1640
  "Hosted audio is sent to the configured hosted endpoint for drafting; use only synthetic or "
 
14
  from figment.config import FigmentConfig, load_config
15
  from figment.model_client import ModelClient, ModelClientError, hosted_audio_limits_text, validate_hosted_audio_file
16
  from figment.navigator import run_navigation
17
+ from figment.parakeet_asr import (
18
+ ParakeetAsrError,
19
+ parakeet_audio_limits_text,
20
+ transcribe_audio_with_parakeet,
21
+ validate_parakeet_audio_file,
22
+ )
23
  from figment.retrieval import load_protocol_cards, query_from_intake, retrieval_source_summary, search_protocol_cards
24
  from figment.rules import evaluate_rules, run_red_flag_checks
25
  from figment.sbar import render_sbar
 
164
  provider_payload = ModelClient(config).generate_audio_draft(audio_file)
165
  except ModelClientError as exc:
166
  provider_error = f"Hosted Omni audio draft failed; typed transcript or canned fallback required. {exc}"
167
+ elif audio_file and not transcript.strip() and provider_payload is None and _should_use_parakeet_audio(config):
168
+ try:
169
+ validate_parakeet_audio_file(audio_file)
170
+ except ParakeetAsrError as exc:
171
+ provider_error = f"Parakeet ASR draft skipped; typed transcript or canned fallback required. {exc}"
172
+ else:
173
+ try:
174
+ provider_payload = transcribe_audio_with_parakeet(audio_file, config=config)
175
+ except ParakeetAsrError as exc:
176
+ provider_error = f"Parakeet ASR draft failed; typed transcript or canned fallback required. {exc}"
177
  draft = _draft_audio_intake(
178
  transcript=transcript,
179
  config=config,
 
192
  hosted_disclosure = _hosted_audio_disclosure_text()
193
  draft["hosted_audio_disclosure"] = hosted_disclosure
194
  retention_note = f"{retention_note} {hosted_disclosure}"
195
+ elif _should_use_parakeet_audio(config):
196
+ retention_note = (
197
+ f"{retention_note} Parakeet ASR runs on the configured local/ZeroGPU runtime; "
198
+ f"limit: {parakeet_audio_limits_text()}."
199
+ )
200
  draft["audio_retention_note"] = retention_note
201
  if provider_error and draft.get("audio_intake_path") == "audio_received_needs_transcript_or_model":
202
  draft["processing_status"] = provider_error
 
1656
  )
1657
 
1658
 
1659
+ def _should_use_parakeet_audio(config: FigmentConfig) -> bool:
1660
+ return (
1661
+ config.enable_audio_intake
1662
+ and config.audio_backend == "parakeet_nemo"
1663
+ and config.allow_local_asr
1664
+ and config.model_stack == "local_4b_parakeet"
1665
+ )
1666
+
1667
+
1668
  def _hosted_audio_disclosure_text() -> str:
1669
  return (
1670
  "Hosted audio is sent to the configured hosted endpoint for drafting; use only synthetic or "
docs/local_parakeet_asr_evidence.md CHANGED
@@ -17,6 +17,16 @@ This note separates local Parakeet ASR artifact availability from a real local A
17
 
18
  Use the helper to capture local ASR evidence:
19
 
 
 
 
 
 
 
 
 
 
 
20
  ```bash
21
  PYTHON_DOTENV_DISABLED=true \
22
  python3 scripts/run_local_asr_evidence.py \
@@ -29,6 +39,7 @@ The helper writes a timestamped evidence directory under `traces/local_asr_parak
29
 
30
  - `artifact_metadata.json`: Parakeet `.nemo` presence, size, and hash
31
  - `audio_metadata.json`: optional source-audio metadata and hash only; raw audio is not copied into the evidence bundle
 
32
  - `provider_payload_metadata.json`: provider output file hash
33
  - `audio_draft.json`: Figment draft generated from the provider payload under `AUDIO_BACKEND=parakeet_nemo` and `ALLOW_LOCAL_ASR=true`
34
  - `draft_checks.json`: evidence-gated checks for Parakeet provenance, confirmation status, and raw-audio handling
@@ -53,4 +64,4 @@ raw_audio_stored=false
53
  asr_evidence_manifest_path=/tmp/figment-local-asr-artifact-only-manifest-check/asr_evidence_manifest.json
54
  ```
55
 
56
- This means Parakeet remains not demo-visible as local ASR proof. It can become proof only after a real local ASR adapter or device runtime produces a provider payload, and the helper records `counts_as_local_asr_proof=true`.
 
17
 
18
  Use the helper to capture local ASR evidence:
19
 
20
+ ```bash
21
+ PYTHON_DOTENV_DISABLED=true \
22
+ python3 scripts/run_local_asr_evidence.py \
23
+ --audio <source-audio.wav> \
24
+ --transcribe-audio \
25
+ --provider-note "<device/runtime command>"
26
+ ```
27
+
28
+ If a provider payload was captured by a separate local runtime, pass it directly:
29
+
30
  ```bash
31
  PYTHON_DOTENV_DISABLED=true \
32
  python3 scripts/run_local_asr_evidence.py \
 
39
 
40
  - `artifact_metadata.json`: Parakeet `.nemo` presence, size, and hash
41
  - `audio_metadata.json`: optional source-audio metadata and hash only; raw audio is not copied into the evidence bundle
42
+ - `provider_payload.json`: provider output generated by `--transcribe-audio`, when that path is used
43
  - `provider_payload_metadata.json`: provider output file hash
44
  - `audio_draft.json`: Figment draft generated from the provider payload under `AUDIO_BACKEND=parakeet_nemo` and `ALLOW_LOCAL_ASR=true`
45
  - `draft_checks.json`: evidence-gated checks for Parakeet provenance, confirmation status, and raw-audio handling
 
64
  asr_evidence_manifest_path=/tmp/figment-local-asr-artifact-only-manifest-check/asr_evidence_manifest.json
65
  ```
66
 
67
+ This means artifact presence alone remains insufficient. The app now has a Parakeet ASR adapter path; the proof upgrades only after a real audio run produces a provider payload and the helper records `counts_as_local_asr_proof=true`.
docs/model_parameter_evidence_ledger.md CHANGED
@@ -6,11 +6,11 @@ Purpose: keep parameter, route, locality, adapter, ASR, and organizer-confirmati
6
 
7
  ## Current Claim Boundary
8
 
9
- - Hosted Omni has measured eval evidence through the eval harness. The public Space is now verified runnable in no-secret canned-fallback mode, but that public Space proof is not live hosted Omni generation evidence.
10
- - The public Space target exists and cold-boots from the Space URL. Current public API evidence: `runtime.stage=RUNNING`, `hardware=cpu-basic`, 167 siblings, `app.py` present, `figment/observation_targets.py` present, and Space URL HTTP 200. Public workflow evidence remains no-secret canned fallback unless a later non-canned public trace is recorded.
11
  - The public model archive now records published measured Figment 4B LoRA merged artifacts through `figment_sft_v14p`. The strongest measured result is v14p repair-union on the corrected 150-case field-workflow holdout: 150/150 competence, 150/150 expected labels, 150/150 final validation, 0 deterministic patches, and 0 fallback. This is tuned model-system evidence, not no-cloud or clinical validation evidence.
12
  - The local 4B + Parakeet route is still the preferred no-cloud/off-grid proof path. The full BF16 4B artifact and Parakeet artifact are present locally, and the tuned v14p GGUF is published, but no-cloud route proof and local ASR provider proof are still separate gates.
13
- - Well-Tuned wording may cite the published measured v14p tuned artifacts if the submission/judging interpretation accepts the merged-model archive and local route support. Do not imply the public no-secret Space is serving the tuned model.
14
  - Organizer confirmation is still needed for the Omni 31B body-count versus 33B sidebar ambiguity and for any additive local stack or adapter-count interpretation.
15
 
16
  ## Parameter Ledger
@@ -20,6 +20,7 @@ Purpose: keep parameter, route, locality, adapter, ASR, and organizer-confirmati
20
  | Hosted Omni primary | `nvidia/Nemotron-3-Nano-Omni-30B-A3B-Reasoning-BF16`; API route `nvidia/nemotron-3-nano-omni-30b-a3b-reasoning` | NVIDIA model-card body: 31B total parameters; HF sidebar has been observed as 33B in planning docs | Roughly 3B active parameters per token is a runtime/MoE note, not the compliance number | None used in current evals | Native Omni speech encoder is part of the Omni model-card count; no separate ASR model is claimed for hosted Omni | Hosted NVIDIA API route in current evals; self-hosted no-cloud route not recorded | Pending: ask organizers whether model-card body count is acceptable if sidebar count differs | Baseline eval: 28/50 whole-output competence, 22/50 full fallback, 50/50 final validation. Follow-up eval: 31/50 competence, 8/50 full fallback, 480/650 model-retained fields, 170/650 deterministic patches, 50/50 final validation |
21
  | Self-hosted Omni no-cloud target | `nvidia/Nemotron-3-Nano-Omni-30B-A3B-Reasoning-BF16`, FP8, or NVFP4 variant if served locally | Same Omni 31B body-count claim, with same 33B sidebar ambiguity | Active parameters do not decide compliance | None recorded | Native Omni audio if used locally; included in Omni count if organizers accept the model-card count | Would be local/self-hosted only if served with no runtime cloud APIs | Pending for count ambiguity and hardware/runtime proof | No recorded no-cloud eval or public demo trace yet. Do not claim Off the Grid achieved |
22
  | Local 4B + Parakeet proof path | Text base: `nvidia/NVIDIA-Nemotron-3-Nano-4B-BF16`; tuned archive: `build-small-hackathon/figment-finetuned-model-archive`; ASR: `nvidia/parakeet-rnnt-1.1b`; local route `MODEL_BACKEND=llama_cpp`, `MODEL_STACK=local_4b_parakeet` | Workback model-card notes: 3.97B text model plus about 1.1B Parakeet, roughly 5.1B nominal before adapters | No active-parameter substitution; use additive total-count story if organizers require stack accounting | Published merged LoRA artifacts exist through `figment_sft_v14p`; exact adapter-only parameter count is not used as the primary public claim | About 1.1B for Parakeet RNNT ASR, only if real local ASR is enabled and proven | Intended local OpenAI-compatible endpoint serving the tuned GGUF plus local ASR; no-cloud only after recorded proof | Pending: confirm additive multi-model counting and adapter-count treatment | Full BF16 4B snapshot downloaded at repo revision `dfaf35de3e30f1867dd8dbc38a7fc9fb52d3914f`; `model.safetensors` is `7947142640` bytes with SHA-256 `55d4e2519456c4a9bddf596b0748d630e3b2ce6ff6f4c2b7ed3e07e2b00dad42`. Parakeet artifact downloaded at repo revision `a07b19e98a26c1873a3f2622c446a4a1ca6316cb`; `parakeet-rnnt-1.1b.nemo` is `4283105280` bytes with SHA-256 `535896f014953d945b287ac533560e20da8103c6781b152de4645528e2b60738`. The v14p repair-union measured result is 150/150 competence, 150/150 expected labels, 150/150 final validation, 0 deterministic patches, and 0 fallback on the corrected 150-case field-workflow holdout. No no-cloud local route proof, local ASR provider proof, or target-user trace is recorded yet |
 
23
  | 4B Figment tuned archive | `build-small-hackathon/figment-finetuned-model-archive`, especially `figment_sft_v14p/figment-sft-v14p-lora-merged-bf16/` and `figment_sft_v14p/figment-sft-v14p-lora-merged-bf16.bf16.gguf` | Base model is the 3.97B Nemotron 4B BF16 target; merged LoRA artifacts are derived from that base | Not applicable | Published as merged BF16 and GGUF artifacts with merge manifests; adapter-only count remains a documentation detail if needed by organizers | None for text-only eval | Public HF model repo plus local OpenAI-compatible app route support | Pending only for any organizer-specific adapter-count interpretation | Public model repo is `private=False`, current commit `7da772ec7c0de20011d42780ea8afa65af4aef70`, with v1 pilot plus v5-v14p artifacts. v14p model card records the repair-union result and GGUF SHA. |
24
  | Canned fallback | No live model | Not a model-compliance artifact | Not applicable | Not applicable | Not applicable | Local deterministic fallback; public Space no-secret fallback verified | Not applicable | Useful for safety, deployment health, and cold-start fallback only. Cannot count as model competence, Off the Grid proof, Llama Champion proof, or Well-Tuned proof |
25
 
@@ -27,7 +28,7 @@ Purpose: keep parameter, route, locality, adapter, ASR, and organizer-confirmati
27
 
28
  | Claim | Required upgrade evidence |
29
  | --- | --- |
30
- | Public Space runnable | Satisfied for no-secret canned-fallback mode: app files present, clean cold boot from the Space URL, and route/fallback labeling preserved. Non-canned public model traces remain separate proof. |
31
  | Hosted model load-bearing | Cite hosted eval metrics separately from final validation: 31/50 whole-output competence and 480/650 model-retained fields in the follow-up run |
32
  | <=32B hosted Omni compliance | Organizer accepts the 31B model-card body count or the submission falls back to a clearly eligible smaller route |
33
  | Off the Grid | Recorded no-cloud run with trace evidence, either self-hosted Omni or local 4B + Parakeet/typed intake |
 
6
 
7
  ## Current Claim Boundary
8
 
9
+ - Hosted Omni has measured eval evidence through the eval harness. The public Space proof is now live HF ZeroGPU v14p serving evidence, but it is not live hosted Omni generation evidence.
10
+ - The public Space target exists and runs on HF ZeroGPU. Current public API evidence on 2026-06-15: `runtime.stage=RUNNING`, `hardware=zero-a10g`, `MODEL_BACKEND=hf_zerogpu`, `MODEL_STACK=local_4b_parakeet`, and a synthetic `/run_navigator` route with `raw_route=hf_zerogpu`, `final_route=model_with_deterministic_patches`, and `validation_status=passed`.
11
  - The public model archive now records published measured Figment 4B LoRA merged artifacts through `figment_sft_v14p`. The strongest measured result is v14p repair-union on the corrected 150-case field-workflow holdout: 150/150 competence, 150/150 expected labels, 150/150 final validation, 0 deterministic patches, and 0 fallback. This is tuned model-system evidence, not no-cloud or clinical validation evidence.
12
  - The local 4B + Parakeet route is still the preferred no-cloud/off-grid proof path. The full BF16 4B artifact and Parakeet artifact are present locally, and the tuned v14p GGUF is published, but no-cloud route proof and local ASR provider proof are still separate gates.
13
+ - Well-Tuned wording may cite the published measured v14p tuned artifacts if the submission/judging interpretation accepts the merged-model archive and HF ZeroGPU/local route support. Keep deterministic patch use visible when citing public Space route checks.
14
  - Organizer confirmation is still needed for the Omni 31B body-count versus 33B sidebar ambiguity and for any additive local stack or adapter-count interpretation.
15
 
16
  ## Parameter Ledger
 
20
  | Hosted Omni primary | `nvidia/Nemotron-3-Nano-Omni-30B-A3B-Reasoning-BF16`; API route `nvidia/nemotron-3-nano-omni-30b-a3b-reasoning` | NVIDIA model-card body: 31B total parameters; HF sidebar has been observed as 33B in planning docs | Roughly 3B active parameters per token is a runtime/MoE note, not the compliance number | None used in current evals | Native Omni speech encoder is part of the Omni model-card count; no separate ASR model is claimed for hosted Omni | Hosted NVIDIA API route in current evals; self-hosted no-cloud route not recorded | Pending: ask organizers whether model-card body count is acceptable if sidebar count differs | Baseline eval: 28/50 whole-output competence, 22/50 full fallback, 50/50 final validation. Follow-up eval: 31/50 competence, 8/50 full fallback, 480/650 model-retained fields, 170/650 deterministic patches, 50/50 final validation |
21
  | Self-hosted Omni no-cloud target | `nvidia/Nemotron-3-Nano-Omni-30B-A3B-Reasoning-BF16`, FP8, or NVFP4 variant if served locally | Same Omni 31B body-count claim, with same 33B sidebar ambiguity | Active parameters do not decide compliance | None recorded | Native Omni audio if used locally; included in Omni count if organizers accept the model-card count | Would be local/self-hosted only if served with no runtime cloud APIs | Pending for count ambiguity and hardware/runtime proof | No recorded no-cloud eval or public demo trace yet. Do not claim Off the Grid achieved |
22
  | Local 4B + Parakeet proof path | Text base: `nvidia/NVIDIA-Nemotron-3-Nano-4B-BF16`; tuned archive: `build-small-hackathon/figment-finetuned-model-archive`; ASR: `nvidia/parakeet-rnnt-1.1b`; local route `MODEL_BACKEND=llama_cpp`, `MODEL_STACK=local_4b_parakeet` | Workback model-card notes: 3.97B text model plus about 1.1B Parakeet, roughly 5.1B nominal before adapters | No active-parameter substitution; use additive total-count story if organizers require stack accounting | Published merged LoRA artifacts exist through `figment_sft_v14p`; exact adapter-only parameter count is not used as the primary public claim | About 1.1B for Parakeet RNNT ASR, only if real local ASR is enabled and proven | Intended local OpenAI-compatible endpoint serving the tuned GGUF plus local ASR; no-cloud only after recorded proof | Pending: confirm additive multi-model counting and adapter-count treatment | Full BF16 4B snapshot downloaded at repo revision `dfaf35de3e30f1867dd8dbc38a7fc9fb52d3914f`; `model.safetensors` is `7947142640` bytes with SHA-256 `55d4e2519456c4a9bddf596b0748d630e3b2ce6ff6f4c2b7ed3e07e2b00dad42`. Parakeet artifact downloaded at repo revision `a07b19e98a26c1873a3f2622c446a4a1ca6316cb`; `parakeet-rnnt-1.1b.nemo` is `4283105280` bytes with SHA-256 `535896f014953d945b287ac533560e20da8103c6781b152de4645528e2b60738`. The v14p repair-union measured result is 150/150 competence, 150/150 expected labels, 150/150 final validation, 0 deterministic patches, and 0 fallback on the corrected 150-case field-workflow holdout. No no-cloud local route proof, local ASR provider proof, or target-user trace is recorded yet |
23
+ | HF ZeroGPU v14p + Parakeet ASR Space route | Text model: `build-small-hackathon/figment-finetuned-model-archive` subfolder `figment_sft_v14p/figment-sft-v14p-lora-merged-bf16`; ASR model: `nvidia/parakeet-ctc-1.1b` when `PARAKEET_ASR_RUNTIME=transformers` | 4B tuned text route plus about 1.1B Parakeet CTC ASR | No active-parameter substitution | Published merged LoRA artifacts exist through `figment_sft_v14p` | About 1.1B for Parakeet CTC ASR on the Space route | Hosted HF ZeroGPU, not no-cloud/off-grid | Pending only for any organizer-specific additive stack interpretation | The text route is live on `zero-a10g`; Parakeet ASR is implemented as gated draft intake and should be cited only after a live audio-draft route check or evidence bundle is recorded |
24
  | 4B Figment tuned archive | `build-small-hackathon/figment-finetuned-model-archive`, especially `figment_sft_v14p/figment-sft-v14p-lora-merged-bf16/` and `figment_sft_v14p/figment-sft-v14p-lora-merged-bf16.bf16.gguf` | Base model is the 3.97B Nemotron 4B BF16 target; merged LoRA artifacts are derived from that base | Not applicable | Published as merged BF16 and GGUF artifacts with merge manifests; adapter-only count remains a documentation detail if needed by organizers | None for text-only eval | Public HF model repo plus local OpenAI-compatible app route support | Pending only for any organizer-specific adapter-count interpretation | Public model repo is `private=False`, current commit `7da772ec7c0de20011d42780ea8afa65af4aef70`, with v1 pilot plus v5-v14p artifacts. v14p model card records the repair-union result and GGUF SHA. |
25
  | Canned fallback | No live model | Not a model-compliance artifact | Not applicable | Not applicable | Not applicable | Local deterministic fallback; public Space no-secret fallback verified | Not applicable | Useful for safety, deployment health, and cold-start fallback only. Cannot count as model competence, Off the Grid proof, Llama Champion proof, or Well-Tuned proof |
26
 
 
28
 
29
  | Claim | Required upgrade evidence |
30
  | --- | --- |
31
+ | Public Space runnable | Satisfied for HF ZeroGPU v14p: app files present, Space is `RUNNING` on `zero-a10g`, `/runtime` reports `MODEL_BACKEND=hf_zerogpu`, and a synthetic route check preserves fallback/patch labeling. |
32
  | Hosted model load-bearing | Cite hosted eval metrics separately from final validation: 31/50 whole-output competence and 480/650 model-retained fields in the follow-up run |
33
  | <=32B hosted Omni compliance | Organizer accepts the 31B model-card body count or the submission falls back to a clearly eligible smaller route |
34
  | Off the Grid | Recorded no-cloud run with trace evidence, either self-hosted Omni or local 4B + Parakeet/typed intake |
docs/submission_checklist.md CHANGED
@@ -22,7 +22,7 @@ Primary tracker: [adversarial review action items](adversarial-review-action-ite
22
  | No-cloud/off-grid trace | Proof needed before claiming Off the Grid achieved | Pending |
23
  | Hosted Omni eval results | Measured | [hosted_omni_eval_results.md](hosted_omni_eval_results.md): 31/50 whole-output competence, 8/50 full fallback, 480/650 model-retained fields, 170/650 deterministic patches, 50/50 final validation in the follow-up run |
24
  | 4B LoRA system eval results | Published and measured | v14p repair-union on the corrected 150-case field-workflow holdout: 150/150 competence, 150/150 expected labels, 150/150 final validation, 0 deterministic patches, 0 fallback; raw first-pass success is 146/150 and 4/150 close through focused model repair. This is model-system evidence, not no-cloud proof or clinical validation |
25
- | Local 4B + Parakeet no-cloud evidence | Helpers ready; proof needed | Full BF16 4B snapshot and Parakeet `.nemo` artifact are present locally; `scripts/run_local_4b_evidence.py` captures endpoint metadata, route smoke, eval records, eval summary, and `eval_evidence_manifest.json` once the local endpoint is live; `scripts/run_local_asr_evidence.py` captures Parakeet ASR provider evidence and `asr_evidence_manifest.json`. Pending no-cloud 50-case eval and real local ASR proof |
26
  | Parameter/evidence ledger | Present; organizer confirmation pending | [model_parameter_evidence_ledger.md](model_parameter_evidence_ledger.md) |
27
  | Submission claim audit | Present | `make audit-claims` scans submission-facing copy for premature Off the Grid, Llama Champion, Well-Tuned, Backyard user-use, local 4B, local ASR, demo-video, and social-post claims |
28
  | Evidence gate status report | Present; incomplete by design until external proofs exist | `make evidence-gates` reports each evidence gate, paths found, and next actions. Current missing gates are badge/demo/user-proof gates, not missing Hub repos: no-cloud route, Llama Champion route, local ASR provider proof, trained-responder user test, demo video, and social post |
@@ -52,7 +52,7 @@ The README may say the project is built for a real trained responder. It should
52
 
53
  ## Eval Evidence Boundary
54
 
55
- The hosted Omni eval proves model and fallback behavior through the eval harness. The public Space proof currently proves deployment health and no-secret fallback behavior, not live hosted Omni generation. Use the follow-up hosted eval run as the current hosted eval score: 31/50 whole-output hosted competence, 8/50 full fallback, 480/650 model-retained fields, 170/650 deterministic patches, and 50/50 final validation.
56
 
57
  The 4B LoRA model archive proves a published, measured tuned local-model artifact. Use the v14p repair-union result as the current small-model score: 150/150 competence, 150/150 expected labels, 150/150 final validation, 0 deterministic patches, and 0 fallback on the corrected 150-case field-workflow holdout. Do not convert that into Off the Grid, local ASR, target-user, or clinical-validation evidence.
58
 
 
22
  | No-cloud/off-grid trace | Proof needed before claiming Off the Grid achieved | Pending |
23
  | Hosted Omni eval results | Measured | [hosted_omni_eval_results.md](hosted_omni_eval_results.md): 31/50 whole-output competence, 8/50 full fallback, 480/650 model-retained fields, 170/650 deterministic patches, 50/50 final validation in the follow-up run |
24
  | 4B LoRA system eval results | Published and measured | v14p repair-union on the corrected 150-case field-workflow holdout: 150/150 competence, 150/150 expected labels, 150/150 final validation, 0 deterministic patches, 0 fallback; raw first-pass success is 146/150 and 4/150 close through focused model repair. This is model-system evidence, not no-cloud proof or clinical validation |
25
+ | Local 4B + Parakeet no-cloud evidence | Helpers ready; proof needed | Full BF16 4B snapshot and Parakeet `.nemo` artifact are present locally; `scripts/run_local_4b_evidence.py` captures endpoint metadata, route smoke, eval records, eval summary, and `eval_evidence_manifest.json` once the local endpoint is live; `scripts/run_local_asr_evidence.py --audio <source.wav> --transcribe-audio` captures Parakeet ASR provider evidence and `asr_evidence_manifest.json`. Pending no-cloud 50-case eval and real local ASR proof |
26
  | Parameter/evidence ledger | Present; organizer confirmation pending | [model_parameter_evidence_ledger.md](model_parameter_evidence_ledger.md) |
27
  | Submission claim audit | Present | `make audit-claims` scans submission-facing copy for premature Off the Grid, Llama Champion, Well-Tuned, Backyard user-use, local 4B, local ASR, demo-video, and social-post claims |
28
  | Evidence gate status report | Present; incomplete by design until external proofs exist | `make evidence-gates` reports each evidence gate, paths found, and next actions. Current missing gates are badge/demo/user-proof gates, not missing Hub repos: no-cloud route, Llama Champion route, local ASR provider proof, trained-responder user test, demo video, and social post |
 
52
 
53
  ## Eval Evidence Boundary
54
 
55
+ The hosted Omni eval proves model and fallback behavior through the eval harness. The public Space proof currently proves live HF ZeroGPU v14p serving and deployment health, not hosted Omni generation. Use the follow-up hosted eval run as the current hosted eval score: 31/50 whole-output hosted competence, 8/50 full fallback, 480/650 model-retained fields, 170/650 deterministic patches, and 50/50 final validation.
56
 
57
  The 4B LoRA model archive proves a published, measured tuned local-model artifact. Use the v14p repair-union result as the current small-model score: 150/150 competence, 150/150 expected labels, 150/150 final validation, 0 deterministic patches, and 0 fallback on the corrected 150-case field-workflow holdout. Do not convert that into Off the Grid, local ASR, target-user, or clinical-validation evidence.
58
 
figment/audio_intake.py CHANGED
@@ -16,7 +16,6 @@ from .config import (
16
  FigmentConfig,
17
  NVIDIA_NEMOTRON_3_NANO_4B_BF16_MODEL_ID,
18
  OMNI_MODEL_ID,
19
- PARAKEET_ASR_MODEL_ID,
20
  load_config,
21
  )
22
  from .schemas import AudioDraft, AudioFieldSuggestion
@@ -211,7 +210,7 @@ def draft_audio_intake(
211
  audio_model_id = OMNI_MODEL_ID
212
  draft_source = "omni_audio_provider"
213
  elif provider_payload_used and audio_enabled and _is_local_parakeet_backend(config):
214
- audio_model_id = PARAKEET_ASR_MODEL_ID
215
  field_fill_model_id = _local_field_fill_model_id(config)
216
  runtime = LOCAL_PARAKEET_RUNTIME
217
  path = LOCAL_PARAKEET_PATH
 
16
  FigmentConfig,
17
  NVIDIA_NEMOTRON_3_NANO_4B_BF16_MODEL_ID,
18
  OMNI_MODEL_ID,
 
19
  load_config,
20
  )
21
  from .schemas import AudioDraft, AudioFieldSuggestion
 
210
  audio_model_id = OMNI_MODEL_ID
211
  draft_source = "omni_audio_provider"
212
  elif provider_payload_used and audio_enabled and _is_local_parakeet_backend(config):
213
+ audio_model_id = config.audio_model_id
214
  field_fill_model_id = _local_field_fill_model_id(config)
215
  runtime = LOCAL_PARAKEET_RUNTIME
216
  path = LOCAL_PARAKEET_PATH
figment/config.py CHANGED
@@ -12,6 +12,7 @@ OMNI_FP8_MODEL_ID = "nvidia/Nemotron-3-Nano-Omni-30B-A3B-Reasoning-FP8"
12
  OMNI_NVFP4_MODEL_ID = "nvidia/Nemotron-3-Nano-Omni-30B-A3B-Reasoning-NVFP4"
13
  NVIDIA_NEMOTRON_3_NANO_4B_BF16_MODEL_ID = "nvidia/NVIDIA-Nemotron-3-Nano-4B-BF16"
14
  PARAKEET_ASR_MODEL_ID = "nvidia/parakeet-rnnt-1.1b"
 
15
  NVIDIA_OMNI_API_MODEL_ID = "nvidia/nemotron-3-nano-omni-30b-a3b-reasoning"
16
  NVIDIA_API_BASE_URL = "https://integrate.api.nvidia.com/v1"
17
  FIGMENT_CANNED_MODEL_ID = "figment-canned-deterministic"
@@ -91,6 +92,8 @@ class FigmentConfig:
91
  llama_base_url: str = "http://127.0.0.1:8001/v1"
92
  zerogpu_model_repo: str = FIGMENT_V14P_MODEL_REPO
93
  zerogpu_model_subfolder: str = FIGMENT_V14P_MODEL_SUBFOLDER
 
 
94
  trace_dir: Path = Path("traces")
95
 
96
  @classmethod
@@ -156,6 +159,9 @@ class FigmentConfig:
156
  or FIGMENT_V14P_MODEL_REPO,
157
  zerogpu_model_subfolder=os.getenv("ZEROGPU_MODEL_SUBFOLDER", FIGMENT_V14P_MODEL_SUBFOLDER).strip()
158
  or FIGMENT_V14P_MODEL_SUBFOLDER,
 
 
 
159
  trace_dir=Path(os.getenv("FIGMENT_TRACE_DIR", "traces").strip() or "traces"),
160
  ).validated()
161
 
@@ -179,6 +185,8 @@ class FigmentConfig:
179
  errors.append("AUDIO_BACKEND=parakeet_nemo requires ALLOW_LOCAL_ASR=true")
180
  if self.audio_backend == "parakeet_nemo" and self.model_stack != "local_4b_parakeet":
181
  errors.append("AUDIO_BACKEND=parakeet_nemo requires MODEL_STACK=local_4b_parakeet")
 
 
182
  errors.extend(
183
  _mode_consistency_errors(
184
  self.figment_mode,
@@ -211,7 +219,7 @@ class FigmentConfig:
211
  if self.audio_backend == "omni_native":
212
  return OMNI_MODEL_ID
213
  if self.audio_backend == "parakeet_nemo":
214
- return PARAKEET_ASR_MODEL_ID
215
  return None
216
 
217
  @property
 
12
  OMNI_NVFP4_MODEL_ID = "nvidia/Nemotron-3-Nano-Omni-30B-A3B-Reasoning-NVFP4"
13
  NVIDIA_NEMOTRON_3_NANO_4B_BF16_MODEL_ID = "nvidia/NVIDIA-Nemotron-3-Nano-4B-BF16"
14
  PARAKEET_ASR_MODEL_ID = "nvidia/parakeet-rnnt-1.1b"
15
+ PARAKEET_TRANSFORMERS_CTC_MODEL_ID = "nvidia/parakeet-ctc-1.1b"
16
  NVIDIA_OMNI_API_MODEL_ID = "nvidia/nemotron-3-nano-omni-30b-a3b-reasoning"
17
  NVIDIA_API_BASE_URL = "https://integrate.api.nvidia.com/v1"
18
  FIGMENT_CANNED_MODEL_ID = "figment-canned-deterministic"
 
92
  llama_base_url: str = "http://127.0.0.1:8001/v1"
93
  zerogpu_model_repo: str = FIGMENT_V14P_MODEL_REPO
94
  zerogpu_model_subfolder: str = FIGMENT_V14P_MODEL_SUBFOLDER
95
+ parakeet_asr_model_id: str = PARAKEET_ASR_MODEL_ID
96
+ parakeet_asr_runtime: str = "auto"
97
  trace_dir: Path = Path("traces")
98
 
99
  @classmethod
 
159
  or FIGMENT_V14P_MODEL_REPO,
160
  zerogpu_model_subfolder=os.getenv("ZEROGPU_MODEL_SUBFOLDER", FIGMENT_V14P_MODEL_SUBFOLDER).strip()
161
  or FIGMENT_V14P_MODEL_SUBFOLDER,
162
+ parakeet_asr_model_id=os.getenv("PARAKEET_ASR_MODEL_ID", PARAKEET_ASR_MODEL_ID).strip()
163
+ or PARAKEET_ASR_MODEL_ID,
164
+ parakeet_asr_runtime=os.getenv("PARAKEET_ASR_RUNTIME", "auto").strip().lower() or "auto",
165
  trace_dir=Path(os.getenv("FIGMENT_TRACE_DIR", "traces").strip() or "traces"),
166
  ).validated()
167
 
 
185
  errors.append("AUDIO_BACKEND=parakeet_nemo requires ALLOW_LOCAL_ASR=true")
186
  if self.audio_backend == "parakeet_nemo" and self.model_stack != "local_4b_parakeet":
187
  errors.append("AUDIO_BACKEND=parakeet_nemo requires MODEL_STACK=local_4b_parakeet")
188
+ if self.parakeet_asr_runtime not in {"auto", "nemo", "transformers"}:
189
+ errors.append("PARAKEET_ASR_RUNTIME must be one of ['auto', 'nemo', 'transformers']")
190
  errors.extend(
191
  _mode_consistency_errors(
192
  self.figment_mode,
 
219
  if self.audio_backend == "omni_native":
220
  return OMNI_MODEL_ID
221
  if self.audio_backend == "parakeet_nemo":
222
+ return self.parakeet_asr_model_id
223
  return None
224
 
225
  @property
figment/parakeet_asr.py ADDED
@@ -0,0 +1,191 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Parakeet ASR adapters for Figment audio draft intake."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from functools import lru_cache
6
+ import os
7
+ from pathlib import Path
8
+ import threading
9
+ from typing import Any
10
+ from contextlib import suppress
11
+ import wave
12
+
13
+ from .config import FigmentConfig, PARAKEET_ASR_MODEL_ID
14
+
15
+
16
+ PARAKEET_TRANSFORMERS_CTC_MODEL_ID = "nvidia/parakeet-ctc-1.1b"
17
+ LOCAL_ASR_MAX_BYTES = int(os.getenv("PARAKEET_ASR_MAX_BYTES", str(25 * 1024 * 1024)))
18
+ LOCAL_ASR_MAX_SECONDS = float(os.getenv("PARAKEET_ASR_MAX_SECONDS", "120"))
19
+
20
+
21
+ try: # pragma: no cover - exercised on Hugging Face Spaces.
22
+ import spaces
23
+ except ImportError: # pragma: no cover - local tests run without spaces.
24
+
25
+ class _SpacesCompat:
26
+ @staticmethod
27
+ def GPU(**_kwargs: Any):
28
+ def decorator(func):
29
+ return func
30
+
31
+ return decorator
32
+
33
+ spaces = _SpacesCompat()
34
+
35
+
36
+ class ParakeetAsrError(RuntimeError):
37
+ """Raised when Parakeet cannot produce a usable transcript."""
38
+
39
+
40
+ @spaces.GPU(
41
+ duration=int(os.getenv("PARAKEET_ASR_DURATION_SECONDS", os.getenv("ZEROGPU_DURATION_SECONDS", "60"))),
42
+ size=os.getenv("PARAKEET_ASR_SIZE", os.getenv("ZEROGPU_SIZE", "large")),
43
+ )
44
+ def transcribe_audio_with_parakeet(audio_file: str, *, config: FigmentConfig) -> dict[str, Any]:
45
+ """Return a Figment provider payload from a local or ZeroGPU Parakeet ASR run."""
46
+
47
+ validate_parakeet_audio_file(audio_file)
48
+ model_id = getattr(config, "parakeet_asr_model_id", PARAKEET_ASR_MODEL_ID) or PARAKEET_ASR_MODEL_ID
49
+ runtime_name = getattr(config, "parakeet_asr_runtime", "auto") or "auto"
50
+ runtime = _runtime_for(runtime_name=runtime_name, model_id=model_id)
51
+ transcript = _clean_transcript(runtime.transcribe(audio_file))
52
+ if not transcript:
53
+ raise ParakeetAsrError("Parakeet ASR returned an empty transcript")
54
+ return {
55
+ "transcript": transcript,
56
+ "suggested_fields": [],
57
+ "missing_or_unclear_fields": [],
58
+ "provisional_red_flag_mentions": [],
59
+ "provider_metadata": {
60
+ "asr_model_id": model_id,
61
+ "asr_runtime": runtime.runtime_name,
62
+ "raw_audio_stored": False,
63
+ },
64
+ }
65
+
66
+
67
+ def validate_parakeet_audio_file(audio_file: str) -> None:
68
+ path = Path(audio_file)
69
+ if not path.exists():
70
+ raise ParakeetAsrError(f"audio file does not exist: {audio_file}")
71
+ size = path.stat().st_size
72
+ if size > LOCAL_ASR_MAX_BYTES:
73
+ raise ParakeetAsrError(
74
+ f"audio file exceeds Parakeet ASR size limit: {size} bytes > {LOCAL_ASR_MAX_BYTES} bytes"
75
+ )
76
+ duration = _wav_duration_seconds(path)
77
+ if duration is not None and duration > LOCAL_ASR_MAX_SECONDS:
78
+ raise ParakeetAsrError(
79
+ f"audio file exceeds Parakeet ASR duration limit: {duration:.1f}s > {LOCAL_ASR_MAX_SECONDS:.1f}s"
80
+ )
81
+
82
+
83
+ def parakeet_audio_limits_text() -> str:
84
+ mb = LOCAL_ASR_MAX_BYTES / (1024 * 1024)
85
+ return f"{mb:.0f} MB, {LOCAL_ASR_MAX_SECONDS:.0f} seconds"
86
+
87
+
88
+ def _wav_duration_seconds(path: Path) -> float | None:
89
+ with suppress(wave.Error, OSError, EOFError):
90
+ with wave.open(str(path), "rb") as wav:
91
+ rate = wav.getframerate()
92
+ if not rate:
93
+ return None
94
+ return wav.getnframes() / rate
95
+ return None
96
+
97
+
98
+ def _clean_transcript(value: Any) -> str:
99
+ if isinstance(value, str):
100
+ return value.strip()
101
+ return str(value or "").strip()
102
+
103
+
104
+ @lru_cache(maxsize=8)
105
+ def _runtime_for(*, runtime_name: str, model_id: str):
106
+ normalized = runtime_name.strip().lower()
107
+ if normalized not in {"auto", "nemo", "transformers"}:
108
+ raise ParakeetAsrError("PARAKEET_ASR_RUNTIME must be one of auto, nemo, transformers")
109
+ if normalized == "nemo":
110
+ return _NemoParakeetRuntime(model_id)
111
+ if normalized == "transformers":
112
+ return _TransformersParakeetRuntime(model_id)
113
+ if model_id == PARAKEET_ASR_MODEL_ID:
114
+ try:
115
+ return _NemoParakeetRuntime(model_id)
116
+ except ParakeetAsrError as exc:
117
+ raise ParakeetAsrError(
118
+ f"{model_id} is a NeMo .nemo checkpoint; install NeMo or set "
119
+ f"PARAKEET_ASR_MODEL_ID={PARAKEET_TRANSFORMERS_CTC_MODEL_ID} with "
120
+ "PARAKEET_ASR_RUNTIME=transformers"
121
+ ) from exc
122
+ return _TransformersParakeetRuntime(model_id)
123
+
124
+
125
+ class _NemoParakeetRuntime:
126
+ runtime_name = "nemo"
127
+
128
+ def __init__(self, model_id: str) -> None:
129
+ self.model_id = model_id
130
+ self.lock = threading.Lock()
131
+ try:
132
+ import nemo.collections.asr as nemo_asr
133
+ except Exception as exc: # pragma: no cover - NeMo is optional in local CI.
134
+ raise ParakeetAsrError(f"NeMo ASR is unavailable: {exc}") from exc
135
+ try:
136
+ if Path(model_id).exists():
137
+ self.model = nemo_asr.models.ASRModel.restore_from(restore_path=model_id)
138
+ else:
139
+ self.model = nemo_asr.models.ASRModel.from_pretrained(model_name=model_id)
140
+ with suppress(Exception):
141
+ self.model.eval()
142
+ except Exception as exc: # pragma: no cover - heavyweight model path.
143
+ raise ParakeetAsrError(f"failed to load NeMo Parakeet model {model_id}: {exc}") from exc
144
+
145
+ def transcribe(self, audio_file: str) -> str:
146
+ with self.lock:
147
+ try:
148
+ result = self.model.transcribe([audio_file])
149
+ except Exception as exc: # pragma: no cover - heavyweight model path.
150
+ raise ParakeetAsrError(f"NeMo Parakeet transcription failed: {exc}") from exc
151
+ return _transcription_text(result)
152
+
153
+
154
+ class _TransformersParakeetRuntime:
155
+ runtime_name = "transformers"
156
+
157
+ def __init__(self, model_id: str) -> None:
158
+ self.model_id = model_id
159
+ self.lock = threading.Lock()
160
+ try:
161
+ import torch
162
+ from transformers import pipeline
163
+ except Exception as exc:
164
+ raise ParakeetAsrError(f"Transformers ASR dependencies are unavailable: {exc}") from exc
165
+ device = 0 if torch.cuda.is_available() else -1
166
+ kwargs: dict[str, Any] = {"model": model_id, "device": device}
167
+ try:
168
+ self.pipeline = pipeline("automatic-speech-recognition", **kwargs)
169
+ except Exception as exc:
170
+ raise ParakeetAsrError(f"failed to load Transformers Parakeet model {model_id}: {exc}") from exc
171
+
172
+ def transcribe(self, audio_file: str) -> str:
173
+ with self.lock:
174
+ try:
175
+ result = self.pipeline(audio_file)
176
+ except Exception as exc:
177
+ raise ParakeetAsrError(f"Transformers Parakeet transcription failed: {exc}") from exc
178
+ return _transcription_text(result)
179
+
180
+
181
+ def _transcription_text(result: Any) -> str:
182
+ if isinstance(result, list):
183
+ if not result:
184
+ return ""
185
+ return _transcription_text(result[0])
186
+ if isinstance(result, dict):
187
+ return _clean_transcript(result.get("text") or result.get("transcript"))
188
+ text = getattr(result, "text", None)
189
+ if text is not None:
190
+ return _clean_transcript(text)
191
+ return _clean_transcript(result)