Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -135,12 +135,14 @@ jobs:
- name: System deps (PortAudio + ffmpeg)
run: sudo apt-get update && sudo apt-get install -y libportaudio2 ffmpeg

# The local pytest hook runs `python -m pytest`, so the package + dev group
# must be importable. `pip install --group` needs pip >= 25.1, so upgrade first.
# The local pytest hook runs `uv run --frozen python -m pytest`, so the tests
# resolve the LOCKED dependency versions (uv.lock) rather than the newest
# release `pip install` would pull — which is what keeps the byte-exact
# `--help` snapshots stable. Install uv and materialize the frozen env here.
- name: Install
run: |
python -m pip install --upgrade pip
python -m pip install -e . --group dev
python -m pip install --upgrade pip uv
uv sync --frozen

- uses: pre-commit/action@2c7b3805fd2a0fd8c1884dcaebf91fc102a13ecd # v3.0.1

Expand Down
13 changes: 11 additions & 2 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -41,16 +41,25 @@ repos:

- repo: local
hooks:
# Run through `uv run --frozen` so tests resolve the LOCKED dependency
# versions (uv.lock), not whatever `pip install -e .` happened to pull. The
# byte-exact `--help` snapshots are pinned to the locked deps (e.g. the
# assemblyai SDK's SpeechModel enum); an unpinned `python -m pytest` breaks
# them the moment an upstream release adds a value.
- id: pytest
name: pytest
entry: python -m pytest -q -m "not e2e"
# Mirror check.sh: exclude both e2e (real API) and install_script (builds a
# wheel + runs install.sh / pip --user). install_script has its own dedicated
# "package install — real" CI jobs; running it here is slow and breaks under
# the locked .venv (the user-site install can't import aai_cli).
entry: uv run --frozen python -m pytest -q -m "not e2e and not install_script"
language: system
types: [python]
pass_filenames: false
always_run: true
- id: pytest-e2e
name: pytest-e2e (real API; skips without ASSEMBLYAI_API_KEY + kokoro)
entry: python -m pytest -q -m e2e
entry: uv run --frozen python -m pytest -q -m e2e
language: system
types: [python]
pass_filenames: false
Expand Down
2 changes: 2 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ uv run pytest -m install_script # builds a wheel and runs install.sh for real;

CLI output is pinned by **syrupy snapshot tests** (`tests/__snapshots__/*.ambr`). Changing help text, tables, or rendered output will fail those tests until you regenerate them with `uv run pytest --snapshot-update` and commit the updated `.ambr` files. The auto-format hook only touches `*.py`, and pre-commit's whitespace fixers deliberately skip `tests/__snapshots__/` (syrupy's indentation must stay byte-for-byte), so never hand-edit a snapshot — always regenerate.

The suite is hermetic by construction, enforced three ways (`tests/conftest.py` + `pyproject.toml` `[tool.pytest.ini_options]`): **pytest-randomly** shuffles order, an autouse `pin_timezone` fixture pins `TZ` to a fixed non-UTC zone (UTC-normalized rendering must be unaffected; use **time-machine** to freeze `now`), and **pytest-socket** (`--disable-socket`) blocks real network so an unmocked SDK/HTTP call fails loudly instead of hitting the API. A test that only binds a loopback server opts back in with the tight `@pytest.mark.allow_hosts(["127.0.0.1"])` (still blocks external hosts). The `e2e`/`install`/`install_script` marker suites legitimately reach the real network in-process (PyPI reachability probes, real-API runs), so a `pytest_collection_modifyitems` hook in `conftest.py` auto-grants them full sockets — adding a network marker is all that's needed, no per-test `enable_socket`.

## Naming & packaging gotchas

- The **package/module** is `aai_cli`; the **distribution** name is `aai-cli`; the **console command** is `aai` (`[project.scripts] aai = "aai_cli.main:run"`).
Expand Down
12 changes: 6 additions & 6 deletions aai_cli/init/templates/audio-transcription/static/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ const APP_CONFIG = {
sampleUrl: "https://assembly.ai/wildfires.mp3",
pollIntervalMs: 2000,
speakerPalette: [
"#171717",
"#525252",
"#737373",
"#262626",
"#404040",
"#a3a3a3",
"#3923c7",
"#1d1b16",
"#614fd2",
"#4a4945",
"#887bdd",
"#777673",
],
};

Expand Down
12 changes: 11 additions & 1 deletion aai_cli/init/templates/audio-transcription/static/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,14 @@
</head>
<body class="template-page audio-transcription-template">
<main class="app-shell">
<a class="brand" href="https://www.assemblyai.com" target="_blank" rel="noopener">
<img class="brand-logo" src="https://www.assemblyai.com/_aai/images/logos/assemblyai-logo-primary.svg" alt="AssemblyAI" />
</a>

<header class="page-header">
<span class="eyebrow">Speech-to-Text</span>
<h1 class="page-title">Transcribe a pre-recorded file</h1>
<p class="page-subtitle">Transcribe an audio or video URL (or upload a file), then explore speakers, chapters, sentiment, entities, and highlights.</p>
<p class="page-subtitle">Paste an audio or video URL or upload a file. You get back a full transcript, plus the speakers, chapters, sentiment, entities, and highlights that come with it.</p>
</header>

<section class="panel upload-panel">
Expand Down Expand Up @@ -38,6 +43,11 @@ <h1 class="page-title">Transcribe a pre-recorded file</h1>

<nav id="tabs" class="tab-list" aria-label="Transcript views"></nav>
<div id="view" class="result-view"></div>

<footer class="page-footer">
<span>Built with AssemblyAI</span>
<a class="footer-link" href="https://www.assemblyai.com" target="_blank" rel="noopener">assemblyai.com →</a>
</footer>
</main>

<script src="/static/app.js"></script>
Expand Down
Loading
Loading