Spaces:
Running on Zero
Running on Zero
Codex commited on
Commit ·
b9b02f6
1
Parent(s): 8f9062d
Harden endpoint audio delivery
Browse files- README.md +13 -3
- app.py +107 -25
- production.py +50 -23
- quality_runtime.py +497 -9
- tests/test_coverage_adaptive.py +223 -1
- tests/test_inference_cleanup.py +88 -1
- tests/test_production.py +38 -4
- tests/test_quality_runtime.py +69 -5
- tests/test_release_pins.py +31 -11
README.md
CHANGED
|
@@ -92,6 +92,8 @@ the runtime additionally verifies the exact weight SHA-256 before deserializatio
|
|
| 92 |
每第四個 retry 使用 completion-headroom(4.2 CJK / 3.6 ASCII)。Refill 使用
|
| 93 |
`root seed + global generation offset`,不會重新生成其他已覆蓋 chunks。三種 policy 都只改 native-duration endpoint estimate,
|
| 94 |
margin 固定 +1 latent step、`min_len` 固定為 2,不會為了播放目標語速硬撐 generation loop。
|
|
|
|
|
|
|
| 95 |
選中完整 trajectory 或 coverage-sequence-DP 混合路徑後,log 會記錄每個 chunk 的 candidate、seed、policy、實際 CFG,
|
| 96 |
並記錄每個已嘗試 row-local ordinal 的 schedule CFG。Ordinal 0 與正偶數使用 primary CFG 3.0,
|
| 97 |
正奇數使用 alternate CFG 2.0;含 URL/email component 的 chunk 仍有 CFG 3.0 的內容安全下限。
|
|
@@ -103,8 +105,9 @@ speech-unit counter;只有 URL/email-conditioned native endpoint estimate 對
|
|
| 103 |
採用除以 2 的保守 counter。這個 counter 刻意同時決定 adaptive weak-stop 的
|
| 104 |
`expected_steps` progress 與 `max_len` hard cap;兩者屬於同一份 native endpoint plan,
|
| 105 |
但不會進入播放 pace、chunk planning 或 32/800 work accounting,`min_len` 仍固定為 2。
|
| 106 |
-
終端 outcome 另輸出 content-free canonical evidence schema
|
| 107 |
row-local ordinal、network provenance、CFG contract、32/800 預算用量與 selected-path 交叉檢查,
|
|
|
|
| 108 |
每個 local row 的 independent-large-v3 attempted/pass/proof-count/result attestation,以及
|
| 109 |
local、joined、independent-large-v3 與 final gate 的 bounded SQUIM scalar,
|
| 110 |
不包含 target/transcript/audio/embedding。
|
|
@@ -115,8 +118,15 @@ local、joined、independent-large-v3 與 final gate 的 bounded SQUIM scalar,
|
|
| 115 |
不會執行 refill 或 DP。若失敗,之後只做單 chunk refill,不再生成第二條完整 trajectory。
|
| 116 |
Ragged DP 可混合已通過 hard gate 的 chunks,
|
| 117 |
以及下述唯一 boundary-only、drop 不超過 0.15 的 DP-only chunks。切段保留標點,並依逗號、分號或句末標點
|
| 118 |
-
插入不同長度的停頓。
|
| 119 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 120 |
完成 RMS matching、edge fade、pause、crossfade 與使用者 speed 後,服務會再對最終整段 waveform
|
| 121 |
執行 normalized target 的 prefix/whole/suffix/tail、pace 與 speaker anchor/boundary gate,並要求
|
| 122 |
turbo 與 full large-v3 的語意 hard intersection;這個 post-join gate 失敗時不會回傳先前已通過的
|
|
|
|
| 92 |
每第四個 retry 使用 completion-headroom(4.2 CJK / 3.6 ASCII)。Refill 使用
|
| 93 |
`root seed + global generation offset`,不會重新生成其他已覆蓋 chunks。三種 policy 都只改 native-duration endpoint estimate,
|
| 94 |
margin 固定 +1 latent step、`min_len` 固定為 2,不會為了播放目標語速硬撐 generation loop。
|
| 95 |
+
唯一例外是 completion-headroom 的一至兩單位短句:其 sparse retry 將 hard cap 下限提高到 5 steps,
|
| 96 |
+
讓第一個 eligible weak-stop 有一次真正的 threshold 判定機會;所有額外內容仍須通過雙 ASR 與 tail=0。
|
| 97 |
選中完整 trajectory 或 coverage-sequence-DP 混合路徑後,log 會記錄每個 chunk 的 candidate、seed、policy、實際 CFG,
|
| 98 |
並記錄每個已嘗試 row-local ordinal 的 schedule CFG。Ordinal 0 與正偶數使用 primary CFG 3.0,
|
| 99 |
正奇數使用 alternate CFG 2.0;含 URL/email component 的 chunk 仍有 CFG 3.0 的內容安全下限。
|
|
|
|
| 105 |
採用除以 2 的保守 counter。這個 counter 刻意同時決定 adaptive weak-stop 的
|
| 106 |
`expected_steps` progress 與 `max_len` hard cap;兩者屬於同一份 native endpoint plan,
|
| 107 |
但不會進入播放 pace、chunk planning 或 32/800 work accounting,`min_len` 仍固定為 2。
|
| 108 |
+
終端 outcome 另輸出 content-free canonical evidence schema v6,包含 original chunk indices、
|
| 109 |
row-local ordinal、network provenance、CFG contract、32/800 預算用量與 selected-path 交叉檢查,
|
| 110 |
+
每個 chunk 的 stop reason、pre-fade endpoint energy、generated/hard-stop steps,
|
| 111 |
每個 local row 的 independent-large-v3 attempted/pass/proof-count/result attestation,以及
|
| 112 |
local、joined、independent-large-v3 與 final gate 的 bounded SQUIM scalar,
|
| 113 |
不包含 target/transcript/audio/embedding。
|
|
|
|
| 118 |
不會執行 refill 或 DP。若失敗,之後只做單 chunk refill,不再生成第二條完整 trajectory。
|
| 119 |
Ragged DP 可混合已通過 hard gate 的 chunks,
|
| 120 |
以及下述唯一 boundary-only、drop 不超過 0.15 的 DP-only chunks。切段保留標點,並依逗號、分號或句末標點
|
| 121 |
+
插入不同長度的停頓。已通過 hard gate 的候選再加入 bounded endpoint soft cost:
|
| 122 |
+
任何到達 hard cap(即使 threshold 恰於同一步 crossing)皆加 0.05,再加上 `0.02 ×`
|
| 123 |
+
最後 5 ms RMS/全波形 peak。只有在目前 preferred 候選到達 hard cap 時,才允許真正於 cap
|
| 124 |
+
前自然停止的候選使用最多 STOI 0.02/PESQ 0.03 的 preferred-tier slack;speaker 與 boundary
|
| 125 |
+
在既有長度 gate 適用時仍須完整達到 preferred 門檻,所有 hard gate 亦維持不變。
|
| 126 |
+
輸出最後會套用保守的 RMS floor 與 peak limit、固定 5 ms cosine-squared 收尾與 180 ms silence,
|
| 127 |
+
接著先量化到 PCM16 並以 WAV decoder 等價波形執行 joined/final verifier。公開 wrapper 再編碼時
|
| 128 |
+
逐 sample 冪等,因此驗證的就是使用者收到的 PCM codes;同時不讓 Gradio 對 float ndarray
|
| 129 |
+
再做 peak normalization,以免額外放大底噪。
|
| 130 |
完成 RMS matching、edge fade、pause、crossfade 與使用者 speed 後,服務會再對最終整段 waveform
|
| 131 |
執行 normalized target 的 prefix/whole/suffix/tail、pace 與 speaker anchor/boundary gate,並要求
|
| 132 |
turbo 與 full large-v3 的語意 hard intersection;這個 post-join gate 失敗時不會回傳先前已通過的
|
app.py
CHANGED
|
@@ -2,7 +2,7 @@
|
|
| 2 |
|
| 3 |
from __future__ import annotations
|
| 4 |
|
| 5 |
-
from dataclasses import replace
|
| 6 |
from importlib import metadata as importlib_metadata
|
| 7 |
import inspect
|
| 8 |
import json
|
|
@@ -103,6 +103,7 @@ from production import (
|
|
| 103 |
normalize_spoken_forms,
|
| 104 |
punctuation_pause_seconds,
|
| 105 |
pcm16_audio_output,
|
|
|
|
| 106 |
plan_generation_chunks,
|
| 107 |
select_generation_cps,
|
| 108 |
set_generation_seed,
|
|
@@ -133,6 +134,7 @@ from quality_runtime import (
|
|
| 133 |
candidate_gate_evidence,
|
| 134 |
active_audio_rms_db,
|
| 135 |
active_audio_median_f0_hz,
|
|
|
|
| 136 |
format_cascade_evidence_log,
|
| 137 |
generation_cfg_for_candidate_offset,
|
| 138 |
generation_policy_for_candidate_offset,
|
|
@@ -191,6 +193,7 @@ QUALITY_MEDIUM_CHUNK_UNITS = 24
|
|
| 191 |
CROSSFADE_MS = 80.0
|
| 192 |
CHUNK_EDGE_FADE_MS = 80.0
|
| 193 |
CHUNK_RMS_MATCH_DB = 4.0
|
|
|
|
| 194 |
NETWORK_GENERATION_MIN_UNITS = 8
|
| 195 |
NETWORK_GENERATION_TARGET_UNITS = 32
|
| 196 |
NETWORK_GENERATION_MAX_UNITS = 36
|
|
@@ -375,6 +378,15 @@ def _apply_speed(
|
|
| 375 |
)
|
| 376 |
|
| 377 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 378 |
def _generate_chunk(
|
| 379 |
text: str,
|
| 380 |
centroid: torch.Tensor,
|
|
@@ -384,7 +396,7 @@ def _generate_chunk(
|
|
| 384 |
request_seed: int,
|
| 385 |
policy: GenerationPolicy,
|
| 386 |
network_conditioned: bool = False,
|
| 387 |
-
) ->
|
| 388 |
generation_cps = (
|
| 389 |
policy.ascii_cps
|
| 390 |
if network_conditioned
|
|
@@ -407,6 +419,19 @@ def _generate_chunk(
|
|
| 407 |
add_terminal_punctuation=count_speech_units(text) >= MIN_ENDPOINT_CUE_UNITS,
|
| 408 |
duration_units=endpoint_duration_units,
|
| 409 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 410 |
# Do not hold generation open to enforce pace. The model can finish the
|
| 411 |
# requested text early; extending its latent sequence creates tail speech.
|
| 412 |
min_len = 2
|
|
@@ -445,6 +470,16 @@ def _generate_chunk(
|
|
| 445 |
finally:
|
| 446 |
if _STOP_CONTROLLER is not None:
|
| 447 |
_STOP_CONTROLLER.end()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 448 |
if _STOP_CONTROLLER is not None:
|
| 449 |
print(
|
| 450 |
"[BlueMagpie] endpoint "
|
|
@@ -458,9 +493,21 @@ def _generate_chunk(
|
|
| 458 |
f"duration_units={endpoint_duration_units} "
|
| 459 |
f"duration_counter={'network_conservative' if network_conditioned else 'public'} "
|
| 460 |
f"expected_steps={expected_steps} hard_stop_steps={hard_stop_steps} "
|
| 461 |
-
f"min_len={min_len}"
|
|
|
|
| 462 |
)
|
| 463 |
audio = audio.detach().float().cpu().numpy().reshape(-1)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 464 |
pace_speed = target_pace_speed(
|
| 465 |
audio.size,
|
| 466 |
SR,
|
|
@@ -498,7 +545,7 @@ def _generate_chunk(
|
|
| 498 |
try:
|
| 499 |
corrected_active_duration = active_voiced_duration_seconds(corrected, SR)
|
| 500 |
except (TypeError, ValueError, RuntimeError, OverflowError):
|
| 501 |
-
return corrected
|
| 502 |
rerender_speed = active_pace_correction_speed(
|
| 503 |
corrected_active_duration,
|
| 504 |
text,
|
|
@@ -535,7 +582,7 @@ def _generate_chunk(
|
|
| 535 |
try:
|
| 536 |
final_active_duration = active_voiced_duration_seconds(final_audio, SR)
|
| 537 |
except (TypeError, ValueError, RuntimeError, OverflowError):
|
| 538 |
-
return final_audio
|
| 539 |
observed_cps = count_speech_units(text) / final_active_duration
|
| 540 |
if observed_cps > QUALITY_MAX_PACE_CPS:
|
| 541 |
fallback_residual = active_pace_correction_speed(
|
|
@@ -555,12 +602,14 @@ def _generate_chunk(
|
|
| 555 |
f"residual_rate={fallback_residual:.6f} "
|
| 556 |
f"total_rate={fallback_speed:.6f}"
|
| 557 |
)
|
| 558 |
-
return
|
| 559 |
-
|
| 560 |
-
|
| 561 |
-
|
|
|
|
|
|
|
| 562 |
)
|
| 563 |
-
return final_audio
|
| 564 |
|
| 565 |
|
| 566 |
def _speaker_anchor_array(centroid: torch.Tensor) -> np.ndarray:
|
|
@@ -583,9 +632,10 @@ def _generate_trajectory(
|
|
| 583 |
policy: GenerationPolicy,
|
| 584 |
network_cfg_min: float = NETWORK_TEXT_CFG_MIN,
|
| 585 |
network_conditioned: tuple[bool, ...] | None = None,
|
| 586 |
-
) -> tuple[np.ndarray, ...]:
|
| 587 |
scheduled_cfg = float(cfg)
|
| 588 |
trajectory: list[np.ndarray] = []
|
|
|
|
| 589 |
if network_conditioned is not None and len(network_conditioned) != len(chunks):
|
| 590 |
raise ValueError("network provenance must align with generation chunks")
|
| 591 |
for local_chunk_index, chunk in enumerate(chunks):
|
|
@@ -617,18 +667,18 @@ def _generate_trajectory(
|
|
| 617 |
f"network_floor_applied={network_floor_applied} "
|
| 618 |
f"short_floor_applied={short_floor_applied}"
|
| 619 |
)
|
| 620 |
-
|
| 621 |
-
|
| 622 |
-
|
| 623 |
-
|
| 624 |
-
|
| 625 |
-
|
| 626 |
-
|
| 627 |
-
|
| 628 |
-
network_conditioned=network_chunk,
|
| 629 |
-
)
|
| 630 |
)
|
| 631 |
-
|
|
|
|
|
|
|
| 632 |
|
| 633 |
|
| 634 |
def _attach_transition_f0(
|
|
@@ -1099,8 +1149,14 @@ def _assemble_trajectory_audio(
|
|
| 1099 |
max_gain=3.0,
|
| 1100 |
)
|
| 1101 |
waveform = _apply_speed(waveform, playback_speed)
|
| 1102 |
-
|
| 1103 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1104 |
|
| 1105 |
|
| 1106 |
def _verification_metric_log_fields(verification) -> str:
|
|
@@ -1504,6 +1560,10 @@ def _synthesize(
|
|
| 1504 |
anchor = _speaker_anchor_array(centroid)
|
| 1505 |
independent_cache = WholeWaveformVerificationCache()
|
| 1506 |
generation_context_by_seed: dict[int, CandidateGenerationContext] = {}
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1507 |
|
| 1508 |
def canonical_chunks_for_context(
|
| 1509 |
generation_context: CandidateGenerationContext,
|
|
@@ -1714,7 +1774,7 @@ def _synthesize(
|
|
| 1714 |
candidate_chunks,
|
| 1715 |
generation_context=generation_context,
|
| 1716 |
)
|
| 1717 |
-
|
| 1718 |
candidate_chunks,
|
| 1719 |
centroid,
|
| 1720 |
cfg=candidate_cfg(candidate_ordinal),
|
|
@@ -1723,6 +1783,10 @@ def _synthesize(
|
|
| 1723 |
policy=generation_policy_for_candidate_offset(candidate_ordinal),
|
| 1724 |
network_conditioned=network_flags,
|
| 1725 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1726 |
|
| 1727 |
def candidate_generation_evidence(
|
| 1728 |
candidate_index: int,
|
|
@@ -1773,6 +1837,11 @@ def _synthesize(
|
|
| 1773 |
strict=True,
|
| 1774 |
)
|
| 1775 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1776 |
return CandidateGenerationEvidence(
|
| 1777 |
chunk_indices=chunk_indices,
|
| 1778 |
chunk_text_units=tuple(
|
|
@@ -1784,6 +1853,18 @@ def _synthesize(
|
|
| 1784 |
chunk_candidate_ordinals=candidate_ordinals,
|
| 1785 |
network_conditioned=network_flags,
|
| 1786 |
chunk_text_variants=text_variants,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1787 |
)
|
| 1788 |
|
| 1789 |
try:
|
|
@@ -1855,6 +1936,7 @@ def _synthesize(
|
|
| 1855 |
preferred_min_squim_audio_duration_seconds=(
|
| 1856 |
QUALITY_PREFERRED_SQUIM_MIN_DURATION_SECONDS
|
| 1857 |
),
|
|
|
|
| 1858 |
)
|
| 1859 |
except NoQualifiedCandidateError as error:
|
| 1860 |
print(
|
|
|
|
| 2 |
|
| 3 |
from __future__ import annotations
|
| 4 |
|
| 5 |
+
from dataclasses import dataclass, replace
|
| 6 |
from importlib import metadata as importlib_metadata
|
| 7 |
import inspect
|
| 8 |
import json
|
|
|
|
| 103 |
normalize_spoken_forms,
|
| 104 |
punctuation_pause_seconds,
|
| 105 |
pcm16_audio_output,
|
| 106 |
+
pcm16_verification_waveform,
|
| 107 |
plan_generation_chunks,
|
| 108 |
select_generation_cps,
|
| 109 |
set_generation_seed,
|
|
|
|
| 134 |
candidate_gate_evidence,
|
| 135 |
active_audio_rms_db,
|
| 136 |
active_audio_median_f0_hz,
|
| 137 |
+
endpoint_tail_energy_ratio,
|
| 138 |
format_cascade_evidence_log,
|
| 139 |
generation_cfg_for_candidate_offset,
|
| 140 |
generation_policy_for_candidate_offset,
|
|
|
|
| 193 |
CROSSFADE_MS = 80.0
|
| 194 |
CHUNK_EDGE_FADE_MS = 80.0
|
| 195 |
CHUNK_RMS_MATCH_DB = 4.0
|
| 196 |
+
FINAL_ENDPOINT_FADE_MS = 5.0
|
| 197 |
NETWORK_GENERATION_MIN_UNITS = 8
|
| 198 |
NETWORK_GENERATION_TARGET_UNITS = 32
|
| 199 |
NETWORK_GENERATION_MAX_UNITS = 36
|
|
|
|
| 378 |
)
|
| 379 |
|
| 380 |
|
| 381 |
+
@dataclass(frozen=True)
|
| 382 |
+
class _ChunkGenerationOutcome:
|
| 383 |
+
audio: np.ndarray
|
| 384 |
+
stop_reason: str
|
| 385 |
+
endpoint_energy_ratio: float
|
| 386 |
+
generated_steps: int
|
| 387 |
+
hard_stop_steps: int
|
| 388 |
+
|
| 389 |
+
|
| 390 |
def _generate_chunk(
|
| 391 |
text: str,
|
| 392 |
centroid: torch.Tensor,
|
|
|
|
| 396 |
request_seed: int,
|
| 397 |
policy: GenerationPolicy,
|
| 398 |
network_conditioned: bool = False,
|
| 399 |
+
) -> _ChunkGenerationOutcome:
|
| 400 |
generation_cps = (
|
| 401 |
policy.ascii_cps
|
| 402 |
if network_conditioned
|
|
|
|
| 419 |
add_terminal_punctuation=count_speech_units(text) >= MIN_ENDPOINT_CUE_UNITS,
|
| 420 |
duration_units=endpoint_duration_units,
|
| 421 |
)
|
| 422 |
+
public_text_units = count_speech_units(text)
|
| 423 |
+
short_headroom_max_units = int(
|
| 424 |
+
getattr(policy, "short_headroom_max_units", 0)
|
| 425 |
+
)
|
| 426 |
+
short_hard_stop_floor_steps = int(
|
| 427 |
+
getattr(policy, "short_hard_stop_floor_steps", 0)
|
| 428 |
+
)
|
| 429 |
+
short_headroom_floor_applied = bool(
|
| 430 |
+
0 < public_text_units <= short_headroom_max_units
|
| 431 |
+
and hard_stop_steps < short_hard_stop_floor_steps
|
| 432 |
+
)
|
| 433 |
+
if short_headroom_floor_applied:
|
| 434 |
+
hard_stop_steps = short_hard_stop_floor_steps
|
| 435 |
# Do not hold generation open to enforce pace. The model can finish the
|
| 436 |
# requested text early; extending its latent sequence creates tail speech.
|
| 437 |
min_len = 2
|
|
|
|
| 470 |
finally:
|
| 471 |
if _STOP_CONTROLLER is not None:
|
| 472 |
_STOP_CONTROLLER.end()
|
| 473 |
+
stop_reason = (
|
| 474 |
+
_STOP_CONTROLLER.last_stop_reason
|
| 475 |
+
if _STOP_CONTROLLER is not None
|
| 476 |
+
else "native_stop"
|
| 477 |
+
)
|
| 478 |
+
generated_steps = (
|
| 479 |
+
_STOP_CONTROLLER.last_generated_steps
|
| 480 |
+
if _STOP_CONTROLLER is not None
|
| 481 |
+
else hard_stop_steps
|
| 482 |
+
)
|
| 483 |
if _STOP_CONTROLLER is not None:
|
| 484 |
print(
|
| 485 |
"[BlueMagpie] endpoint "
|
|
|
|
| 493 |
f"duration_units={endpoint_duration_units} "
|
| 494 |
f"duration_counter={'network_conservative' if network_conditioned else 'public'} "
|
| 495 |
f"expected_steps={expected_steps} hard_stop_steps={hard_stop_steps} "
|
| 496 |
+
f"min_len={min_len} "
|
| 497 |
+
f"short_headroom_floor_applied={short_headroom_floor_applied}"
|
| 498 |
)
|
| 499 |
audio = audio.detach().float().cpu().numpy().reshape(-1)
|
| 500 |
+
|
| 501 |
+
def outcome(waveform: np.ndarray) -> _ChunkGenerationOutcome:
|
| 502 |
+
normalized = np.asarray(waveform, dtype=np.float32).reshape(-1)
|
| 503 |
+
return _ChunkGenerationOutcome(
|
| 504 |
+
audio=normalized,
|
| 505 |
+
stop_reason=stop_reason,
|
| 506 |
+
endpoint_energy_ratio=endpoint_tail_energy_ratio(normalized, SR),
|
| 507 |
+
generated_steps=generated_steps,
|
| 508 |
+
hard_stop_steps=hard_stop_steps,
|
| 509 |
+
)
|
| 510 |
+
|
| 511 |
pace_speed = target_pace_speed(
|
| 512 |
audio.size,
|
| 513 |
SR,
|
|
|
|
| 545 |
try:
|
| 546 |
corrected_active_duration = active_voiced_duration_seconds(corrected, SR)
|
| 547 |
except (TypeError, ValueError, RuntimeError, OverflowError):
|
| 548 |
+
return outcome(corrected)
|
| 549 |
rerender_speed = active_pace_correction_speed(
|
| 550 |
corrected_active_duration,
|
| 551 |
text,
|
|
|
|
| 582 |
try:
|
| 583 |
final_active_duration = active_voiced_duration_seconds(final_audio, SR)
|
| 584 |
except (TypeError, ValueError, RuntimeError, OverflowError):
|
| 585 |
+
return outcome(final_audio)
|
| 586 |
observed_cps = count_speech_units(text) / final_active_duration
|
| 587 |
if observed_cps > QUALITY_MAX_PACE_CPS:
|
| 588 |
fallback_residual = active_pace_correction_speed(
|
|
|
|
| 602 |
f"residual_rate={fallback_residual:.6f} "
|
| 603 |
f"total_rate={fallback_speed:.6f}"
|
| 604 |
)
|
| 605 |
+
return outcome(
|
| 606 |
+
_apply_speed(
|
| 607 |
+
audio,
|
| 608 |
+
fallback_speed,
|
| 609 |
+
network_conditioned=False,
|
| 610 |
+
)
|
| 611 |
)
|
| 612 |
+
return outcome(final_audio)
|
| 613 |
|
| 614 |
|
| 615 |
def _speaker_anchor_array(centroid: torch.Tensor) -> np.ndarray:
|
|
|
|
| 632 |
policy: GenerationPolicy,
|
| 633 |
network_cfg_min: float = NETWORK_TEXT_CFG_MIN,
|
| 634 |
network_conditioned: tuple[bool, ...] | None = None,
|
| 635 |
+
) -> tuple[tuple[np.ndarray, ...], tuple[_ChunkGenerationOutcome, ...]]:
|
| 636 |
scheduled_cfg = float(cfg)
|
| 637 |
trajectory: list[np.ndarray] = []
|
| 638 |
+
endpoint_outcomes: list[_ChunkGenerationOutcome] = []
|
| 639 |
if network_conditioned is not None and len(network_conditioned) != len(chunks):
|
| 640 |
raise ValueError("network provenance must align with generation chunks")
|
| 641 |
for local_chunk_index, chunk in enumerate(chunks):
|
|
|
|
| 667 |
f"network_floor_applied={network_floor_applied} "
|
| 668 |
f"short_floor_applied={short_floor_applied}"
|
| 669 |
)
|
| 670 |
+
outcome = _generate_chunk(
|
| 671 |
+
chunk,
|
| 672 |
+
centroid,
|
| 673 |
+
cfg=network_adjusted_cfg,
|
| 674 |
+
steps=steps,
|
| 675 |
+
request_seed=request_seed,
|
| 676 |
+
policy=policy,
|
| 677 |
+
network_conditioned=network_chunk,
|
|
|
|
|
|
|
| 678 |
)
|
| 679 |
+
trajectory.append(outcome.audio)
|
| 680 |
+
endpoint_outcomes.append(outcome)
|
| 681 |
+
return tuple(trajectory), tuple(endpoint_outcomes)
|
| 682 |
|
| 683 |
|
| 684 |
def _attach_transition_f0(
|
|
|
|
| 1149 |
max_gain=3.0,
|
| 1150 |
)
|
| 1151 |
waveform = _apply_speed(waveform, playback_speed)
|
| 1152 |
+
waveform = finish_audio(
|
| 1153 |
+
waveform,
|
| 1154 |
+
SR,
|
| 1155 |
+
fade_ms=FINAL_ENDPOINT_FADE_MS,
|
| 1156 |
+
)
|
| 1157 |
+
# Joined/final ASR, SQUIM, and speaker gates must inspect the exact
|
| 1158 |
+
# decoder-equivalent waveform represented by the public PCM16 response.
|
| 1159 |
+
return pcm16_verification_waveform(waveform)
|
| 1160 |
|
| 1161 |
|
| 1162 |
def _verification_metric_log_fields(verification) -> str:
|
|
|
|
| 1560 |
anchor = _speaker_anchor_array(centroid)
|
| 1561 |
independent_cache = WholeWaveformVerificationCache()
|
| 1562 |
generation_context_by_seed: dict[int, CandidateGenerationContext] = {}
|
| 1563 |
+
generation_endpoint_evidence_by_seed: dict[
|
| 1564 |
+
int,
|
| 1565 |
+
tuple[_ChunkGenerationOutcome, ...],
|
| 1566 |
+
] = {}
|
| 1567 |
|
| 1568 |
def canonical_chunks_for_context(
|
| 1569 |
generation_context: CandidateGenerationContext,
|
|
|
|
| 1774 |
candidate_chunks,
|
| 1775 |
generation_context=generation_context,
|
| 1776 |
)
|
| 1777 |
+
trajectory, endpoint_outcomes = _generate_trajectory(
|
| 1778 |
candidate_chunks,
|
| 1779 |
centroid,
|
| 1780 |
cfg=candidate_cfg(candidate_ordinal),
|
|
|
|
| 1783 |
policy=generation_policy_for_candidate_offset(candidate_ordinal),
|
| 1784 |
network_conditioned=network_flags,
|
| 1785 |
)
|
| 1786 |
+
if len(endpoint_outcomes) != len(candidate_chunks):
|
| 1787 |
+
raise ValueError("generation endpoint evidence is incomplete")
|
| 1788 |
+
generation_endpoint_evidence_by_seed[seed] = endpoint_outcomes
|
| 1789 |
+
return trajectory
|
| 1790 |
|
| 1791 |
def candidate_generation_evidence(
|
| 1792 |
candidate_index: int,
|
|
|
|
| 1837 |
strict=True,
|
| 1838 |
)
|
| 1839 |
)
|
| 1840 |
+
endpoint_outcomes = generation_endpoint_evidence_by_seed.get(seed)
|
| 1841 |
+
if endpoint_outcomes is None or len(endpoint_outcomes) != len(
|
| 1842 |
+
candidate_chunks
|
| 1843 |
+
):
|
| 1844 |
+
raise ValueError("generation endpoint evidence is missing")
|
| 1845 |
return CandidateGenerationEvidence(
|
| 1846 |
chunk_indices=chunk_indices,
|
| 1847 |
chunk_text_units=tuple(
|
|
|
|
| 1853 |
chunk_candidate_ordinals=candidate_ordinals,
|
| 1854 |
network_conditioned=network_flags,
|
| 1855 |
chunk_text_variants=text_variants,
|
| 1856 |
+
chunk_stop_reasons=tuple(
|
| 1857 |
+
outcome.stop_reason for outcome in endpoint_outcomes
|
| 1858 |
+
),
|
| 1859 |
+
chunk_endpoint_energy_ratios=tuple(
|
| 1860 |
+
outcome.endpoint_energy_ratio for outcome in endpoint_outcomes
|
| 1861 |
+
),
|
| 1862 |
+
chunk_generated_steps=tuple(
|
| 1863 |
+
outcome.generated_steps for outcome in endpoint_outcomes
|
| 1864 |
+
),
|
| 1865 |
+
chunk_hard_stop_steps=tuple(
|
| 1866 |
+
outcome.hard_stop_steps for outcome in endpoint_outcomes
|
| 1867 |
+
),
|
| 1868 |
)
|
| 1869 |
|
| 1870 |
try:
|
|
|
|
| 1936 |
preferred_min_squim_audio_duration_seconds=(
|
| 1937 |
QUALITY_PREFERRED_SQUIM_MIN_DURATION_SECONDS
|
| 1938 |
),
|
| 1939 |
+
require_endpoint_evidence=True,
|
| 1940 |
)
|
| 1941 |
except NoQualifiedCandidateError as error:
|
| 1942 |
print(
|
production.py
CHANGED
|
@@ -419,8 +419,9 @@ class StopHysteresisController(nn.Module):
|
|
| 419 |
should_stop = eligible and self._hits >= self.consecutive
|
| 420 |
stop_reason = "stop_threshold" if should_stop else "running"
|
| 421 |
if self._hard_stop_steps > 0 and generated_steps >= self._hard_stop_steps:
|
| 422 |
-
|
| 423 |
-
|
|
|
|
| 424 |
self._step += 1
|
| 425 |
self.last_generated_steps = generated_steps
|
| 426 |
self.last_stop_reason = stop_reason
|
|
@@ -3116,7 +3117,15 @@ def finish_audio(
|
|
| 3116 |
max(0, int(round(float(fade_ms) * int(sample_rate) / 1000.0))),
|
| 3117 |
)
|
| 3118 |
if fade_samples > 0:
|
| 3119 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3120 |
silence_samples = max(
|
| 3121 |
0,
|
| 3122 |
int(round(float(trailing_silence_ms) * int(sample_rate) / 1000.0)),
|
|
@@ -4602,17 +4611,51 @@ def _peak_rms(audio: np.ndarray) -> tuple[float, float]:
|
|
| 4602 |
return peak, rms
|
| 4603 |
|
| 4604 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4605 |
def pcm16_audio_output(
|
| 4606 |
sample_rate: int,
|
| 4607 |
audio: np.ndarray,
|
| 4608 |
) -> tuple[int, np.ndarray]:
|
| 4609 |
-
"""Serialize
|
| 4610 |
|
| 4611 |
Gradio peak-normalizes floating-point ndarray outputs before writing them.
|
| 4612 |
Returning explicit PCM16 preserves the level already selected by the
|
| 4613 |
production loudness/peak limiter, including its intended noise headroom.
|
| 4614 |
-
|
| 4615 |
-
|
| 4616 |
"""
|
| 4617 |
|
| 4618 |
if isinstance(sample_rate, (bool, np.bool_)):
|
|
@@ -4623,23 +4666,7 @@ def pcm16_audio_output(
|
|
| 4623 |
raise ValueError("sample_rate must be a positive integer") from error
|
| 4624 |
if rate_hz <= 0:
|
| 4625 |
raise ValueError("sample_rate must be a positive integer")
|
| 4626 |
-
|
| 4627 |
-
values = np.asarray(audio)
|
| 4628 |
-
if values.ndim != 1 or values.size <= 0 or not np.issubdtype(
|
| 4629 |
-
values.dtype,
|
| 4630 |
-
np.floating,
|
| 4631 |
-
):
|
| 4632 |
-
raise ValueError("audio must be a non-empty mono floating-point array")
|
| 4633 |
-
finite = values.astype(np.float64, copy=False)
|
| 4634 |
-
if not np.isfinite(finite).all():
|
| 4635 |
-
raise ValueError("audio must contain only finite samples")
|
| 4636 |
-
if float(np.max(np.abs(finite))) > 1.0:
|
| 4637 |
-
raise ValueError("audio samples must be bounded to [-1, 1]")
|
| 4638 |
-
|
| 4639 |
-
# 32767 is intentional: it gives a symmetric mapping and, unlike Gradio's
|
| 4640 |
-
# float conversion, never divides by the waveform peak.
|
| 4641 |
-
pcm = np.rint(finite * 32767.0).astype(np.int16)
|
| 4642 |
-
return int(rate_hz), pcm
|
| 4643 |
|
| 4644 |
|
| 4645 |
def match_chunk_rms(reference: np.ndarray, chunk: np.ndarray, max_adjust_db: float = 4.0) -> np.ndarray:
|
|
|
|
| 419 |
should_stop = eligible and self._hits >= self.consecutive
|
| 420 |
stop_reason = "stop_threshold" if should_stop else "running"
|
| 421 |
if self._hard_stop_steps > 0 and generated_steps >= self._hard_stop_steps:
|
| 422 |
+
if not should_stop:
|
| 423 |
+
should_stop = True
|
| 424 |
+
stop_reason = "hard_stop"
|
| 425 |
self._step += 1
|
| 426 |
self.last_generated_steps = generated_steps
|
| 427 |
self.last_stop_reason = stop_reason
|
|
|
|
| 3117 |
max(0, int(round(float(fade_ms) * int(sample_rate) / 1000.0))),
|
| 3118 |
)
|
| 3119 |
if fade_samples > 0:
|
| 3120 |
+
phase = np.linspace(
|
| 3121 |
+
0.0,
|
| 3122 |
+
np.pi / 2.0,
|
| 3123 |
+
fade_samples,
|
| 3124 |
+
dtype=np.float32,
|
| 3125 |
+
)
|
| 3126 |
+
envelope = np.square(np.cos(phase))
|
| 3127 |
+
envelope[-1] = 0.0
|
| 3128 |
+
signal[-fade_samples:] *= envelope
|
| 3129 |
silence_samples = max(
|
| 3130 |
0,
|
| 3131 |
int(round(float(trailing_silence_ms) * int(sample_rate) / 1000.0)),
|
|
|
|
| 4611 |
return peak, rms
|
| 4612 |
|
| 4613 |
|
| 4614 |
+
def encode_pcm16(audio: np.ndarray) -> np.ndarray:
|
| 4615 |
+
"""Encode finite mono audio with the standard signed PCM16 scale."""
|
| 4616 |
+
|
| 4617 |
+
values = np.asarray(audio)
|
| 4618 |
+
if values.ndim != 1 or values.size <= 0 or not np.issubdtype(
|
| 4619 |
+
values.dtype,
|
| 4620 |
+
np.floating,
|
| 4621 |
+
):
|
| 4622 |
+
raise ValueError("audio must be a non-empty mono floating-point array")
|
| 4623 |
+
finite = values.astype(np.float64, copy=False)
|
| 4624 |
+
if not np.isfinite(finite).all():
|
| 4625 |
+
raise ValueError("audio must contain only finite samples")
|
| 4626 |
+
if float(np.max(np.abs(finite))) > 1.0:
|
| 4627 |
+
raise ValueError("audio samples must be bounded to [-1, 1]")
|
| 4628 |
+
|
| 4629 |
+
scaled = np.rint(finite * 32768.0)
|
| 4630 |
+
return np.clip(scaled, -32768.0, 32767.0).astype(np.int16)
|
| 4631 |
+
|
| 4632 |
+
|
| 4633 |
+
def decode_pcm16(pcm: np.ndarray) -> np.ndarray:
|
| 4634 |
+
"""Decode one mono PCM16 buffer exactly as a WAV reader does."""
|
| 4635 |
+
|
| 4636 |
+
values = np.asarray(pcm)
|
| 4637 |
+
if values.ndim != 1 or values.size <= 0 or values.dtype != np.int16:
|
| 4638 |
+
raise ValueError("pcm must be a non-empty mono int16 array")
|
| 4639 |
+
return values.astype(np.float32) / np.float32(32768.0)
|
| 4640 |
+
|
| 4641 |
+
|
| 4642 |
+
def pcm16_verification_waveform(audio: np.ndarray) -> np.ndarray:
|
| 4643 |
+
"""Return the decoder-equivalent waveform for the exact public PCM codes."""
|
| 4644 |
+
|
| 4645 |
+
return decode_pcm16(encode_pcm16(audio))
|
| 4646 |
+
|
| 4647 |
+
|
| 4648 |
def pcm16_audio_output(
|
| 4649 |
sample_rate: int,
|
| 4650 |
audio: np.ndarray,
|
| 4651 |
) -> tuple[int, np.ndarray]:
|
| 4652 |
+
"""Serialize verified mono float audio as PCM16 without peak normalization.
|
| 4653 |
|
| 4654 |
Gradio peak-normalizes floating-point ndarray outputs before writing them.
|
| 4655 |
Returning explicit PCM16 preserves the level already selected by the
|
| 4656 |
production loudness/peak limiter, including its intended noise headroom.
|
| 4657 |
+
Callers should verify ``pcm16_verification_waveform(audio)``; encoding that
|
| 4658 |
+
canonical waveform here is sample-for-sample idempotent.
|
| 4659 |
"""
|
| 4660 |
|
| 4661 |
if isinstance(sample_rate, (bool, np.bool_)):
|
|
|
|
| 4666 |
raise ValueError("sample_rate must be a positive integer") from error
|
| 4667 |
if rate_hz <= 0:
|
| 4668 |
raise ValueError("sample_rate must be a positive integer")
|
| 4669 |
+
return int(rate_hz), encode_pcm16(audio)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4670 |
|
| 4671 |
|
| 4672 |
def match_chunk_rms(reference: np.ndarray, chunk: np.ndarray, max_adjust_db: float = 4.0) -> np.ndarray:
|
quality_runtime.py
CHANGED
|
@@ -61,7 +61,12 @@ RELEASE_SPEAKER_TRIGGER_SECONDS = 1.48
|
|
| 61 |
SEQUENCE_FALLBACK_MAX_LOCAL_BOUNDARY_SPEAKER_DROP = 0.15
|
| 62 |
SEQUENCE_FALLBACK_SPEAKER_WEIGHT = 0.05
|
| 63 |
SEQUENCE_FALLBACK_BOUNDARY_WEIGHT = 0.10
|
| 64 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 65 |
CASCADE_EVIDENCE_LOG_PREFIX = "[BlueMagpie] cascade evidence "
|
| 66 |
CASCADE_EVIDENCE_MAX_ATTEMPTS = ADAPTIVE_CASCADE_STAGE_LIMITS[-1]
|
| 67 |
CASCADE_EVIDENCE_MAX_LOCAL_RESULTS = ADAPTIVE_CASCADE_STAGE_LIMITS[-1]
|
|
@@ -76,6 +81,9 @@ _CASCADE_EVIDENCE_SELECTION_MODES = frozenset(
|
|
| 76 |
{"whole_trajectory", "sequence_dp", "coverage_sequence_dp"}
|
| 77 |
)
|
| 78 |
_CFG_FLOOR_REASONS = frozenset({"network", "short_text"})
|
|
|
|
|
|
|
|
|
|
| 79 |
_CASCADE_EVIDENCE_REJECTION_CODES = frozenset(
|
| 80 |
{
|
| 81 |
"boundary_speaker_drop",
|
|
@@ -115,6 +123,8 @@ class GenerationPolicy:
|
|
| 115 |
cjk_cps: float
|
| 116 |
ascii_cps: float
|
| 117 |
hard_stop_margin_steps: int
|
|
|
|
|
|
|
| 118 |
|
| 119 |
|
| 120 |
@dataclass(frozen=True)
|
|
@@ -151,6 +161,8 @@ COMPLETION_HEADROOM_GENERATION_POLICY = GenerationPolicy(
|
|
| 151 |
cjk_cps=4.2,
|
| 152 |
ascii_cps=3.6,
|
| 153 |
hard_stop_margin_steps=1,
|
|
|
|
|
|
|
| 154 |
)
|
| 155 |
MIXED_CFG_SCHEDULE = "row_ordinal_zero_and_even_primary_odd_alternate"
|
| 156 |
MIXED_CFG_PRIMARY = 3.0
|
|
@@ -1446,6 +1458,40 @@ def active_audio_rms_db(audio: np.ndarray | Sequence[float], *, top_db: float =
|
|
| 1446 |
return 20.0 * math.log10(rms)
|
| 1447 |
|
| 1448 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1449 |
def active_audio_median_f0_hz(
|
| 1450 |
audio: np.ndarray | Sequence[float],
|
| 1451 |
sample_rate: int,
|
|
@@ -1521,6 +1567,10 @@ class ChunkCandidateArtifact:
|
|
| 1521 |
speaker_embedding: np.ndarray | None = None
|
| 1522 |
rms_db: float | None = None
|
| 1523 |
median_f0_hz: float | None = None
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1524 |
|
| 1525 |
|
| 1526 |
@dataclass(frozen=True)
|
|
@@ -1584,6 +1634,10 @@ class CandidateGenerationEvidence:
|
|
| 1584 |
chunk_candidate_ordinals: tuple[int, ...] = ()
|
| 1585 |
network_conditioned: tuple[bool, ...] = ()
|
| 1586 |
chunk_text_variants: tuple[str, ...] = ()
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1587 |
|
| 1588 |
|
| 1589 |
@dataclass(frozen=True)
|
|
@@ -1602,6 +1656,10 @@ class CandidateAttemptEvidence:
|
|
| 1602 |
chunk_candidate_ordinals: tuple[int, ...]
|
| 1603 |
network_conditioned: tuple[bool, ...]
|
| 1604 |
chunk_text_variants: tuple[str, ...]
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1605 |
scheduled_cfg: float | None
|
| 1606 |
effective_cfgs: tuple[float, ...]
|
| 1607 |
floor_reasons: tuple[tuple[str, ...], ...]
|
|
@@ -2530,6 +2588,12 @@ def _candidate_attempt_evidence_payload(
|
|
| 2530 |
"chunk_policies": chunk_policies,
|
| 2531 |
"chunk_text_variants": list(evidence.chunk_text_variants),
|
| 2532 |
"network_conditioned": list(evidence.network_conditioned),
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2533 |
"scheduled_cfg": evidence.scheduled_cfg,
|
| 2534 |
"effective_cfgs": list(evidence.effective_cfgs),
|
| 2535 |
"floor_reasons": [list(reasons) for reasons in evidence.floor_reasons],
|
|
@@ -2619,7 +2683,12 @@ def _selected_generation_evidence_payload(
|
|
| 2619 |
policies: list[str | None] = []
|
| 2620 |
network_conditioned: list[bool | None] = []
|
| 2621 |
chunk_text_variants: list[str | None] = []
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2622 |
complete = True
|
|
|
|
| 2623 |
for chunk_index, candidate_index in enumerate(
|
| 2624 |
selection.chunk_candidate_indices
|
| 2625 |
):
|
|
@@ -2633,6 +2702,11 @@ def _selected_generation_evidence_payload(
|
|
| 2633 |
policies.append(None)
|
| 2634 |
network_conditioned.append(None)
|
| 2635 |
chunk_text_variants.append(None)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2636 |
continue
|
| 2637 |
try:
|
| 2638 |
local_index = attempt.chunk_indices.index(chunk_index)
|
|
@@ -2647,6 +2721,11 @@ def _selected_generation_evidence_payload(
|
|
| 2647 |
policies.append(None)
|
| 2648 |
network_conditioned.append(None)
|
| 2649 |
chunk_text_variants.append(None)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2650 |
continue
|
| 2651 |
try:
|
| 2652 |
ordinal = attempt.chunk_candidate_ordinals[local_index]
|
|
@@ -2672,8 +2751,41 @@ def _selected_generation_evidence_payload(
|
|
| 2672 |
except IndexError:
|
| 2673 |
complete = False
|
| 2674 |
chunk_text_variants.append(None)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2675 |
return {
|
| 2676 |
"complete": complete,
|
|
|
|
| 2677 |
"chunk_scheduled_cfgs": scheduled_cfgs,
|
| 2678 |
"chunk_effective_cfgs": effective_cfgs,
|
| 2679 |
"chunk_floor_reasons": floor_reasons,
|
|
@@ -2681,9 +2793,47 @@ def _selected_generation_evidence_payload(
|
|
| 2681 |
"chunk_policies": policies,
|
| 2682 |
"network_conditioned": network_conditioned,
|
| 2683 |
"chunk_text_variants": chunk_text_variants,
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2684 |
}
|
| 2685 |
|
| 2686 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2687 |
def format_cascade_evidence_log(
|
| 2688 |
diagnostics: CascadeDiagnostics,
|
| 2689 |
*,
|
|
@@ -2723,6 +2873,19 @@ def format_cascade_evidence_log(
|
|
| 2723 |
"generated_text_unit_limit must be an integer between 1 and 800"
|
| 2724 |
)
|
| 2725 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2726 |
selected: dict[str, Any] | None = None
|
| 2727 |
if selection is not None:
|
| 2728 |
if not isinstance(selection, CascadeResult):
|
|
@@ -2759,7 +2922,6 @@ def format_cascade_evidence_log(
|
|
| 2759 |
),
|
| 2760 |
}
|
| 2761 |
|
| 2762 |
-
attempts = diagnostics.attempts[:CASCADE_EVIDENCE_MAX_ATTEMPTS]
|
| 2763 |
generation_evidence_complete = bool(attempts) and all(
|
| 2764 |
attempt.scheduled_cfg is not None
|
| 2765 |
and len(attempt.chunk_indices) == len(attempt.chunk_text_units)
|
|
@@ -2771,6 +2933,10 @@ def format_cascade_evidence_log(
|
|
| 2771 |
and bool(attempt.chunk_indices)
|
| 2772 |
for attempt in attempts
|
| 2773 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2774 |
generated_chunk_count = sum(len(attempt.chunk_indices) for attempt in attempts)
|
| 2775 |
generated_text_units = sum(
|
| 2776 |
sum(attempt.chunk_text_units) for attempt in attempts
|
|
@@ -2804,6 +2970,7 @@ def format_cascade_evidence_log(
|
|
| 2804 |
},
|
| 2805 |
"attempt_count": len(diagnostics.attempts),
|
| 2806 |
"generation_evidence_complete": generation_evidence_complete,
|
|
|
|
| 2807 |
"generated_chunk_count": generated_chunk_count,
|
| 2808 |
"generated_text_units": generated_text_units,
|
| 2809 |
"attempts": [
|
|
@@ -3285,6 +3452,7 @@ def _validated_candidate_generation_evidence(
|
|
| 3285 |
chunks: tuple[str, ...],
|
| 3286 |
expected_candidate_ordinals: tuple[int, ...],
|
| 3287 |
require_explicit_candidate_ordinals: bool,
|
|
|
|
| 3288 |
) -> CandidateGenerationEvidence:
|
| 3289 |
"""Validate deterministic CFG evidence supplied by the hosted app."""
|
| 3290 |
|
|
@@ -3326,6 +3494,55 @@ def _validated_candidate_generation_evidence(
|
|
| 3326 |
chunk_text_variants = value.chunk_text_variants
|
| 3327 |
else:
|
| 3328 |
chunk_text_variants = ("base",) * len(chunks)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3329 |
raw_ordinals = value.chunk_candidate_ordinals
|
| 3330 |
if not raw_ordinals:
|
| 3331 |
if require_explicit_candidate_ordinals:
|
|
@@ -3406,6 +3623,10 @@ def _validated_candidate_generation_evidence(
|
|
| 3406 |
chunk_candidate_ordinals=candidate_ordinals,
|
| 3407 |
network_conditioned=network_conditioned,
|
| 3408 |
chunk_text_variants=chunk_text_variants,
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3409 |
)
|
| 3410 |
|
| 3411 |
|
|
@@ -3447,6 +3668,20 @@ def _candidate_attempt_evidence(
|
|
| 3447 |
chunk_text_variants=(
|
| 3448 |
generation.chunk_text_variants if generation is not None else ()
|
| 3449 |
),
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3450 |
scheduled_cfg=(generation.scheduled_cfg if generation is not None else None),
|
| 3451 |
effective_cfgs=(generation.effective_cfgs if generation is not None else ()),
|
| 3452 |
floor_reasons=(generation.floor_reasons if generation is not None else ()),
|
|
@@ -3598,7 +3833,17 @@ def _sequence_fallback_search(
|
|
| 3598 |
except ValueError:
|
| 3599 |
speaker_artifact_valid = False
|
| 3600 |
if speaker_artifact_valid:
|
| 3601 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3602 |
local_scores[chunk_index].append(score)
|
| 3603 |
sequence_results.append(tuple(adjusted_results))
|
| 3604 |
|
|
@@ -3981,6 +4226,50 @@ def _validate_coverage_evidence(
|
|
| 3981 |
return verification
|
| 3982 |
|
| 3983 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3984 |
def _coverage_artifact_is_valid(
|
| 3985 |
result: CandidateGateResult,
|
| 3986 |
artifact: ChunkCandidateArtifact,
|
|
@@ -4006,6 +4295,8 @@ def _coverage_artifact_is_valid(
|
|
| 4006 |
minimum=1.0,
|
| 4007 |
) is None:
|
| 4008 |
return False
|
|
|
|
|
|
|
| 4009 |
embedding = artifact.speaker_embedding
|
| 4010 |
if result.speaker_gate_applied is True and embedding is None:
|
| 4011 |
return False
|
|
@@ -4018,6 +4309,127 @@ def _coverage_artifact_is_valid(
|
|
| 4018 |
return True
|
| 4019 |
|
| 4020 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4021 |
def _coverage_local_candidate(
|
| 4022 |
*,
|
| 4023 |
candidate_index: int,
|
|
@@ -4042,6 +4454,11 @@ def _coverage_local_candidate(
|
|
| 4042 |
return None
|
| 4043 |
if not _coverage_artifact_is_valid(adjusted, artifact):
|
| 4044 |
raise RuntimeError("local verifier passed without valid acoustic evidence")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4045 |
return _RaggedChunkCandidate(
|
| 4046 |
candidate_index=candidate_index,
|
| 4047 |
seed=seed,
|
|
@@ -4132,6 +4549,7 @@ def run_coverage_adaptive_cascade(
|
|
| 4132 |
preferred_min_squim_stoi: float | None = None,
|
| 4133 |
preferred_min_squim_pesq: float | None = None,
|
| 4134 |
preferred_min_squim_audio_duration_seconds: float = 0.0,
|
|
|
|
| 4135 |
) -> CascadeResult:
|
| 4136 |
"""Run one whole trajectory, then deterministic low-coverage refills.
|
| 4137 |
|
|
@@ -4168,6 +4586,12 @@ def run_coverage_adaptive_cascade(
|
|
| 4168 |
generation_evidence_factory
|
| 4169 |
):
|
| 4170 |
raise ValueError("generation_evidence_factory must be callable")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4171 |
if candidate_generation_text_transform is not None and not callable(
|
| 4172 |
candidate_generation_text_transform
|
| 4173 |
):
|
|
@@ -4408,6 +4832,7 @@ def run_coverage_adaptive_cascade(
|
|
| 4408 |
chunks=candidate_chunks,
|
| 4409 |
expected_candidate_ordinals=expected_ordinals,
|
| 4410 |
require_explicit_candidate_ordinals=context_aware_evidence,
|
|
|
|
| 4411 |
)
|
| 4412 |
except Exception as error:
|
| 4413 |
raise RuntimeError("candidate generation evidence is invalid") from error
|
|
@@ -4461,6 +4886,11 @@ def run_coverage_adaptive_cascade(
|
|
| 4461 |
chunk_count,
|
| 4462 |
verifier_name="whole candidate verifier",
|
| 4463 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4464 |
diagnostic_candidates.append(
|
| 4465 |
_VerifiedTrajectoryCandidate(
|
| 4466 |
candidate_index=0,
|
|
@@ -4687,6 +5117,11 @@ def run_coverage_adaptive_cascade(
|
|
| 4687 |
1,
|
| 4688 |
verifier_name="refill candidate verifier",
|
| 4689 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4690 |
latest_local_results[chunk_index] = refill_verification.candidate_results[0]
|
| 4691 |
diagnostic_candidates.append(
|
| 4692 |
_VerifiedTrajectoryCandidate(
|
|
@@ -4729,14 +5164,67 @@ def run_coverage_adaptive_cascade(
|
|
| 4729 |
min_squim_audio_duration_seconds=preferred_squim_duration,
|
| 4730 |
)
|
| 4731 |
):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4732 |
return CascadeResult(
|
| 4733 |
-
trajectory=
|
| 4734 |
-
verification=
|
| 4735 |
-
seed=seed,
|
| 4736 |
-
candidate_index=
|
| 4737 |
attempted_seeds=tuple(attempted_seeds),
|
| 4738 |
-
chunk_candidate_indices=(
|
| 4739 |
-
chunk_seeds=(seed,),
|
| 4740 |
selection_mode="whole_trajectory",
|
| 4741 |
diagnostics=_cascade_diagnostics(diagnostic_candidates),
|
| 4742 |
generated_chunk_count=generated_chunks,
|
|
|
|
| 61 |
SEQUENCE_FALLBACK_MAX_LOCAL_BOUNDARY_SPEAKER_DROP = 0.15
|
| 62 |
SEQUENCE_FALLBACK_SPEAKER_WEIGHT = 0.05
|
| 63 |
SEQUENCE_FALLBACK_BOUNDARY_WEIGHT = 0.10
|
| 64 |
+
ENDPOINT_TAIL_WINDOW_MS = 5.0
|
| 65 |
+
ENDPOINT_HARD_STOP_PENALTY = 0.05
|
| 66 |
+
ENDPOINT_ENERGY_WEIGHT = 0.02
|
| 67 |
+
ENDPOINT_PREFERRED_SQUIM_STOI_SLACK = 0.02
|
| 68 |
+
ENDPOINT_PREFERRED_SQUIM_PESQ_SLACK = 0.03
|
| 69 |
+
CASCADE_EVIDENCE_SCHEMA_VERSION = 6
|
| 70 |
CASCADE_EVIDENCE_LOG_PREFIX = "[BlueMagpie] cascade evidence "
|
| 71 |
CASCADE_EVIDENCE_MAX_ATTEMPTS = ADAPTIVE_CASCADE_STAGE_LIMITS[-1]
|
| 72 |
CASCADE_EVIDENCE_MAX_LOCAL_RESULTS = ADAPTIVE_CASCADE_STAGE_LIMITS[-1]
|
|
|
|
| 81 |
{"whole_trajectory", "sequence_dp", "coverage_sequence_dp"}
|
| 82 |
)
|
| 83 |
_CFG_FLOOR_REASONS = frozenset({"network", "short_text"})
|
| 84 |
+
_GENERATION_STOP_REASONS = frozenset(
|
| 85 |
+
{"hard_stop", "native_stop", "stop_threshold"}
|
| 86 |
+
)
|
| 87 |
_CASCADE_EVIDENCE_REJECTION_CODES = frozenset(
|
| 88 |
{
|
| 89 |
"boundary_speaker_drop",
|
|
|
|
| 123 |
cjk_cps: float
|
| 124 |
ascii_cps: float
|
| 125 |
hard_stop_margin_steps: int
|
| 126 |
+
short_headroom_max_units: int = 0
|
| 127 |
+
short_hard_stop_floor_steps: int = 0
|
| 128 |
|
| 129 |
|
| 130 |
@dataclass(frozen=True)
|
|
|
|
| 161 |
cjk_cps=4.2,
|
| 162 |
ascii_cps=3.6,
|
| 163 |
hard_stop_margin_steps=1,
|
| 164 |
+
short_headroom_max_units=2,
|
| 165 |
+
short_hard_stop_floor_steps=5,
|
| 166 |
)
|
| 167 |
MIXED_CFG_SCHEDULE = "row_ordinal_zero_and_even_primary_odd_alternate"
|
| 168 |
MIXED_CFG_PRIMARY = 3.0
|
|
|
|
| 1458 |
return 20.0 * math.log10(rms)
|
| 1459 |
|
| 1460 |
|
| 1461 |
+
def endpoint_tail_energy_ratio(
|
| 1462 |
+
audio: np.ndarray | Sequence[float],
|
| 1463 |
+
sample_rate: int,
|
| 1464 |
+
*,
|
| 1465 |
+
window_ms: float = ENDPOINT_TAIL_WINDOW_MS,
|
| 1466 |
+
) -> float:
|
| 1467 |
+
"""Measure pre-fade endpoint RMS relative to the waveform peak.
|
| 1468 |
+
|
| 1469 |
+
The ratio is intentionally scale-independent and is measured before final
|
| 1470 |
+
fade/padding. A strongly voiced forced endpoint approaches one, while a
|
| 1471 |
+
naturally quiet endpoint approaches zero.
|
| 1472 |
+
"""
|
| 1473 |
+
|
| 1474 |
+
waveform = _mono_audio(audio)
|
| 1475 |
+
if isinstance(sample_rate, (bool, np.bool_)):
|
| 1476 |
+
raise ValueError("sample_rate must be a positive integer")
|
| 1477 |
+
try:
|
| 1478 |
+
rate = operator.index(sample_rate)
|
| 1479 |
+
duration_ms = float(window_ms)
|
| 1480 |
+
except (TypeError, ValueError, OverflowError) as error:
|
| 1481 |
+
raise ValueError("endpoint window must be finite and positive") from error
|
| 1482 |
+
if rate <= 0 or not math.isfinite(duration_ms) or duration_ms <= 0.0:
|
| 1483 |
+
raise ValueError("endpoint window must be finite and positive")
|
| 1484 |
+
window = max(1, int(round(duration_ms * int(rate) / 1000.0)))
|
| 1485 |
+
tail = waveform[-min(waveform.size, window) :]
|
| 1486 |
+
peak = float(np.max(np.abs(waveform)))
|
| 1487 |
+
if not math.isfinite(peak) or peak <= 1.0e-8:
|
| 1488 |
+
return 0.0
|
| 1489 |
+
tail_rms = float(np.sqrt(np.mean(np.square(tail, dtype=np.float64))))
|
| 1490 |
+
if not math.isfinite(tail_rms) or tail_rms < 0.0:
|
| 1491 |
+
raise ValueError("endpoint energy is invalid")
|
| 1492 |
+
return float(np.clip(tail_rms / peak, 0.0, 1.0))
|
| 1493 |
+
|
| 1494 |
+
|
| 1495 |
def active_audio_median_f0_hz(
|
| 1496 |
audio: np.ndarray | Sequence[float],
|
| 1497 |
sample_rate: int,
|
|
|
|
| 1567 |
speaker_embedding: np.ndarray | None = None
|
| 1568 |
rms_db: float | None = None
|
| 1569 |
median_f0_hz: float | None = None
|
| 1570 |
+
stop_reason: str | None = None
|
| 1571 |
+
endpoint_energy_ratio: float | None = None
|
| 1572 |
+
generated_steps: int | None = None
|
| 1573 |
+
hard_stop_steps: int | None = None
|
| 1574 |
|
| 1575 |
|
| 1576 |
@dataclass(frozen=True)
|
|
|
|
| 1634 |
chunk_candidate_ordinals: tuple[int, ...] = ()
|
| 1635 |
network_conditioned: tuple[bool, ...] = ()
|
| 1636 |
chunk_text_variants: tuple[str, ...] = ()
|
| 1637 |
+
chunk_stop_reasons: tuple[str, ...] = ()
|
| 1638 |
+
chunk_endpoint_energy_ratios: tuple[float, ...] = ()
|
| 1639 |
+
chunk_generated_steps: tuple[int, ...] = ()
|
| 1640 |
+
chunk_hard_stop_steps: tuple[int, ...] = ()
|
| 1641 |
|
| 1642 |
|
| 1643 |
@dataclass(frozen=True)
|
|
|
|
| 1656 |
chunk_candidate_ordinals: tuple[int, ...]
|
| 1657 |
network_conditioned: tuple[bool, ...]
|
| 1658 |
chunk_text_variants: tuple[str, ...]
|
| 1659 |
+
chunk_stop_reasons: tuple[str, ...]
|
| 1660 |
+
chunk_endpoint_energy_ratios: tuple[float, ...]
|
| 1661 |
+
chunk_generated_steps: tuple[int, ...]
|
| 1662 |
+
chunk_hard_stop_steps: tuple[int, ...]
|
| 1663 |
scheduled_cfg: float | None
|
| 1664 |
effective_cfgs: tuple[float, ...]
|
| 1665 |
floor_reasons: tuple[tuple[str, ...], ...]
|
|
|
|
| 2588 |
"chunk_policies": chunk_policies,
|
| 2589 |
"chunk_text_variants": list(evidence.chunk_text_variants),
|
| 2590 |
"network_conditioned": list(evidence.network_conditioned),
|
| 2591 |
+
"chunk_stop_reasons": list(evidence.chunk_stop_reasons),
|
| 2592 |
+
"chunk_endpoint_energy_ratios": list(
|
| 2593 |
+
evidence.chunk_endpoint_energy_ratios
|
| 2594 |
+
),
|
| 2595 |
+
"chunk_generated_steps": list(evidence.chunk_generated_steps),
|
| 2596 |
+
"chunk_hard_stop_steps": list(evidence.chunk_hard_stop_steps),
|
| 2597 |
"scheduled_cfg": evidence.scheduled_cfg,
|
| 2598 |
"effective_cfgs": list(evidence.effective_cfgs),
|
| 2599 |
"floor_reasons": [list(reasons) for reasons in evidence.floor_reasons],
|
|
|
|
| 2683 |
policies: list[str | None] = []
|
| 2684 |
network_conditioned: list[bool | None] = []
|
| 2685 |
chunk_text_variants: list[str | None] = []
|
| 2686 |
+
stop_reasons: list[str | None] = []
|
| 2687 |
+
endpoint_energy_ratios: list[float | None] = []
|
| 2688 |
+
generated_steps: list[int | None] = []
|
| 2689 |
+
hard_stop_steps: list[int | None] = []
|
| 2690 |
complete = True
|
| 2691 |
+
endpoint_complete = True
|
| 2692 |
for chunk_index, candidate_index in enumerate(
|
| 2693 |
selection.chunk_candidate_indices
|
| 2694 |
):
|
|
|
|
| 2702 |
policies.append(None)
|
| 2703 |
network_conditioned.append(None)
|
| 2704 |
chunk_text_variants.append(None)
|
| 2705 |
+
stop_reasons.append(None)
|
| 2706 |
+
endpoint_energy_ratios.append(None)
|
| 2707 |
+
generated_steps.append(None)
|
| 2708 |
+
hard_stop_steps.append(None)
|
| 2709 |
+
endpoint_complete = False
|
| 2710 |
continue
|
| 2711 |
try:
|
| 2712 |
local_index = attempt.chunk_indices.index(chunk_index)
|
|
|
|
| 2721 |
policies.append(None)
|
| 2722 |
network_conditioned.append(None)
|
| 2723 |
chunk_text_variants.append(None)
|
| 2724 |
+
stop_reasons.append(None)
|
| 2725 |
+
endpoint_energy_ratios.append(None)
|
| 2726 |
+
generated_steps.append(None)
|
| 2727 |
+
hard_stop_steps.append(None)
|
| 2728 |
+
endpoint_complete = False
|
| 2729 |
continue
|
| 2730 |
try:
|
| 2731 |
ordinal = attempt.chunk_candidate_ordinals[local_index]
|
|
|
|
| 2751 |
except IndexError:
|
| 2752 |
complete = False
|
| 2753 |
chunk_text_variants.append(None)
|
| 2754 |
+
try:
|
| 2755 |
+
stop_reason = attempt.chunk_stop_reasons[local_index]
|
| 2756 |
+
endpoint_energy_ratio = (
|
| 2757 |
+
attempt.chunk_endpoint_energy_ratios[local_index]
|
| 2758 |
+
)
|
| 2759 |
+
generated_step_count = attempt.chunk_generated_steps[local_index]
|
| 2760 |
+
hard_stop_step_count = attempt.chunk_hard_stop_steps[local_index]
|
| 2761 |
+
except IndexError:
|
| 2762 |
+
endpoint_complete = False
|
| 2763 |
+
stop_reasons.append(None)
|
| 2764 |
+
endpoint_energy_ratios.append(None)
|
| 2765 |
+
generated_steps.append(None)
|
| 2766 |
+
hard_stop_steps.append(None)
|
| 2767 |
+
else:
|
| 2768 |
+
endpoint_artifact = ChunkCandidateArtifact(
|
| 2769 |
+
stop_reason=stop_reason,
|
| 2770 |
+
endpoint_energy_ratio=endpoint_energy_ratio,
|
| 2771 |
+
generated_steps=generated_step_count,
|
| 2772 |
+
hard_stop_steps=hard_stop_step_count,
|
| 2773 |
+
)
|
| 2774 |
+
if (
|
| 2775 |
+
stop_reason is None
|
| 2776 |
+
or endpoint_energy_ratio is None
|
| 2777 |
+
or generated_step_count is None
|
| 2778 |
+
or hard_stop_step_count is None
|
| 2779 |
+
or not _endpoint_artifact_is_valid(endpoint_artifact)
|
| 2780 |
+
):
|
| 2781 |
+
endpoint_complete = False
|
| 2782 |
+
stop_reasons.append(stop_reason)
|
| 2783 |
+
endpoint_energy_ratios.append(endpoint_energy_ratio)
|
| 2784 |
+
generated_steps.append(generated_step_count)
|
| 2785 |
+
hard_stop_steps.append(hard_stop_step_count)
|
| 2786 |
return {
|
| 2787 |
"complete": complete,
|
| 2788 |
+
"endpoint_complete": endpoint_complete,
|
| 2789 |
"chunk_scheduled_cfgs": scheduled_cfgs,
|
| 2790 |
"chunk_effective_cfgs": effective_cfgs,
|
| 2791 |
"chunk_floor_reasons": floor_reasons,
|
|
|
|
| 2793 |
"chunk_policies": policies,
|
| 2794 |
"network_conditioned": network_conditioned,
|
| 2795 |
"chunk_text_variants": chunk_text_variants,
|
| 2796 |
+
"chunk_stop_reasons": stop_reasons,
|
| 2797 |
+
"chunk_endpoint_energy_ratios": endpoint_energy_ratios,
|
| 2798 |
+
"chunk_generated_steps": generated_steps,
|
| 2799 |
+
"chunk_hard_stop_steps": hard_stop_steps,
|
| 2800 |
}
|
| 2801 |
|
| 2802 |
|
| 2803 |
+
def _attempt_endpoint_evidence_is_complete(
|
| 2804 |
+
attempt: CandidateAttemptEvidence,
|
| 2805 |
+
) -> bool:
|
| 2806 |
+
"""Validate every bounded endpoint row before declaring it complete."""
|
| 2807 |
+
|
| 2808 |
+
row_count = len(attempt.chunk_indices)
|
| 2809 |
+
endpoint_rows = (
|
| 2810 |
+
attempt.chunk_stop_reasons,
|
| 2811 |
+
attempt.chunk_endpoint_energy_ratios,
|
| 2812 |
+
attempt.chunk_generated_steps,
|
| 2813 |
+
attempt.chunk_hard_stop_steps,
|
| 2814 |
+
)
|
| 2815 |
+
if row_count == 0 or any(len(row) != row_count for row in endpoint_rows):
|
| 2816 |
+
return False
|
| 2817 |
+
return all(
|
| 2818 |
+
reason is not None
|
| 2819 |
+
and energy is not None
|
| 2820 |
+
and generated is not None
|
| 2821 |
+
and hard_stop is not None
|
| 2822 |
+
and _endpoint_artifact_is_valid(
|
| 2823 |
+
ChunkCandidateArtifact(
|
| 2824 |
+
stop_reason=reason,
|
| 2825 |
+
endpoint_energy_ratio=energy,
|
| 2826 |
+
generated_steps=generated,
|
| 2827 |
+
hard_stop_steps=hard_stop,
|
| 2828 |
+
)
|
| 2829 |
+
)
|
| 2830 |
+
for reason, energy, generated, hard_stop in zip(
|
| 2831 |
+
*endpoint_rows,
|
| 2832 |
+
strict=True,
|
| 2833 |
+
)
|
| 2834 |
+
)
|
| 2835 |
+
|
| 2836 |
+
|
| 2837 |
def format_cascade_evidence_log(
|
| 2838 |
diagnostics: CascadeDiagnostics,
|
| 2839 |
*,
|
|
|
|
| 2873 |
"generated_text_unit_limit must be an integer between 1 and 800"
|
| 2874 |
)
|
| 2875 |
|
| 2876 |
+
attempts = diagnostics.attempts[:CASCADE_EVIDENCE_MAX_ATTEMPTS]
|
| 2877 |
+
for attempt in attempts:
|
| 2878 |
+
endpoint_rows = (
|
| 2879 |
+
attempt.chunk_stop_reasons,
|
| 2880 |
+
attempt.chunk_endpoint_energy_ratios,
|
| 2881 |
+
attempt.chunk_generated_steps,
|
| 2882 |
+
attempt.chunk_hard_stop_steps,
|
| 2883 |
+
)
|
| 2884 |
+
if any(endpoint_rows) and not _attempt_endpoint_evidence_is_complete(
|
| 2885 |
+
attempt
|
| 2886 |
+
):
|
| 2887 |
+
raise ValueError("canonical endpoint evidence is invalid")
|
| 2888 |
+
|
| 2889 |
selected: dict[str, Any] | None = None
|
| 2890 |
if selection is not None:
|
| 2891 |
if not isinstance(selection, CascadeResult):
|
|
|
|
| 2922 |
),
|
| 2923 |
}
|
| 2924 |
|
|
|
|
| 2925 |
generation_evidence_complete = bool(attempts) and all(
|
| 2926 |
attempt.scheduled_cfg is not None
|
| 2927 |
and len(attempt.chunk_indices) == len(attempt.chunk_text_units)
|
|
|
|
| 2933 |
and bool(attempt.chunk_indices)
|
| 2934 |
for attempt in attempts
|
| 2935 |
)
|
| 2936 |
+
endpoint_evidence_complete = bool(attempts) and all(
|
| 2937 |
+
_attempt_endpoint_evidence_is_complete(attempt)
|
| 2938 |
+
for attempt in attempts
|
| 2939 |
+
)
|
| 2940 |
generated_chunk_count = sum(len(attempt.chunk_indices) for attempt in attempts)
|
| 2941 |
generated_text_units = sum(
|
| 2942 |
sum(attempt.chunk_text_units) for attempt in attempts
|
|
|
|
| 2970 |
},
|
| 2971 |
"attempt_count": len(diagnostics.attempts),
|
| 2972 |
"generation_evidence_complete": generation_evidence_complete,
|
| 2973 |
+
"endpoint_evidence_complete": endpoint_evidence_complete,
|
| 2974 |
"generated_chunk_count": generated_chunk_count,
|
| 2975 |
"generated_text_units": generated_text_units,
|
| 2976 |
"attempts": [
|
|
|
|
| 3452 |
chunks: tuple[str, ...],
|
| 3453 |
expected_candidate_ordinals: tuple[int, ...],
|
| 3454 |
require_explicit_candidate_ordinals: bool,
|
| 3455 |
+
require_endpoint_evidence: bool,
|
| 3456 |
) -> CandidateGenerationEvidence:
|
| 3457 |
"""Validate deterministic CFG evidence supplied by the hosted app."""
|
| 3458 |
|
|
|
|
| 3494 |
chunk_text_variants = value.chunk_text_variants
|
| 3495 |
else:
|
| 3496 |
chunk_text_variants = ("base",) * len(chunks)
|
| 3497 |
+
endpoint_rows = (
|
| 3498 |
+
value.chunk_stop_reasons,
|
| 3499 |
+
value.chunk_endpoint_energy_ratios,
|
| 3500 |
+
value.chunk_generated_steps,
|
| 3501 |
+
value.chunk_hard_stop_steps,
|
| 3502 |
+
)
|
| 3503 |
+
endpoint_evidence_present = any(endpoint_rows)
|
| 3504 |
+
if require_endpoint_evidence and not all(endpoint_rows):
|
| 3505 |
+
raise ValueError("generation endpoint evidence is required")
|
| 3506 |
+
if endpoint_evidence_present and not all(
|
| 3507 |
+
isinstance(row, tuple) and len(row) == len(chunks)
|
| 3508 |
+
for row in endpoint_rows
|
| 3509 |
+
):
|
| 3510 |
+
raise ValueError("generation endpoint evidence does not match the attempt")
|
| 3511 |
+
stop_reasons: list[str] = []
|
| 3512 |
+
endpoint_energy_ratios: list[float] = []
|
| 3513 |
+
generated_steps: list[int] = []
|
| 3514 |
+
hard_stop_steps: list[int] = []
|
| 3515 |
+
if endpoint_evidence_present:
|
| 3516 |
+
for raw_reason, raw_energy, raw_generated, raw_hard_stop in zip(
|
| 3517 |
+
*endpoint_rows,
|
| 3518 |
+
strict=True,
|
| 3519 |
+
):
|
| 3520 |
+
if raw_reason not in _GENERATION_STOP_REASONS:
|
| 3521 |
+
raise ValueError("generation stop reason is invalid")
|
| 3522 |
+
energy = _finite_float(raw_energy, minimum=0.0, maximum=1.0)
|
| 3523 |
+
if energy is None:
|
| 3524 |
+
raise ValueError("generation endpoint energy is invalid")
|
| 3525 |
+
if any(
|
| 3526 |
+
isinstance(value, (bool, np.bool_))
|
| 3527 |
+
for value in (raw_generated, raw_hard_stop)
|
| 3528 |
+
):
|
| 3529 |
+
raise ValueError("generation endpoint steps are invalid")
|
| 3530 |
+
try:
|
| 3531 |
+
generated = operator.index(raw_generated)
|
| 3532 |
+
hard_stop = operator.index(raw_hard_stop)
|
| 3533 |
+
except (TypeError, ValueError, OverflowError) as error:
|
| 3534 |
+
raise ValueError("generation endpoint steps are invalid") from error
|
| 3535 |
+
if (
|
| 3536 |
+
not 1 <= generated <= 2_000
|
| 3537 |
+
or not 1 <= hard_stop <= 2_000
|
| 3538 |
+
or generated > hard_stop
|
| 3539 |
+
or (raw_reason == "hard_stop" and generated != hard_stop)
|
| 3540 |
+
):
|
| 3541 |
+
raise ValueError("generation endpoint steps are invalid")
|
| 3542 |
+
stop_reasons.append(raw_reason)
|
| 3543 |
+
endpoint_energy_ratios.append(energy)
|
| 3544 |
+
generated_steps.append(int(generated))
|
| 3545 |
+
hard_stop_steps.append(int(hard_stop))
|
| 3546 |
raw_ordinals = value.chunk_candidate_ordinals
|
| 3547 |
if not raw_ordinals:
|
| 3548 |
if require_explicit_candidate_ordinals:
|
|
|
|
| 3623 |
chunk_candidate_ordinals=candidate_ordinals,
|
| 3624 |
network_conditioned=network_conditioned,
|
| 3625 |
chunk_text_variants=chunk_text_variants,
|
| 3626 |
+
chunk_stop_reasons=tuple(stop_reasons),
|
| 3627 |
+
chunk_endpoint_energy_ratios=tuple(endpoint_energy_ratios),
|
| 3628 |
+
chunk_generated_steps=tuple(generated_steps),
|
| 3629 |
+
chunk_hard_stop_steps=tuple(hard_stop_steps),
|
| 3630 |
)
|
| 3631 |
|
| 3632 |
|
|
|
|
| 3668 |
chunk_text_variants=(
|
| 3669 |
generation.chunk_text_variants if generation is not None else ()
|
| 3670 |
),
|
| 3671 |
+
chunk_stop_reasons=(
|
| 3672 |
+
generation.chunk_stop_reasons if generation is not None else ()
|
| 3673 |
+
),
|
| 3674 |
+
chunk_endpoint_energy_ratios=(
|
| 3675 |
+
generation.chunk_endpoint_energy_ratios
|
| 3676 |
+
if generation is not None
|
| 3677 |
+
else ()
|
| 3678 |
+
),
|
| 3679 |
+
chunk_generated_steps=(
|
| 3680 |
+
generation.chunk_generated_steps if generation is not None else ()
|
| 3681 |
+
),
|
| 3682 |
+
chunk_hard_stop_steps=(
|
| 3683 |
+
generation.chunk_hard_stop_steps if generation is not None else ()
|
| 3684 |
+
),
|
| 3685 |
scheduled_cfg=(generation.scheduled_cfg if generation is not None else None),
|
| 3686 |
effective_cfgs=(generation.effective_cfgs if generation is not None else ()),
|
| 3687 |
floor_reasons=(generation.floor_reasons if generation is not None else ()),
|
|
|
|
| 3833 |
except ValueError:
|
| 3834 |
speaker_artifact_valid = False
|
| 3835 |
if speaker_artifact_valid:
|
| 3836 |
+
endpoint_cost = candidate_endpoint_selection_cost(
|
| 3837 |
+
artifact
|
| 3838 |
+
)
|
| 3839 |
+
adjusted_score = adjusted_result.score + endpoint_cost
|
| 3840 |
+
if math.isfinite(adjusted_score):
|
| 3841 |
+
adjusted_result = replace(
|
| 3842 |
+
adjusted_result,
|
| 3843 |
+
score=adjusted_score,
|
| 3844 |
+
)
|
| 3845 |
+
adjusted_results[-1] = adjusted_result
|
| 3846 |
+
score = adjusted_score
|
| 3847 |
local_scores[chunk_index].append(score)
|
| 3848 |
sequence_results.append(tuple(adjusted_results))
|
| 3849 |
|
|
|
|
| 4226 |
return verification
|
| 4227 |
|
| 4228 |
|
| 4229 |
+
def _endpoint_artifact_is_valid(artifact: ChunkCandidateArtifact) -> bool:
|
| 4230 |
+
"""Validate an optional all-or-none endpoint provenance row."""
|
| 4231 |
+
|
| 4232 |
+
endpoint_values = (
|
| 4233 |
+
artifact.stop_reason,
|
| 4234 |
+
artifact.endpoint_energy_ratio,
|
| 4235 |
+
artifact.generated_steps,
|
| 4236 |
+
artifact.hard_stop_steps,
|
| 4237 |
+
)
|
| 4238 |
+
if all(value is None for value in endpoint_values):
|
| 4239 |
+
return True
|
| 4240 |
+
if any(value is not None for value in endpoint_values):
|
| 4241 |
+
if any(value is None for value in endpoint_values):
|
| 4242 |
+
return False
|
| 4243 |
+
if artifact.stop_reason not in _GENERATION_STOP_REASONS:
|
| 4244 |
+
return False
|
| 4245 |
+
energy = _finite_float(
|
| 4246 |
+
artifact.endpoint_energy_ratio,
|
| 4247 |
+
minimum=0.0,
|
| 4248 |
+
maximum=1.0,
|
| 4249 |
+
)
|
| 4250 |
+
if energy is None or any(
|
| 4251 |
+
isinstance(value, (bool, np.bool_))
|
| 4252 |
+
for value in (artifact.generated_steps, artifact.hard_stop_steps)
|
| 4253 |
+
):
|
| 4254 |
+
return False
|
| 4255 |
+
try:
|
| 4256 |
+
generated = operator.index(artifact.generated_steps)
|
| 4257 |
+
hard_stop = operator.index(artifact.hard_stop_steps)
|
| 4258 |
+
except (TypeError, ValueError, OverflowError):
|
| 4259 |
+
return False
|
| 4260 |
+
if (
|
| 4261 |
+
not 1 <= generated <= 2_000
|
| 4262 |
+
or not 1 <= hard_stop <= 2_000
|
| 4263 |
+
or generated > hard_stop
|
| 4264 |
+
or (
|
| 4265 |
+
artifact.stop_reason == "hard_stop"
|
| 4266 |
+
and generated != hard_stop
|
| 4267 |
+
)
|
| 4268 |
+
):
|
| 4269 |
+
return False
|
| 4270 |
+
return True
|
| 4271 |
+
|
| 4272 |
+
|
| 4273 |
def _coverage_artifact_is_valid(
|
| 4274 |
result: CandidateGateResult,
|
| 4275 |
artifact: ChunkCandidateArtifact,
|
|
|
|
| 4295 |
minimum=1.0,
|
| 4296 |
) is None:
|
| 4297 |
return False
|
| 4298 |
+
if not _endpoint_artifact_is_valid(artifact):
|
| 4299 |
+
return False
|
| 4300 |
embedding = artifact.speaker_embedding
|
| 4301 |
if result.speaker_gate_applied is True and embedding is None:
|
| 4302 |
return False
|
|
|
|
| 4309 |
return True
|
| 4310 |
|
| 4311 |
|
| 4312 |
+
def _bind_generation_endpoint_evidence(
|
| 4313 |
+
verification: TrajectoryGateResult,
|
| 4314 |
+
generation: CandidateGenerationEvidence | None,
|
| 4315 |
+
*,
|
| 4316 |
+
required: bool,
|
| 4317 |
+
) -> TrajectoryGateResult:
|
| 4318 |
+
"""Attach validated generation endpoint provenance to chunk artifacts."""
|
| 4319 |
+
|
| 4320 |
+
if generation is None or not generation.chunk_stop_reasons:
|
| 4321 |
+
if required:
|
| 4322 |
+
raise RuntimeError("candidate endpoint evidence is missing")
|
| 4323 |
+
return verification
|
| 4324 |
+
row_count = len(verification.chunk_artifacts)
|
| 4325 |
+
endpoint_rows = (
|
| 4326 |
+
generation.chunk_stop_reasons,
|
| 4327 |
+
generation.chunk_endpoint_energy_ratios,
|
| 4328 |
+
generation.chunk_generated_steps,
|
| 4329 |
+
generation.chunk_hard_stop_steps,
|
| 4330 |
+
)
|
| 4331 |
+
if any(len(row) != row_count for row in endpoint_rows):
|
| 4332 |
+
raise RuntimeError("candidate endpoint evidence is misaligned")
|
| 4333 |
+
artifacts = tuple(
|
| 4334 |
+
replace(
|
| 4335 |
+
artifact,
|
| 4336 |
+
stop_reason=reason,
|
| 4337 |
+
endpoint_energy_ratio=energy,
|
| 4338 |
+
generated_steps=generated,
|
| 4339 |
+
hard_stop_steps=hard_stop,
|
| 4340 |
+
)
|
| 4341 |
+
for artifact, reason, energy, generated, hard_stop in zip(
|
| 4342 |
+
verification.chunk_artifacts,
|
| 4343 |
+
*endpoint_rows,
|
| 4344 |
+
strict=True,
|
| 4345 |
+
)
|
| 4346 |
+
)
|
| 4347 |
+
if any(
|
| 4348 |
+
not _coverage_artifact_is_valid(result, artifact)
|
| 4349 |
+
for result, artifact in zip(
|
| 4350 |
+
verification.candidate_results,
|
| 4351 |
+
artifacts,
|
| 4352 |
+
strict=True,
|
| 4353 |
+
)
|
| 4354 |
+
if result.comparison.passed is True
|
| 4355 |
+
):
|
| 4356 |
+
raise RuntimeError("candidate endpoint evidence is invalid")
|
| 4357 |
+
return replace(verification, chunk_artifacts=artifacts)
|
| 4358 |
+
|
| 4359 |
+
|
| 4360 |
+
def candidate_endpoint_selection_cost(
|
| 4361 |
+
artifact: ChunkCandidateArtifact,
|
| 4362 |
+
) -> float:
|
| 4363 |
+
"""Return a bounded soft preference for natural, quiet endpoints."""
|
| 4364 |
+
|
| 4365 |
+
if artifact.stop_reason is None and artifact.endpoint_energy_ratio is None:
|
| 4366 |
+
return 0.0
|
| 4367 |
+
if not _endpoint_artifact_is_valid(artifact):
|
| 4368 |
+
return math.inf
|
| 4369 |
+
energy = float(artifact.endpoint_energy_ratio)
|
| 4370 |
+
hard_stop = (
|
| 4371 |
+
ENDPOINT_HARD_STOP_PENALTY
|
| 4372 |
+
if _endpoint_artifact_reached_hard_cap(artifact)
|
| 4373 |
+
else 0.0
|
| 4374 |
+
)
|
| 4375 |
+
return hard_stop + ENDPOINT_ENERGY_WEIGHT * energy
|
| 4376 |
+
|
| 4377 |
+
|
| 4378 |
+
def _endpoint_artifact_reached_hard_cap(
|
| 4379 |
+
artifact: ChunkCandidateArtifact,
|
| 4380 |
+
) -> bool:
|
| 4381 |
+
"""Return whether endpoint evidence reached the configured hard cap.
|
| 4382 |
+
|
| 4383 |
+
A threshold crossing can coincide with the final permitted generation
|
| 4384 |
+
step. The stop reason correctly records that the model crossed the
|
| 4385 |
+
threshold, but endpoint selection must still treat it as cap-reached so it
|
| 4386 |
+
cannot evade the bounded hard-cap cost or natural-endpoint waiver rules.
|
| 4387 |
+
"""
|
| 4388 |
+
|
| 4389 |
+
if not _endpoint_artifact_is_valid(artifact):
|
| 4390 |
+
return False
|
| 4391 |
+
if artifact.generated_steps is None or artifact.hard_stop_steps is None:
|
| 4392 |
+
return False
|
| 4393 |
+
return artifact.generated_steps >= artifact.hard_stop_steps
|
| 4394 |
+
|
| 4395 |
+
|
| 4396 |
+
def _preferred_natural_endpoint_waiver(
|
| 4397 |
+
verification: TrajectoryGateResult,
|
| 4398 |
+
artifact: ChunkCandidateArtifact,
|
| 4399 |
+
*,
|
| 4400 |
+
min_speaker_similarity: float | None,
|
| 4401 |
+
max_boundary_speaker_drop: float | None,
|
| 4402 |
+
min_squim_stoi: float | None,
|
| 4403 |
+
min_squim_pesq: float | None,
|
| 4404 |
+
min_squim_audio_duration_seconds: float,
|
| 4405 |
+
) -> bool:
|
| 4406 |
+
"""Allow only a tightly bounded quality trade for a true pre-cap stop."""
|
| 4407 |
+
|
| 4408 |
+
if (
|
| 4409 |
+
artifact.stop_reason != "stop_threshold"
|
| 4410 |
+
or _endpoint_artifact_reached_hard_cap(artifact)
|
| 4411 |
+
):
|
| 4412 |
+
return False
|
| 4413 |
+
relaxed_stoi = (
|
| 4414 |
+
None
|
| 4415 |
+
if min_squim_stoi is None
|
| 4416 |
+
else max(0.0, min_squim_stoi - ENDPOINT_PREFERRED_SQUIM_STOI_SLACK)
|
| 4417 |
+
)
|
| 4418 |
+
relaxed_pesq = (
|
| 4419 |
+
None
|
| 4420 |
+
if min_squim_pesq is None
|
| 4421 |
+
else max(0.0, min_squim_pesq - ENDPOINT_PREFERRED_SQUIM_PESQ_SLACK)
|
| 4422 |
+
)
|
| 4423 |
+
return _preferred_release_verification(
|
| 4424 |
+
verification,
|
| 4425 |
+
min_speaker_similarity=min_speaker_similarity,
|
| 4426 |
+
max_boundary_speaker_drop=max_boundary_speaker_drop,
|
| 4427 |
+
min_squim_stoi=relaxed_stoi,
|
| 4428 |
+
min_squim_pesq=relaxed_pesq,
|
| 4429 |
+
min_squim_audio_duration_seconds=min_squim_audio_duration_seconds,
|
| 4430 |
+
)
|
| 4431 |
+
|
| 4432 |
+
|
| 4433 |
def _coverage_local_candidate(
|
| 4434 |
*,
|
| 4435 |
candidate_index: int,
|
|
|
|
| 4454 |
return None
|
| 4455 |
if not _coverage_artifact_is_valid(adjusted, artifact):
|
| 4456 |
raise RuntimeError("local verifier passed without valid acoustic evidence")
|
| 4457 |
+
endpoint_cost = candidate_endpoint_selection_cost(artifact)
|
| 4458 |
+
adjusted_score = adjusted.score + endpoint_cost
|
| 4459 |
+
if not math.isfinite(adjusted_score) or adjusted_score < 0.0:
|
| 4460 |
+
raise RuntimeError("local verifier passed without valid endpoint evidence")
|
| 4461 |
+
adjusted = replace(adjusted, score=adjusted_score)
|
| 4462 |
return _RaggedChunkCandidate(
|
| 4463 |
candidate_index=candidate_index,
|
| 4464 |
seed=seed,
|
|
|
|
| 4549 |
preferred_min_squim_stoi: float | None = None,
|
| 4550 |
preferred_min_squim_pesq: float | None = None,
|
| 4551 |
preferred_min_squim_audio_duration_seconds: float = 0.0,
|
| 4552 |
+
require_endpoint_evidence: bool = False,
|
| 4553 |
) -> CascadeResult:
|
| 4554 |
"""Run one whole trajectory, then deterministic low-coverage refills.
|
| 4555 |
|
|
|
|
| 4586 |
generation_evidence_factory
|
| 4587 |
):
|
| 4588 |
raise ValueError("generation_evidence_factory must be callable")
|
| 4589 |
+
if type(require_endpoint_evidence) is not bool:
|
| 4590 |
+
raise ValueError("require_endpoint_evidence must be a boolean")
|
| 4591 |
+
if require_endpoint_evidence and generation_evidence_factory is None:
|
| 4592 |
+
raise ValueError(
|
| 4593 |
+
"endpoint evidence requires a generation evidence factory"
|
| 4594 |
+
)
|
| 4595 |
if candidate_generation_text_transform is not None and not callable(
|
| 4596 |
candidate_generation_text_transform
|
| 4597 |
):
|
|
|
|
| 4832 |
chunks=candidate_chunks,
|
| 4833 |
expected_candidate_ordinals=expected_ordinals,
|
| 4834 |
require_explicit_candidate_ordinals=context_aware_evidence,
|
| 4835 |
+
require_endpoint_evidence=require_endpoint_evidence,
|
| 4836 |
)
|
| 4837 |
except Exception as error:
|
| 4838 |
raise RuntimeError("candidate generation evidence is invalid") from error
|
|
|
|
| 4886 |
chunk_count,
|
| 4887 |
verifier_name="whole candidate verifier",
|
| 4888 |
)
|
| 4889 |
+
initial_verification = _bind_generation_endpoint_evidence(
|
| 4890 |
+
initial_verification,
|
| 4891 |
+
initial_generation_evidence,
|
| 4892 |
+
required=require_endpoint_evidence,
|
| 4893 |
+
)
|
| 4894 |
diagnostic_candidates.append(
|
| 4895 |
_VerifiedTrajectoryCandidate(
|
| 4896 |
candidate_index=0,
|
|
|
|
| 5117 |
1,
|
| 5118 |
verifier_name="refill candidate verifier",
|
| 5119 |
)
|
| 5120 |
+
refill_verification = _bind_generation_endpoint_evidence(
|
| 5121 |
+
refill_verification,
|
| 5122 |
+
refill_generation_evidence,
|
| 5123 |
+
required=require_endpoint_evidence,
|
| 5124 |
+
)
|
| 5125 |
latest_local_results[chunk_index] = refill_verification.candidate_results[0]
|
| 5126 |
diagnostic_candidates.append(
|
| 5127 |
_VerifiedTrajectoryCandidate(
|
|
|
|
| 5164 |
min_squim_audio_duration_seconds=preferred_squim_duration,
|
| 5165 |
)
|
| 5166 |
):
|
| 5167 |
+
preferred_candidate = diagnostic_candidates[-1]
|
| 5168 |
+
preferred_artifact = preferred_candidate.verification.chunk_artifacts[0]
|
| 5169 |
+
preferred_reached_hard_cap = (
|
| 5170 |
+
_endpoint_artifact_reached_hard_cap(preferred_artifact)
|
| 5171 |
+
)
|
| 5172 |
+
selectable = [
|
| 5173 |
+
candidate
|
| 5174 |
+
for candidate in diagnostic_candidates
|
| 5175 |
+
if candidate.verification.passed is True
|
| 5176 |
+
and math.isfinite(candidate.verification.score)
|
| 5177 |
+
and len(candidate.verification.chunk_artifacts) == 1
|
| 5178 |
+
and (
|
| 5179 |
+
_preferred_release_verification(
|
| 5180 |
+
candidate.verification,
|
| 5181 |
+
min_speaker_similarity=preferred_similarity,
|
| 5182 |
+
max_boundary_speaker_drop=preferred_boundary,
|
| 5183 |
+
min_squim_stoi=preferred_stoi,
|
| 5184 |
+
min_squim_pesq=preferred_pesq,
|
| 5185 |
+
min_squim_audio_duration_seconds=(
|
| 5186 |
+
preferred_squim_duration
|
| 5187 |
+
),
|
| 5188 |
+
)
|
| 5189 |
+
or (
|
| 5190 |
+
preferred_reached_hard_cap
|
| 5191 |
+
and _preferred_natural_endpoint_waiver(
|
| 5192 |
+
candidate.verification,
|
| 5193 |
+
candidate.verification.chunk_artifacts[0],
|
| 5194 |
+
min_speaker_similarity=preferred_similarity,
|
| 5195 |
+
max_boundary_speaker_drop=preferred_boundary,
|
| 5196 |
+
min_squim_stoi=preferred_stoi,
|
| 5197 |
+
min_squim_pesq=preferred_pesq,
|
| 5198 |
+
min_squim_audio_duration_seconds=(
|
| 5199 |
+
preferred_squim_duration
|
| 5200 |
+
),
|
| 5201 |
+
)
|
| 5202 |
+
)
|
| 5203 |
+
)
|
| 5204 |
+
and math.isfinite(
|
| 5205 |
+
candidate_endpoint_selection_cost(
|
| 5206 |
+
candidate.verification.chunk_artifacts[0]
|
| 5207 |
+
)
|
| 5208 |
+
)
|
| 5209 |
+
]
|
| 5210 |
+
selected_candidate = min(
|
| 5211 |
+
selectable,
|
| 5212 |
+
key=lambda candidate: (
|
| 5213 |
+
candidate.verification.score
|
| 5214 |
+
+ candidate_endpoint_selection_cost(
|
| 5215 |
+
candidate.verification.chunk_artifacts[0]
|
| 5216 |
+
),
|
| 5217 |
+
candidate.candidate_index,
|
| 5218 |
+
),
|
| 5219 |
+
)
|
| 5220 |
return CascadeResult(
|
| 5221 |
+
trajectory=selected_candidate.trajectory,
|
| 5222 |
+
verification=selected_candidate.verification,
|
| 5223 |
+
seed=selected_candidate.seed,
|
| 5224 |
+
candidate_index=selected_candidate.candidate_index,
|
| 5225 |
attempted_seeds=tuple(attempted_seeds),
|
| 5226 |
+
chunk_candidate_indices=(selected_candidate.candidate_index,),
|
| 5227 |
+
chunk_seeds=(selected_candidate.seed,),
|
| 5228 |
selection_mode="whole_trajectory",
|
| 5229 |
diagnostics=_cascade_diagnostics(diagnostic_candidates),
|
| 5230 |
generated_chunk_count=generated_chunks,
|
tests/test_coverage_adaptive.py
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
|
|
| 1 |
import json
|
| 2 |
import math
|
| 3 |
|
|
@@ -368,6 +369,222 @@ def test_single_chunk_requires_joint_preferred_quality_and_speaker_for_early_ret
|
|
| 368 |
assert payload["selection"]["generated_chunks"] == 3
|
| 369 |
|
| 370 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 371 |
def test_single_chunk_final_cap_selects_lowest_bounded_soft_quality_cost():
|
| 372 |
chunk = ("完整內容",)
|
| 373 |
profiles = {
|
|
@@ -567,7 +784,7 @@ def test_refill_budget_accounts_exact_generated_chunks_and_text_units():
|
|
| 567 |
selection=result,
|
| 568 |
)
|
| 569 |
payload = json.loads(line.removeprefix(CASCADE_EVIDENCE_LOG_PREFIX))
|
| 570 |
-
assert payload["schema_version"] ==
|
| 571 |
assert payload["generation_evidence_complete"] is True
|
| 572 |
assert payload["request_chunk_count"] == 2
|
| 573 |
assert payload["generated_chunk_count"] == 3
|
|
@@ -590,6 +807,11 @@ def test_refill_budget_accounts_exact_generated_chunks_and_text_units():
|
|
| 590 |
"chunk_policies": ["safe_duration", "base"],
|
| 591 |
"network_conditioned": [False, False],
|
| 592 |
"chunk_text_variants": ["base", "base"],
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 593 |
}
|
| 594 |
|
| 595 |
|
|
|
|
| 1 |
+
from dataclasses import replace
|
| 2 |
import json
|
| 3 |
import math
|
| 4 |
|
|
|
|
| 369 |
assert payload["selection"]["generated_chunks"] == 3
|
| 370 |
|
| 371 |
|
| 372 |
+
def test_preferred_refill_selects_prior_natural_endpoint_over_forced_candidate():
|
| 373 |
+
chunk = ("完整內容",)
|
| 374 |
+
generated = []
|
| 375 |
+
profiles = {
|
| 376 |
+
10: (0.65, 1.15),
|
| 377 |
+
11: (0.71, 1.19),
|
| 378 |
+
12: (0.73, 1.21),
|
| 379 |
+
}
|
| 380 |
+
|
| 381 |
+
def verifier(trajectory, chunks, seed):
|
| 382 |
+
stoi, pesq = profiles[seed]
|
| 383 |
+
return _squim_verification(
|
| 384 |
+
chunks,
|
| 385 |
+
stoi=stoi,
|
| 386 |
+
pesq=pesq,
|
| 387 |
+
speaker_similarity=0.30,
|
| 388 |
+
)
|
| 389 |
+
|
| 390 |
+
def generation_evidence(candidate_index, seed, chunk_indices, candidate_chunks):
|
| 391 |
+
scheduled = generation_cfg_for_candidate_offset(candidate_index)
|
| 392 |
+
effective = max(3.0, scheduled)
|
| 393 |
+
threshold_stop = candidate_index == 1
|
| 394 |
+
return CandidateGenerationEvidence(
|
| 395 |
+
chunk_indices=chunk_indices,
|
| 396 |
+
chunk_text_units=(4,),
|
| 397 |
+
scheduled_cfg=scheduled,
|
| 398 |
+
effective_cfgs=(effective,),
|
| 399 |
+
floor_reasons=(("short_text",),) if effective != scheduled else ((),),
|
| 400 |
+
chunk_stop_reasons=(
|
| 401 |
+
("stop_threshold",) if threshold_stop else ("hard_stop",)
|
| 402 |
+
),
|
| 403 |
+
chunk_endpoint_energy_ratios=(
|
| 404 |
+
(0.10,) if threshold_stop else (0.90,)
|
| 405 |
+
),
|
| 406 |
+
chunk_generated_steps=((4,) if threshold_stop else (5,)),
|
| 407 |
+
chunk_hard_stop_steps=(5,),
|
| 408 |
+
)
|
| 409 |
+
|
| 410 |
+
result = run_coverage_adaptive_cascade(
|
| 411 |
+
chunk,
|
| 412 |
+
10,
|
| 413 |
+
lambda chunks, seed: generated.append(seed) or (f"audio-{seed}",),
|
| 414 |
+
verifier,
|
| 415 |
+
verifier,
|
| 416 |
+
sequence_final_verifier=lambda result, chunks: _exact_final(chunks),
|
| 417 |
+
generation_evidence_factory=generation_evidence,
|
| 418 |
+
max_generated_chunks=5,
|
| 419 |
+
max_generated_text_units=100,
|
| 420 |
+
preferred_min_speaker_similarity=0.25,
|
| 421 |
+
preferred_max_boundary_speaker_drop=0.05,
|
| 422 |
+
preferred_min_squim_stoi=0.72,
|
| 423 |
+
preferred_min_squim_pesq=1.20,
|
| 424 |
+
require_endpoint_evidence=True,
|
| 425 |
+
)
|
| 426 |
+
|
| 427 |
+
assert generated == [10, 11, 12]
|
| 428 |
+
assert result.candidate_index == 1
|
| 429 |
+
assert result.seed == 11
|
| 430 |
+
artifact = result.verification.chunk_artifacts[0]
|
| 431 |
+
assert artifact.stop_reason == "stop_threshold"
|
| 432 |
+
assert artifact.endpoint_energy_ratio == pytest.approx(0.10)
|
| 433 |
+
payload = json.loads(
|
| 434 |
+
format_cascade_evidence_log(
|
| 435 |
+
result.diagnostics,
|
| 436 |
+
outcome="returned",
|
| 437 |
+
generated_chunk_limit=5,
|
| 438 |
+
generated_text_unit_limit=100,
|
| 439 |
+
selection=result,
|
| 440 |
+
).removeprefix(CASCADE_EVIDENCE_LOG_PREFIX)
|
| 441 |
+
)
|
| 442 |
+
assert payload["endpoint_evidence_complete"] is True
|
| 443 |
+
assert payload["selection"]["generation"]["endpoint_complete"] is True
|
| 444 |
+
assert payload["selection"]["generation"]["chunk_stop_reasons"] == [
|
| 445 |
+
"stop_threshold"
|
| 446 |
+
]
|
| 447 |
+
|
| 448 |
+
|
| 449 |
+
@pytest.mark.parametrize(
|
| 450 |
+
("field", "value"),
|
| 451 |
+
[
|
| 452 |
+
("chunk_stop_reasons", ("unknown",)),
|
| 453 |
+
("chunk_endpoint_energy_ratios", (math.nan,)),
|
| 454 |
+
("chunk_generated_steps", (True,)),
|
| 455 |
+
("chunk_generated_steps", (6,)),
|
| 456 |
+
],
|
| 457 |
+
)
|
| 458 |
+
def test_canonical_log_rejects_invalid_endpoint_rows(field, value):
|
| 459 |
+
chunk = ("完整內容",)
|
| 460 |
+
|
| 461 |
+
def evidence(candidate_index, seed, chunk_indices, candidate_chunks):
|
| 462 |
+
return CandidateGenerationEvidence(
|
| 463 |
+
chunk_indices=chunk_indices,
|
| 464 |
+
chunk_text_units=(4,),
|
| 465 |
+
scheduled_cfg=3.0,
|
| 466 |
+
effective_cfgs=(3.0,),
|
| 467 |
+
floor_reasons=((),),
|
| 468 |
+
chunk_stop_reasons=("stop_threshold",),
|
| 469 |
+
chunk_endpoint_energy_ratios=(0.10,),
|
| 470 |
+
chunk_generated_steps=(4,),
|
| 471 |
+
chunk_hard_stop_steps=(5,),
|
| 472 |
+
)
|
| 473 |
+
|
| 474 |
+
result = run_coverage_adaptive_cascade(
|
| 475 |
+
chunk,
|
| 476 |
+
10,
|
| 477 |
+
lambda chunks, seed: (f"audio-{seed}",),
|
| 478 |
+
lambda trajectory, chunks, seed: _squim_verification(
|
| 479 |
+
chunks,
|
| 480 |
+
stoi=0.73,
|
| 481 |
+
pesq=1.21,
|
| 482 |
+
speaker_similarity=0.30,
|
| 483 |
+
),
|
| 484 |
+
lambda trajectory, chunks, seed: _squim_verification(
|
| 485 |
+
chunks,
|
| 486 |
+
stoi=0.73,
|
| 487 |
+
pesq=1.21,
|
| 488 |
+
speaker_similarity=0.30,
|
| 489 |
+
),
|
| 490 |
+
sequence_final_verifier=lambda result, chunks: _exact_final(chunks),
|
| 491 |
+
generation_evidence_factory=evidence,
|
| 492 |
+
max_generated_chunks=5,
|
| 493 |
+
max_generated_text_units=100,
|
| 494 |
+
preferred_min_speaker_similarity=0.25,
|
| 495 |
+
preferred_max_boundary_speaker_drop=0.05,
|
| 496 |
+
preferred_min_squim_stoi=0.72,
|
| 497 |
+
preferred_min_squim_pesq=1.20,
|
| 498 |
+
require_endpoint_evidence=True,
|
| 499 |
+
)
|
| 500 |
+
|
| 501 |
+
invalid_attempt = replace(
|
| 502 |
+
result.diagnostics.attempts[0],
|
| 503 |
+
**{field: value},
|
| 504 |
+
)
|
| 505 |
+
invalid_diagnostics = replace(
|
| 506 |
+
result.diagnostics,
|
| 507 |
+
attempts=(invalid_attempt,),
|
| 508 |
+
)
|
| 509 |
+
with pytest.raises(ValueError, match="canonical endpoint evidence is invalid"):
|
| 510 |
+
format_cascade_evidence_log(
|
| 511 |
+
invalid_diagnostics,
|
| 512 |
+
outcome="returned",
|
| 513 |
+
generated_chunk_limit=5,
|
| 514 |
+
generated_text_unit_limit=100,
|
| 515 |
+
selection=result,
|
| 516 |
+
)
|
| 517 |
+
|
| 518 |
+
|
| 519 |
+
@pytest.mark.parametrize(
|
| 520 |
+
("natural_stoi", "natural_pesq", "natural_speaker", "natural_steps"),
|
| 521 |
+
[
|
| 522 |
+
(0.69, 1.19, 0.30, 4),
|
| 523 |
+
(0.71, 1.16, 0.30, 4),
|
| 524 |
+
(0.71, 1.19, 0.24, 4),
|
| 525 |
+
(0.71, 1.19, 0.30, 5),
|
| 526 |
+
],
|
| 527 |
+
)
|
| 528 |
+
def test_natural_endpoint_waiver_cannot_bypass_bounded_preferred_tier(
|
| 529 |
+
natural_stoi,
|
| 530 |
+
natural_pesq,
|
| 531 |
+
natural_speaker,
|
| 532 |
+
natural_steps,
|
| 533 |
+
):
|
| 534 |
+
chunk = ("完整內容",)
|
| 535 |
+
profiles = {
|
| 536 |
+
10: (0.65, 1.15, 0.30),
|
| 537 |
+
11: (natural_stoi, natural_pesq, natural_speaker),
|
| 538 |
+
12: (0.73, 1.21, 0.30),
|
| 539 |
+
}
|
| 540 |
+
|
| 541 |
+
def verifier(trajectory, chunks, seed):
|
| 542 |
+
stoi, pesq, speaker = profiles[seed]
|
| 543 |
+
return _squim_verification(
|
| 544 |
+
chunks,
|
| 545 |
+
stoi=stoi,
|
| 546 |
+
pesq=pesq,
|
| 547 |
+
speaker_similarity=speaker,
|
| 548 |
+
)
|
| 549 |
+
|
| 550 |
+
def generation_evidence(candidate_index, seed, chunk_indices, candidate_chunks):
|
| 551 |
+
natural = candidate_index == 1
|
| 552 |
+
scheduled = generation_cfg_for_candidate_offset(candidate_index)
|
| 553 |
+
return CandidateGenerationEvidence(
|
| 554 |
+
chunk_indices=chunk_indices,
|
| 555 |
+
chunk_text_units=(4,),
|
| 556 |
+
scheduled_cfg=scheduled,
|
| 557 |
+
effective_cfgs=(scheduled,),
|
| 558 |
+
floor_reasons=((),),
|
| 559 |
+
chunk_stop_reasons=(
|
| 560 |
+
("stop_threshold",) if natural else ("hard_stop",)
|
| 561 |
+
),
|
| 562 |
+
chunk_endpoint_energy_ratios=((0.10,) if natural else (0.90,)),
|
| 563 |
+
chunk_generated_steps=((natural_steps,) if natural else (5,)),
|
| 564 |
+
chunk_hard_stop_steps=(5,),
|
| 565 |
+
)
|
| 566 |
+
|
| 567 |
+
result = run_coverage_adaptive_cascade(
|
| 568 |
+
chunk,
|
| 569 |
+
10,
|
| 570 |
+
lambda chunks, seed: (f"audio-{seed}",),
|
| 571 |
+
verifier,
|
| 572 |
+
verifier,
|
| 573 |
+
sequence_final_verifier=lambda result, chunks: _exact_final(chunks),
|
| 574 |
+
generation_evidence_factory=generation_evidence,
|
| 575 |
+
max_generated_chunks=5,
|
| 576 |
+
max_generated_text_units=100,
|
| 577 |
+
preferred_min_speaker_similarity=0.25,
|
| 578 |
+
preferred_max_boundary_speaker_drop=0.05,
|
| 579 |
+
preferred_min_squim_stoi=0.72,
|
| 580 |
+
preferred_min_squim_pesq=1.20,
|
| 581 |
+
require_endpoint_evidence=True,
|
| 582 |
+
)
|
| 583 |
+
|
| 584 |
+
assert result.candidate_index == 2
|
| 585 |
+
assert result.seed == 12
|
| 586 |
+
|
| 587 |
+
|
| 588 |
def test_single_chunk_final_cap_selects_lowest_bounded_soft_quality_cost():
|
| 589 |
chunk = ("完整內容",)
|
| 590 |
profiles = {
|
|
|
|
| 784 |
selection=result,
|
| 785 |
)
|
| 786 |
payload = json.loads(line.removeprefix(CASCADE_EVIDENCE_LOG_PREFIX))
|
| 787 |
+
assert payload["schema_version"] == 6
|
| 788 |
assert payload["generation_evidence_complete"] is True
|
| 789 |
assert payload["request_chunk_count"] == 2
|
| 790 |
assert payload["generated_chunk_count"] == 3
|
|
|
|
| 807 |
"chunk_policies": ["safe_duration", "base"],
|
| 808 |
"network_conditioned": [False, False],
|
| 809 |
"chunk_text_variants": ["base", "base"],
|
| 810 |
+
"endpoint_complete": False,
|
| 811 |
+
"chunk_stop_reasons": [None, None],
|
| 812 |
+
"chunk_endpoint_energy_ratios": [None, None],
|
| 813 |
+
"chunk_generated_steps": [None, None],
|
| 814 |
+
"chunk_hard_stop_steps": [None, None],
|
| 815 |
}
|
| 816 |
|
| 817 |
|
tests/test_inference_cleanup.py
CHANGED
|
@@ -73,6 +73,8 @@ def test_closed_loop_pace_rerenders_once_from_untouched_model_waveform():
|
|
| 73 |
"target_pace_speed": lambda *args, **kwargs: 0.90,
|
| 74 |
"active_voiced_duration_seconds": active_duration,
|
| 75 |
"active_pace_correction_speed": active_correction,
|
|
|
|
|
|
|
| 76 |
"_apply_speed": apply_speed,
|
| 77 |
"_NATIVE_STOP_POLICY": False,
|
| 78 |
"_GENERATE_PARAMETERS": set(),
|
|
@@ -113,7 +115,14 @@ def test_closed_loop_pace_rerenders_once_from_untouched_model_waveform():
|
|
| 113 |
assert apply_calls[0][1] == pytest.approx(0.90)
|
| 114 |
assert apply_calls[1][1] == pytest.approx(0.90 * 0.95)
|
| 115 |
assert all(call[2] is True for call in apply_calls)
|
| 116 |
-
assert np.array_equal(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 117 |
assert len(active_calls) == 2
|
| 118 |
assert np.array_equal(active_calls[0][0], np.ones(16, dtype=np.float32))
|
| 119 |
assert np.array_equal(active_calls[1][0], np.ones(16, dtype=np.float32) * 0.90)
|
|
@@ -124,6 +133,84 @@ def test_closed_loop_pace_rerenders_once_from_untouched_model_waveform():
|
|
| 124 |
}
|
| 125 |
|
| 126 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 127 |
def test_lazy_transition_f0_measures_only_dp_eligible_rows():
|
| 128 |
observations = (
|
| 129 |
CandidateObservation("第一段完整", "第一段完整", 2.0),
|
|
|
|
| 73 |
"target_pace_speed": lambda *args, **kwargs: 0.90,
|
| 74 |
"active_voiced_duration_seconds": active_duration,
|
| 75 |
"active_pace_correction_speed": active_correction,
|
| 76 |
+
"endpoint_tail_energy_ratio": lambda audio, sample_rate: 0.5,
|
| 77 |
+
"_ChunkGenerationOutcome": SimpleNamespace,
|
| 78 |
"_apply_speed": apply_speed,
|
| 79 |
"_NATIVE_STOP_POLICY": False,
|
| 80 |
"_GENERATE_PARAMETERS": set(),
|
|
|
|
| 115 |
assert apply_calls[0][1] == pytest.approx(0.90)
|
| 116 |
assert apply_calls[1][1] == pytest.approx(0.90 * 0.95)
|
| 117 |
assert all(call[2] is True for call in apply_calls)
|
| 118 |
+
assert np.array_equal(
|
| 119 |
+
output.audio,
|
| 120 |
+
np.ones(16, dtype=np.float32) * np.float32(0.855),
|
| 121 |
+
)
|
| 122 |
+
assert output.stop_reason == "native_stop"
|
| 123 |
+
assert output.endpoint_energy_ratio == 0.5
|
| 124 |
+
assert output.generated_steps == 12
|
| 125 |
+
assert output.hard_stop_steps == 12
|
| 126 |
assert len(active_calls) == 2
|
| 127 |
assert np.array_equal(active_calls[0][0], np.ones(16, dtype=np.float32))
|
| 128 |
assert np.array_equal(active_calls[1][0], np.ones(16, dtype=np.float32) * 0.90)
|
|
|
|
| 133 |
}
|
| 134 |
|
| 135 |
|
| 136 |
+
def test_sparse_completion_policy_adds_only_bounded_one_two_unit_headroom():
|
| 137 |
+
def run(units, policy):
|
| 138 |
+
generation_calls = []
|
| 139 |
+
namespace = {
|
| 140 |
+
"np": np,
|
| 141 |
+
"torch": torch,
|
| 142 |
+
"model": SimpleNamespace(
|
| 143 |
+
generate=lambda **kwargs: (
|
| 144 |
+
generation_calls.append(kwargs) or torch.ones(64)
|
| 145 |
+
)
|
| 146 |
+
),
|
| 147 |
+
"select_generation_cps": lambda *args, **kwargs: 5.0,
|
| 148 |
+
"count_network_endpoint_duration_units": lambda text: units,
|
| 149 |
+
"count_speech_units": lambda text: units,
|
| 150 |
+
"endpoint_generation_plan": (
|
| 151 |
+
lambda *args, **kwargs: ("短句。", 3, 4)
|
| 152 |
+
),
|
| 153 |
+
"effective_generation_cfg": lambda text, cfg, **kwargs: cfg,
|
| 154 |
+
"set_generation_seed": lambda seed: None,
|
| 155 |
+
"target_pace_speed": lambda *args, **kwargs: 1.0,
|
| 156 |
+
"active_voiced_duration_seconds": (
|
| 157 |
+
lambda *args, **kwargs: (_ for _ in ()).throw(ValueError())
|
| 158 |
+
),
|
| 159 |
+
"active_pace_correction_speed": lambda *args, **kwargs: 1.0,
|
| 160 |
+
"endpoint_tail_energy_ratio": lambda audio, sample_rate: 0.25,
|
| 161 |
+
"_apply_speed": lambda audio, speed, **kwargs: np.asarray(audio),
|
| 162 |
+
"_ChunkGenerationOutcome": SimpleNamespace,
|
| 163 |
+
"_NATIVE_STOP_POLICY": False,
|
| 164 |
+
"_GENERATE_PARAMETERS": set(),
|
| 165 |
+
"_STOP_CONTROLLER": None,
|
| 166 |
+
"SR": 48_000,
|
| 167 |
+
"STEP_SECONDS": 0.16,
|
| 168 |
+
"MIN_ENDPOINT_CUE_UNITS": 6,
|
| 169 |
+
"SHORT_TEXT_CFG_UNITS": 6,
|
| 170 |
+
"SHORT_TEXT_CFG_MIN": 3.0,
|
| 171 |
+
"TARGET_CPS": 4.0,
|
| 172 |
+
"ACTIVE_PACE_TARGET_CPS": 4.0,
|
| 173 |
+
"CLOSED_LOOP_ACTIVE_PACE_TARGET_CPS": 3.95,
|
| 174 |
+
"MIN_PACE_SPEED": 0.80,
|
| 175 |
+
"STOP_THRESHOLD": 0.50,
|
| 176 |
+
"STOP_CONSECUTIVE": 1,
|
| 177 |
+
}
|
| 178 |
+
generate = _isolated_app_function("_generate_chunk", namespace)
|
| 179 |
+
outcome = generate(
|
| 180 |
+
"短句",
|
| 181 |
+
torch.ones(4),
|
| 182 |
+
cfg=3.0,
|
| 183 |
+
steps=10,
|
| 184 |
+
request_seed=123,
|
| 185 |
+
policy=policy,
|
| 186 |
+
network_conditioned=True,
|
| 187 |
+
)
|
| 188 |
+
return generation_calls[0]["max_len"], outcome
|
| 189 |
+
|
| 190 |
+
base = SimpleNamespace(
|
| 191 |
+
name="base",
|
| 192 |
+
cjk_cps=5.2,
|
| 193 |
+
ascii_cps=4.6,
|
| 194 |
+
hard_stop_margin_steps=1,
|
| 195 |
+
short_headroom_max_units=0,
|
| 196 |
+
short_hard_stop_floor_steps=0,
|
| 197 |
+
)
|
| 198 |
+
completion = SimpleNamespace(
|
| 199 |
+
name="completion_headroom",
|
| 200 |
+
cjk_cps=4.2,
|
| 201 |
+
ascii_cps=3.6,
|
| 202 |
+
hard_stop_margin_steps=1,
|
| 203 |
+
short_headroom_max_units=2,
|
| 204 |
+
short_hard_stop_floor_steps=5,
|
| 205 |
+
)
|
| 206 |
+
|
| 207 |
+
assert run(2, base)[0] == 4
|
| 208 |
+
headroom_cap, headroom = run(2, completion)
|
| 209 |
+
assert headroom_cap == 5
|
| 210 |
+
assert headroom.hard_stop_steps == 5
|
| 211 |
+
assert run(3, completion)[0] == 4
|
| 212 |
+
|
| 213 |
+
|
| 214 |
def test_lazy_transition_f0_measures_only_dp_eligible_rows():
|
| 215 |
observations = (
|
| 216 |
CandidateObservation("第一段完整", "第一段完整", 2.0),
|
tests/test_production.py
CHANGED
|
@@ -20,7 +20,9 @@ from production import (
|
|
| 20 |
count_network_endpoint_duration_units,
|
| 21 |
count_speech_units,
|
| 22 |
duration_hard_stop_steps,
|
|
|
|
| 23 |
email_domain_mail_generation_variant,
|
|
|
|
| 24 |
effective_generation_cfg,
|
| 25 |
endpoint_generation_plan,
|
| 26 |
ensure_terminal_punctuation,
|
|
@@ -39,6 +41,7 @@ from production import (
|
|
| 39 |
normalize_tts_text,
|
| 40 |
plan_generation_chunks,
|
| 41 |
pcm16_audio_output,
|
|
|
|
| 42 |
select_candidate_sequence,
|
| 43 |
select_generation_cps,
|
| 44 |
split_leading_clause,
|
|
@@ -834,6 +837,24 @@ def test_stop_controller_can_stop_on_first_confident_hit():
|
|
| 834 |
assert decisions == [0, 0, 1]
|
| 835 |
|
| 836 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 837 |
def test_stop_controller_relaxes_near_endpoint_and_enforces_hard_stop():
|
| 838 |
relaxed = StopHysteresisController(
|
| 839 |
_SequenceStopHead([0.6] * 10),
|
|
@@ -3234,12 +3255,25 @@ def test_pcm16_output_preserves_production_level_without_peak_normalizing():
|
|
| 3234 |
|
| 3235 |
assert sample_rate == 48_000
|
| 3236 |
assert pcm.dtype == np.int16
|
| 3237 |
-
assert float(np.max(np.abs(pcm.astype(np.float64))) /
|
| 3238 |
0.62,
|
| 3239 |
-
abs=1.0 /
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3240 |
)
|
| 3241 |
-
restored = pcm.astype(np.float64) / 32767.0
|
| 3242 |
-
np.testing.assert_allclose(restored, waveform, atol=1.0 / 32767.0)
|
| 3243 |
|
| 3244 |
|
| 3245 |
@pytest.mark.parametrize(
|
|
|
|
| 20 |
count_network_endpoint_duration_units,
|
| 21 |
count_speech_units,
|
| 22 |
duration_hard_stop_steps,
|
| 23 |
+
decode_pcm16,
|
| 24 |
email_domain_mail_generation_variant,
|
| 25 |
+
encode_pcm16,
|
| 26 |
effective_generation_cfg,
|
| 27 |
endpoint_generation_plan,
|
| 28 |
ensure_terminal_punctuation,
|
|
|
|
| 41 |
normalize_tts_text,
|
| 42 |
plan_generation_chunks,
|
| 43 |
pcm16_audio_output,
|
| 44 |
+
pcm16_verification_waveform,
|
| 45 |
select_candidate_sequence,
|
| 46 |
select_generation_cps,
|
| 47 |
split_leading_clause,
|
|
|
|
| 837 |
assert decisions == [0, 0, 1]
|
| 838 |
|
| 839 |
|
| 840 |
+
def test_stop_controller_preserves_threshold_reason_at_the_hard_cap():
|
| 841 |
+
controller = StopHysteresisController(
|
| 842 |
+
_SequenceStopHead([0.01, 0.01, 0.01, 0.9]),
|
| 843 |
+
threshold=0.50,
|
| 844 |
+
late_threshold=0.05,
|
| 845 |
+
consecutive=1,
|
| 846 |
+
)
|
| 847 |
+
controller.begin(min_len=2, expected_steps=3, hard_stop_steps=4)
|
| 848 |
+
|
| 849 |
+
decisions = [
|
| 850 |
+
controller(torch.zeros(1, 2)).argmax(dim=-1).item()
|
| 851 |
+
for _ in range(4)
|
| 852 |
+
]
|
| 853 |
+
|
| 854 |
+
assert decisions == [0, 0, 0, 1]
|
| 855 |
+
assert controller.last_stop_reason == "stop_threshold"
|
| 856 |
+
|
| 857 |
+
|
| 858 |
def test_stop_controller_relaxes_near_endpoint_and_enforces_hard_stop():
|
| 859 |
relaxed = StopHysteresisController(
|
| 860 |
_SequenceStopHead([0.6] * 10),
|
|
|
|
| 3255 |
|
| 3256 |
assert sample_rate == 48_000
|
| 3257 |
assert pcm.dtype == np.int16
|
| 3258 |
+
assert float(np.max(np.abs(pcm.astype(np.float64))) / 32768.0) == pytest.approx(
|
| 3259 |
0.62,
|
| 3260 |
+
abs=1.0 / 32768.0,
|
| 3261 |
+
)
|
| 3262 |
+
restored = decode_pcm16(pcm)
|
| 3263 |
+
np.testing.assert_allclose(restored, waveform, atol=1.0 / 32768.0)
|
| 3264 |
+
|
| 3265 |
+
|
| 3266 |
+
def test_pcm16_verification_roundtrip_is_exhaustively_idempotent():
|
| 3267 |
+
codes = np.arange(-32768, 32768, dtype=np.int32).astype(np.int16)
|
| 3268 |
+
|
| 3269 |
+
decoded = decode_pcm16(codes)
|
| 3270 |
+
reencoded = encode_pcm16(decoded)
|
| 3271 |
+
|
| 3272 |
+
np.testing.assert_array_equal(reencoded, codes)
|
| 3273 |
+
np.testing.assert_array_equal(
|
| 3274 |
+
encode_pcm16(pcm16_verification_waveform(decoded)),
|
| 3275 |
+
codes,
|
| 3276 |
)
|
|
|
|
|
|
|
| 3277 |
|
| 3278 |
|
| 3279 |
@pytest.mark.parametrize(
|
tests/test_quality_runtime.py
CHANGED
|
@@ -19,6 +19,10 @@ from quality_runtime import (
|
|
| 19 |
COMPLETION_HEADROOM_GENERATION_POLICY,
|
| 20 |
CASCADE_EVIDENCE_LOG_PREFIX,
|
| 21 |
CASCADE_EVIDENCE_SCHEMA_VERSION,
|
|
|
|
|
|
|
|
|
|
|
|
|
| 22 |
SAFE_DURATION_GENERATION_POLICY,
|
| 23 |
SQUIM_OBJECTIVE_ASSET_PATH,
|
| 24 |
SQUIM_OBJECTIVE_SAMPLE_RATE,
|
|
@@ -51,9 +55,11 @@ from quality_runtime import (
|
|
| 51 |
active_voiced_duration_seconds,
|
| 52 |
candidate_gate_evidence,
|
| 53 |
candidate_chunk_transition_score,
|
|
|
|
| 54 |
candidate_limit_for_chunk_budget,
|
| 55 |
cosine_similarity,
|
| 56 |
exact_waveform_sha256,
|
|
|
|
| 57 |
format_cascade_evidence_log,
|
| 58 |
generation_cfg_for_candidate_offset,
|
| 59 |
generation_policy_for_candidate_offset,
|
|
@@ -295,11 +301,20 @@ def test_candidate_generation_policy_mapping_uses_sparse_completion_headroom():
|
|
| 295 |
assert ADAPTIVE_CASCADE_STAGE_LIMITS == (1, 5, 10, 15, 20, 24, 28, 32)
|
| 296 |
base = generation_policy_for_candidate_offset(0)
|
| 297 |
assert base is BASE_GENERATION_POLICY
|
| 298 |
-
assert (
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 299 |
"base",
|
| 300 |
5.2,
|
| 301 |
4.6,
|
| 302 |
1,
|
|
|
|
|
|
|
| 303 |
)
|
| 304 |
|
| 305 |
for offset in (1, 2, 5, 9):
|
|
@@ -310,9 +325,11 @@ def test_candidate_generation_policy_mapping_uses_sparse_completion_headroom():
|
|
| 310 |
safe.cjk_cps,
|
| 311 |
safe.ascii_cps,
|
| 312 |
safe.hard_stop_margin_steps,
|
| 313 |
-
|
|
|
|
|
|
|
| 314 |
|
| 315 |
-
for offset in (4, 8, 12, 16):
|
| 316 |
headroom = generation_policy_for_candidate_offset(offset)
|
| 317 |
assert headroom is COMPLETION_HEADROOM_GENERATION_POLICY
|
| 318 |
assert (
|
|
@@ -320,7 +337,54 @@ def test_candidate_generation_policy_mapping_uses_sparse_completion_headroom():
|
|
| 320 |
headroom.cjk_cps,
|
| 321 |
headroom.ascii_cps,
|
| 322 |
headroom.hard_stop_margin_steps,
|
| 323 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 324 |
|
| 325 |
|
| 326 |
@pytest.mark.parametrize("offset", [-1, 0.5, 1.0, True, None, "one"])
|
|
@@ -1675,7 +1739,7 @@ def test_canonical_attempt_evidence_distinguishes_local_v3_pass_and_not_run():
|
|
| 1675 |
)
|
| 1676 |
attempt = payload["attempts"][0]
|
| 1677 |
|
| 1678 |
-
assert payload["schema_version"] ==
|
| 1679 |
assert attempt["independent_local_evidence_complete"] is True
|
| 1680 |
assert attempt["independent_local_results"] == [
|
| 1681 |
{
|
|
|
|
| 19 |
COMPLETION_HEADROOM_GENERATION_POLICY,
|
| 20 |
CASCADE_EVIDENCE_LOG_PREFIX,
|
| 21 |
CASCADE_EVIDENCE_SCHEMA_VERSION,
|
| 22 |
+
ENDPOINT_ENERGY_WEIGHT,
|
| 23 |
+
ENDPOINT_HARD_STOP_PENALTY,
|
| 24 |
+
ENDPOINT_PREFERRED_SQUIM_PESQ_SLACK,
|
| 25 |
+
ENDPOINT_PREFERRED_SQUIM_STOI_SLACK,
|
| 26 |
SAFE_DURATION_GENERATION_POLICY,
|
| 27 |
SQUIM_OBJECTIVE_ASSET_PATH,
|
| 28 |
SQUIM_OBJECTIVE_SAMPLE_RATE,
|
|
|
|
| 55 |
active_voiced_duration_seconds,
|
| 56 |
candidate_gate_evidence,
|
| 57 |
candidate_chunk_transition_score,
|
| 58 |
+
candidate_endpoint_selection_cost,
|
| 59 |
candidate_limit_for_chunk_budget,
|
| 60 |
cosine_similarity,
|
| 61 |
exact_waveform_sha256,
|
| 62 |
+
endpoint_tail_energy_ratio,
|
| 63 |
format_cascade_evidence_log,
|
| 64 |
generation_cfg_for_candidate_offset,
|
| 65 |
generation_policy_for_candidate_offset,
|
|
|
|
| 301 |
assert ADAPTIVE_CASCADE_STAGE_LIMITS == (1, 5, 10, 15, 20, 24, 28, 32)
|
| 302 |
base = generation_policy_for_candidate_offset(0)
|
| 303 |
assert base is BASE_GENERATION_POLICY
|
| 304 |
+
assert (
|
| 305 |
+
base.name,
|
| 306 |
+
base.cjk_cps,
|
| 307 |
+
base.ascii_cps,
|
| 308 |
+
base.hard_stop_margin_steps,
|
| 309 |
+
base.short_headroom_max_units,
|
| 310 |
+
base.short_hard_stop_floor_steps,
|
| 311 |
+
) == (
|
| 312 |
"base",
|
| 313 |
5.2,
|
| 314 |
4.6,
|
| 315 |
1,
|
| 316 |
+
0,
|
| 317 |
+
0,
|
| 318 |
)
|
| 319 |
|
| 320 |
for offset in (1, 2, 5, 9):
|
|
|
|
| 325 |
safe.cjk_cps,
|
| 326 |
safe.ascii_cps,
|
| 327 |
safe.hard_stop_margin_steps,
|
| 328 |
+
safe.short_headroom_max_units,
|
| 329 |
+
safe.short_hard_stop_floor_steps,
|
| 330 |
+
) == ("safe_duration", 4.6, 4.0, 1, 0, 0)
|
| 331 |
|
| 332 |
+
for offset in (4, 8, 12, 16, 20, 24, 28):
|
| 333 |
headroom = generation_policy_for_candidate_offset(offset)
|
| 334 |
assert headroom is COMPLETION_HEADROOM_GENERATION_POLICY
|
| 335 |
assert (
|
|
|
|
| 337 |
headroom.cjk_cps,
|
| 338 |
headroom.ascii_cps,
|
| 339 |
headroom.hard_stop_margin_steps,
|
| 340 |
+
headroom.short_headroom_max_units,
|
| 341 |
+
headroom.short_hard_stop_floor_steps,
|
| 342 |
+
) == ("completion_headroom", 4.2, 3.6, 1, 2, 5)
|
| 343 |
+
|
| 344 |
+
|
| 345 |
+
def test_endpoint_tail_energy_and_selection_cost_prefer_natural_quiet_endings():
|
| 346 |
+
waveform = np.concatenate(
|
| 347 |
+
(
|
| 348 |
+
np.ones(950, dtype=np.float32),
|
| 349 |
+
np.full(50, 0.25, dtype=np.float32),
|
| 350 |
+
)
|
| 351 |
+
)
|
| 352 |
+
energy = endpoint_tail_energy_ratio(
|
| 353 |
+
waveform,
|
| 354 |
+
10_000,
|
| 355 |
+
window_ms=5.0,
|
| 356 |
+
)
|
| 357 |
+
threshold = ChunkCandidateArtifact(
|
| 358 |
+
stop_reason="stop_threshold",
|
| 359 |
+
endpoint_energy_ratio=energy,
|
| 360 |
+
generated_steps=4,
|
| 361 |
+
hard_stop_steps=5,
|
| 362 |
+
)
|
| 363 |
+
threshold_at_cap = ChunkCandidateArtifact(
|
| 364 |
+
stop_reason="stop_threshold",
|
| 365 |
+
endpoint_energy_ratio=energy,
|
| 366 |
+
generated_steps=5,
|
| 367 |
+
hard_stop_steps=5,
|
| 368 |
+
)
|
| 369 |
+
forced = ChunkCandidateArtifact(
|
| 370 |
+
stop_reason="hard_stop",
|
| 371 |
+
endpoint_energy_ratio=energy,
|
| 372 |
+
generated_steps=5,
|
| 373 |
+
hard_stop_steps=5,
|
| 374 |
+
)
|
| 375 |
+
|
| 376 |
+
assert energy == pytest.approx(0.25)
|
| 377 |
+
assert candidate_endpoint_selection_cost(threshold) == pytest.approx(
|
| 378 |
+
ENDPOINT_ENERGY_WEIGHT * 0.25
|
| 379 |
+
)
|
| 380 |
+
assert candidate_endpoint_selection_cost(threshold_at_cap) == pytest.approx(
|
| 381 |
+
ENDPOINT_HARD_STOP_PENALTY + ENDPOINT_ENERGY_WEIGHT * 0.25
|
| 382 |
+
)
|
| 383 |
+
assert candidate_endpoint_selection_cost(forced) == pytest.approx(
|
| 384 |
+
ENDPOINT_HARD_STOP_PENALTY + ENDPOINT_ENERGY_WEIGHT * 0.25
|
| 385 |
+
)
|
| 386 |
+
assert ENDPOINT_PREFERRED_SQUIM_STOI_SLACK == pytest.approx(0.02)
|
| 387 |
+
assert ENDPOINT_PREFERRED_SQUIM_PESQ_SLACK == pytest.approx(0.03)
|
| 388 |
|
| 389 |
|
| 390 |
@pytest.mark.parametrize("offset", [-1, 0.5, 1.0, True, None, "one"])
|
|
|
|
| 1739 |
)
|
| 1740 |
attempt = payload["attempts"][0]
|
| 1741 |
|
| 1742 |
+
assert payload["schema_version"] == 6
|
| 1743 |
assert attempt["independent_local_evidence_complete"] is True
|
| 1744 |
assert attempt["independent_local_results"] == [
|
| 1745 |
{
|
tests/test_release_pins.py
CHANGED
|
@@ -12,6 +12,7 @@ from production import (
|
|
| 12 |
join_audio_chunks_variable,
|
| 13 |
match_chunk_rms,
|
| 14 |
normalize_spoken_forms,
|
|
|
|
| 15 |
plan_generation_chunks,
|
| 16 |
punctuation_pause_seconds,
|
| 17 |
)
|
|
@@ -103,6 +104,7 @@ def _isolated_assemble_trajectory_audio():
|
|
| 103 |
"NETWORK_INTERNAL_FADE_MS": constants["NETWORK_INTERNAL_FADE_MS"],
|
| 104 |
"CHUNK_EDGE_FADE_MS": constants["CHUNK_EDGE_FADE_MS"],
|
| 105 |
"CROSSFADE_MS": constants["CROSSFADE_MS"],
|
|
|
|
| 106 |
"match_chunk_rms": match_chunk_rms,
|
| 107 |
"punctuation_pause_seconds": punctuation_pause_seconds,
|
| 108 |
"fade_variable_internal_edges": fade_variable_internal_edges,
|
|
@@ -111,6 +113,7 @@ def _isolated_assemble_trajectory_audio():
|
|
| 111 |
"_apply_speed": lambda waveform, _speed: waveform,
|
| 112 |
"count_speech_units": count_speech_units,
|
| 113 |
"finish_audio": lambda waveform, _sample_rate, **_kwargs: waveform,
|
|
|
|
| 114 |
}
|
| 115 |
exec(compile(module, str(app_path), "exec"), namespace)
|
| 116 |
return namespace["_assemble_trajectory_audio"]
|
|
@@ -363,6 +366,18 @@ def test_app_wires_row_local_candidate_ordinal_to_generation_policy_and_logs_it(
|
|
| 363 |
assert "effective_cfg={effective_cfg:.2f}" in source
|
| 364 |
assert "network_floor_applied={network_floor_applied}" in source
|
| 365 |
assert "short_floor_applied={short_floor_applied}" in source
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 366 |
|
| 367 |
|
| 368 |
def test_app_rejects_ambiguous_iri_before_frontend_normalization():
|
|
@@ -646,7 +661,7 @@ def test_network_local_dual_asr_capability_is_range_bound_for_initial_and_refill
|
|
| 646 |
assert "chunk_artifacts=primary_verification.chunk_artifacts" in (
|
| 647 |
intersection_source
|
| 648 |
)
|
| 649 |
-
assert "CASCADE_EVIDENCE_SCHEMA_VERSION =
|
| 650 |
assert '"chunk_text_variants"' in quality_source
|
| 651 |
assert "local_candidate_has_coverage_eligibility(" in helper_source
|
| 652 |
assert "independent_local_results=" in initial_source
|
|
@@ -861,15 +876,14 @@ def test_app_reverifies_the_post_join_speed_adjusted_whole_waveform():
|
|
| 861 |
speed_index = assemble_source.index(
|
| 862 |
"waveform = _apply_speed(waveform, playback_speed)"
|
| 863 |
)
|
| 864 |
-
finish_index = assemble_source.index(
|
| 865 |
-
|
| 866 |
-
|
| 867 |
-
assert speed_index < finish_index
|
| 868 |
-
assert (
|
| 869 |
-
'finish_fade_ms = 0.0 if count_speech_units("".join(chunks)) <= 6 else 5.0'
|
| 870 |
-
in assemble_source
|
| 871 |
)
|
| 872 |
-
assert
|
|
|
|
|
|
|
|
|
|
| 873 |
production_source = (ROOT / "production.py").read_text(encoding="utf-8")
|
| 874 |
assert "trailing_silence_ms: float = 180.0" in production_source
|
| 875 |
assemble_index = synthesize_source.index(
|
|
@@ -951,7 +965,7 @@ def test_chunk_generation_closed_loop_rerenders_final_audio_from_raw_once():
|
|
| 951 |
assert "fallback_speed = final_speed * fallback_residual" in generate_source
|
| 952 |
assert "_apply_speed(\n corrected" not in generate_source
|
| 953 |
assert "_apply_speed(\n audio,\n final_speed" in generate_source
|
| 954 |
-
assert "
|
| 955 |
assert "PACE_STRETCH_N_FFT = 1536" in source
|
| 956 |
assert "PACE_STRETCH_HOP_LENGTH = 384" in source
|
| 957 |
assert "NETWORK_PACE_STRETCH_N_FFT = 2048" in source
|
|
@@ -962,7 +976,7 @@ def test_chunk_generation_closed_loop_rerenders_final_audio_from_raw_once():
|
|
| 962 |
assert "hop_length=hop_length" in apply_speed_source
|
| 963 |
|
| 964 |
|
| 965 |
-
def
|
| 966 |
source = (ROOT / "app.py").read_text(encoding="utf-8")
|
| 967 |
tree = ast.parse(source)
|
| 968 |
functions = {
|
|
@@ -971,8 +985,14 @@ def test_public_tts_wrappers_serialize_pcm16_after_float_verification():
|
|
| 971 |
if isinstance(node, ast.FunctionDef)
|
| 972 |
}
|
| 973 |
synthesize_source = ast.get_source_segment(source, functions["_synthesize"])
|
|
|
|
|
|
|
|
|
|
|
|
|
| 974 |
|
| 975 |
assert synthesize_source is not None
|
|
|
|
|
|
|
| 976 |
assert "pcm16_audio_output" not in synthesize_source
|
| 977 |
assert "return SR, waveform" in synthesize_source
|
| 978 |
for wrapper_name in ("tts_speaker", "tts_reference", "tts_longform"):
|
|
|
|
| 12 |
join_audio_chunks_variable,
|
| 13 |
match_chunk_rms,
|
| 14 |
normalize_spoken_forms,
|
| 15 |
+
pcm16_verification_waveform,
|
| 16 |
plan_generation_chunks,
|
| 17 |
punctuation_pause_seconds,
|
| 18 |
)
|
|
|
|
| 104 |
"NETWORK_INTERNAL_FADE_MS": constants["NETWORK_INTERNAL_FADE_MS"],
|
| 105 |
"CHUNK_EDGE_FADE_MS": constants["CHUNK_EDGE_FADE_MS"],
|
| 106 |
"CROSSFADE_MS": constants["CROSSFADE_MS"],
|
| 107 |
+
"FINAL_ENDPOINT_FADE_MS": constants["FINAL_ENDPOINT_FADE_MS"],
|
| 108 |
"match_chunk_rms": match_chunk_rms,
|
| 109 |
"punctuation_pause_seconds": punctuation_pause_seconds,
|
| 110 |
"fade_variable_internal_edges": fade_variable_internal_edges,
|
|
|
|
| 113 |
"_apply_speed": lambda waveform, _speed: waveform,
|
| 114 |
"count_speech_units": count_speech_units,
|
| 115 |
"finish_audio": lambda waveform, _sample_rate, **_kwargs: waveform,
|
| 116 |
+
"pcm16_verification_waveform": pcm16_verification_waveform,
|
| 117 |
}
|
| 118 |
exec(compile(module, str(app_path), "exec"), namespace)
|
| 119 |
return namespace["_assemble_trajectory_audio"]
|
|
|
|
| 366 |
assert "effective_cfg={effective_cfg:.2f}" in source
|
| 367 |
assert "network_floor_applied={network_floor_applied}" in source
|
| 368 |
assert "short_floor_applied={short_floor_applied}" in source
|
| 369 |
+
assert "short_headroom_floor_applied={short_headroom_floor_applied}" in source
|
| 370 |
+
assert "generation_endpoint_evidence_by_seed" in source
|
| 371 |
+
assert "chunk_stop_reasons=tuple(" in source
|
| 372 |
+
assert "chunk_endpoint_energy_ratios=tuple(" in source
|
| 373 |
+
assert "require_endpoint_evidence=True" in source
|
| 374 |
+
quality_source = (ROOT / "quality_runtime.py").read_text(encoding="utf-8")
|
| 375 |
+
assert "short_headroom_max_units=2" in quality_source
|
| 376 |
+
assert "short_hard_stop_floor_steps=5" in quality_source
|
| 377 |
+
assert "ENDPOINT_HARD_STOP_PENALTY = 0.05" in quality_source
|
| 378 |
+
assert "ENDPOINT_ENERGY_WEIGHT = 0.02" in quality_source
|
| 379 |
+
assert "ENDPOINT_PREFERRED_SQUIM_STOI_SLACK = 0.02" in quality_source
|
| 380 |
+
assert "ENDPOINT_PREFERRED_SQUIM_PESQ_SLACK = 0.03" in quality_source
|
| 381 |
|
| 382 |
|
| 383 |
def test_app_rejects_ambiguous_iri_before_frontend_normalization():
|
|
|
|
| 661 |
assert "chunk_artifacts=primary_verification.chunk_artifacts" in (
|
| 662 |
intersection_source
|
| 663 |
)
|
| 664 |
+
assert "CASCADE_EVIDENCE_SCHEMA_VERSION = 6" in quality_source
|
| 665 |
assert '"chunk_text_variants"' in quality_source
|
| 666 |
assert "local_candidate_has_coverage_eligibility(" in helper_source
|
| 667 |
assert "independent_local_results=" in initial_source
|
|
|
|
| 876 |
speed_index = assemble_source.index(
|
| 877 |
"waveform = _apply_speed(waveform, playback_speed)"
|
| 878 |
)
|
| 879 |
+
finish_index = assemble_source.index("waveform = finish_audio(")
|
| 880 |
+
pcm_index = assemble_source.index(
|
| 881 |
+
"return pcm16_verification_waveform(waveform)"
|
|
|
|
|
|
|
|
|
|
|
|
|
| 882 |
)
|
| 883 |
+
assert speed_index < finish_index < pcm_index
|
| 884 |
+
assert "fade_ms=FINAL_ENDPOINT_FADE_MS" in assemble_source
|
| 885 |
+
assert "FINAL_ENDPOINT_FADE_MS = 5.0" in source
|
| 886 |
+
assert "finish_fade_ms" not in assemble_source
|
| 887 |
production_source = (ROOT / "production.py").read_text(encoding="utf-8")
|
| 888 |
assert "trailing_silence_ms: float = 180.0" in production_source
|
| 889 |
assemble_index = synthesize_source.index(
|
|
|
|
| 965 |
assert "fallback_speed = final_speed * fallback_residual" in generate_source
|
| 966 |
assert "_apply_speed(\n corrected" not in generate_source
|
| 967 |
assert "_apply_speed(\n audio,\n final_speed" in generate_source
|
| 968 |
+
assert "audio,\n fallback_speed" in generate_source
|
| 969 |
assert "PACE_STRETCH_N_FFT = 1536" in source
|
| 970 |
assert "PACE_STRETCH_HOP_LENGTH = 384" in source
|
| 971 |
assert "NETWORK_PACE_STRETCH_N_FFT = 2048" in source
|
|
|
|
| 976 |
assert "hop_length=hop_length" in apply_speed_source
|
| 977 |
|
| 978 |
|
| 979 |
+
def test_public_tts_wrappers_serialize_the_same_pcm16_grid_used_for_verification():
|
| 980 |
source = (ROOT / "app.py").read_text(encoding="utf-8")
|
| 981 |
tree = ast.parse(source)
|
| 982 |
functions = {
|
|
|
|
| 985 |
if isinstance(node, ast.FunctionDef)
|
| 986 |
}
|
| 987 |
synthesize_source = ast.get_source_segment(source, functions["_synthesize"])
|
| 988 |
+
assemble_source = ast.get_source_segment(
|
| 989 |
+
source,
|
| 990 |
+
functions["_assemble_trajectory_audio"],
|
| 991 |
+
)
|
| 992 |
|
| 993 |
assert synthesize_source is not None
|
| 994 |
+
assert assemble_source is not None
|
| 995 |
+
assert "return pcm16_verification_waveform(waveform)" in assemble_source
|
| 996 |
assert "pcm16_audio_output" not in synthesize_source
|
| 997 |
assert "return SR, waveform" in synthesize_source
|
| 998 |
for wrapper_name in ("tts_speaker", "tts_reference", "tts_longform"):
|