Files
audio-scribe/pyproject.toml
T
JMR-devandClaude Opus 5 2ca46074d3 feat(backends): add GPU detection, runtime fallback and the OpenVINO backend
Detection is two-phase by construction: the registry only calls probe_toolchain
once probe_hardware confirms the vendor, which is what structurally keeps torch
from being imported on an Intel-only box. A test asserts exactly that.

Hardware probing reads each render node's bound driver rather than loaded kernel
modules: /sys/module/xe exists here with zero bound devices while i915 owns the
card, so a module-presence check false-positives.

Fallback is runtime, not detection-time -- construction and the first generate()
sit in the same try, because the render-node permission failure and the OpenCL
JIT failure both surface there rather than at device enumeration. A failure
demotes the backend process-wide so a 50-job batch does not retry it 50 times,
and an explicit --device never falls back silently.

NVIDIA and AMD are interface-only: detection is real and the error names the
module to implement and the model format required. The cached model is OpenVINO
IR and cannot load on CUDA or ROCm, and CTranslate2 has no ROCm support, so
those are two separate paths rather than one parameterized one.

Model resolution is offline-first, and CACHE_DIR is anchored under XDG rather
than the working directory, which the benchmark scripts depend on.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-13 14:33:21 -05:00

105 lines
2.7 KiB
TOML

[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[project]
name = "ccn-transcribe"
version = "0.1.0"
description = "Download videos, extract FLAC, and transcribe with Whisper on whatever GPU is present."
requires-python = ">=3.12"
dependencies = [
"click>=8.1,<9",
"numpy>=2.5,<3",
"huggingface-hub>=1.31,<2",
"yt-dlp[default,deno]>=2026.8.19",
"yt-dlp-ejs>=0.8",
"openvino==2026.3.1",
"openvino-genai==2026.3.1.0",
]
[project.scripts]
ccn-transcribe = "ccn_transcribe.cli:main"
[dependency-groups]
dev = [
"pytest>=8",
"pytest-cov>=5",
"ruff>=0.6",
"pyright>=1.1.380",
"mypy>=1.11",
"pylint>=3.2",
"pre-commit>=3.8",
]
[tool.hatch.build.targets.wheel]
packages = ["src/ccn_transcribe"]
[tool.ruff]
line-length = 100
src = ["src", "tests"]
# ruff format also restyles Python blocks inside Markdown; docs are not ours to restyle.
extend-exclude = ["*.md"]
[tool.ruff.lint]
select = ["E", "F", "W", "I", "N", "UP", "B", "A", "C4", "SIM", "PTH", "RET", "ARG", "TID", "TC", "RUF", "S"]
# S607: binaries are looked up on PATH on purpose and preflight-checked with
# shutil.which; hardcoding absolute paths would be less portable, not safer.
ignore = ["S607"]
[tool.ruff.lint.per-file-ignores]
# S101: asserts are the point of a test file.
"tests/*" = ["ARG001", "ARG002", "S101"]
# Throwaway benchmarks, not pipeline code.
"scripts/*" = ["S603"]
[tool.pyright]
include = ["src", "tests"]
typeCheckingMode = "strict"
venvPath = "."
venv = ".venv"
[tool.mypy]
strict = true
files = ["src", "tests"]
[[tool.mypy.overrides]]
# These ship no py.typed marker.
module = ["openvino.*", "openvino_genai.*", "huggingface_hub.*", "yt_dlp.*"]
ignore_missing_imports = true
[tool.pylint.design]
max-attributes = 15
# Keyword-only arguments do not carry the readability cost this check guards against.
max-args = 9
[tool.pylint.main]
# W0621: pytest fixtures shadow their names by design.
# C1803: asserting == () is more precise than truthiness about what a call returns.
# R0903: dataclasses and pytest grouping classes legitimately have few methods.
disable = [
"C0114", "C0115", "C0116", "C0301",
"W0611", "W0612", "W0621",
"R0801", "R0903", "C1803",
]
[tool.pytest.ini_options]
testpaths = ["tests"]
# NOTE: --cov-fail-under deliberately lives in the pre-commit hook, not here, so a
# single-file TDD run (`uv run pytest tests/test_x.py`) is not blocked by coverage.
addopts = "-q"
[tool.coverage.run]
branch = true
source = ["src/ccn_transcribe"]
[tool.coverage.report]
fail_under = 100
show_missing = true
exclude_also = [
"if TYPE_CHECKING:",
'if __name__ == "__main__":',
"@overload",
"raise NotImplementedError",
"class .*\\(Protocol\\):",
]