suvradeepp commited on
Commit
d782513
·
verified ·
1 Parent(s): f7e8732

Publish Tiny Hinglish Turn Detector development preview

Browse files

release inventory sha256: f381f906d00c3963b2975bf84b770ea4954880fdc834c2e981dcf4a25f914d8b

MODEL_CARD.md CHANGED
@@ -303,7 +303,7 @@ failure aggregates, silence perturbation report, exact environment files, CPU
303
  benchmarks, and guarded release tooling. Per-example validation predictions and
304
  the text-bearing split manifest remain in the private local workspace; the
305
  public package contains aggregate reports and hashes, not those sensitive rows.
306
- The quality gate completed with Ruff 0.15.16 passing and 130/130 automated tests
307
  passing via Python `unittest` discovery. The configured Hugging Face owner is
308
  `suvradeepp`.
309
 
 
303
  benchmarks, and guarded release tooling. Per-example validation predictions and
304
  the text-bearing split manifest remain in the private local workspace; the
305
  public package contains aggregate reports and hashes, not those sensitive rows.
306
+ The quality gate completed with Ruff 0.15.16 passing and 131/131 automated tests
307
  passing via Python `unittest` discovery. The configured Hugging Face owner is
308
  `suvradeepp`.
309
 
README.md CHANGED
@@ -303,7 +303,7 @@ failure aggregates, silence perturbation report, exact environment files, CPU
303
  benchmarks, and guarded release tooling. Per-example validation predictions and
304
  the text-bearing split manifest remain in the private local workspace; the
305
  public package contains aggregate reports and hashes, not those sensitive rows.
306
- The quality gate completed with Ruff 0.15.16 passing and 130/130 automated tests
307
  passing via Python `unittest` discovery. The configured Hugging Face owner is
308
  `suvradeepp`.
309
 
 
303
  benchmarks, and guarded release tooling. Per-example validation predictions and
304
  the text-bearing split manifest remain in the private local workspace; the
305
  public package contains aggregate reports and hashes, not those sensitive rows.
306
+ The quality gate completed with Ruff 0.15.16 passing and 131/131 automated tests
307
  passing via Python `unittest` discovery. The configured Hugging Face owner is
308
  `suvradeepp`.
309
 
REPORT.md CHANGED
@@ -525,8 +525,8 @@ calendar days or the missing external data collection occurred.
525
  | 13 | Integrate controller and demo | replay, three-state controller, Gradio, Hinglish recording prompts | Preview model and synthetic controller integration complete; real sequence replay pending |
526
  | 14 | Freeze test, package, publish | sealed-test guard, atomic release builder, exact-mirror publisher | Development packaging path ready; official-test/final gates not satisfied |
527
 
528
- The repository quality gate passed Ruff 0.15.16 and all 130 automated tests
529
- (130 passed via Python `unittest` discovery). That validates the implemented behavior under test; it does not fill
530
  the missing empirical datasets or rights review.
531
 
532
  ## 9. Decision log and next experiments
 
525
  | 13 | Integrate controller and demo | replay, three-state controller, Gradio, Hinglish recording prompts | Preview model and synthetic controller integration complete; real sequence replay pending |
526
  | 14 | Freeze test, package, publish | sealed-test guard, atomic release builder, exact-mirror publisher | Development packaging path ready; official-test/final gates not satisfied |
527
 
528
+ The repository quality gate passed Ruff 0.15.16 and all 131 automated tests
529
+ (131 passed via Python `unittest` discovery). That validates the implemented behavior under test; it does not fill
530
  the missing empirical datasets or rights review.
531
 
532
  ## 9. Decision log and next experiments
SOURCE_README.md CHANGED
@@ -26,7 +26,7 @@ engineering evidence, not a production-readiness claim.
26
  | Domain-shift stress | Measured, confounded | Source-held-out AP 0.5500/0.5368 for TinyTCN/baseline; both near chance in ranking, with wide nine-source bootstrap intervals |
27
  | Runtime/export | Measured | 611 KiB FP32 ONNX; exact PyTorch/ONNX parity; ONNX p95 0.956 ms neural-only and 1.629 ms waveform-to-probability |
28
  | Controller integration | Synthetic only | Metadata-bound 8-checkpoint/3-turn fixture emits 3 response edges with 0 duplicates; not model or product-quality evidence |
29
- | Code quality gate | Passed | Ruff 0.15.16; 130/130 automated tests passed via `unittest` discovery |
30
  | Accuracy/generalization | **Not established** | No full-corpus run, collected Hinglish recordings, real conversation replay, or official-test evaluation |
31
  | Hugging Face publication | Not claimed here | Local guarded release/publisher path exists; verify any remote publication separately |
32
 
 
26
  | Domain-shift stress | Measured, confounded | Source-held-out AP 0.5500/0.5368 for TinyTCN/baseline; both near chance in ranking, with wide nine-source bootstrap intervals |
27
  | Runtime/export | Measured | 611 KiB FP32 ONNX; exact PyTorch/ONNX parity; ONNX p95 0.956 ms neural-only and 1.629 ms waveform-to-probability |
28
  | Controller integration | Synthetic only | Metadata-bound 8-checkpoint/3-turn fixture emits 3 response edges with 0 duplicates; not model or product-quality evidence |
29
+ | Code quality gate | Passed | Ruff 0.15.16; 131/131 automated tests passed via `unittest` discovery |
30
  | Accuracy/generalization | **Not established** | No full-corpus run, collected Hinglish recordings, real conversation replay, or official-test evaluation |
31
  | Hugging Face publication | Not claimed here | Local guarded release/publisher path exists; verify any remote publication separately |
32
 
export_manifest.json CHANGED
@@ -126,9 +126,9 @@
126
  "sha256": "146763ebbe4d4ca0858c3fda2f56aa235aa9a4b6686b3216bcea58d148945d04"
127
  },
128
  {
129
- "bytes": 37627,
130
  "path": "scripts/build_release.py",
131
- "sha256": "c7b6fbca43fb28bf8f1835287f647954f5b5adf5877cddb0a8ee728315878117"
132
  },
133
  {
134
  "bytes": 10147,
@@ -196,9 +196,9 @@
196
  "sha256": "40569f1e553f0cb340cf81414e072839ca734a7d303c5cb5f1e46c5035590804"
197
  },
198
  {
199
- "bytes": 66,
200
  "path": "space/requirements.txt",
201
- "sha256": "44a1657dc82cbc10dabf766dfa64ff0cdcd773a99b5ee0303e11e34fe76bdce6"
202
  },
203
  {
204
  "bytes": 160,
@@ -371,7 +371,7 @@
371
  "sha256": "da0eac829fe43615f7bb149998c2f2762f148790fb0c14d4ba6db4d6b25298f4"
372
  }
373
  ],
374
- "source_inventory_sha256": "259931c509dc4abd54a3c5c72ca12948449bd19d3aed2b2c2ea0fac88a6a705b",
375
  "task": "audio-turn-end-detection",
376
  "threshold": 0.741000771522522,
377
  "training_data": {
 
126
  "sha256": "146763ebbe4d4ca0858c3fda2f56aa235aa9a4b6686b3216bcea58d148945d04"
127
  },
128
  {
129
+ "bytes": 40091,
130
  "path": "scripts/build_release.py",
131
+ "sha256": "07963aacb56af58add680f0a011dc58baefa24355e127b2dc0f10c018bde9525"
132
  },
133
  {
134
  "bytes": 10147,
 
196
  "sha256": "40569f1e553f0cb340cf81414e072839ca734a7d303c5cb5f1e46c5035590804"
197
  },
198
  {
199
+ "bytes": 51,
200
  "path": "space/requirements.txt",
201
+ "sha256": "7b99ddd361d3626972bc819c85237ee929b6c579fa70b66d845ef88dd8bda7e7"
202
  },
203
  {
204
  "bytes": 160,
 
371
  "sha256": "da0eac829fe43615f7bb149998c2f2762f148790fb0c14d4ba6db4d6b25298f4"
372
  }
373
  ],
374
+ "source_inventory_sha256": "e4f7592fd12f2fa89ff838df39dbb7ce487edf50ed439e8a17098e03cb71a6ab",
375
  "task": "audio-turn-end-detection",
376
  "threshold": 0.741000771522522,
377
  "training_data": {
release_provenance.json CHANGED
@@ -16,7 +16,7 @@
16
  },
17
  "MODEL_CARD.md": {
18
  "bytes": 14805,
19
- "sha256": "6add0853cdc0f09ff1abb594149c59e9d53f29ab4dba5de52bed7278cfb13c1b"
20
  },
21
  "Makefile": {
22
  "bytes": 777,
@@ -28,15 +28,15 @@
28
  },
29
  "README.md": {
30
  "bytes": 14805,
31
- "sha256": "6add0853cdc0f09ff1abb594149c59e9d53f29ab4dba5de52bed7278cfb13c1b"
32
  },
33
  "REPORT.md": {
34
  "bytes": 32272,
35
- "sha256": "9205011a4c547b8cf537d5b3538d25f1b8a9545c9bb020694f6d94deb26683f7"
36
  },
37
  "SOURCE_README.md": {
38
  "bytes": 20535,
39
- "sha256": "64539b78efae390a42ca19a718b8e7354327826fff81dc6c1a9c7841b11132e0"
40
  },
41
  "app.py": {
42
  "bytes": 10381,
@@ -108,7 +108,7 @@
108
  },
109
  "export_manifest.json": {
110
  "bytes": 12430,
111
- "sha256": "1f70d8ec79c9c2430c9d3a16942f51254202279c984048e02a781a33313f242b"
112
  },
113
  "model.onnx": {
114
  "bytes": 625431,
@@ -247,8 +247,8 @@
247
  "sha256": "146763ebbe4d4ca0858c3fda2f56aa235aa9a4b6686b3216bcea58d148945d04"
248
  },
249
  "scripts/build_release.py": {
250
- "bytes": 37627,
251
- "sha256": "c7b6fbca43fb28bf8f1835287f647954f5b5adf5877cddb0a8ee728315878117"
252
  },
253
  "scripts/compare_models.py": {
254
  "bytes": 10147,
@@ -303,8 +303,8 @@
303
  "sha256": "40569f1e553f0cb340cf81414e072839ca734a7d303c5cb5f1e46c5035590804"
304
  },
305
  "space/requirements.txt": {
306
- "bytes": 66,
307
- "sha256": "44a1657dc82cbc10dabf766dfa64ff0cdcd773a99b5ee0303e11e34fe76bdce6"
308
  },
309
  "src/turn_detection/__init__.py": {
310
  "bytes": 160,
@@ -531,8 +531,8 @@
531
  "sha256": "5af81ad7995b6bfd3816b7d97ee1226027659dc5b8a7cb4fe4376fa850dcd14e"
532
  },
533
  "tests/test_release_guardrails.py": {
534
- "bytes": 17399,
535
- "sha256": "8f7cccb7345be11943361808f6ff4b4e9e9ca2297bdac16312c6ae3240cfc9b0"
536
  },
537
  "tests/test_runtime_controller.py": {
538
  "bytes": 3086,
@@ -566,15 +566,15 @@
566
  },
567
  "MODEL_CARD.md": {
568
  "bytes": 14805,
569
- "sha256": "6add0853cdc0f09ff1abb594149c59e9d53f29ab4dba5de52bed7278cfb13c1b"
570
  },
571
  "NOTICE": {
572
  "bytes": 563,
573
  "sha256": "aee9451763081ff03b717ba3b821b52f0a57eac9e1c7689817b9d41e6317b36c"
574
  },
575
  "README.md": {
576
- "bytes": 1325,
577
- "sha256": "26d2cc8f3eaebd4fd91a9406005724ac4c6f47de871eedcbd1051815d014b5db"
578
  },
579
  "app.py": {
580
  "bytes": 10381,
@@ -589,8 +589,8 @@
589
  "sha256": "43636ad5efb642138c281a4582e85f19b5aae2f4f6cca69211169341ae4399b4"
590
  },
591
  "requirements.txt": {
592
- "bytes": 66,
593
- "sha256": "44a1657dc82cbc10dabf766dfa64ff0cdcd773a99b5ee0303e11e34fe76bdce6"
594
  },
595
  "src/turn_detection/__init__.py": {
596
  "bytes": 160,
@@ -626,5 +626,5 @@
626
  "metrics_file": "development_metrics.json",
627
  "metrics_scope": "development",
628
  "model_file": "model.onnx",
629
- "source_and_artifact_inventory_sha256": "4c327046a4f44513d65a2a920a67566c646bf9c82e1f770a7f1ee6614006a47e"
630
  }
 
16
  },
17
  "MODEL_CARD.md": {
18
  "bytes": 14805,
19
+ "sha256": "05162a2792ee71d642605d87bef18089cf5f57b52e6a9b32e6d34cbd26789b29"
20
  },
21
  "Makefile": {
22
  "bytes": 777,
 
28
  },
29
  "README.md": {
30
  "bytes": 14805,
31
+ "sha256": "05162a2792ee71d642605d87bef18089cf5f57b52e6a9b32e6d34cbd26789b29"
32
  },
33
  "REPORT.md": {
34
  "bytes": 32272,
35
+ "sha256": "40284013cd8d435f624464b5e9f7a3427f41a9a6410a5ae917ef34863a9a95b1"
36
  },
37
  "SOURCE_README.md": {
38
  "bytes": 20535,
39
+ "sha256": "e74584ad5bc721c333d83346d9ee25e4f9a22c4c31f8efcf3ef30089dd3f8d0c"
40
  },
41
  "app.py": {
42
  "bytes": 10381,
 
108
  },
109
  "export_manifest.json": {
110
  "bytes": 12430,
111
+ "sha256": "7a5ec279128eeb68095467b00fd4c1ef5a644876f5a77867dcefbf81e20d99b8"
112
  },
113
  "model.onnx": {
114
  "bytes": 625431,
 
247
  "sha256": "146763ebbe4d4ca0858c3fda2f56aa235aa9a4b6686b3216bcea58d148945d04"
248
  },
249
  "scripts/build_release.py": {
250
+ "bytes": 40091,
251
+ "sha256": "07963aacb56af58add680f0a011dc58baefa24355e127b2dc0f10c018bde9525"
252
  },
253
  "scripts/compare_models.py": {
254
  "bytes": 10147,
 
303
  "sha256": "40569f1e553f0cb340cf81414e072839ca734a7d303c5cb5f1e46c5035590804"
304
  },
305
  "space/requirements.txt": {
306
+ "bytes": 51,
307
+ "sha256": "7b99ddd361d3626972bc819c85237ee929b6c579fa70b66d845ef88dd8bda7e7"
308
  },
309
  "src/turn_detection/__init__.py": {
310
  "bytes": 160,
 
531
  "sha256": "5af81ad7995b6bfd3816b7d97ee1226027659dc5b8a7cb4fe4376fa850dcd14e"
532
  },
533
  "tests/test_release_guardrails.py": {
534
+ "bytes": 18405,
535
+ "sha256": "bc94fd488aadb1859172e9cdd803f4b7cb828d8884e79b1899286019af28af19"
536
  },
537
  "tests/test_runtime_controller.py": {
538
  "bytes": 3086,
 
566
  },
567
  "MODEL_CARD.md": {
568
  "bytes": 14805,
569
+ "sha256": "05162a2792ee71d642605d87bef18089cf5f57b52e6a9b32e6d34cbd26789b29"
570
  },
571
  "NOTICE": {
572
  "bytes": 563,
573
  "sha256": "aee9451763081ff03b717ba3b821b52f0a57eac9e1c7689817b9d41e6317b36c"
574
  },
575
  "README.md": {
576
+ "bytes": 1314,
577
+ "sha256": "37e7617fceca4ee6196d2875b2cbda5e3211dd825f8c1b4a610a5a59fe2bf89c"
578
  },
579
  "app.py": {
580
  "bytes": 10381,
 
589
  "sha256": "43636ad5efb642138c281a4582e85f19b5aae2f4f6cca69211169341ae4399b4"
590
  },
591
  "requirements.txt": {
592
+ "bytes": 51,
593
+ "sha256": "7b99ddd361d3626972bc819c85237ee929b6c579fa70b66d845ef88dd8bda7e7"
594
  },
595
  "src/turn_detection/__init__.py": {
596
  "bytes": 160,
 
626
  "metrics_file": "development_metrics.json",
627
  "metrics_scope": "development",
628
  "model_file": "model.onnx",
629
+ "source_and_artifact_inventory_sha256": "1ef74a0b13c1cf68a4b96090911ca715e9bdfc2917bcfc4ac8483fc20d1d786a"
630
  }
scripts/build_release.py CHANGED
@@ -19,6 +19,11 @@ SOURCE_ROOT = ROOT / "src"
19
  if str(SOURCE_ROOT) not in sys.path:
20
  sys.path.insert(0, str(SOURCE_ROOT))
21
 
 
 
 
 
 
22
 
23
  def parse_args() -> argparse.Namespace:
24
  parser = argparse.ArgumentParser(description=__doc__)
@@ -61,6 +66,59 @@ def _copy_file(source: Path, destination: Path) -> None:
61
  shutil.copy2(source, destination)
62
 
63
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
64
  def _copy_runtime(destination: Path) -> None:
65
  package_root = destination / "src" / "turn_detection"
66
  package_root.mkdir(parents=True, exist_ok=True)
@@ -694,6 +752,7 @@ def main() -> int:
694
  ROOT / "reports" / "controller_replay_integration.summary.json",
695
  metadata.get("controller"),
696
  )
 
697
 
698
  frozen_manifest: dict | None = None
699
  if not metadata_is_development:
 
19
  if str(SOURCE_ROOT) not in sys.path:
20
  sys.path.insert(0, str(SOURCE_ROOT))
21
 
22
+ _SPACE_CARD_COLORS = frozenset(
23
+ {"red", "yellow", "green", "blue", "indigo", "purple", "pink", "gray"}
24
+ )
25
+ _SPACE_SHORT_DESCRIPTION_MAX_LENGTH = 60
26
+
27
 
28
  def parse_args() -> argparse.Namespace:
29
  parser = argparse.ArgumentParser(description=__doc__)
 
66
  shutil.copy2(source, destination)
67
 
68
 
69
+ def _space_card_frontmatter(path: Path) -> dict[str, str]:
70
+ """Parse the scalar fields used by the packaged Hugging Face Space card."""
71
+
72
+ try:
73
+ lines = path.read_text(encoding="utf-8").splitlines()
74
+ except OSError as exc:
75
+ raise SystemExit(f"Space README is unreadable: {path}") from exc
76
+ if not lines or lines[0].strip() != "---":
77
+ raise SystemExit("Space README must start with YAML frontmatter")
78
+ try:
79
+ closing_index = next(
80
+ index for index, line in enumerate(lines[1:], start=1) if line.strip() == "---"
81
+ )
82
+ except StopIteration as exc:
83
+ raise SystemExit("Space README frontmatter is not closed") from exc
84
+
85
+ metadata: dict[str, str] = {}
86
+ for line in lines[1:closing_index]:
87
+ stripped = line.strip()
88
+ if not stripped or stripped.startswith("#"):
89
+ continue
90
+ if ":" not in stripped:
91
+ raise SystemExit("Space README frontmatter must contain scalar key/value pairs")
92
+ key, value = stripped.split(":", 1)
93
+ key = key.strip()
94
+ value = value.strip().strip("'\"")
95
+ if not key or key in metadata:
96
+ raise SystemExit(f"Space README has an invalid or duplicate metadata key: {key!r}")
97
+ metadata[key] = value
98
+ return metadata
99
+
100
+
101
+ def _validate_space_card(path: Path) -> None:
102
+ metadata = _space_card_frontmatter(path)
103
+ if metadata.get("sdk") != "gradio":
104
+ raise SystemExit("Space README sdk must be 'gradio'")
105
+ if metadata.get("app_file") != "app.py":
106
+ raise SystemExit("Space README app_file must be 'app.py'")
107
+ for field in ("colorFrom", "colorTo"):
108
+ color = metadata.get(field)
109
+ if color not in _SPACE_CARD_COLORS:
110
+ allowed = ", ".join(sorted(_SPACE_CARD_COLORS))
111
+ raise SystemExit(f"Space README {field} must be one of: {allowed}")
112
+ short_description = metadata.get("short_description", "")
113
+ if not short_description:
114
+ raise SystemExit("Space README short_description must be non-empty")
115
+ if len(short_description) > _SPACE_SHORT_DESCRIPTION_MAX_LENGTH:
116
+ raise SystemExit(
117
+ "Space README short_description must be at most "
118
+ f"{_SPACE_SHORT_DESCRIPTION_MAX_LENGTH} characters"
119
+ )
120
+
121
+
122
  def _copy_runtime(destination: Path) -> None:
123
  package_root = destination / "src" / "turn_detection"
124
  package_root.mkdir(parents=True, exist_ok=True)
 
752
  ROOT / "reports" / "controller_replay_integration.summary.json",
753
  metadata.get("controller"),
754
  )
755
+ _validate_space_card(ROOT / "space" / "README.md")
756
 
757
  frozen_manifest: dict | None = None
758
  if not metadata_is_development:
space/requirements.txt CHANGED
@@ -1,4 +1,3 @@
1
- gradio==5.49.1
2
  numpy==2.3.5
3
  onnxruntime==1.26.0
4
  soundfile==0.14.0
 
 
1
  numpy==2.3.5
2
  onnxruntime==1.26.0
3
  soundfile==0.14.0
tests/test_release_guardrails.py CHANGED
@@ -85,6 +85,37 @@ class ReleaseGuardrailTest(unittest.TestCase):
85
  self.assertTrue((destination / "new.txt").is_file())
86
  self.assertFalse((destination / "old.txt").exists())
87
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
88
  def test_synthetic_replay_must_be_labelled_and_hash_bound(self) -> None:
89
  from scripts.build_release import _validate_synthetic_replay
90
 
 
85
  self.assertTrue((destination / "new.txt").is_file())
86
  self.assertFalse((destination / "old.txt").exists())
87
 
88
+ def test_space_card_rejects_server_invalid_frontmatter(self) -> None:
89
+ from scripts.build_release import _validate_space_card
90
+
91
+ valid = """---
92
+ title: Test Space
93
+ colorFrom: yellow
94
+ colorTo: indigo
95
+ sdk: gradio
96
+ app_file: app.py
97
+ short_description: Tiny endpoint detector
98
+ ---
99
+ """
100
+ with tempfile.TemporaryDirectory() as directory:
101
+ card = Path(directory) / "README.md"
102
+ card.write_text(valid, encoding="utf-8")
103
+ _validate_space_card(card)
104
+
105
+ card.write_text(
106
+ valid.replace("colorFrom: yellow", "colorFrom: orange"),
107
+ encoding="utf-8",
108
+ )
109
+ with self.assertRaisesRegex(SystemExit, "colorFrom"):
110
+ _validate_space_card(card)
111
+
112
+ card.write_text(
113
+ valid.replace("Tiny endpoint detector", "x" * 61),
114
+ encoding="utf-8",
115
+ )
116
+ with self.assertRaisesRegex(SystemExit, "at most 60"):
117
+ _validate_space_card(card)
118
+
119
  def test_synthetic_replay_must_be_labelled_and_hash_bound(self) -> None:
120
  from scripts.build_release import _validate_synthetic_replay
121