phostt 0.4.2

Local STT server powered by Zipformer-vi RNN-T — on-device Vietnamese speech recognition via ONNX Runtime
Documentation
name: CI

on:
  push:
    branches: [master]
  pull_request:
    branches: [master]

env:
  FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true

jobs:
  fmt:
    runs-on: ubuntu-latest
    name: Format
    steps:
      - uses: actions/checkout@v6
      - uses: dtolnay/rust-toolchain@stable
        with:
          components: rustfmt
      - run: cargo fmt --check

  clippy:
    runs-on: ubuntu-latest
    name: Clippy
    steps:
      - uses: actions/checkout@v6
      - uses: dtolnay/rust-toolchain@stable
        with:
          components: clippy
      - uses: actions/cache@v5
        with:
          path: |
            ~/.cargo/registry
            ~/.cargo/git
            target
          key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
      - run: cargo clippy -- -D warnings -A dead_code

  unit-tests:
    runs-on: ubuntu-latest
    name: Unit Tests
    steps:
      - uses: actions/checkout@v6
      - uses: dtolnay/rust-toolchain@stable
      - uses: actions/cache@v5
        with:
          path: |
            ~/.cargo/registry
            ~/.cargo/git
            target
          key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
      - run: cargo test

  build-coreml:
    runs-on: macos-14
    name: Build (CoreML)
    steps:
      - uses: actions/checkout@v6
      - uses: dtolnay/rust-toolchain@stable
      - uses: actions/cache@v5
        with:
          path: |
            ~/.cargo/registry
            ~/.cargo/git
            target
          key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
      - run: cargo build --release --features coreml

  build-cuda:
    runs-on: ubuntu-latest
    name: Build (CUDA)
    steps:
      - uses: actions/checkout@v6
      - uses: dtolnay/rust-toolchain@stable
      - uses: actions/cache@v5
        with:
          path: |
            ~/.cargo/registry
            ~/.cargo/git
            target
          key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
      - run: cargo build --release --features cuda

  build-diarization:
    runs-on: ubuntu-latest
    name: Build (Diarization)
    steps:
      - uses: actions/checkout@v6
      - uses: dtolnay/rust-toolchain@stable
      - uses: actions/cache@v5
        with:
          path: |
            ~/.cargo/registry
            ~/.cargo/git
            target
          key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
      - run: cargo build --release --features diarization

  build-arm-linux:
    runs-on: ubuntu-latest
    name: Build (ARM Linux)
    steps:
      - uses: actions/checkout@v6
      - uses: dtolnay/rust-toolchain@stable
        with:
          targets: aarch64-unknown-linux-gnu
      - uses: actions/cache@v5
        with:
          path: |
            ~/.cargo/registry
            ~/.cargo/git
            target
          key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
      - name: Install cross-compiler
        run: |
          sudo apt-get update
          sudo apt-get install -y gcc-aarch64-linux-gnu g++-aarch64-linux-gnu libc6-dev-arm64-cross
          echo "CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc" >> "$GITHUB_ENV"
          echo "CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_AR=aarch64-linux-gnu-ar" >> "$GITHUB_ENV"
      - run: cargo check --target aarch64-unknown-linux-gnu --release

  e2e-tests:
    # Only run on main push — PRs get fast feedback from unit tests + clippy
    if: github.ref == 'refs/heads/master' && github.event_name == 'push'
    runs-on: ubuntu-latest
    name: E2E Tests
    steps:
      - uses: actions/checkout@v6
      - uses: dtolnay/rust-toolchain@stable
      - uses: actions/cache@v5
        with:
          path: |
            ~/.cargo/registry
            ~/.cargo/git
            target
          key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}

      - name: Cache model
        id: cache-model
        uses: actions/cache@v5
        with:
          path: ~/.phostt/models
          key: phostt-model-v3-onnx-${{ hashFiles('src/model/mod.rs') }}

      - name: Download model
        if: steps.cache-model.outputs.cache-hit != 'true'
        run: cargo run -- download

      - name: Run e2e tests
        run: cargo test --test e2e_rest --test e2e_ws --test e2e_errors --test e2e_shutdown -- --ignored --test-threads=1
        timeout-minutes: 30

      - name: Run quality tests (bundled Vietnamese WAVs)
        run: cargo test --test wer -- --ignored
        timeout-minutes: 10

      - name: Run load tests
        run: cargo test --test load_test -- --ignored --test-threads=1
        timeout-minutes: 10

  e2e-pr:
    if: github.event_name == 'pull_request'
    runs-on: ubuntu-latest
    name: E2E Tests (PR)
    steps:
      - uses: actions/checkout@v6
      - uses: dtolnay/rust-toolchain@stable
      - uses: actions/cache@v5
        with:
          path: |
            ~/.cargo/registry
            ~/.cargo/git
            target
          key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}

      - name: Cache model
        id: cache-model
        uses: actions/cache@v5
        with:
          path: ~/.phostt/models
          key: phostt-model-v3-onnx-${{ hashFiles('src/model/mod.rs') }}

      - name: Download model
        if: steps.cache-model.outputs.cache-hit != 'true'
        run: cargo run -- download

      - name: Run e2e tests
        run: cargo test --test e2e_rest --test e2e_ws --test e2e_errors --test e2e_shutdown -- --ignored --test-threads=1
        timeout-minutes: 30

      - name: Run quality tests (bundled Vietnamese WAVs)
        run: cargo test --test wer -- --ignored
        timeout-minutes: 10

  audit:
    runs-on: ubuntu-latest
    name: Security Audit
    steps:
      - uses: actions/checkout@v6
      # `rustsec/audit-check` ships a prebuilt cargo-audit, saving the ~90 s
      # `cargo install --locked` rebuild on every PR run.
      - uses: rustsec/audit-check@v2
        with:
          token: ${{ secrets.GITHUB_TOKEN }}

  deny:
    runs-on: ubuntu-latest
    name: Cargo Deny
    steps:
      - uses: actions/checkout@v6
      - uses: EmbarkStudios/cargo-deny-action@v2
        with:
          # Default `check` covers licenses + advisories + bans + sources.
          # An earlier attempt passed them as `arguments: licenses advisories …`,
          # but the stable-musl `cargo-deny` refused the trailing positional
          # args as subcommands (`unrecognized subcommand 'licenses'`).
          command: check