Load any Canopy variant from the Hub or from GitHub
Browse files- README.md +18 -7
- canopy/inference/__init__.py +2 -1
- canopy/inference/__main__.py +3 -0
- canopy/inference/api.py +54 -0
- canopy/inference/cli.py +36 -0
- canopy/inference/hub.py +54 -0
- canopy/inference/transcriber.py +12 -4
- canopy_m.py +39 -56
README.md
CHANGED
|
@@ -49,27 +49,38 @@ One block is half SwiGLU, rotary attention, a squeeze-excite depthwise convoluti
|
|
| 49 |
|
| 50 |
## Use
|
| 51 |
|
| 52 |
-
|
|
|
|
|
|
|
| 53 |
|
| 54 |
```bash
|
| 55 |
pip install torch torchaudio soundfile numpy pyyaml huggingface_hub
|
| 56 |
hf auth login
|
| 57 |
hf download ProximaAI/Canopy-M --local-dir Canopy-M
|
| 58 |
-
python Canopy-M/canopy_m.py clip.wav --language urd
|
| 59 |
-
python Canopy-M/canopy_m.py clip.wav --language snd --device cpu
|
| 60 |
```
|
| 61 |
|
| 62 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 63 |
|
| 64 |
```python
|
| 65 |
-
from
|
| 66 |
|
| 67 |
-
asr =
|
|
|
|
| 68 |
print(asr.transcribe("clip.wav", language="urd"))
|
| 69 |
print(asr.transcribe("clip.wav", language="snd"))
|
| 70 |
```
|
| 71 |
|
| 72 |
-
|
| 73 |
|
| 74 |
## Training data
|
| 75 |
|
|
|
|
| 49 |
|
| 50 |
## Use
|
| 51 |
|
| 52 |
+
Each Canopy variant is its own Hub repository. This one is `canopy-m` (`ProximaAI/Canopy-M`). The same loader accepts a short name or any `org/repo` id, so the next checkpoint does not need a new API. Log in once with a token that can read the repo.
|
| 53 |
+
|
| 54 |
+
From this snapshot, without GitHub:
|
| 55 |
|
| 56 |
```bash
|
| 57 |
pip install torch torchaudio soundfile numpy pyyaml huggingface_hub
|
| 58 |
hf auth login
|
| 59 |
hf download ProximaAI/Canopy-M --local-dir Canopy-M
|
| 60 |
+
python Canopy-M/canopy_m.py clip.wav --model canopy-m --language urd
|
| 61 |
+
python Canopy-M/canopy_m.py clip.wav --model ProximaAI/Canopy-M --language snd --device cpu
|
| 62 |
```
|
| 63 |
|
| 64 |
+
From GitHub, one install for every variant:
|
| 65 |
+
|
| 66 |
+
```bash
|
| 67 |
+
pip install torch torchaudio soundfile numpy pyyaml huggingface_hub
|
| 68 |
+
pip install "git+https://github.com/mwzkhalil/canopy.git@danish#subdirectory=canopy"
|
| 69 |
+
hf auth login
|
| 70 |
+
canopy-transcribe clip.wav --model canopy-m --language urd
|
| 71 |
+
canopy-transcribe clip.wav --model ProximaAI/Canopy-M --language snd
|
| 72 |
+
```
|
| 73 |
|
| 74 |
```python
|
| 75 |
+
from canopy.inference import Canopy
|
| 76 |
|
| 77 |
+
asr = Canopy.from_pretrained("canopy-m") # ProximaAI/Canopy-M
|
| 78 |
+
asr = Canopy.from_pretrained("ProximaAI/Canopy-M") # same checkpoint
|
| 79 |
print(asr.transcribe("clip.wav", language="urd"))
|
| 80 |
print(asr.transcribe("clip.wav", language="snd"))
|
| 81 |
```
|
| 82 |
|
| 83 |
+
`language` accepts `urd` / `ur` / `urdu` and `snd` / `sd` / `sindhi` for this checkpoint. A future repo is loaded with its own id, for example `Canopy.from_pretrained("ProximaAI/Canopy-S")`, once that repository exists. If a repository contains more than one `.pt` file, pass `filename=`. Decoding here is greedy CTC. Audio may be any sample rate; it is resampled to 16 kHz. Files longer than 30 seconds are transcribed in chunks.
|
| 84 |
|
| 85 |
## Training data
|
| 86 |
|
canopy/inference/__init__.py
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
|
|
| 1 |
from canopy.inference.transcriber import Transcriber
|
| 2 |
|
| 3 |
-
__all__ = ["Transcriber"]
|
|
|
|
| 1 |
+
from canopy.inference.api import Canopy
|
| 2 |
from canopy.inference.transcriber import Transcriber
|
| 3 |
|
| 4 |
+
__all__ = ["Canopy", "Transcriber"]
|
canopy/inference/__main__.py
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from canopy.inference.cli import main
|
| 2 |
+
|
| 3 |
+
main()
|
canopy/inference/api.py
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""User-facing loader for every Canopy checkpoint."""
|
| 2 |
+
|
| 3 |
+
from __future__ import annotations
|
| 4 |
+
|
| 5 |
+
from pathlib import Path
|
| 6 |
+
|
| 7 |
+
import torch
|
| 8 |
+
|
| 9 |
+
from canopy.inference.hub import resolve_repo
|
| 10 |
+
from canopy.inference.transcriber import Transcriber
|
| 11 |
+
|
| 12 |
+
LANGUAGE_ALIASES = {"ur": "urd", "urdu": "urd", "sd": "snd", "sindhi": "snd"}
|
| 13 |
+
|
| 14 |
+
|
| 15 |
+
def resolve_language(language: str | None) -> str | None:
|
| 16 |
+
if language is None:
|
| 17 |
+
return None
|
| 18 |
+
return LANGUAGE_ALIASES.get(language.strip().lower(), language.strip().lower())
|
| 19 |
+
|
| 20 |
+
|
| 21 |
+
class Canopy:
|
| 22 |
+
"""One interface for every Canopy variant.
|
| 23 |
+
|
| 24 |
+
``model`` is a short name (``canopy-m``) or a Hub id (``ProximaAI/Canopy-M``).
|
| 25 |
+
A path to a local ``.pt`` file loads that file and does not contact the Hub.
|
| 26 |
+
"""
|
| 27 |
+
|
| 28 |
+
def __init__(self, transcriber: Transcriber, model: str):
|
| 29 |
+
self.transcriber = transcriber
|
| 30 |
+
self.model = model
|
| 31 |
+
self.languages = list(transcriber.languages)
|
| 32 |
+
|
| 33 |
+
@classmethod
|
| 34 |
+
def from_pretrained(cls, model: str = "canopy-m", *, filename: str | None = None,
|
| 35 |
+
device: str | None = None, token: str | None = None,
|
| 36 |
+
revision: str | None = None) -> Canopy:
|
| 37 |
+
if device is None:
|
| 38 |
+
device = "cuda" if torch.cuda.is_available() else "cpu"
|
| 39 |
+
path = Path(model)
|
| 40 |
+
if path.is_file():
|
| 41 |
+
asr = Transcriber.from_checkpoint(path, device=device)
|
| 42 |
+
return cls(asr, str(path))
|
| 43 |
+
repo_id = resolve_repo(model)
|
| 44 |
+
asr = Transcriber.from_pretrained(
|
| 45 |
+
repo_id, filename=filename, device=device, token=token, revision=revision,
|
| 46 |
+
)
|
| 47 |
+
return cls(asr, repo_id)
|
| 48 |
+
|
| 49 |
+
def transcribe(self, audio, language: str | None = "urd", decoder: str = "greedy", **kw) -> str:
|
| 50 |
+
code = resolve_language(language)
|
| 51 |
+
if code is not None and self.languages and code not in self.languages:
|
| 52 |
+
known = ", ".join(self.languages)
|
| 53 |
+
raise ValueError(f"{self.model} was trained on {known}, not {language!r}")
|
| 54 |
+
return self.transcriber.transcribe(audio, language=code, decoder=decoder, **kw)
|
canopy/inference/cli.py
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Transcribe with any published Canopy checkpoint.
|
| 2 |
+
|
| 3 |
+
GitHub install (one package, every variant):
|
| 4 |
+
|
| 5 |
+
pip install torch torchaudio soundfile numpy pyyaml huggingface_hub
|
| 6 |
+
pip install "git+https://github.com/mwzkhalil/canopy.git@danish#subdirectory=canopy"
|
| 7 |
+
hf auth login
|
| 8 |
+
canopy-transcribe clip.wav --model canopy-m --language urd
|
| 9 |
+
canopy-transcribe clip.wav --model ProximaAI/Canopy-M --language snd
|
| 10 |
+
"""
|
| 11 |
+
|
| 12 |
+
from __future__ import annotations
|
| 13 |
+
|
| 14 |
+
import argparse
|
| 15 |
+
|
| 16 |
+
from canopy.inference.api import LANGUAGE_ALIASES, Canopy
|
| 17 |
+
from canopy.inference.hub import VARIANTS
|
| 18 |
+
|
| 19 |
+
|
| 20 |
+
def main() -> None:
|
| 21 |
+
names = ", ".join(sorted(VARIANTS))
|
| 22 |
+
ap = argparse.ArgumentParser(description="Transcribe with a Canopy checkpoint")
|
| 23 |
+
ap.add_argument("audio", nargs="+", help="wav, flac, or mp3 paths")
|
| 24 |
+
ap.add_argument("--model", default="canopy-m", help=f"variant name ({names}) or org/repo id")
|
| 25 |
+
ap.add_argument("--filename", default=None, help="checkpoint filename when a repo has several")
|
| 26 |
+
ap.add_argument("--language", required=True, help="ISO code, for example urd or snd")
|
| 27 |
+
ap.add_argument("--device", default=None, help="cpu, cuda, or omit for auto")
|
| 28 |
+
ap.add_argument("--decoder", choices=["greedy", "beam"], default="greedy")
|
| 29 |
+
args = ap.parse_args()
|
| 30 |
+
asr = Canopy.from_pretrained(args.model, filename=args.filename, device=args.device)
|
| 31 |
+
for path in args.audio:
|
| 32 |
+
text = asr.transcribe(path, language=args.language, decoder=args.decoder)
|
| 33 |
+
print(f"{path}\t{text}")
|
| 34 |
+
|
| 35 |
+
|
| 36 |
+
__all__ = ["LANGUAGE_ALIASES", "main"]
|
canopy/inference/hub.py
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Resolve a Canopy variant to a Hugging Face repo and checkpoint file.
|
| 2 |
+
|
| 3 |
+
A variant is either a short name from ``VARIANTS`` or a full ``org/repo`` id.
|
| 4 |
+
Add a line to ``VARIANTS`` when a new checkpoint is published. Passing
|
| 5 |
+
``org/repo`` directly works before that line exists.
|
| 6 |
+
"""
|
| 7 |
+
|
| 8 |
+
from __future__ import annotations
|
| 9 |
+
|
| 10 |
+
from pathlib import Path
|
| 11 |
+
|
| 12 |
+
# Short name -> Hub repo. Weights stay on the Hub; this table is only the address.
|
| 13 |
+
VARIANTS: dict[str, str] = {
|
| 14 |
+
"canopy-m": "ProximaAI/Canopy-M",
|
| 15 |
+
}
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
def resolve_repo(model: str) -> str:
|
| 19 |
+
"""Return an ``org/repo`` id. Local checkpoint paths are not repos."""
|
| 20 |
+
key = model.strip()
|
| 21 |
+
if not key:
|
| 22 |
+
raise ValueError("model name is empty")
|
| 23 |
+
if key.lower() in VARIANTS:
|
| 24 |
+
return VARIANTS[key.lower()]
|
| 25 |
+
if "/" in key and not Path(key).exists():
|
| 26 |
+
return key
|
| 27 |
+
known = ", ".join(sorted(VARIANTS))
|
| 28 |
+
raise ValueError(
|
| 29 |
+
f"unknown Canopy variant {model!r}. Use one of: {known}. "
|
| 30 |
+
"Or pass a Hub id such as ProximaAI/Canopy-M."
|
| 31 |
+
)
|
| 32 |
+
|
| 33 |
+
|
| 34 |
+
def checkpoint_name(repo_id: str) -> str:
|
| 35 |
+
"""Default weight file: the repo name, lowercased, with a .pt suffix."""
|
| 36 |
+
name = repo_id.split("/")[-1].strip().lower()
|
| 37 |
+
return name if name.endswith(".pt") else f"{name}.pt"
|
| 38 |
+
|
| 39 |
+
|
| 40 |
+
def pick_checkpoint(repo_id: str, files: list[str], filename: str | None = None) -> str:
|
| 41 |
+
"""Choose one ``.pt`` at the repo root. ``filename`` wins when it is present."""
|
| 42 |
+
root = [f for f in files if "/" not in f and f.endswith(".pt")]
|
| 43 |
+
if filename:
|
| 44 |
+
if filename not in files and filename not in root:
|
| 45 |
+
raise FileNotFoundError(f"{repo_id} has no file {filename!r}. Root checkpoints: {root or 'none'}")
|
| 46 |
+
return filename
|
| 47 |
+
preferred = checkpoint_name(repo_id)
|
| 48 |
+
if preferred in root:
|
| 49 |
+
return preferred
|
| 50 |
+
if len(root) == 1:
|
| 51 |
+
return root[0]
|
| 52 |
+
raise FileNotFoundError(
|
| 53 |
+
f"{repo_id} has {len(root)} checkpoint files {root}. Pass filename= to choose one."
|
| 54 |
+
)
|
canopy/inference/transcriber.py
CHANGED
|
@@ -50,14 +50,22 @@ class Transcriber:
|
|
| 50 |
return cls(model, _tokenizer_from_checkpoint(ck, tokenizer_dir), device=device, **kw)
|
| 51 |
|
| 52 |
@classmethod
|
| 53 |
-
def from_pretrained(cls, repo_id: str = "ProximaAI/Canopy-M", *, filename: str =
|
| 54 |
device: str = "cpu", revision: str | None = None, token: str | None = None, **kw) -> Transcriber:
|
| 55 |
-
"""Download an inference checkpoint from the Hugging Face Hub and load it.
|
|
|
|
|
|
|
|
|
|
|
|
|
| 56 |
try:
|
| 57 |
-
from huggingface_hub import hf_hub_download
|
| 58 |
except ImportError as exc:
|
| 59 |
raise ImportError("pip install huggingface_hub") from exc
|
| 60 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 61 |
return cls.from_checkpoint(path, device=device, **kw)
|
| 62 |
|
| 63 |
def attach_lm(self, language: str, lm) -> None:
|
|
|
|
| 50 |
return cls(model, _tokenizer_from_checkpoint(ck, tokenizer_dir), device=device, **kw)
|
| 51 |
|
| 52 |
@classmethod
|
| 53 |
+
def from_pretrained(cls, repo_id: str = "ProximaAI/Canopy-M", *, filename: str | None = None,
|
| 54 |
device: str = "cpu", revision: str | None = None, token: str | None = None, **kw) -> Transcriber:
|
| 55 |
+
"""Download an inference checkpoint from the Hugging Face Hub and load it.
|
| 56 |
+
|
| 57 |
+
``repo_id`` is an ``org/name`` id. ``filename`` defaults to the single
|
| 58 |
+
``.pt`` at the repo root, preferring ``<repo-name>.pt``.
|
| 59 |
+
"""
|
| 60 |
try:
|
| 61 |
+
from huggingface_hub import hf_hub_download, list_repo_files
|
| 62 |
except ImportError as exc:
|
| 63 |
raise ImportError("pip install huggingface_hub") from exc
|
| 64 |
+
from canopy.inference.hub import pick_checkpoint
|
| 65 |
+
|
| 66 |
+
files = list_repo_files(repo_id, revision=revision, token=token)
|
| 67 |
+
chosen = pick_checkpoint(repo_id, files, filename)
|
| 68 |
+
path = hf_hub_download(repo_id=repo_id, filename=chosen, revision=revision, token=token)
|
| 69 |
return cls.from_checkpoint(path, device=device, **kw)
|
| 70 |
|
| 71 |
def attach_lm(self, language: str, lm) -> None:
|
canopy_m.py
CHANGED
|
@@ -1,26 +1,31 @@
|
|
| 1 |
#!/usr/bin/env python
|
| 2 |
-
"""Transcribe
|
| 3 |
|
| 4 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 5 |
|
| 6 |
pip install torch torchaudio soundfile numpy pyyaml huggingface_hub
|
| 7 |
hf auth login
|
|
|
|
|
|
|
| 8 |
|
| 9 |
-
|
| 10 |
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
|
|
|
|
|
|
| 14 |
|
| 15 |
-
|
| 16 |
|
| 17 |
-
from
|
| 18 |
-
asr =
|
|
|
|
| 19 |
print(asr.transcribe("clip.wav", language="urd"))
|
| 20 |
-
print(asr.transcribe("clip.wav", language="sindhi"))
|
| 21 |
-
|
| 22 |
-
``language`` is ``urd`` or ``snd``. ``ur`` / ``urdu`` and ``sd`` / ``sindhi`` are accepted.
|
| 23 |
-
The published scores use greedy CTC with the language id on.
|
| 24 |
"""
|
| 25 |
|
| 26 |
from __future__ import annotations
|
|
@@ -30,58 +35,36 @@ import sys
|
|
| 30 |
from pathlib import Path
|
| 31 |
|
| 32 |
_HERE = Path(__file__).resolve().parent
|
| 33 |
-
for _root in (_HERE, _HERE.parent):
|
| 34 |
-
if (_root / "canopy" / "__init__.py").is_file():
|
| 35 |
-
sys.path.insert(0, str(_root))
|
| 36 |
-
break
|
| 37 |
-
|
| 38 |
-
import torch
|
| 39 |
-
|
| 40 |
-
from canopy.inference.transcriber import Transcriber
|
| 41 |
-
|
| 42 |
-
REPO_ID = "ProximaAI/Canopy-M"
|
| 43 |
-
ALIASES = {"ur": "urd", "urdu": "urd", "urd": "urd", "sd": "snd", "sindhi": "snd", "snd": "snd"}
|
| 44 |
-
|
| 45 |
-
|
| 46 |
-
def resolve_language(language: str) -> str:
|
| 47 |
-
key = language.strip().lower()
|
| 48 |
-
if key not in ALIASES:
|
| 49 |
-
known = "urd, snd (also ur, urdu, sd, sindhi)"
|
| 50 |
-
raise ValueError(f"unknown language {language!r}. Use one of: {known}")
|
| 51 |
-
return ALIASES[key]
|
| 52 |
-
|
| 53 |
-
|
| 54 |
-
class CanopyM:
|
| 55 |
-
"""Urdu and Sindhi CTC recogniser backed by the Canopy-M checkpoint."""
|
| 56 |
-
|
| 57 |
-
def __init__(self, transcriber: Transcriber):
|
| 58 |
-
self.transcriber = transcriber
|
| 59 |
|
| 60 |
-
@classmethod
|
| 61 |
-
def from_pretrained(cls, repo_id: str = REPO_ID, *, device: str | None = None, token: str | None = None) -> CanopyM:
|
| 62 |
-
if device is None:
|
| 63 |
-
device = "cuda" if torch.cuda.is_available() else "cpu"
|
| 64 |
-
local = _HERE / "canopy-m.pt"
|
| 65 |
-
if local.is_file():
|
| 66 |
-
asr = Transcriber.from_checkpoint(local, device=device)
|
| 67 |
-
else:
|
| 68 |
-
asr = Transcriber.from_pretrained(repo_id, device=device, token=token)
|
| 69 |
-
return cls(asr)
|
| 70 |
|
| 71 |
-
|
| 72 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 73 |
|
| 74 |
|
| 75 |
def main() -> None:
|
| 76 |
-
|
|
|
|
| 77 |
ap.add_argument("audio", nargs="+", help="wav, flac, or mp3 paths")
|
| 78 |
-
ap.add_argument("--
|
|
|
|
|
|
|
| 79 |
ap.add_argument("--device", default=None, help="cpu, cuda, or omit for auto")
|
| 80 |
-
ap.add_argument("--
|
| 81 |
args = ap.parse_args()
|
| 82 |
-
asr =
|
| 83 |
for path in args.audio:
|
| 84 |
-
print(f"{path}\t{asr.transcribe(path, language=args.language)}")
|
| 85 |
|
| 86 |
|
| 87 |
if __name__ == "__main__":
|
|
|
|
| 1 |
#!/usr/bin/env python
|
| 2 |
+
"""Transcribe with any Canopy variant.
|
| 3 |
|
| 4 |
+
The weights for each variant live in their own Hugging Face repo. This script
|
| 5 |
+
is the same for all of them. The code can come from this model snapshot or
|
| 6 |
+
from GitHub.
|
| 7 |
+
|
| 8 |
+
Snapshot (no GitHub):
|
| 9 |
|
| 10 |
pip install torch torchaudio soundfile numpy pyyaml huggingface_hub
|
| 11 |
hf auth login
|
| 12 |
+
hf download ProximaAI/Canopy-M --local-dir Canopy-M
|
| 13 |
+
python Canopy-M/canopy_m.py clip.wav --model canopy-m --language urd
|
| 14 |
|
| 15 |
+
GitHub (one install, then any Hub repo):
|
| 16 |
|
| 17 |
+
pip install "git+https://github.com/mwzkhalil/canopy.git@danish#subdirectory=canopy"
|
| 18 |
+
pip install huggingface_hub
|
| 19 |
+
hf auth login
|
| 20 |
+
canopy-transcribe clip.wav --model canopy-m --language urd
|
| 21 |
+
canopy-transcribe clip.wav --model ProximaAI/Canopy-M --language snd
|
| 22 |
|
| 23 |
+
Python:
|
| 24 |
|
| 25 |
+
from canopy.inference import Canopy
|
| 26 |
+
asr = Canopy.from_pretrained("canopy-m")
|
| 27 |
+
asr = Canopy.from_pretrained("ProximaAI/Canopy-M")
|
| 28 |
print(asr.transcribe("clip.wav", language="urd"))
|
|
|
|
|
|
|
|
|
|
|
|
|
| 29 |
"""
|
| 30 |
|
| 31 |
from __future__ import annotations
|
|
|
|
| 35 |
from pathlib import Path
|
| 36 |
|
| 37 |
_HERE = Path(__file__).resolve().parent
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 38 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 39 |
|
| 40 |
+
def _load_api():
|
| 41 |
+
try:
|
| 42 |
+
from canopy.inference.api import Canopy
|
| 43 |
+
from canopy.inference.hub import VARIANTS
|
| 44 |
+
return Canopy, VARIANTS
|
| 45 |
+
except ImportError:
|
| 46 |
+
for root in (_HERE, _HERE.parent):
|
| 47 |
+
if (root / "canopy" / "__init__.py").is_file():
|
| 48 |
+
sys.path.insert(0, str(root))
|
| 49 |
+
break
|
| 50 |
+
from canopy.inference.api import Canopy
|
| 51 |
+
from canopy.inference.hub import VARIANTS
|
| 52 |
+
return Canopy, VARIANTS
|
| 53 |
|
| 54 |
|
| 55 |
def main() -> None:
|
| 56 |
+
Canopy, variants = _load_api()
|
| 57 |
+
ap = argparse.ArgumentParser(description="Transcribe with a Canopy checkpoint")
|
| 58 |
ap.add_argument("audio", nargs="+", help="wav, flac, or mp3 paths")
|
| 59 |
+
ap.add_argument("--model", default="canopy-m", help="variant name or org/repo. Known: " + ", ".join(sorted(variants)))
|
| 60 |
+
ap.add_argument("--filename", default=None, help="checkpoint file when a repo contains several")
|
| 61 |
+
ap.add_argument("--language", required=True, help="language code, for example urd or snd")
|
| 62 |
ap.add_argument("--device", default=None, help="cpu, cuda, or omit for auto")
|
| 63 |
+
ap.add_argument("--decoder", choices=["greedy", "beam"], default="greedy")
|
| 64 |
args = ap.parse_args()
|
| 65 |
+
asr = Canopy.from_pretrained(args.model, filename=args.filename, device=args.device)
|
| 66 |
for path in args.audio:
|
| 67 |
+
print(f"{path}\t{asr.transcribe(path, language=args.language, decoder=args.decoder)}")
|
| 68 |
|
| 69 |
|
| 70 |
if __name__ == "__main__":
|