build(arm64): cross-compile parakeet-cli for the Raspberry Pi 5 #200
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: ci | |
| on: | |
| push: | |
| pull_request: | |
| # closed-loop job runs on pull_request (gate) and manual dispatch (see below). | |
| workflow_dispatch: | |
| jobs: | |
| # ------------------------------------------------------------------------- | |
| # build: configure, compile, run model-independent unit tests. | |
| # Runs on every push and pull_request. Never downloads a model — fast gate. | |
| # ------------------------------------------------------------------------- | |
| build: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| submodules: recursive | |
| - name: configure | |
| # GGML_NATIVE=OFF for portability in CI (no host-cpu ISA extensions) | |
| run: cmake -B build -DPARAKEET_BUILD_TESTS=ON -DGGML_NATIVE=OFF | |
| - name: build | |
| run: cmake --build build -j | |
| - name: test (model-independent only) | |
| # -LE model excludes the model-labelled tests (check_convert, | |
| # test_model_loader, check_baseline) that need the Python venv and the | |
| # cached NeMo checkpoint. Those will run in a separate workflow_dispatch | |
| # job once a models bundle is published (Phase 4). | |
| run: ctest --test-dir build --output-on-failure -LE model | |
| # ------------------------------------------------------------------------- | |
| # server-e2e: drive the real parakeet-server over HTTP. | |
| # | |
| # Runs on pull_request (merge gate) and manual workflow_dispatch. Not on every | |
| # push: it downloads the ~125 MB tdt_ctc-110m-q4_k model via the alias path. | |
| # Much lighter than closed-loop (no NeMo/Python venv) — it builds the server, | |
| # then tests/server_e2e.sh starts it, transcribes tests/fixtures/speech.wav in | |
| # json/text/verbose_json (with word timestamps), and checks the 400 paths. | |
| # ------------------------------------------------------------------------- | |
| server-e2e: | |
| if: github.event_name == 'pull_request' || github.event_name == 'workflow_dispatch' | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 20 | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| submodules: recursive | |
| - name: Install build dependencies | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y cmake build-essential curl ca-certificates | |
| - name: Configure | |
| run: | | |
| cmake -B build \ | |
| -DPARAKEET_BUILD_SERVER=ON \ | |
| -DPARAKEET_BUILD_TESTS=ON \ | |
| -DGGML_NATIVE=OFF | |
| - name: Build parakeet-server | |
| run: cmake --build build --target parakeet-server -j | |
| - name: Run server e2e | |
| # PARAKEET_SERVER_E2E=1 flips the test from skip (77) to a real run. | |
| env: | |
| PARAKEET_SERVER_E2E: "1" | |
| # First-run model download speed varies on hosted runners; the job | |
| # timeout remains the outer cap. | |
| PARAKEET_SERVER_E2E_READY_TIMEOUT: "600" | |
| run: ctest --test-dir build --output-on-failure -R '^server_e2e$' | |
| # ------------------------------------------------------------------------- | |
| # closed-loop: full end-to-end transcript assertion. | |
| # | |
| # Runs on pull_request (merge gate) and manual workflow_dispatch. Not on every | |
| # push, since this job downloads nvidia/parakeet-tdt_ctc-110m (~440 MB via | |
| # NeMo/HuggingFace Hub) and installs the nemo_toolkit Python env (~60 min). | |
| # | |
| # What it does: | |
| # 1. Check out the repo (submodules recursive). | |
| # 2. Install system build deps + Python 3.12 + pip. | |
| # 3. Create a venv and install CPU torch + scripts/requirements.txt | |
| # (nemo_toolkit[asr] + gguf) — same setup as the developer guide. | |
| # 4. Build the project (GGML_NATIVE=OFF for runner portability, | |
| # PARAKEET_BUILD_TESTS=ON, PARAKEET_BUILD_CLI=ON). | |
| # 5. Convert nvidia/parakeet-tdt_ctc-110m → /tmp/pk110m_cl.gguf | |
| # (F32, default dtype; NeMo auto-downloads the checkpoint on first use). | |
| # 6. Run `parakeet-cli transcribe` on tests/fixtures/speech.wav with | |
| # --decoder tdt (the TDT head of the hybrid model). | |
| # 7. Assert the output matches the committed NeMo reference transcript: | |
| # "Well, I don't wish to see it any more, observed Phoebe, | |
| # turning away her eyes. It is certainly very like the old portrait." | |
| # Fail the job if it doesn't match. | |
| # ------------------------------------------------------------------------- | |
| closed-loop: | |
| if: github.event_name == 'pull_request' || github.event_name == 'workflow_dispatch' | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 60 | |
| steps: | |
| - name: Checkout (with submodules) | |
| uses: actions/checkout@v4 | |
| with: | |
| submodules: recursive | |
| - name: Install system build dependencies | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y cmake build-essential python3 python3-venv python3-pip | |
| - name: Set up Python venv | |
| # CPU-only torch wheel; nemo_toolkit[asr] + gguf from requirements.txt. | |
| # Mirror the developer setup documented in AGENTS.md / README.md. | |
| run: | | |
| python3 -m venv .venv | |
| .venv/bin/pip install --quiet --upgrade pip | |
| .venv/bin/pip install --quiet torch --index-url https://download.pytorch.org/whl/cpu | |
| .venv/bin/pip install --quiet -r scripts/requirements.txt | |
| - name: Configure CMake | |
| run: | | |
| cmake -B build \ | |
| -DPARAKEET_BUILD_TESTS=ON \ | |
| -DPARAKEET_BUILD_CLI=ON \ | |
| -DGGML_NATIVE=OFF | |
| - name: Build | |
| run: cmake --build build -j | |
| - name: Convert nvidia/parakeet-tdt_ctc-110m to GGUF | |
| # NeMo downloads the ~440 MB checkpoint from HuggingFace on first use. | |
| # The resulting GGUF is ~438 MB (F32). | |
| run: | | |
| .venv/bin/python scripts/convert_parakeet_to_gguf.py \ | |
| --model nvidia/parakeet-tdt_ctc-110m \ | |
| --output /tmp/pk110m_cl.gguf | |
| - name: Transcribe speech fixture with TDT decoder | |
| run: | | |
| ./build/examples/cli/parakeet-cli transcribe \ | |
| --model /tmp/pk110m_cl.gguf \ | |
| --input tests/fixtures/speech.wav \ | |
| --decoder tdt \ | |
| > /tmp/cl_transcript.txt | |
| echo "--- transcript ---" | |
| cat /tmp/cl_transcript.txt | |
| - name: Assert transcript matches NeMo reference | |
| # Reference transcript (TDT head, hybrid 110m) committed to docs/parity.md | |
| # and validated at WER 0.0 vs NeMo 2.7.3 (see docs/parity.md § Phase 3). | |
| run: | | |
| EXPECTED="Well, I don't wish to see it any more, observed Phoebe, turning away her eyes. It is certainly very like the old portrait." | |
| ACTUAL="$(cat /tmp/cl_transcript.txt)" | |
| python3 - <<'PYEOF' | |
| import sys | |
| expected = "Well, I don't wish to see it any more, observed Phoebe, turning away her eyes. It is certainly very like the old portrait." | |
| with open("/tmp/cl_transcript.txt") as f: | |
| actual = f.read().strip() | |
| if actual == expected: | |
| print("PASS: transcript matches NeMo reference (WER 0.0)") | |
| sys.exit(0) | |
| else: | |
| print("FAIL: transcript mismatch") | |
| print(f" expected: {expected!r}") | |
| print(f" actual: {actual!r}") | |
| sys.exit(1) | |
| PYEOF |