{
  "$type": "site.standard.document",
  "bskyPostRef": {
    "cid": "bafyreif5qcahqdhwntq2wnscpoqhejjrb5fvuinx4fcqlj5k6326id35hy",
    "uri": "at://did:plc:pgryn3ephfd2xgft23qokfzt/app.bsky.feed.post/3mknbercjoiy2"
  },
  "path": "/t/module-torchaudio-has-no-attribute-audiometadata/175647#post_2",
  "publishedAt": "2026-04-29T12:28:50.000Z",
  "site": "https://discuss.huggingface.co",
  "tags": [
    "TorchAudio 2.8 torchaudio.info / AudioMetaData deprecation docs",
    "TorchAudio 2.8 package warning: many APIs deprecated in 2.8 and removed in 2.9",
    "TorchAudio 2.9 docs: APIs deprecated in 2.8 were removed in 2.9",
    "PyTorch Audio issue: Update on TorchAudio’s future",
    "Matching pyannote issue: AttributeError: module 'torchaudio' has no attribute 'AudioMetaData'",
    "uv running scripts guide",
    "uv PyTorch integration guide",
    "TorchAudio installation docs: PyTorch and TorchAudio versions must match",
    "TorchCodec README compatibility table",
    "pyannote 3.4.0 release note",
    "TorchAudio 2.8 docs",
    "TorchCodec README",
    "faster-whisper README",
    "TorchAudio installation compatibility notes",
    "uv docs: locking script dependencies",
    "pyannote.audio GitHub repository",
    "pyannote speaker-diarization-community-1 model card",
    "pyannote/speaker-diarization-3.1",
    "pyannote/speaker-diarization-community-1",
    "Hugging Face access tokens docs",
    "TorchAudio future / TorchCodec migration issue"
  ],
  "textContent": "Seems maybe just a compatibility issue. If you just want to work around the issue, pinning the library version should suffice, but if you want to use the latest version of the library, you may need to make some modifications to the script:\n\n* * *\n\n# Fixing `AttributeError: module 'torchaudio' has no attribute 'AudioMetaData'` in a pyannote + faster-whisper + uv script\n\n## Short diagnosis\n\nThis is very likely a **dependency compatibility issue** , not a bug in your diarization or transcription logic.\n\nThe important clue is that the crash happens during this import:\n\n\n    from pyannote.audio import Inference, Model, Pipeline\n\n\nThe script is not reaching the real diarization/transcription part yet. Python is still importing `pyannote.audio`, and the crash happens inside pyannote’s audio I/O module:\n\n\n    ) -> torchaudio.AudioMetaData:\n          ^^^^^^^^^^^^^^^^^^^^^^^^\n    AttributeError: module 'torchaudio' has no attribute 'AudioMetaData'\n\n\nThat means pyannote code is referencing:\n\n\n    torchaudio.AudioMetaData\n\n\nbut the installed `torchaudio` package no longer exposes that object.\n\nThis fits the current TorchAudio transition: `AudioMetaData` and related audio I/O APIs were deprecated in TorchAudio 2.8 and removed in TorchAudio 2.9 as part of TorchAudio’s move into maintenance mode and the shift of media decoding/encoding functionality toward TorchCodec.\n\nUseful references:\n\n  * TorchAudio 2.8 torchaudio.info / AudioMetaData deprecation docs\n  * TorchAudio 2.8 package warning: many APIs deprecated in 2.8 and removed in 2.9\n  * TorchAudio 2.9 docs: APIs deprecated in 2.8 were removed in 2.9\n  * PyTorch Audio issue: Update on TorchAudio’s future\n  * Matching pyannote issue: AttributeError: module 'torchaudio' has no attribute 'AudioMetaData'\n\n\n\nThe likely version story is:\n\n\n    Your script asks uv for broad/latest-ish package versions\n            ↓\n    uv resolves a newer TorchAudio, probably 2.9+\n            ↓\n    the installed pyannote.audio code still references torchaudio.AudioMetaData\n            ↓\n    import pyannote.audio fails before your own script logic runs\n\n\n* * *\n\n## Why your current dependency block is fragile\n\nYour current inline metadata has this shape:\n\n\n    #!/usr/bin/env -S uv run\n    # /// script\n    # requires-python = \">=3.10\"\n    # dependencies = [\n    #   \"faster-whisper\",\n    #   \"nvidia-cublas-cu12\",\n    #   \"nvidia-cudnn-cu12\",\n    #   \"numpy\",\n    #   \"pyannote.audio>=3.1\",\n    #   \"nvidia-cublas\",\n    #   \"nvidia-cudnn-cu13\",\n    #   \"nvidia-npp\",\n    #   \"scikit-learn\",\n    #   \"torch\",\n    #   \"torchaudio\",\n    #   \"torchcodec\",\n    #   \"omegaconf\",\n    #   \"brouhaha @ file:///home/user/diarization/repos/.venv/brouhaha-vad\",\n    # ]\n    # ///\n\n\nThe main risk is here:\n\n\n    \"pyannote.audio>=3.1\",\n    \"torch\",\n    \"torchaudio\",\n    \"torchcodec\",\n\n\nThose constraints are too broad for a fast-moving audio/ML stack.\n\nThey allow uv to pick a package family like:\n\n\n    pyannote.audio 3.x\n    torch 2.9.x\n    torchaudio 2.9.x\n    torchcodec 0.8.x or 0.9.x\n\n\nThat is exactly the kind of combination that can fail: pyannote 3.x-era code may still reference older TorchAudio APIs, while TorchAudio 2.9 removed APIs deprecated in 2.8.\n\nThis is not really uv’s fault. uv is resolving from the constraints you gave it. The problem is that the constraints are too loose for a stack where `torch`, `torchaudio`, `torchcodec`, CUDA libraries, FFmpeg, pyannote, and faster-whisper all interact.\n\nRelevant docs:\n\n  * uv running scripts guide\n  * uv PyTorch integration guide\n  * TorchAudio installation docs: PyTorch and TorchAudio versions must match\n  * TorchCodec README compatibility table\n\n\n\n* * *\n\n## Recommended fix: recover first with a pinned compatible stack\n\nI would not start by rewriting the whole diarization/transcription pipeline. First, recover the existing script by pinning a compatible version family.\n\nUse this dependency block first:\n\n\n    #!/usr/bin/env -S uv run --script\n    # /// script\n    # requires-python = \">=3.10,<3.14\"\n    # dependencies = [\n    #   \"faster-whisper\",\n    #   \"numpy\",\n    #   \"pyannote.audio==3.4.0\",\n    #   \"scikit-learn\",\n    #   \"torch==2.8.0\",\n    #   \"torchaudio==2.8.0\",\n    #   \"torchcodec==0.7.*\",\n    #   \"omegaconf\",\n    #   \"brouhaha @ file:///home/user/diarization/repos/.venv/brouhaha-vad\",\n    # ]\n    # ///\n\n\n### Why these pins?\n\nPackage | Reason\n---|---\n`pyannote.audio==3.4.0` | Keeps you on the pyannote 3.x generation, which is likely closer to your current script. The pyannote 3.4.0 release was a maintenance release that pinned related `pyannote.{core,database,metrics,pipeline}` dependencies to avoid breakage in the 3.x branch. See the pyannote 3.4.0 release note.\n`torch==2.8.0` | Keeps PyTorch in the last generation before the TorchAudio 2.9 removal boundary.\n`torchaudio==2.8.0` | Keeps `torchaudio.AudioMetaData` available. TorchAudio 2.8 has it, though deprecated. See the TorchAudio 2.8 docs.\n`torchcodec==0.7.*` | TorchCodec’s own compatibility table maps TorchCodec `0.7` to Torch `2.8`. See the TorchCodec README.\n`requires-python = \">=3.10,<3.14\"` | Your traceback shows Python 3.12. TorchCodec `0.7` supports Python `>=3.9, <=3.13`, so Python 3.12 is a reasonable target.\n\nThe practical point is simple:\n\n\n    TorchAudio 2.9+ removed AudioMetaData\n            ↓\n    pyannote import crashes\n            ↓\n    pin TorchAudio to 2.8.0\n            ↓\n    AudioMetaData exists again\n            ↓\n    pyannote can import\n\n\n* * *\n\n## Remove the manually listed NVIDIA packages for the first recovery attempt\n\nI would remove these from the first recovery attempt:\n\n\n    \"nvidia-cublas-cu12\",\n    \"nvidia-cudnn-cu12\",\n    \"nvidia-cublas\",\n    \"nvidia-cudnn-cu13\",\n    \"nvidia-npp\",\n\n\nReasons:\n\n  1. They are not the cause of the current error.\n  2. The current error is a Python import-time attribute lookup, not a CUDA runtime error.\n  3. The block mixes CUDA 12 and CUDA 13 package names.\n  4. Manually mixing NVIDIA runtime packages can make the environment harder to reason about.\n  5. PyTorch CUDA wheel selection should be handled coherently through the PyTorch wheel/index strategy, not by mixing low-level NVIDIA packages casually.\n\n\n\nThis does not mean CUDA never matters. It does mean CUDA should be debugged **after** pyannote imports.\n\nFor faster-whisper GPU execution, you may later need CUDA/cuDNN-related fixes. The faster-whisper project documents CUDA and cuDNN expectations in its README:\n\n  * faster-whisper README\n\n\n\nBut that is a second-stage issue. First fix:\n\n\n    from pyannote.audio import Inference, Model, Pipeline\n\n\n* * *\n\n## Also fix the shebang and quotes\n\nUse:\n\n\n    #!/usr/bin/env -S uv run --script\n\n\ninstead of:\n\n\n    #!/usr/bin/env -S uv run\n\n\nThe uv docs use `uv run --script` for scripts with inline metadata:\n\n  * uv running scripts guide\n\n\n\nAlso make sure your actual file uses straight quotes, not curly quotes.\n\nBad if literally present in the file:\n\n\n    “torch”\n\n\nGood:\n\n\n    \"torch\"\n\n\nIf the curly quotes only appeared because of formatting while pasting into a forum, ignore this. If they are actually in the file, the inline metadata is not valid TOML.\n\n* * *\n\n## Step-by-step recovery procedure\n\n### Step 1: Replace the dependency block\n\nUse this exact header first:\n\n\n    #!/usr/bin/env -S uv run --script\n    # /// script\n    # requires-python = \">=3.10,<3.14\"\n    # dependencies = [\n    #   \"faster-whisper\",\n    #   \"numpy\",\n    #   \"pyannote.audio==3.4.0\",\n    #   \"scikit-learn\",\n    #   \"torch==2.8.0\",\n    #   \"torchaudio==2.8.0\",\n    #   \"torchcodec==0.7.*\",\n    #   \"omegaconf\",\n    #   \"brouhaha @ file:///home/user/diarization/repos/.venv/brouhaha-vad\",\n    # ]\n    # ///\n\n\n* * *\n\n### Step 2: Test pyannote import in isolation\n\nBefore testing the full diarization/transcription script, create a small file called `check_pyannote_import.py`:\n\n\n    #!/usr/bin/env -S uv run --script\n    # /// script\n    # requires-python = \">=3.10,<3.14\"\n    # dependencies = [\n    #   \"pyannote.audio==3.4.0\",\n    #   \"torch==2.8.0\",\n    #   \"torchaudio==2.8.0\",\n    #   \"torchcodec==0.7.*\",\n    # ]\n    # ///\n\n    import sys\n    from importlib.metadata import version\n\n    import torch\n    import torchaudio\n    from pyannote.audio import Pipeline\n\n    print(\"python:\", sys.version)\n    print(\"torch:\", torch.__version__)\n    print(\"torchaudio:\", torchaudio.__version__)\n    print(\"torchcodec:\", version(\"torchcodec\"))\n    print(\"AudioMetaData exists:\", hasattr(torchaudio, \"AudioMetaData\"))\n    print(\"pyannote import OK\")\n\n\nRun it with a fresh resolution:\n\n\n    uv run --refresh --script check_pyannote_import.py\n\n\nExpected output should include something like:\n\n\n    torch: 2.8.0...\n    torchaudio: 2.8.0...\n    torchcodec: 0.7...\n    AudioMetaData exists: True\n    pyannote import OK\n\n\nThe most important line is:\n\n\n    AudioMetaData exists: True\n\n\nIf that line is `False`, you are still not running with the TorchAudio version you think you are running.\n\n* * *\n\n### Step 3: Inspect the resolved dependency tree\n\nRun:\n\n\n    uv tree --script diaritranscribe3.py\n\n\nLook for:\n\n\n    pyannote.audio==3.4.0\n    torch==2.8.0\n    torchaudio==2.8.0\n    torchcodec==0.7.x\n\n\nFor this recovery path, you do **not** want:\n\n\n    torchaudio==2.9.x\n    torch==2.9.x\n\n\nTorchAudio and PyTorch should be matched. Do not use a mixed pair like:\n\n\n    torch 2.8 + torchaudio 2.9\n\n\nor:\n\n\n    torch 2.9 + torchaudio 2.8\n\n\nThe safer recovery pair is:\n\n\n    torch 2.8.0 + torchaudio 2.8.0\n\n\nReference:\n\n  * TorchAudio installation compatibility notes\n\n\n\n* * *\n\n### Step 4: Run your real script with refresh\n\nAfter the minimal import test works:\n\n\n    uv run --refresh --script diaritranscribe3.py\n\n\nIf the script is executable:\n\n\n    chmod +x diaritranscribe3.py\n    ./diaritranscribe3.py\n\n\n* * *\n\n### Step 5: Lock the script after it works\n\nOnce the import works and the script begins running normally, lock the dependency set:\n\n\n    uv lock --script diaritranscribe3.py\n\n\nuv supports lockfiles for PEP 723 inline scripts. The lockfile is created next to the script, for example:\n\n\n    diaritranscribe3.py.lock\n\n\nReference:\n\n  * uv docs: locking script dependencies\n\n\n\nThis is important because your current error is exactly the kind of failure that lockfiles prevent. Without a lockfile, the same script can work today and break later when a newer `torchaudio`, `torchcodec`, `pyannote-core`, `pyannote-metrics`, or other dependency becomes resolvable.\n\n* * *\n\n## Why I recommend recovery before full migration\n\nThere are two possible paths:\n\nPath | Meaning | When to choose it\n---|---|---\nRecovery path | Keep your current pyannote 3.x-style script and pin compatible versions. | Best first move when the script fails at import time and you want minimal code changes.\nMigration path | Move to current pyannote 4.x / `community-1` / TorchCodec / FFmpeg assumptions. | Better long-term, but may require code changes and may expose new TorchCodec/FFmpeg issues.\n\nFor your case, I would choose **recovery first**.\n\nReason: the traceback proves the import environment is broken. It does **not** prove that your diarization logic, faster-whisper logic, VAD logic, or speaker-label alignment logic is wrong.\n\nThe disciplined order is:\n\n\n    fix pyannote import\n            ↓\n    test pyannote alone\n            ↓\n    test faster-whisper alone\n            ↓\n    test speaker/transcript alignment\n            ↓\n    then consider migrating to newer pyannote conventions\n\n\n* * *\n\n## What the forward-migration path would look like later\n\nThe current pyannote direction is more TorchCodec-centered. The current pyannote repository describes pyannote.audio as a PyTorch-based speaker diarization toolkit, and current pyannote usage increasingly assumes TorchCodec and FFmpeg for audio decoding.\n\nReferences:\n\n  * pyannote.audio GitHub repository\n  * pyannote speaker-diarization-community-1 model card\n  * TorchCodec README\n\n\n\nA newer pyannote-style snippet can look like this:\n\n\n    import torch\n    from pyannote.audio import Pipeline\n    from pyannote.audio.pipelines.utils.hook import ProgressHook\n\n    pipeline = Pipeline.from_pretrained(\n        \"pyannote/speaker-diarization-community-1\",\n        token=\"<HUGGINGFACE_ACCESS_TOKEN>\",\n    )\n\n    pipeline.to(torch.device(\"cuda\"))\n\n    with ProgressHook() as hook:\n        output = pipeline(\"audio.wav\", hook=hook)\n\n    for turn, speaker in output.speaker_diarization:\n        print(f\"start={turn.start:.1f}s stop={turn.end:.1f}s speaker_{speaker}\")\n\n\nIn normal prose, that token placeholder would be written as `\\<HUGGINGFACE_ACCESS_TOKEN\\>`.\n\nThat newer path may be the right long-term direction, but it is a migration, not just a one-line dependency fix. It may change:\n\n  * model name;\n  * access/token handling;\n  * audio decoding assumptions;\n  * FFmpeg requirements;\n  * TorchCodec version requirements;\n  * output object shape;\n  * how you iterate diarization results;\n  * how you align diarization segments with transcript segments.\n\n\n\nOlder pyannote 3.x code commonly looks more like this:\n\n\n    for turn, _, speaker in diarization.itertracks(yield_label=True):\n        print(f\"start={turn.start:.1f}s stop={turn.end:.1f}s speaker_{speaker}\")\n\n\nSo moving from pyannote 3.x to pyannote 4.x may require real script edits. That is why I would first recover your current script.\n\n* * *\n\n## What to test after the import works\n\nAfter this import stops crashing:\n\n\n    from pyannote.audio import Inference, Model, Pipeline\n\n\ntest each subsystem separately.\n\n### 1. Test PyTorch and CUDA\n\n\n    import torch\n\n    print(\"torch:\", torch.__version__)\n    print(\"torch cuda build:\", torch.version.cuda)\n    print(\"cuda available:\", torch.cuda.is_available())\n\n    if torch.cuda.is_available():\n        print(\"gpu:\", torch.cuda.get_device_name(0))\n\n\nIf this prints:\n\n\n    cuda available: False\n\n\nthen the pyannote import may be fixed, but your PyTorch build is CPU-only or CUDA-incompatible. That is a separate problem.\n\n* * *\n\n### 2. Test pyannote alone on a small WAV\n\nFor the first test, avoid MP3/M4A/WEBM. Normalize to a small mono 16 kHz WAV:\n\n\n    ffmpeg -y -i input.mp3 -ac 1 -ar 16000 test.wav\n\n\nThen test only diarization:\n\n\n    from pyannote.audio import Pipeline\n    import torch\n\n    pipeline = Pipeline.from_pretrained(\n        \"pyannote/speaker-diarization-3.1\",\n        use_auth_token=\"<HUGGINGFACE_ACCESS_TOKEN>\",\n    )\n\n    if torch.cuda.is_available():\n        pipeline.to(torch.device(\"cuda\"))\n\n    diarization = pipeline(\"test.wav\")\n\n    for turn, _, speaker in diarization.itertracks(yield_label=True):\n        print(turn.start, turn.end, speaker)\n\n\nIn normal prose, write the token placeholder as `\\<HUGGINGFACE_ACCESS_TOKEN\\>`.\n\nUseful model page:\n\n  * pyannote/speaker-diarization-3.1\n\n\n\n* * *\n\n### 3. Test faster-whisper alone\n\n\n    from faster_whisper import WhisperModel\n\n    model = WhisperModel(\"small\", device=\"cuda\", compute_type=\"float16\")\n    segments, info = model.transcribe(\"test.wav\", beam_size=5)\n\n    print(\"language:\", info.language, info.language_probability)\n\n    for segment in segments:\n        print(segment.start, segment.end, segment.text)\n\n\nImportant faster-whisper detail: `segments` is a generator, so transcription starts when you iterate over it or convert it to a list. The faster-whisper README documents this behavior.\n\nReference:\n\n  * faster-whisper README\n\n\n\nIf faster-whisper fails with CUDA/cuDNN/cuBLAS errors, that is a different layer from the pyannote import failure.\n\n* * *\n\n### 4. Then combine diarization and transcription\n\nOnce both pyannote and faster-whisper work independently, then debug the speaker-attributed transcript logic.\n\nThe next hard problem is usually timestamp reconciliation:\n\n\n    diarization:\n    SPEAKER_00 from 10.0s to 14.8s\n\n    transcription:\n    \"yeah that makes sense\" from 13.9s to 16.2s\n\n\nYou need a policy for assigning transcript text to speakers.\n\nCommon policies:\n\nPolicy | Meaning | Tradeoff\n---|---|---\nMidpoint assignment | Assign a transcript segment to the speaker active at the segment midpoint. | Simple, but weak for long segments that cross speaker changes.\nMaximum overlap | Assign the transcript segment to the speaker with the largest time overlap. | Usually a good first implementation.\nSplit at speaker boundaries | Split transcript segments when diarization changes speakers. | More accurate, more code.\nWord-level assignment | Use word timestamps and assign each word separately. | Best when word timestamps are reliable.\nExclusive diarization | Prefer non-overlapping diarization when available. | Easier to reconcile with transcript timestamps.\n\nFor a first robust script, I would use **maximum overlap** at the segment level. Later, if transcript quality matters a lot, move to word-level assignment.\n\n* * *\n\n## Why not just monkey-patch pyannote?\n\nSome workarounds patch the installed pyannote file and replace something like:\n\n\n    ) -> torchaudio.AudioMetaData:\n\n\nwith:\n\n\n    ) -> object:\n\n\nor a quoted annotation.\n\nThat can work temporarily because the failing reference is often annotation-related. But I would not keep that as the real solution.\n\nReasons:\n\n  * it modifies files inside `site-packages`;\n  * uv can rebuild the environment and erase the patch;\n  * it hides the real version mismatch;\n  * another removed TorchAudio API may fail later;\n  * it makes the environment non-reproducible;\n  * it is harder to explain or maintain.\n\n\n\nFor this script, version pinning is cleaner.\n\n* * *\n\n## Likely next errors after this fix\n\nAfter you fix `AudioMetaData`, you may hit another layer. That is normal.\n\n### Possible next error: Hugging Face model access\n\nIf you load pyannote models from Hugging Face, you may need to accept model conditions and use a token.\n\nPossible symptoms:\n\n\n    401 Unauthorized\n    403 Forbidden\n    Repository not found\n    You are not in the authorized list\n\n\nUseful links:\n\n  * pyannote/speaker-diarization-3.1\n  * pyannote/speaker-diarization-community-1\n  * Hugging Face access tokens docs\n\n\n\n### Possible next error: TorchCodec / FFmpeg\n\nIf you migrate toward newer pyannote or use TorchCodec-backed decoding, you may see errors like:\n\n\n    Could not load libtorchcodec\n    FFmpeg is not properly installed\n\n\nUseful links:\n\n  * TorchCodec README\n  * TorchAudio future / TorchCodec migration issue\n\n\n\n### Possible next error: CUDA unavailable\n\nIf:\n\n\n    torch.cuda.is_available()\n\n\nreturns:\n\n\n    False\n\n\nthen the import problem is fixed, but your PyTorch install is not seeing the GPU. That is a PyTorch wheel/index/CUDA issue.\n\nUseful link:\n\n  * uv PyTorch integration guide\n\n\n\n### Possible next error: faster-whisper CUDA/cuDNN/CTranslate2\n\nPossible symptoms:\n\n\n    Library libcudnn_ops_infer.so not found\n    CUDA failed\n    unsupported compute type\n\n\nUseful link:\n\n  * faster-whisper README\n\n\n\n* * *\n\n## Final recommended script header\n\nFor your current script, I would start with this:\n\n\n    #!/usr/bin/env -S uv run --script\n    # /// script\n    # requires-python = \">=3.10,<3.14\"\n    # dependencies = [\n    #   \"faster-whisper\",\n    #   \"numpy\",\n    #   \"pyannote.audio==3.4.0\",\n    #   \"scikit-learn\",\n    #   \"torch==2.8.0\",\n    #   \"torchaudio==2.8.0\",\n    #   \"torchcodec==0.7.*\",\n    #   \"omegaconf\",\n    #   \"brouhaha @ file:///home/user/diarization/repos/.venv/brouhaha-vad\",\n    # ]\n    # ///\n\n\nThen run:\n\n\n    uv run --refresh --script diaritranscribe3.py\n\n\nThen inspect:\n\n\n    uv tree --script diaritranscribe3.py\n\n\nThen lock:\n\n\n    uv lock --script diaritranscribe3.py\n\n\n* * *\n\n## Bottom line\n\nThe fix is not to install a random missing package. The fix is to choose a coherent version family.\n\nFor your current script, the most practical recovery family is:\n\n\n    pyannote.audio 3.4.0\n    torch 2.8.0\n    torchaudio 2.8.0\n    torchcodec 0.7.x\n    Python 3.12\n\n\nThat combination is aimed at the exact failure:\n\n\n    AttributeError: module 'torchaudio' has no attribute 'AudioMetaData'\n\n\nAfter that works, debug CUDA, faster-whisper, model access, FFmpeg/TorchCodec, and speaker-transcript alignment as separate layers.\n\n## Short summary\n\n  * The error is almost certainly a dependency compatibility issue.\n  * `torchaudio.AudioMetaData` existed in TorchAudio 2.8 but was removed in TorchAudio 2.9.\n  * Your dependency block lets uv resolve incompatible versions.\n  * Pin `pyannote.audio==3.4.0`, `torch==2.8.0`, `torchaudio==2.8.0`, and `torchcodec==0.7.*`.\n  * Remove the mixed manual `nvidia-*` packages for the first recovery attempt.\n  * Test pyannote import by itself.\n  * Use `uv run --refresh --script ...`.\n  * Inspect with `uv tree --script ...`.\n  * Lock with `uv lock --script ...`.\n  * Consider pyannote 4.x / `community-1` later as a real migration, not the first fix.\n\n",
  "title": "Module 'torchaudio' has no attribute 'AudioMetaData'"
}