from __future__ import annotations import ast from dataclasses import dataclass import hashlib import json from pathlib import Path from types import MappingProxyType, SimpleNamespace import numpy as np import pytest from glyph_assets import ( AssetSegment, GenerationAttemptRecord, GlyphAssetError, SemanticPlanCommitment, compute_ordered_attempt_ledger_sha256, ) from glyph_hybrid_plan import GlyphHybridPlanError from latency_timing import latency_stage from production import count_speech_units, pcm16_audio_output from quality_runtime import CandidateGenerationContext ROOT = Path(__file__).resolve().parents[1] APP_PATH = ROOT / "app.py" class FakeGradioError(Exception): pass def _isolated_nodes(names: tuple[str, ...], namespace: dict[str, object]): namespace.setdefault("latency_stage", latency_stage) tree = ast.parse(APP_PATH.read_text(encoding="utf-8")) selected = [ node for node in tree.body if isinstance(node, (ast.FunctionDef, ast.ClassDef)) and node.name in names ] observed = {node.name for node in selected} assert observed == set(names) module = ast.Module( body=[ ast.ImportFrom( module="__future__", names=[ast.alias(name="annotations")], level=0, ), *selected, ], type_ignores=[], ) ast.fix_missing_locations(module) exec(compile(module, APP_PATH, "exec"), namespace) return SimpleNamespace(**{name: namespace[name] for name in names}) def _function_source(name: str) -> str: source = APP_PATH.read_text(encoding="utf-8") tree = ast.parse(source) node = next( item for item in tree.body if isinstance(item, ast.FunctionDef) and item.name == name ) result = ast.get_source_segment(source, node) assert result is not None return result def test_schema7_adapter_uses_frozen_per_return_gate_thresholds(): source = APP_PATH.read_text(encoding="utf-8") start = source.index( "_GLYPH_HYBRID_EVIDENCE_ADAPTER = HardenedGlyphHybridAdapter(" ) end = source.index("\ndef _network_fragment_proof_rows", start) adapter_assignment = source[start:end] assert ( "min_speaker_similarity=(\n" " QUALITY_RELEASE_MIN_SPEAKER_SIMILARITY" ) in adapter_assignment assert ( "max_boundary_speaker_drop=(\n" " QUALITY_RELEASE_MAX_BOUNDARY_SPEAKER_DROP" ) in adapter_assignment assert ( "min_squim_stoi=QUALITY_PREFERRED_MIN_SQUIM_STOI" in adapter_assignment ) assert ( "min_squim_pesq=QUALITY_PREFERRED_MIN_SQUIM_PESQ" in adapter_assignment ) def test_profile_selection_requires_exact_default_speaker_object_identity(): default = object() namespace = { "DEFAULT_SPEAKER": "內建語者 B", "DEFAULT_CENTROID": default, "SPEAKERS": { "內建語者 A": object(), "內建語者 B": default, }, } selected = _isolated_nodes( ("_glyph_profile_selected",), namespace, )._glyph_profile_selected assert selected("內建語者 B") is True assert selected("內建語者 A") is False assert selected("female_voice") is False namespace["SPEAKERS"]["內建語者 B"] = object() assert selected("內建語者 B") is False def test_network_route_is_pre_generation_fail_closed_and_never_partial_fallback(): calls: list[tuple[str, object]] = [] available = SimpleNamespace( available=True, asset_entry_sha256_by_asset_id=MappingProxyType({"asset": "0" * 64}), ) current_state = {"value": available} namespace = { "gr": SimpleNamespace(Error=FakeGradioError), "GlyphHybridPlanError": GlyphHybridPlanError, "GlyphAssetError": GlyphAssetError, "_glyph_profile_selected": lambda speaker: speaker == "default", "_glyph_request_network_looking": ( lambda text: any(marker in str(text).lower() for marker in ("@", "http://")) ), "_validate_glyph_runtime_controls": ( lambda **kwargs: calls.append(("controls", kwargs)) ), "_GLYPH_PROFILE_STATE": available, "build_glyph_hybrid_plan": ( lambda raw, **kwargs: calls.append(("plan", raw)) or None ), "_synthesize_glyph_hybrid": ( lambda *args, **kwargs: calls.append(("synthesize", args[0])) or (48_000, np.zeros(8, dtype=np.float32)) ), } route = _isolated_nodes( ("_maybe_synthesize_glyph_speaker_request",), namespace, )._maybe_synthesize_glyph_speaker_request assert ( route("普通文字", "default", cfg=3.0, steps=10, speed=1.0) is None ) assert calls == [] assert ( route("bad@network", "other", cfg=3.0, steps=10, speed=1.0) is None ) assert calls == [] with pytest.raises(FakeGradioError, match="嚴格小寫 ASCII"): route("bad@network", "default", cfg=3.0, steps=10, speed=1.0) assert [name for name, _ in calls] == ["controls", "plan"] assert not any(name == "synthesize" for name, _ in calls) calls.clear() namespace["_GLYPH_PROFILE_STATE"] = SimpleNamespace( available=False, unavailable_reason="hash_mismatch", ) with pytest.raises(FakeGradioError, match="資產目前不可用"): route("bad@network", "default", cfg=3.0, steps=10, speed=1.0) assert [name for name, _ in calls] == ["controls"] def test_valid_strict_plan_is_the_only_network_path_that_reaches_synthesis(): plan = object() calls: list[str] = [] state = SimpleNamespace( available=True, asset_entry_sha256_by_asset_id=MappingProxyType({"asset": "0" * 64}), ) namespace = { "gr": SimpleNamespace(Error=FakeGradioError), "GlyphHybridPlanError": GlyphHybridPlanError, "GlyphAssetError": GlyphAssetError, "_glyph_profile_selected": lambda speaker: speaker == "default", "_glyph_request_network_looking": lambda text: "@" in str(text), "_validate_glyph_runtime_controls": lambda **kwargs: calls.append("controls"), "_GLYPH_PROFILE_STATE": state, "build_glyph_hybrid_plan": ( lambda *args, **kwargs: calls.append("plan") or plan ), "_synthesize_glyph_hybrid": ( lambda raw, exact_plan, exact_state, **kwargs: ( calls.append("synthesize") or ( (48_000, np.zeros(8, dtype=np.float32)) if exact_plan is plan and exact_state is state else None ) ) ), } route = _isolated_nodes( ("_maybe_synthesize_glyph_speaker_request",), namespace, )._maybe_synthesize_glyph_speaker_request result = route( "mead@forest.org", "default", cfg=3.0, steps=10, speed=1.0, ) assert result[0] == 48_000 assert calls == ["controls", "plan", "synthesize"] def test_request_attempt_ledger_accounts_rejected_candidates_and_selection(): namespace = { "dataclass": dataclass, "np": np, "hashlib": hashlib, "GenerationAttemptRecord": GenerationAttemptRecord, "CandidateGenerationContext": CandidateGenerationContext, "count_speech_units": count_speech_units, "GLYPH_MAX_GENERATED_CHUNK_BUDGET": 32, "GLYPH_MAX_GENERATED_TEXT_UNIT_BUDGET": 800, "_canonical_json_sha256": ( lambda value: hashlib.sha256( json.dumps( value, ensure_ascii=True, separators=(",", ":"), sort_keys=True, ).encode("ascii") ).hexdigest() ), } api = _isolated_nodes( ( "_GlyphAttemptReservation", "_GlyphCompletedAttempt", "_GlyphRequestAttemptLedger", "_GlyphCarrierGenerationAudit", ), namespace, ) ledger = api._GlyphRequestAttemptLedger() audit = api._GlyphCarrierGenerationAudit(ledger, "carrier-0") for candidate_index, text in enumerate(("第一個候選", "第二個候選")): context = CandidateGenerationContext( candidate_index=candidate_index, seed=100 + candidate_index, chunk_indices=(0,), chunk_candidate_ordinals=(candidate_index,), ) reservation = audit.begin( (text,), 100 + candidate_index, context, candidate_index, False, ) audit.complete( reservation, ( SimpleNamespace( stop_reason="threshold", endpoint_energy_ratio=0.001, generated_steps=5, hard_stop_steps=7, audio=np.ones(32, dtype=np.float32), ), ), ) selected_waveform = np.linspace(-0.1, 0.1, 64, dtype=np.float32) audit.select( SimpleNamespace(chunk_candidate_indices=(1,)), selected_waveform, ) assert len(ledger.records) == 2 assert len(ledger.completed_attempts) == 2 assert [record.ordinal for record in ledger.records] == [0, 1] assert audit.selected() == ledger.records[1] assert np.array_equal(audit.selected_waveform(), selected_waveform) assert compute_ordered_attempt_ledger_sha256(ledger.records) def test_pure_asset_integration_makes_zero_model_calls_and_still_emits_schema7(): pcm = np.array([0, 100, -100, 0], dtype="