diff --git a/.github/workflows/publish-docker.yml b/.github/workflows/publish-docker.yml new file mode 100644 index 0000000..42239ec --- /dev/null +++ b/.github/workflows/publish-docker.yml @@ -0,0 +1,61 @@ +name: Publish Docker Images + +on: + push: + tags: + - "v*" + workflow_dispatch: + inputs: + tag: + description: "Image tag to publish (without image suffix)" + required: true + type: string + +permissions: + contents: read + packages: write + +jobs: + docker: + runs-on: ubuntu-latest + env: + IMAGE_TAG: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.tag || github.ref_name }} + strategy: + fail-fast: false + matrix: + include: + - image_suffix: cpu-diarization-sortformer + dockerfile: Dockerfile.cpu + extras: cpu,diarization-sortformer + - image_suffix: cu129-diarization-sortformer + dockerfile: Dockerfile + extras: gpu-cu129,diarization-sortformer + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set lowercase owner + id: owner + run: echo "value=${GITHUB_REPOSITORY_OWNER,,}" >> "${GITHUB_OUTPUT}" + + - name: Login to GHCR + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Setup Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Build and push image + uses: docker/build-push-action@v6 + with: + context: . + file: ./${{ matrix.dockerfile }} + push: true + build-args: | + EXTRAS=${{ matrix.extras }} + tags: | + ghcr.io/${{ steps.owner.outputs.value }}/whisperlivekit:${{ env.IMAGE_TAG }}-${{ matrix.image_suffix }} + ghcr.io/${{ steps.owner.outputs.value }}/whisperlivekit:latest-${{ matrix.image_suffix }} diff --git a/.github/workflows/support-matrix.yml b/.github/workflows/support-matrix.yml new file mode 100644 index 0000000..06264b7 --- /dev/null +++ b/.github/workflows/support-matrix.yml @@ -0,0 +1,134 @@ +name: Support Matrix + +on: + pull_request: + workflow_dispatch: + inputs: + timeout_sec: + description: "Per-case timeout in seconds" + required: true + default: "300" + +permissions: + contents: read + +jobs: + test-and-support-matrix: + name: | + ${{ matrix.os }} | py${{ matrix.python-version }} | tests + support matrix + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, macos-latest, windows-latest] + python-version: ["3.11", "3.12", "3.13"] + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup uv + uses: astral-sh/setup-uv@v6 + + - name: Install dependencies for tests + run: uv sync --extra test --python ${{ matrix.python-version }} + + # - name: Run unit tests + # run: uv run pytest tests/ -v + + - name: Run compatibility matrix + shell: bash + env: + MATRIX_PY: ${{ matrix.python-version }} + TIMEOUT_SEC: ${{ github.event.inputs.timeout_sec || '300' }} + run: | + set -euo pipefail + + base_port=8010 + + run_case() { + local name="$1" + shift 1 + + echo "[matrix] scenario=${name}" + + uv run wlk \ + --host 127.0.0.1 \ + --port "${base_port}" \ + --warmup-file "" \ + --model tiny \ + "$@" & + local server_pid=$! + + cleanup() { + kill "${server_pid}" >/dev/null 2>&1 || true + wait "${server_pid}" >/dev/null 2>&1 || true + } + trap cleanup RETURN + + local ready=0 + local checks=$((TIMEOUT_SEC / 2)) + local i=0 + while [ "${i}" -lt "${checks}" ]; do + if python -c "import urllib.request; urllib.request.urlopen('http://127.0.0.1:${base_port}/', timeout=2).read(1)" >/dev/null 2>&1; then + ready=1 + break + fi + if ! kill -0 "${server_pid}" >/dev/null 2>&1; then + break + fi + sleep 2 + i=$((i + 1)) + done + + if [ "${ready}" -ne 1 ]; then + echo "[matrix] ${name} failed (startup_not_ready)" + return 1 + fi + + echo "[matrix] ${name} passed" + base_port=$((base_port + 1)) + } + + # FW profile: cpu + diart + sortformer + translation + export UV_PROJECT_ENVIRONMENT=".ci-envs/${{ matrix.os }}-py${{ matrix.python-version }}-fw" + uv sync --python "${MATRIX_PY}" --no-dev \ + --extra cpu \ + --extra diarization-diart \ + --extra diarization-sortformer \ + --extra translation + + run_case \ + "fw-diart-translation" \ + --backend faster-whisper \ + --diarization \ + --diarization-backend diart \ + --language en \ + --target-language es + + run_case \ + "fw-sortformer-translation" \ + --backend faster-whisper \ + --diarization \ + --diarization-backend sortformer \ + --language en \ + --target-language es + + unset UV_PROJECT_ENVIRONMENT + + # Voxtral profile: cpu + diart + voxtral-hf + translation + export UV_PROJECT_ENVIRONMENT=".ci-envs/${{ matrix.os }}-py${{ matrix.python-version }}-voxtral" + uv sync --python "${MATRIX_PY}" --no-dev \ + --extra cpu \ + --extra diarization-diart \ + --extra voxtral-hf \ + --extra translation + + run_case \ + "voxtral-diart-translation" \ + --backend voxtral \ + --diarization \ + --diarization-backend diart \ + --language en \ + --target-language es + + unset UV_PROJECT_ENVIRONMENT