Files
diodiogod-TTS-Audio-Suite/scripts/generate_engine_tables.py
T
diodiogod 4f0782e75d Show all 10 engines in README comparison table
- Removed arbitrary filtering that only showed 7 engines
- Now displays complete engine list for informative overview
- Table remains condensed (4 columns) but comprehensive
2026-01-28 11:14:26 -03:00

342 lines
11 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
"""
TTS Audio Suite - Engine Tables Generator
Generates three documentation tables from YAML source of truth
Also injects condensed table into README.md between markers
"""
import yaml
import re
from pathlib import Path
def load_data():
"""Load YAML data"""
yaml_path = Path(__file__).parent.parent / "docs/Dev reports/tts_audio_suite_engines.yaml"
with open(yaml_path, encoding="utf-8") as f:
return yaml.safe_load(f)
def format_support(value, notes=""):
"""Format boolean/partial support with optional notes"""
if value is None:
return "N/A"
elif value == "partial":
return f"⚠️ {notes}" if notes else "⚠️"
elif value is True:
return f"✅ {notes}" if notes else "✅"
else:
return "❌"
def get_speed_emoji(speed_note):
"""Convert speed note to emoji"""
if "Very Fast" in speed_note:
return "⚡⚡"
elif "Fast" in speed_note:
return "⚡"
else:
return "🐌"
def generate_engine_comparison(data):
"""Generate main engine comparison table"""
engines = data["engines"]
output = []
output.append("# TTS Engines Reference Tables")
output.append("")
output.append("## Engine Comparison")
output.append("")
output.append("| Engine | Models | Size | TTS | SRT | VC | Special Features | Languages |")
output.append("| ------------------ | ----------------------------------------- | ------------ | --- | --- | --- | ---------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------- |")
for e in engines:
# Extract flags from languages
flags = "".join(
lang_data["flag"]
for lang_data in e["languages"].values()
if lang_data["supported"]
)
# Format special features with proper spacing
features = ", ".join(e.get("special_features", []))
# Handle ChatterBox 23L special case for languages display
if e["id"] == "chatterbox-23l":
flags += "(+9)"
row = [
f"**{e['name']}**".ljust(18),
e["models"].ljust(41),
e["size"].ljust(12),
format_support(e["capabilities"]["tts"]),
format_support(e["capabilities"]["srt"]),
format_support(e["capabilities"]["vc"]),
features.ljust(88),
flags.ljust(88)
]
output.append("| " + " | ".join(row) + " |")
return "\n".join(output)
def generate_readme_condensed_table(data):
"""Generate condensed table for README.md"""
engines = data["engines"]
output = []
output.append("## Quick Engine Comparison")
output.append("")
output.append("| Engine | Languages | Size | Key Features |")
output.append("|--------|-----------|------|--------------|")
# Show ALL engines
for e in engines:
# Get first 6-8 language flags
flags = []
count = 0
for lang_data in e["languages"].values():
if lang_data["supported"]:
flags.append(lang_data["flag"])
count += 1
if count >= 6: # Limit to 6 flags for readability
break
lang_display = "".join(flags)
# Special handling for ChatterBox 23L
if e["id"] == "chatterbox-23l":
lang_display = "🌐 24 languages"
# Special handling for RVC
elif e["id"] == "rvc":
lang_display = "🌐 Any"
else:
# Add count if more languages exist
total_langs = sum(1 for ld in e["languages"].values() if ld["supported"])
if total_langs > 6:
lang_display += f" +{total_langs - 6}"
# Get 1-2 key features
special_features = e.get("special_features", [])
if len(special_features) > 2:
key_features = ", ".join(special_features[:2])
else:
key_features = ", ".join(special_features)
row = [
f"**{e['name']}**",
lang_display,
e["size"],
key_features
]
output.append("| " + " | ".join(row) + " |")
# Add footer with links
output.append("")
output.append("📊 **[Full comparison tables →](docs/ENGINE_COMPARISON.md)** | "
"**[Language matrix →](docs/LANGUAGE_SUPPORT.md)** | "
"**[Feature matrix →](docs/FEATURE_COMPARISON.md)**")
return "\n".join(output)
def generate_language_support(data):
"""Generate language support matrix"""
engines = data["engines"]
lang_meta = data["language_metadata"]
# Get all language codes in order
lang_codes = list(lang_meta.keys())
output = []
output.append("# Language Support by Engine")
output.append("")
output.append("## Language Support by Engine")
output.append("")
# Build header
header = "| Language | Code |"
separator = "|---|---|"
for e in engines:
header += f" {e['name']} |"
separator += "---|"
output.append(header)
output.append(separator)
# Build rows for each language
for lang_code in lang_codes:
lang_info = lang_meta[lang_code]
# Get flag from first engine's language data (all have same flag)
flag = engines[0]["languages"][lang_code]["flag"]
row = [
f"{flag} **{lang_info['name']}**".ljust(14),
lang_info['code'].ljust(4)
]
for e in engines:
lang_support = e["languages"][lang_code]
cell = format_support(lang_support["supported"], lang_support["notes"])
row.append(cell)
output.append("| " + " | ".join(row) + " |")
# Add notes
output.append("")
output.append("**Notes:**")
output.append("")
for note in data["table_notes"]["language_support"]:
output.append(f"- {note}")
return "\n".join(output)
def generate_feature_comparison(data):
"""Generate feature comparison matrix"""
engines = data["engines"]
feat_meta = data["feature_metadata"]
output = []
output.append("# Feature Comparison Matrix")
output.append("")
output.append("## Feature Comparison Matrix")
output.append("")
# Build header
header = "| Feature |"
separator = "|---|"
for e in engines:
header += f" {e['name']} |"
separator += "---|"
output.append(header)
output.append(separator)
# Build rows for each feature
for feat_key, feat_info in feat_meta.items():
row = [feat_info["display"].ljust(28)]
for e in engines:
feat_support = e["features"][feat_key]
cell = format_support(feat_support["supported"], feat_support["notes"])
row.append(cell)
output.append("| " + " | ".join(row) + " |")
return "\n".join(output)
def inject_into_readme(condensed_table):
"""Inject condensed table into README.md between markers. Returns: True=written, False=unchanged, None=error"""
readme_path = Path(__file__).parent.parent / "README.md"
# Read current README
with open(readme_path, "r", encoding="utf-8") as f:
content = f.read()
# Define markers
start_marker = "<!-- ENGINE_COMPARISON_START -->"
end_marker = "<!-- ENGINE_COMPARISON_END -->"
# Check if markers exist
if start_marker not in content or end_marker not in content:
print("⚠️ Markers not found in README.md")
print(f" Please add these markers where you want the table:")
print(f" {start_marker}")
print(f" {end_marker}")
return None # Error
# Replace content between markers
pattern = f"{re.escape(start_marker)}.*?{re.escape(end_marker)}"
replacement = f"{start_marker}\n\n{condensed_table}\n\n{end_marker}"
new_content = re.sub(pattern, replacement, content, flags=re.DOTALL)
# Check if content actually changed
if new_content == content:
return False # No change
# Write back only if changed
with open(readme_path, "w", encoding="utf-8") as f:
f.write(new_content)
return True # Written
def write_if_changed(file_path, new_content):
"""Write file only if content changed. Returns True if written."""
# Check if file exists and compare content
if file_path.exists():
with open(file_path, "r", encoding="utf-8") as f:
existing_content = f.read()
if existing_content == new_content:
return False # No change needed
# Write the file
with open(file_path, "w", encoding="utf-8") as f:
f.write(new_content)
return True # File was written
def main():
"""Generate all tables and optionally inject into README"""
import sys
data = load_data()
docs_dir = Path(__file__).parent.parent / "docs"
# Generate Engine Comparison
print("Generating Engine Comparison table...")
engine_comp = generate_engine_comparison(data)
if write_if_changed(docs_dir / "ENGINE_COMPARISON.md", engine_comp):
print(f"✅ Written to {docs_dir / 'ENGINE_COMPARISON.md'}")
else:
print(f"⏭️ Skipped {docs_dir / 'ENGINE_COMPARISON.md'} (unchanged)")
# Generate Language Support
print("Generating Language Support table...")
lang_support = generate_language_support(data)
if write_if_changed(docs_dir / "LANGUAGE_SUPPORT.md", lang_support):
print(f"✅ Written to {docs_dir / 'LANGUAGE_SUPPORT.md'}")
else:
print(f"⏭️ Skipped {docs_dir / 'LANGUAGE_SUPPORT.md'} (unchanged)")
# Generate Feature Comparison
print("Generating Feature Comparison table...")
feat_comp = generate_feature_comparison(data)
if write_if_changed(docs_dir / "FEATURE_COMPARISON.md", feat_comp):
print(f"✅ Written to {docs_dir / 'FEATURE_COMPARISON.md'}")
else:
print(f"⏭️ Skipped {docs_dir / 'FEATURE_COMPARISON.md'} (unchanged)")
# Generate and inject condensed README table
print("\nGenerating condensed README table...")
condensed = generate_readme_condensed_table(data)
# Check if --readme flag is passed
if "--readme" in sys.argv:
print("Injecting into README.md...")
result = inject_into_readme(condensed)
if result is True:
print("✅ README.md updated successfully!")
elif result is False:
print("⏭️ Skipped README.md (unchanged)")
else: # None = error
print("❌ README.md injection failed (markers not found)")
else:
print("ℹ️ Condensed table generated (use --readme flag to inject into README.md)")
print("\nPreview:")
print(condensed)
print("\n✅ All tables generated successfully!")
if __name__ == "__main__":
main()