tts-test / scripts /check_constants_sync.py
aaxaxax's picture
feat: add full project source for HF Spaces deployment
10ea63e
Raw
History Blame Contribute Delete
4.83 kB
"""
Parity check: backend/constants.py vs frontend/src/constants.ts.
Run from project root: python3 scripts/check_constants_sync.py
Exits 0 if in sync, 1 if drift detected.
"""
import re
import sys
from pathlib import Path
ROOT = Path(__file__).parent.parent
BACKEND = ROOT / "backend" / "app" / "constants.py"
FRONTEND = ROOT / "frontend" / "src" / "constants.ts"
EMOTION_KEYS = {"calm", "happy", "narrative", "angry", "excited", "sad", "fearful", "command"}
errors = []
# ── backend/constants.py ──────────────────────────────────────────────────────
py_text = BACKEND.read_text()
# reliability: "angry": {"label": "Angry", ..., "reliability": "medium"},
py_reliability: dict[str, str] = {}
for m in re.finditer(r'"(calm|happy|narrative|angry|excited|sad|fearful|command)":\s*\{[^}]*"reliability":\s*"(high|medium)"', py_text):
py_reliability[m.group(1)] = m.group(2)
# EMOTION_TEMPLATES speaker blocks: find lines like `"Yash": {` then scan for emotion keys
# until next top-level speaker or closing of the outer dict
def extract_template_keys_py(text: str, speaker: str) -> set[str]:
# Find the speaker block inside EMOTION_TEMPLATES
pattern = rf'"{speaker}":\s*\{{'
m = re.search(pattern, text)
if not m:
return set()
start = m.end()
# Scan forward collecting emotion keys until balanced brace closes
depth = 1
pos = start
keys: set[str] = set()
while pos < len(text) and depth > 0:
if text[pos] == '{':
depth += 1
elif text[pos] == '}':
depth -= 1
if depth == 0:
break
# Check for emotion key line: "calm": or "happy":
m2 = re.match(r'\s*"(calm|happy|narrative|angry|excited|sad|fearful|command)":\s*', text[pos:pos+30])
if m2:
keys.add(m2.group(1))
pos += 1
return keys
py_yash_emo = extract_template_keys_py(py_text, "Yash")
py_neha_emo = extract_template_keys_py(py_text, "Neha")
# ── frontend/src/constants.ts ─────────────────────────────────────────────────
ts_text = FRONTEND.read_text()
# reliability: angry: { label: "Angry", emoji: "😠", reliability: "medium" },
ts_reliability: dict[str, str] = {}
for m in re.finditer(r'(calm|happy|narrative|angry|excited|sad|fearful|command):\s*\{[^}]*reliability:\s*"(high|medium)"', ts_text):
ts_reliability[m.group(1)] = m.group(2)
# EMOTION_TEMPLATES speaker blocks (TypeScript): `Yash: {`
def extract_template_keys_ts(text: str, speaker: str) -> set[str]:
pattern = rf'\b{speaker}:\s*\{{'
m = re.search(pattern, text)
if not m:
return set()
start = m.end()
depth = 1
pos = start
keys: set[str] = set()
while pos < len(text) and depth > 0:
if text[pos] == '{':
depth += 1
elif text[pos] == '}':
depth -= 1
if depth == 0:
break
m2 = re.match(r'\s*(calm|happy|narrative|angry|excited|sad|fearful|command):\s*', text[pos:pos+30])
if m2:
keys.add(m2.group(1))
pos += 1
return keys
ts_yash_emo = extract_template_keys_ts(ts_text, "Yash")
ts_neha_emo = extract_template_keys_ts(ts_text, "Neha")
# ── Compare ───────────────────────────────────────────────────────────────────
for key in EMOTION_KEYS:
py_rel = py_reliability.get(key)
ts_rel = ts_reliability.get(key)
if py_rel and ts_rel and py_rel != ts_rel:
errors.append(f"RELIABILITY MISMATCH '{key}': constants.py={py_rel!r}, constants.ts={ts_rel!r}")
if py_rel and not ts_rel:
errors.append(f"MISSING reliability for '{key}' in constants.ts")
if ts_rel and not py_rel:
errors.append(f"MISSING reliability for '{key}' in constants.py")
for label, py_keys, ts_keys in [
("Yash", py_yash_emo, ts_yash_emo),
("Neha", py_neha_emo, ts_neha_emo),
]:
missing_in_ts = EMOTION_KEYS - ts_keys
missing_in_py = EMOTION_KEYS - py_keys
if missing_in_py:
errors.append(f"MISSING EMOTIONS in {label} (constants.py): {sorted(missing_in_py)}")
if missing_in_ts:
errors.append(f"MISSING EMOTIONS in {label} (constants.ts): {sorted(missing_in_ts)}")
if py_keys != ts_keys:
errors.append(f"{label} template keys differ: py={sorted(py_keys)}, ts={sorted(ts_keys)}")
if errors:
print("CONSTANTS SYNC FAILED:")
for e in errors:
print(f" {e}")
sys.exit(1)
else:
print("OK β€” constants.py and constants.ts are in sync.")
sys.exit(0)