| <!DOCTYPE html> |
| <html lang="en"> |
| <head> |
| <meta charset="UTF-8"> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| <title>Cortázar TTS Architecture Explorer</title> |
| <style> |
| :root { |
| --bg: #0f172a; |
| --surface: #1e293b; |
| --surface-hover: #334155; |
| --primary: #8b5cf6; |
| --secondary: #ec4899; |
| --text: #f8fafc; |
| --text-dim: #94a3b8; |
| --accent: #22d3ee; |
| --border: #334155; |
| } |
| |
| body { |
| font-family: 'Inter', system-ui, -apple-system, sans-serif; |
| background-color: var(--bg); |
| color: var(--text); |
| margin: 0; |
| display: flex; |
| height: 100vh; |
| overflow: hidden; |
| } |
| |
| .canvas { |
| flex: 1; |
| position: relative; |
| background-image: |
| radial-gradient(circle at 1px 1px, var(--surface-hover) 1px, transparent 0); |
| background-size: 40px 40px; |
| display: flex; |
| justify-content: center; |
| align-items: center; |
| overflow: auto; |
| } |
| |
| .sidebar { |
| width: 400px; |
| background: rgba(30, 41, 59, 0.95); |
| backdrop-filter: blur(10px); |
| border-left: 1px solid var(--border); |
| padding: 2rem; |
| display: flex; |
| flex-direction: column; |
| gap: 1.5rem; |
| box-shadow: -4px 0 20px rgba(0,0,0,0.3); |
| z-index: 10; |
| } |
| |
| h1 { |
| background: linear-gradient(135deg, var(--primary), var(--secondary)); |
| -webkit-background-clip: text; |
| -webkit-text-fill-color: transparent; |
| margin: 0; |
| font-size: 1.5rem; |
| font-weight: 800; |
| } |
| |
| .node { |
| background: var(--surface); |
| border: 1px solid var(--border); |
| border-radius: 12px; |
| padding: 1rem 1.5rem; |
| min-width: 140px; |
| text-align: center; |
| cursor: pointer; |
| transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); |
| position: relative; |
| box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1); |
| } |
| |
| .node:hover, .node.active { |
| border-color: var(--primary); |
| box-shadow: 0 0 0 2px var(--primary), 0 10px 15px -3px rgba(0, 0, 0, 0.3); |
| transform: translateY(-2px); |
| background: var(--surface-hover); |
| } |
| |
| .node-icon { |
| font-size: 1.5rem; |
| margin-bottom: 0.5rem; |
| display: block; |
| } |
| |
| .node-title { |
| font-weight: 600; |
| font-size: 0.9rem; |
| } |
| |
| .node-subtitle { |
| font-size: 0.75rem; |
| color: var(--text-dim); |
| margin-top: 0.25rem; |
| } |
| |
| .node-order { |
| position: absolute; |
| top: 0.35rem; |
| left: 0.45rem; |
| width: 24px; |
| height: 24px; |
| border-radius: 999px; |
| display: flex; |
| align-items: center; |
| justify-content: center; |
| background: rgba(34, 211, 238, 0.15); |
| color: var(--accent); |
| font-size: 0.75rem; |
| font-weight: 700; |
| border: 1px solid rgba(34, 211, 238, 0.3); |
| pointer-events: none; |
| } |
| |
| .flow-container { |
| display: flex; |
| gap: 4rem; |
| align-items: center; |
| max-width: 1200px; |
| padding: 4rem; |
| } |
| |
| .column { |
| display: flex; |
| flex-direction: column; |
| gap: 2rem; |
| position: relative; |
| } |
| |
| |
| .connector { |
| position: absolute; |
| background: var(--border); |
| z-index: -1; |
| transition: background 0.3s; |
| } |
| |
| .arrow-right::after { |
| content: "→"; |
| position: absolute; |
| right: -2rem; |
| top: 50%; |
| transform: translateY(-50%); |
| color: var(--border); |
| font-size: 1.5rem; |
| } |
| |
| |
| .detail-header { |
| display: flex; |
| align-items: center; |
| gap: 1rem; |
| border-bottom: 1px solid var(--border); |
| padding-bottom: 1rem; |
| } |
| |
| .detail-icon { |
| font-size: 2rem; |
| background: var(--surface); |
| padding: 0.75rem; |
| border-radius: 12px; |
| border: 1px solid var(--border); |
| } |
| |
| .detail-title { |
| font-size: 1.25rem; |
| font-weight: 700; |
| } |
| |
| .detail-badge { |
| font-size: 0.7rem; |
| padding: 0.2rem 0.5rem; |
| border-radius: 99px; |
| text-transform: uppercase; |
| letter-spacing: 0.05em; |
| font-weight: 700; |
| } |
| |
| .badge-arm { background: rgba(34, 211, 238, 0.1); color: var(--accent); } |
| .badge-core { background: rgba(139, 92, 246, 0.1); color: var(--primary); } |
| .badge-fix { background: rgba(236, 72, 153, 0.1); color: var(--secondary); } |
| .badge-data { background: rgba(34, 211, 238, 0.1); color: var(--accent); } |
| .badge-train { background: rgba(139, 92, 246, 0.1); color: var(--primary); } |
| .badge-eval { background: rgba(236, 72, 153, 0.1); color: var(--secondary); } |
| .badge-docs { background: rgba(148, 163, 184, 0.15); color: var(--text-dim); } |
| .badge-idea { background: rgba(34, 211, 238, 0.1); color: var(--accent); } |
| .badge-io { background: rgba(148, 163, 184, 0.15); color: var(--text-dim); } |
| |
| .detail-content { |
| line-height: 1.6; |
| color: var(--text-dim); |
| font-size: 0.95rem; |
| } |
| |
| code { |
| background: rgba(0,0,0,0.3); |
| padding: 0.2rem 0.4rem; |
| border-radius: 4px; |
| font-family: 'JetBrains Mono', monospace; |
| font-size: 0.85em; |
| color: var(--accent); |
| } |
| |
| a { |
| color: var(--accent); |
| text-decoration: none; |
| } |
| |
| a:hover { |
| text-decoration: underline; |
| } |
| |
| pre { |
| background: rgba(0,0,0,0.3); |
| border: 1px solid var(--border); |
| border-radius: 8px; |
| padding: 0.75rem; |
| color: var(--text); |
| font-size: 0.85rem; |
| white-space: pre-wrap; |
| } |
| |
| .tech-stack { |
| display: flex; |
| flex-wrap: wrap; |
| gap: 0.5rem; |
| margin-top: 1rem; |
| } |
| |
| .tech-tag { |
| background: var(--surface); |
| border: 1px solid var(--border); |
| padding: 0.25rem 0.75rem; |
| border-radius: 6px; |
| font-size: 0.8rem; |
| color: var(--text); |
| } |
| |
| |
| svg { |
| position: absolute; |
| top: 0; |
| left: 0; |
| width: 100%; |
| height: 100%; |
| pointer-events: none; |
| z-index: 0; |
| } |
| |
| path { |
| fill: none; |
| stroke: var(--border); |
| stroke-width: 2; |
| } |
| |
| .node-row { |
| position: absolute; |
| bottom: 2rem; |
| left: 2rem; |
| display: flex; |
| gap: 1rem; |
| flex-wrap: wrap; |
| max-width: 980px; |
| } |
| |
| .node.compact { |
| min-width: 110px; |
| } |
| </style> |
| </head> |
| <body> |
|
|
| <div class="canvas" id="canvas"> |
| <svg id="connections"></svg> |
| |
| <div class="flow-container"> |
| |
| <div class="column"> |
| <div class="node" data-id="input" onclick="selectNode('input')"> |
| <span class="node-order">1</span> |
| <span class="node-icon">📄</span> |
| <div class="node-title">Input</div> |
| <div class="node-subtitle">Text & Ref Audio</div> |
| </div> |
| </div> |
|
|
| <div class="arrow-right"></div> |
|
|
| |
| <div class="column"> |
| <div class="node" data-id="preprocess" onclick="selectNode('preprocess')"> |
| <span class="node-order">2</span> |
| <span class="node-icon">🔄</span> |
| <div class="node-title">Preprocessing</div> |
| <div class="node-subtitle">Soundfile & Whisper</div> |
| </div> |
| </div> |
|
|
| <div class="arrow-right"></div> |
|
|
| |
| <div class="column"> |
| <div class="node" data-id="f5tts" onclick="selectNode('f5tts')"> |
| <span class="node-order">3</span> |
| <span class="node-icon">🧠</span> |
| <div class="node-title">F5-TTS (DiT)</div> |
| <div class="node-subtitle">Diffusion Transformer</div> |
| </div> |
| </div> |
|
|
| <div class="arrow-right"></div> |
|
|
| |
| <div class="column"> |
| <div class="node" data-id="vocoder" onclick="selectNode('vocoder')"> |
| <span class="node-order">4</span> |
| <span class="node-icon">🎼</span> |
| <div class="node-title">Vocos</div> |
| <div class="node-subtitle">Mel -> Waveform</div> |
| </div> |
| </div> |
|
|
| <div class="arrow-right"></div> |
|
|
| |
| <div class="column"> |
| <div class="node" data-id="output" onclick="selectNode('output')"> |
| <span class="node-order">5</span> |
| <span class="node-icon">🔊</span> |
| <div class="node-title">Output</div> |
| <div class="node-subtitle">wav file</div> |
| </div> |
| </div> |
| </div> |
|
|
| <div class="node-row"> |
| <div class="node compact" data-id="data_prep" onclick="selectNode('data_prep')"> |
| <span class="node-icon">🧪</span> |
| <div class="node-title">Data Prep</div> |
| </div> |
| <div class="node compact" data-id="training" onclick="selectNode('training')"> |
| <span class="node-icon">🏋️</span> |
| <div class="node-title">Training</div> |
| </div> |
| <div class="node compact" data-id="evaluation" onclick="selectNode('evaluation')"> |
| <span class="node-icon">📊</span> |
| <div class="node-title">Evaluation</div> |
| </div> |
| <div class="node compact" data-id="use_cases" onclick="selectNode('use_cases')"> |
| <span class="node-icon">✨</span> |
| <div class="node-title">Use Cases</div> |
| </div> |
| <div class="node compact" data-id="glossary" onclick="selectNode('glossary')"> |
| <span class="node-icon">📚</span> |
| <div class="node-title">Glossary</div> |
| </div> |
| <div class="node compact" data-id="params" onclick="selectNode('params')"> |
| <span class="node-icon">🎛️</span> |
| <div class="node-title">Parameters</div> |
| </div> |
| <div class="node compact" data-id="model_internals" onclick="selectNode('model_internals')"> |
| <span class="node-icon">🧬</span> |
| <div class="node-title">F5-TTS Diagram</div> |
| </div> |
| <div class="node compact" data-id="aux_models" onclick="selectNode('aux_models')"> |
| <span class="node-icon">🧩</span> |
| <div class="node-title">Other Models</div> |
| </div> |
| <div class="node compact" data-id="requirements" onclick="selectNode('requirements')"> |
| <span class="node-icon">✅</span> |
| <div class="node-title">Requirements</div> |
| </div> |
| <div class="node compact" data-id="data_layout" onclick="selectNode('data_layout')"> |
| <span class="node-icon">🗂️</span> |
| <div class="node-title">Data Layout</div> |
| </div> |
| <div class="node compact" data-id="docker" onclick="selectNode('docker')"> |
| <span class="node-icon">🐳</span> |
| <div class="node-title">Docker Env</div> |
| </div> |
| <div class="node compact" data-id="arm64" onclick="selectNode('arm64')"> |
| <span class="node-icon">⚙️</span> |
| <div class="node-title">ARM64 Fixes</div> |
| </div> |
| </div> |
| </div> |
|
|
| <div class="sidebar"> |
| <div> |
| <h1>Architecture Explorer</h1> |
| <p style="color: var(--text-dim); margin-top: 0.5rem; font-size: 0.9rem;">Interactive guide to the Cortázar TTS pipeline (data → train → eval → infer). The top row is the <b>inference path</b>; training produces the checkpoint that the model node consumes. For end-to-end workflow, see <code>docs/PIPELINE.md</code> and <code>docs/DATA_LAYOUT.md</code>.</p> |
| </div> |
|
|
| <div id="detail-panel"> |
| <div class="detail-header"> |
| <div class="detail-icon" id="d-icon">ℹ️</div> |
| <div> |
| <div class="detail-title" id="d-title">Welcome</div> |
| <div id="d-badges" style="display: flex; gap: 0.5rem; margin-top: 0.25rem;"></div> |
| </div> |
| </div> |
| <div class="detail-content" id="d-content"> |
| Select a component from the diagram to see how it works, what libraries it uses, and specific ARM64 optimizations we implemented. |
| </div> |
| <div class="tech-stack" id="d-stack"></div> |
| </div> |
| </div> |
|
|
| <script> |
| const data = { |
| input: { |
| title: "Input Handling", |
| icon: "📄", |
| badges: ["core"], |
| content: "<b>Inference inputs</b>: target text + reference audio (style prompt) + optional reference text.<br><br><b>Scripts</b>: <code><a href=\"../scripts/cortazarize.sh\">scripts/cortazarize.sh</a></code> (text→TTS or audio→ASR→TTS) → <code><a href=\"../scripts/infer_on_demand.sh\">scripts/infer_on_demand.sh</a></code> → <code><a href=\"../scripts/speak.py\">scripts/speak.py</a></code>.<br><br><b>Output</b>: a single WAV in <code>outputs/infer/</code>.<br><br>Docs: <code><a href=\"./PIPELINE.md\">docs/PIPELINE.md</a></code> and <code><a href=\"./TUNING.md\">docs/TUNING.md</a></code>.", |
| stack: ["bash", "argparse", "pathlib"] |
| }, |
| preprocess: { |
| title: "Preprocessing Module", |
| icon: "🔄", |
| badges: ["fix", "core"], |
| content: "Reference prompts are trimmed + normalized for stable conditioning:<br><br>1) <b>Ref audio trimming</b>: silence-based clipping to ~12s (keeps prompts short and avoids unstable long conditioning).<br>2) <b>Ref text</b>: if missing, we use Whisper ASR (Transformers pipeline). If the ref clip comes from the prepared dataset, we look up its <code>text</code> and skip ASR.<br>3) <b>Chunking + reassembly</b>: long target texts are chunked and reassembled with overlap/cross-fade (and optional overlap alignment) to reduce seams. You can control splits with <code>--max_chars</code> (fewer chunks) or <code>--no_chunk</code> (single-chunk attempt).<br><br><b>Critical fix:</b> prompt mel length is computed from the model’s mel extractor so we slice continuations correctly (prevents prompt-tail words leaking into the generated audio).<br><br><b>Tuning knobs:</b> <code>--speed</code>, <code>--cross_fade_sec</code>, <code>--nfe_step</code>, <code>--cfg_strength</code>.", |
| stack: ["soundfile", "pydub", "transformers (Whisper)", "numpy"] |
| }, |
| data_prep: { |
| title: "Data Preparation", |
| icon: "🧪", |
| badges: ["data", "core", "io"], |
| content: "<b>Input</b>: raw recordings in <code>raw_audio/</code> (plus optional transcripts).<br><b>Process</b>: chunking + VAD + diarization + ASR + speaker pruning.<br><b>Script</b>: <code><a href=\"../scripts/core/prepare_data.py\">scripts/core/prepare_data.py</a></code> (full pipeline wrapper: <code><a href=\"../scripts/pipeline/run_spark.sh\">scripts/pipeline/run_spark.sh</a></code>).<br><b>Output</b>: segments in <code>dataset_prepared/wavs/</code> + HF dataset in <code>dataset_prepared/raw/</code> (fields: <code>audio_path</code>, <code>text</code>, <code>duration</code>) + <code>speaker_prune_report.jsonl</code>.", |
| stack: ["pyannote", "whisper", "datasets", "ffmpeg"] |
| }, |
| training: { |
| title: "Training / Finetune", |
| icon: "🏋️", |
| badges: ["train", "core", "io"], |
| content: "<b>Input</b>: HF dataset synced to <code>F5-TTS/data/cortazar_v2_custom/</code> + base model at <code>F5-TTS/ckpts/base_models/</code>.<br><b>Entrypoint</b>: <code><a href=\"../scripts/core/train.py\">scripts/core/train.py</a></code> (wraps <code>f5_tts.train.finetune_cli</code>).<br><b>Monitoring</b>: <code><a href=\"../scripts/pipeline/train_watchdog.sh\">scripts/pipeline/train_watchdog.sh</a></code> + W&B.<br><b>Output</b>: checkpoints + sample WAVs in <code>F5-TTS/ckpts/cortazar_v2/</code> and logs in <code>outputs/logs/train.log</code>.<br><b>Required for inference</b>: the model node loads <code>model_last.pt</code> (or a specific <code>model_*.pt</code>).", |
| stack: ["accelerate", "pytorch", "wandb"] |
| }, |
| evaluation: { |
| title: "Evaluation / Monitoring", |
| icon: "📊", |
| badges: ["eval", "core", "io"], |
| content: "<b>Online checks</b>: fixed-sample eval (<code><a href=\"../scripts/pipeline/eval_fixed_samples_daemon.sh\">scripts/pipeline/eval_fixed_samples_daemon.sh</a></code>), fail-fast gate (<code><a href=\"../scripts/pipeline/failfast_gate.sh\">scripts/pipeline/failfast_gate.sh</a></code>), periodic inference (<code><a href=\"../scripts/pipeline/periodic_infer.sh\">scripts/pipeline/periodic_infer.sh</a></code>).<br><b>Metrics</b>: WER (ASR), speaker similarity, trend checks; logs to W&B via <code><a href=\"../scripts/pipeline/eval_audio_metrics.py\">scripts/pipeline/eval_audio_metrics.py</a></code>.<br><b>Output</b>: JSONL metrics in <code>outputs/infer/*scores.jsonl</code> and W&B dashboards.", |
| stack: ["wandb", "whisper", "pyannote"] |
| }, |
| f5tts: { |
| title: "F5-TTS Model", |
| icon: "🧠", |
| badges: ["core", "sota"], |
| content: "The heart of the system. F5-TTS is a <b>Flow Matching</b> model based on a <b>Diffusion Transformer (DiT)</b>.<br><br>It treats speech generation as iterative denoising over mel‑spectrograms. It conditions on text tokens + a reference‑audio mel prompt and generates a continuation spectrogram that is decoded by the vocoder.<br><br><b>Prerequisite</b>: requires a trained checkpoint from the Training step (e.g., <code>F5-TTS/ckpts/cortazar_v2/model_last.pt</code>).", |
| stack: ["pytorch", "einops", "accelerate", "hydra"] |
| }, |
| vocoder: { |
| title: "Vocos Vocoder", |
| icon: "🎼", |
| badges: ["core", "fast"], |
| content: "Converts the Mel Spectrogram generated by F5-TTS into an actual audio waveform. <br><br><b>Vocos</b> is an adversarial Fourier vocoder that is significantly faster and higher quality than older vocoders like HiFi-GAN. We install this with `--no-deps` to avoid breaking the PyTorch environment.", |
| stack: ["vocos", "torch-fft"] |
| }, |
| output: { |
| title: "Output Generation", |
| icon: "🔊", |
| badges: ["result"], |
| content: "The final waveform is saved to a `.wav` file in <code>outputs/infer/</code> (and optionally ref ensembles in <code>outputs/ref_ensembles/</code>).<br><br>The system automatically manages sample rates (usually 24kHz) and normalization before saving via <code>soundfile.write</code>.", |
| stack: ["soundfile"] |
| }, |
| use_cases: { |
| title: "Other Use Cases", |
| icon: "✨", |
| badges: ["idea"], |
| content: "<b>Speech → Speech (style transfer)</b>: re‑synthesize an input recording in Cortázar style via <code><a href=\"../scripts/cortazarize.sh\">scripts/cortazarize.sh</a></code> with <code>--input_audio</code>. <i>Caveat</i>: ASR errors propagate; provide a clean transcript when possible.<br><br><b>Long‑form narration</b>: synthesize chapters using a stable reference ensemble (<code><a href=\"../scripts/pipeline/build_ref_ensemble.py\">scripts/pipeline/build_ref_ensemble.py</a></code>). <i>Caveat</i>: long texts are chunked; tune <code>--cross_fade_sec</code> and <code>--speed</code> to reduce seams.<br><br><b>QA / regression checks</b>: fixed samples and checkpoint sweeps (<code><a href=\"../scripts/tune_cortazarize.sh\">scripts/tune_cortazarize.sh</a></code>). <i>Caveat</i>: these are monitoring only, not training data.", |
| stack: ["asr", "ref-ensembles", "qa"] |
| }, |
| glossary: { |
| title: "Glossary / Acronyms", |
| icon: "📚", |
| badges: ["docs"], |
| content: "<b>ASR</b>: automatic speech recognition (Whisper).<br><b>VAD</b>: voice activity detection (speech/non‑speech).<br><b>WER</b>: word error rate (ASR metric).<br><b>CFG</b>: classifier‑free guidance strength (sampling control).<br><b>NFE</b>: number of function evaluations (diffusion steps).<br><b>DiT</b>: diffusion transformer backbone.<br><b>CFM</b>: conditional flow matching model wrapper.<br><b>W&B</b>: Weights & Biases logging.", |
| stack: ["asr", "metrics", "diffusion"] |
| }, |
| params: { |
| title: "Parameter Effects", |
| icon: "🎛️", |
| badges: ["docs", "core"], |
| content: "<b>speed</b>: <1.0 slows cadence, >1.0 speeds up (affects duration).<br><b>cross_fade_sec</b>: overlap between chunks; higher smooths seams but can blur words; 0 disables.<br><b>nfe_step</b>: diffusion steps; higher = better quality, slower.<br><b>cfg_strength</b>: guidance strength; higher = tighter text adherence, can sound strained.<br><b>sway_sampling_coef</b>: flow sampling tweak; negative (e.g., -1) often improves quality.<br><b>max_chars</b>: larger chunks = fewer splits; too large can destabilize long text.<br><b>no_chunk</b>: try single‑chunk generation (risk of failure for long text).<br><b>ref_mode</b>: <i>ensemble</i> blends multiple clips for stability, <i>manual</i> uses one clip.<br><b>ensemble_k</b>: number of ref clips; more can stabilize tone but increases variance if clips differ.<br><b>asr_model</b>: larger = better transcription, slower; recommend <code>openai/whisper-large-v3</code> on CUDA when possible.<br><b>device</b>: <i>cuda</i> faster, <i>cpu</i> for low‑contention runs.", |
| stack: ["tuning", "asr", "quality"] |
| }, |
| model_internals: { |
| title: "F5-TTS Internal Diagram", |
| icon: "🧬", |
| badges: ["docs", "core"], |
| content: "<b>High‑level flow:</b><br><pre>Text → tokenizer → text embeddings\nRef audio → mel extractor → prompt mel\n └─────────────┬──────────────┘\n ↓\n DiT backbone (CFM / flow matching)\n ↓\n generated mel continuation\n ↓\n Vocos vocoder\n ↓\n 24kHz waveform</pre><b>Notes:</b> model predicts a continuation mel conditioned on the prompt mel + text. The prompt mel length is computed from the model’s mel extractor to avoid boundary drift.", |
| stack: ["DiT", "CFM", "mel", "vocos"] |
| }, |
| aux_models: { |
| title: "Other Models in the Pipeline", |
| icon: "🧩", |
| badges: ["docs", "core"], |
| content: "<b>Whisper (ASR)</b>: transcribes audio when no text is provided (inference) and during data prep.<br><b>Pyannote diarization</b>: separates speakers; helps filter interviewer segments.<br><b>Speaker embedding model</b>: verifies target speaker similarity; used for pruning and QA.<br><br><b>Why they matter</b>: these models don’t affect gradients directly, but errors here create bad audio↔text pairs and hurt training quality.", |
| stack: ["whisper", "pyannote", "speaker-emb"] |
| }, |
| requirements: { |
| title: "Requirements / Constraints", |
| icon: "✅", |
| badges: ["docs"], |
| content: "<b>Platform</b>: DGX Spark (ARM64).<br><b>Hard rule</b>: keep the NVIDIA base image stack intact (PyTorch/torchaudio/CUDA).<br><b>Containers</b>: <code>cortex_runner_spark</code> (training) and <code>cortex_infer_spark</code> (inference).<br><b>Storage</b>: large disk required for raw audio, prepared dataset, checkpoints, and W&B artifacts.", |
| stack: ["docker", "arm64", "cuda"] |
| }, |
| data_layout: { |
| title: "Data Layout Map", |
| icon: "🗂️", |
| badges: ["docs", "io"], |
| content: "High‑level flow (paths):<br><pre>raw_audio/\n → dataset_sources/\n → dataset_prepared/wavs/\n → dataset_prepared/raw/\n → F5-TTS/data/cortazar_v2_custom/\n → F5-TTS/ckpts/cortazar_v2/\n → outputs/infer/</pre><b>Canonical docs</b>: <code><a href=\"./DATA_LAYOUT.md\">docs/DATA_LAYOUT.md</a></code>, <code><a href=\"./PIPELINE.md\">docs/PIPELINE.md</a></code>.", |
| stack: ["paths", "artifacts"] |
| }, |
| docker: { |
| title: "Docker Environment", |
| icon: "🐳", |
| badges: ["infra", "nvidia"], |
| content: "Running on <code>nvcr.io/nvidia/pytorch:25.12-py3</code> (see <code>Dockerfile.spark</code>).<br><br><b>Hard constraint:</b> do not upgrade/replace the base image’s PyTorch/torchaudio/CUDA stack. Python deps are installed with <code>--no-deps</code> where needed to avoid pip overwriting the optimized build.", |
| stack: ["docker", "nvidia-container-toolkit"] |
| }, |
| arm64: { |
| title: "ARM64 Adaptations", |
| icon: "⚙️", |
| badges: ["fix"], |
| content: "DGX Spark is ARM64 (Grace Blackwell). The main stability rule is: <b>keep the NVIDIA base image stack intact</b>.<br><br>Patterns used here:<br>1) <b>Manual dependency management</b>: avoid pip changing torch/torchaudio.<br>2) <b>Audio I/O fallbacks</b>: prefer <code>soundfile</code> paths when torchaudio backends are brittle.<br>3) <b>Compatibility shims</b>: small monkeypatches where third-party libs assume x86/standard semver.", |
| stack: ["arm64", "linux-aarch64"] |
| } |
| }; |
| |
| function selectNode(id) { |
| // UI Update |
| document.querySelectorAll('.node').forEach(n => n.classList.remove('active')); |
| document.querySelector(`.node[data-id="${id}"]`).classList.add('active'); |
| |
| // Data Update |
| const info = data[id]; |
| document.getElementById('d-icon').textContent = info.icon; |
| document.getElementById('d-title').textContent = info.title; |
| document.getElementById('d-content').innerHTML = info.content; |
| |
| // Badges |
| const badgeContainer = document.getElementById('d-badges'); |
| badgeContainer.innerHTML = ''; |
| info.badges.forEach(b => { |
| const badge = document.createElement('span'); |
| badge.className = `detail-badge badge-${b}`; |
| badge.textContent = b; |
| badgeContainer.appendChild(badge); |
| }); |
| |
| // Stack |
| const stackContainer = document.getElementById('d-stack'); |
| stackContainer.innerHTML = ''; |
| info.stack.forEach(s => { |
| const tag = document.createElement('span'); |
| tag.className = 'tech-tag'; |
| tag.textContent = s; |
| stackContainer.appendChild(tag); |
| }); |
| } |
| </script> |
| </body> |
| </html> |
|
|