transcribe-cpp 0.0.3__tar.gz → 0.0.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {transcribe_cpp-0.0.3 → transcribe_cpp-0.0.4}/PKG-INFO +3 -3
- {transcribe_cpp-0.0.3 → transcribe_cpp-0.0.4}/pyproject.toml +3 -3
- {transcribe_cpp-0.0.3 → transcribe_cpp-0.0.4}/src/transcribe_cpp/__init__.py +80 -8
- {transcribe_cpp-0.0.3 → transcribe_cpp-0.0.4}/src/transcribe_cpp/_generated.py +9 -3
- {transcribe_cpp-0.0.3 → transcribe_cpp-0.0.4}/tests/test_backends.py +21 -0
- transcribe_cpp-0.0.4/tests/test_device_select.py +55 -0
- {transcribe_cpp-0.0.3 → transcribe_cpp-0.0.4}/.gitignore +0 -0
- {transcribe_cpp-0.0.3 → transcribe_cpp-0.0.4}/LICENSE +0 -0
- {transcribe_cpp-0.0.3 → transcribe_cpp-0.0.4}/README.md +0 -0
- {transcribe_cpp-0.0.3 → transcribe_cpp-0.0.4}/_generate/README.md +0 -0
- {transcribe_cpp-0.0.3 → transcribe_cpp-0.0.4}/_generate/check_version_sync.py +0 -0
- {transcribe_cpp-0.0.3 → transcribe_cpp-0.0.4}/_generate/generate.py +0 -0
- {transcribe_cpp-0.0.3 → transcribe_cpp-0.0.4}/examples/stream_wav.py +0 -0
- {transcribe_cpp-0.0.3 → transcribe_cpp-0.0.4}/examples/transcribe_wav.py +0 -0
- {transcribe_cpp-0.0.3 → transcribe_cpp-0.0.4}/src/transcribe_cpp/_abi.py +0 -0
- {transcribe_cpp-0.0.3 → transcribe_cpp-0.0.4}/src/transcribe_cpp/_library.py +0 -0
- {transcribe_cpp-0.0.3 → transcribe_cpp-0.0.4}/src/transcribe_cpp/errors.py +0 -0
- {transcribe_cpp-0.0.3 → transcribe_cpp-0.0.4}/src/transcribe_cpp/py.typed +0 -0
- {transcribe_cpp-0.0.3 → transcribe_cpp-0.0.4}/tests/conftest.py +0 -0
- {transcribe_cpp-0.0.3 → transcribe_cpp-0.0.4}/tests/test_abi.py +0 -0
- {transcribe_cpp-0.0.3 → transcribe_cpp-0.0.4}/tests/test_errors.py +0 -0
- {transcribe_cpp-0.0.3 → transcribe_cpp-0.0.4}/tests/test_example.py +0 -0
- {transcribe_cpp-0.0.3 → transcribe_cpp-0.0.4}/tests/test_family_ext.py +0 -0
- {transcribe_cpp-0.0.3 → transcribe_cpp-0.0.4}/tests/test_lifetime.py +0 -0
- {transcribe_cpp-0.0.3 → transcribe_cpp-0.0.4}/tests/test_pcm.py +0 -0
- {transcribe_cpp-0.0.3 → transcribe_cpp-0.0.4}/tests/test_provider_discovery.py +0 -0
- {transcribe_cpp-0.0.3 → transcribe_cpp-0.0.4}/tests/test_streaming.py +0 -0
- {transcribe_cpp-0.0.3 → transcribe_cpp-0.0.4}/tests/test_transcribe.py +0 -0
- {transcribe_cpp-0.0.3 → transcribe_cpp-0.0.4}/uv.lock +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: transcribe-cpp
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.4
|
|
4
4
|
Summary: Python bindings for transcribe.cpp
|
|
5
5
|
Project-URL: Homepage, https://github.com/handy-computer/transcribe.cpp
|
|
6
6
|
Project-URL: Repository, https://github.com/handy-computer/transcribe.cpp
|
|
@@ -21,9 +21,9 @@ Classifier: Programming Language :: Python :: 3.13
|
|
|
21
21
|
Classifier: Topic :: Multimedia :: Sound/Audio :: Speech
|
|
22
22
|
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
23
23
|
Requires-Python: >=3.9
|
|
24
|
-
Requires-Dist: transcribe-cpp-native==0.0.
|
|
24
|
+
Requires-Dist: transcribe-cpp-native==0.0.4.*
|
|
25
25
|
Provides-Extra: cu12
|
|
26
|
-
Requires-Dist: transcribe-cpp-native-cu12==0.0.
|
|
26
|
+
Requires-Dist: transcribe-cpp-native-cu12==0.0.4.*; extra == 'cu12'
|
|
27
27
|
Provides-Extra: test
|
|
28
28
|
Requires-Dist: numpy; extra == 'test'
|
|
29
29
|
Requires-Dist: pytest>=7; extra == 'test'
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "transcribe-cpp"
|
|
7
|
-
version = "0.0.
|
|
7
|
+
version = "0.0.4"
|
|
8
8
|
description = "Python bindings for transcribe.cpp"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
# 3.8 is EOL (2024-10); 3.9 is the floor. The binding is ctypes-only, so there
|
|
@@ -34,13 +34,13 @@ classifiers = [
|
|
|
34
34
|
# packaging fix still resolves); the import-time version/header-hash check in
|
|
35
35
|
# _library.py is the runtime backstop. check_version_sync.py gates this pin
|
|
36
36
|
# against include/transcribe.h.
|
|
37
|
-
dependencies = ["transcribe-cpp-native==0.0.
|
|
37
|
+
dependencies = ["transcribe-cpp-native==0.0.4.*"]
|
|
38
38
|
|
|
39
39
|
[project.optional-dependencies]
|
|
40
40
|
# Opt-in accelerator providers — ADDITIVE: they install alongside the default
|
|
41
41
|
# provider and the best one wins at runtime. Same base-version pin contract
|
|
42
42
|
# as the hard dependency (gated by check_version_sync.py).
|
|
43
|
-
cu12 = ["transcribe-cpp-native-cu12==0.0.
|
|
43
|
+
cu12 = ["transcribe-cpp-native-cu12==0.0.4.*"]
|
|
44
44
|
# Test-only deps. Run with: uv run --extra test pytest (from bindings/python).
|
|
45
45
|
# numpy is here so the numpy PCM-input tests run in every lane instead of
|
|
46
46
|
# silently skipping wherever numpy happens to be absent.
|
|
@@ -25,7 +25,7 @@ import os
|
|
|
25
25
|
import threading
|
|
26
26
|
import weakref
|
|
27
27
|
from dataclasses import dataclass
|
|
28
|
-
from typing import Literal, Sequence, Union
|
|
28
|
+
from typing import Literal, Optional, Sequence, Union
|
|
29
29
|
|
|
30
30
|
from . import _abi, _generated
|
|
31
31
|
from ._library import _base_version, artifact_dir, load_library, selected_provider
|
|
@@ -46,7 +46,7 @@ from .errors import (
|
|
|
46
46
|
raise_for_status,
|
|
47
47
|
)
|
|
48
48
|
|
|
49
|
-
__version__ = "0.0.
|
|
49
|
+
__version__ = "0.0.4"
|
|
50
50
|
|
|
51
51
|
# String-enum types, exported so callers (and type checkers) can name them.
|
|
52
52
|
Backend = Literal["auto", "cpu", "metal", "vulkan", "cpu_accel", "cuda"]
|
|
@@ -146,6 +146,10 @@ if _artifact is not None:
|
|
|
146
146
|
|
|
147
147
|
_byref = ctypes.byref
|
|
148
148
|
|
|
149
|
+
# transcribe_tokenize returns INT32_MIN to signal "this model has no tokenizer
|
|
150
|
+
# encode path" (distinct from the negative grow-buffer signal).
|
|
151
|
+
_INT32_MIN = -(2 ** 31)
|
|
152
|
+
|
|
149
153
|
# Callback function types — must match the generated argtypes for
|
|
150
154
|
# transcribe_log_set / transcribe_set_abort_callback. ctypes acquires the GIL
|
|
151
155
|
# when C invokes these, and a CFUNCTYPE instance must be kept alive for as long
|
|
@@ -240,6 +244,14 @@ def native_provider() -> str | None:
|
|
|
240
244
|
return selected_provider()
|
|
241
245
|
|
|
242
246
|
|
|
247
|
+
_DEVICE_TYPE_NAMES = {
|
|
248
|
+
_generated.TRANSCRIBE_DEVICE_TYPE_CPU: "cpu",
|
|
249
|
+
_generated.TRANSCRIBE_DEVICE_TYPE_GPU: "gpu",
|
|
250
|
+
_generated.TRANSCRIBE_DEVICE_TYPE_IGPU: "igpu",
|
|
251
|
+
_generated.TRANSCRIBE_DEVICE_TYPE_ACCEL: "accel",
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
|
|
243
255
|
@dataclass(frozen=True)
|
|
244
256
|
class BackendDevice:
|
|
245
257
|
"""One registered compute device (owned copies of the C strings)."""
|
|
@@ -247,23 +259,53 @@ class BackendDevice:
|
|
|
247
259
|
name: str
|
|
248
260
|
description: str
|
|
249
261
|
kind: str # "cpu" | "accel" | "metal" | "vulkan" | "cuda" | "sycl" | "gpu" | "unknown"
|
|
262
|
+
# Vendor-agnostic class: "cpu" | "gpu" | "igpu" | "accel", or "unknown" for a
|
|
263
|
+
# value reported by a runtime newer than this binding (tell such devices
|
|
264
|
+
# apart by device_id / name, not by this axis).
|
|
265
|
+
device_type: str
|
|
266
|
+
device_id: Optional[str] # stable hw id (PCI bus id), or None (e.g. Metal)
|
|
267
|
+
memory_total: int # reported capacity in bytes, or 0 if unreported
|
|
268
|
+
# Available bytes — a SNAPSHOT at query time, or 0 if unreported. Re-query
|
|
269
|
+
# (via backends() or Model.device) to refresh; backend-defined and not
|
|
270
|
+
# comparable across device kinds.
|
|
271
|
+
memory_free: int
|
|
272
|
+
# Registry index of this device — the value to pass as ``Model(...,
|
|
273
|
+
# gpu_device=index)`` to select it (0 selects the auto / first device).
|
|
274
|
+
# None when the device came from Model.device, since the underlying
|
|
275
|
+
# transcribe_model_get_device() does not expose an index; correlate such a
|
|
276
|
+
# device back to backends() by device_id / name instead. The index is
|
|
277
|
+
# order-dependent and not stable across driver updates or hosts.
|
|
278
|
+
index: Optional[int] = None
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
def _backend_device_from_raw(dev, index: Optional[int] = None) -> BackendDevice:
|
|
282
|
+
"""Build a BackendDevice from a library-filled transcribe_backend_device."""
|
|
283
|
+
return BackendDevice(
|
|
284
|
+
name=_decode(dev.name),
|
|
285
|
+
description=_decode(dev.description),
|
|
286
|
+
kind=_decode(dev.kind),
|
|
287
|
+
device_type=_DEVICE_TYPE_NAMES.get(dev.device_type, "unknown"),
|
|
288
|
+
device_id=_decode(dev.device_id) if dev.device_id else None,
|
|
289
|
+
memory_total=int(dev.memory_total),
|
|
290
|
+
memory_free=int(dev.memory_free),
|
|
291
|
+
index=index,
|
|
292
|
+
)
|
|
250
293
|
|
|
251
294
|
|
|
252
295
|
def backends() -> list[BackendDevice]:
|
|
253
296
|
"""The compute devices registered with the native runtime — what the
|
|
254
297
|
process can actually run on, after backend-module loading and graceful
|
|
255
|
-
degradation (e.g. a Vulkan module skipped on a machine without Vulkan).
|
|
298
|
+
degradation (e.g. a Vulkan module skipped on a machine without Vulkan).
|
|
299
|
+
|
|
300
|
+
Each device's ``memory_free`` is live as of the call; call again to poll
|
|
301
|
+
a device's available memory over time."""
|
|
256
302
|
devices = []
|
|
257
303
|
for i in range(_lib.transcribe_backend_device_count()):
|
|
258
304
|
dev = _generated.transcribe_backend_device()
|
|
259
305
|
_lib.transcribe_backend_device_init(_byref(dev))
|
|
260
306
|
_check(_lib.transcribe_get_backend_device(i, _byref(dev)),
|
|
261
307
|
f"reading backend device {i}")
|
|
262
|
-
devices.append(
|
|
263
|
-
name=_decode(dev.name),
|
|
264
|
-
description=_decode(dev.description),
|
|
265
|
-
kind=_decode(dev.kind),
|
|
266
|
-
))
|
|
308
|
+
devices.append(_backend_device_from_raw(dev, index=i))
|
|
267
309
|
return devices
|
|
268
310
|
|
|
269
311
|
|
|
@@ -781,6 +823,18 @@ class Model:
|
|
|
781
823
|
def backend(self) -> str:
|
|
782
824
|
return _decode(_lib.transcribe_model_backend(self._h))
|
|
783
825
|
|
|
826
|
+
@property
|
|
827
|
+
def device(self) -> BackendDevice:
|
|
828
|
+
"""The compute device this model is running on. ``memory_free`` is a
|
|
829
|
+
live snapshot, so read this again to poll how much device memory is
|
|
830
|
+
left after the model loaded. Raises if the model has no resolved
|
|
831
|
+
compute device."""
|
|
832
|
+
dev = _generated.transcribe_backend_device()
|
|
833
|
+
_lib.transcribe_backend_device_init(_byref(dev))
|
|
834
|
+
_check(_lib.transcribe_model_get_device(self._h, _byref(dev)),
|
|
835
|
+
"model_get_device")
|
|
836
|
+
return _backend_device_from_raw(dev)
|
|
837
|
+
|
|
784
838
|
@property
|
|
785
839
|
def capabilities(self) -> Capabilities:
|
|
786
840
|
caps = _Capabilities()
|
|
@@ -815,6 +869,24 @@ class Model:
|
|
|
815
869
|
return bool(_lib.transcribe_model_accepts_ext_kind(
|
|
816
870
|
self._h, _EXT_SLOTS[options._slot], options._kind))
|
|
817
871
|
|
|
872
|
+
def tokenize(self, text: str) -> list[int]:
|
|
873
|
+
"""Tokenize plain UTF-8 ``text`` into the model's vocabulary ids (no
|
|
874
|
+
BOS/EOS, no special tags). Raises :class:`NotImplementedByModel` for
|
|
875
|
+
families whose tokenizer has no encode path (e.g. SentencePiece today).
|
|
876
|
+
"""
|
|
877
|
+
data = text.encode("utf-8")
|
|
878
|
+
cap = max(len(data), 16)
|
|
879
|
+
while True:
|
|
880
|
+
buf = (ctypes.c_int32 * cap)()
|
|
881
|
+
n = _lib.transcribe_tokenize(self._h, data, buf, cap)
|
|
882
|
+
if n == _INT32_MIN:
|
|
883
|
+
raise NotImplementedByModel(
|
|
884
|
+
"model tokenizer has no encode path")
|
|
885
|
+
if n < 0: # buffer too small: library asked for -n slots, retry
|
|
886
|
+
cap = -n
|
|
887
|
+
continue
|
|
888
|
+
return [buf[i] for i in range(n)]
|
|
889
|
+
|
|
818
890
|
def session(self, *, n_threads: int = 0, kv_type: KVType = "auto",
|
|
819
891
|
n_ctx: int = 0) -> "Session":
|
|
820
892
|
return Session(self, n_threads=n_threads, kv_type=kv_type, n_ctx=n_ctx)
|
|
@@ -13,7 +13,7 @@ import ctypes as _c
|
|
|
13
13
|
# Stable digest of the ABI surface below (structs, enums, macros, layout,
|
|
14
14
|
# prototypes). A native provider package echoes this back so the API
|
|
15
15
|
# package can reject an ABI-mismatched provider before dlopen.
|
|
16
|
-
PUBLIC_HEADER_HASH = "
|
|
16
|
+
PUBLIC_HEADER_HASH = "ebe6a6816e34a24e"
|
|
17
17
|
|
|
18
18
|
# === enum constants ===
|
|
19
19
|
TRANSCRIBE_OK = 0
|
|
@@ -79,6 +79,10 @@ TRANSCRIBE_BACKEND_METAL = 2
|
|
|
79
79
|
TRANSCRIBE_BACKEND_VULKAN = 3
|
|
80
80
|
TRANSCRIBE_BACKEND_CPU_ACCEL = 4
|
|
81
81
|
TRANSCRIBE_BACKEND_CUDA = 5
|
|
82
|
+
TRANSCRIBE_DEVICE_TYPE_CPU = 0
|
|
83
|
+
TRANSCRIBE_DEVICE_TYPE_GPU = 1
|
|
84
|
+
TRANSCRIBE_DEVICE_TYPE_IGPU = 2
|
|
85
|
+
TRANSCRIBE_DEVICE_TYPE_ACCEL = 3
|
|
82
86
|
TRANSCRIBE_FEATURE_INITIAL_PROMPT = 0
|
|
83
87
|
TRANSCRIBE_FEATURE_TEMPERATURE_FALLBACK = 1
|
|
84
88
|
TRANSCRIBE_FEATURE_LONG_FORM = 2
|
|
@@ -145,7 +149,7 @@ class transcribe_whisper_chunk_trace(_c.Structure):
|
|
|
145
149
|
pass
|
|
146
150
|
|
|
147
151
|
transcribe_ext._fields_ = [("size", _c.c_uint64), ("kind", _c.c_uint32)]
|
|
148
|
-
transcribe_backend_device._fields_ = [("struct_size", _c.c_uint64), ("name", _c.c_char_p), ("description", _c.c_char_p), ("kind", _c.c_char_p)]
|
|
152
|
+
transcribe_backend_device._fields_ = [("struct_size", _c.c_uint64), ("name", _c.c_char_p), ("description", _c.c_char_p), ("kind", _c.c_char_p), ("device_id", _c.c_char_p), ("memory_total", _c.c_uint64), ("memory_free", _c.c_uint64), ("device_type", _c.c_int)]
|
|
149
153
|
transcribe_model_load_params._fields_ = [("struct_size", _c.c_uint64), ("backend", _c.c_int), ("gpu_device", _c.c_int)]
|
|
150
154
|
transcribe_session_params._fields_ = [("struct_size", _c.c_uint64), ("n_threads", _c.c_int), ("kv_type", _c.c_int), ("n_ctx", _c.c_int32)]
|
|
151
155
|
transcribe_run_params._fields_ = [("struct_size", _c.c_uint64), ("task", _c.c_int), ("timestamps", _c.c_int), ("pnc", _c.c_int), ("itn", _c.c_int), ("language", _c.c_char_p), ("target_language", _c.c_char_p), ("keep_special_tags", _c.c_bool), ("family", _c.POINTER(transcribe_ext)), ("spec_k_drafts", _c.c_int32)]
|
|
@@ -187,7 +191,7 @@ ABI_STRUCT_IDS = {
|
|
|
187
191
|
# C-compiler layout captured at generation (for offset self-check).
|
|
188
192
|
STRUCT_LAYOUT = {
|
|
189
193
|
'transcribe_ext': {'size': 16, 'align': 8, 'offsets': {'size': 0, 'kind': 8}},
|
|
190
|
-
'transcribe_backend_device': {'size':
|
|
194
|
+
'transcribe_backend_device': {'size': 64, 'align': 8, 'offsets': {'struct_size': 0, 'name': 8, 'description': 16, 'kind': 24, 'device_id': 32, 'memory_total': 40, 'memory_free': 48, 'device_type': 56}},
|
|
191
195
|
'transcribe_model_load_params': {'size': 16, 'align': 8, 'offsets': {'struct_size': 0, 'backend': 8, 'gpu_device': 12}},
|
|
192
196
|
'transcribe_session_params': {'size': 24, 'align': 8, 'offsets': {'struct_size': 0, 'n_threads': 8, 'kv_type': 12, 'n_ctx': 16}},
|
|
193
197
|
'transcribe_run_params': {'size': 64, 'align': 8, 'offsets': {'struct_size': 0, 'task': 8, 'timestamps': 12, 'pnc': 16, 'itn': 20, 'language': 24, 'target_language': 32, 'keep_special_tags': 40, 'family': 48, 'spec_k_drafts': 56}},
|
|
@@ -287,6 +291,8 @@ def configure(lib):
|
|
|
287
291
|
lib.transcribe_model_free.argtypes = [_c.c_void_p]
|
|
288
292
|
lib.transcribe_model_get_capabilities.restype = _c.c_int
|
|
289
293
|
lib.transcribe_model_get_capabilities.argtypes = [_c.c_void_p, _c.POINTER(transcribe_capabilities)]
|
|
294
|
+
lib.transcribe_model_get_device.restype = _c.c_int
|
|
295
|
+
lib.transcribe_model_get_device.argtypes = [_c.c_void_p, _c.POINTER(transcribe_backend_device)]
|
|
290
296
|
lib.transcribe_model_load_file.restype = _c.c_int
|
|
291
297
|
lib.transcribe_model_load_file.argtypes = [_c.c_char_p, _c.POINTER(transcribe_model_load_params), _c.POINTER(_c.c_void_p)]
|
|
292
298
|
lib.transcribe_model_load_params_init.restype = None
|
|
@@ -25,6 +25,27 @@ def test_at_least_one_device_registered():
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
|
|
28
|
+
def test_backends_non_empty():
|
|
29
|
+
# A CPU device always exists, so the list is never empty.
|
|
30
|
+
assert t.backends(), "backends() returned an empty list — a CPU device must exist"
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def test_device_index_and_fields():
|
|
34
|
+
# Each device carries its registry index (the value Model(..., gpu_device=)
|
|
35
|
+
# selects with) and well-formed metadata. Pin the device-selection surface.
|
|
36
|
+
devices = t.backends()
|
|
37
|
+
for i, dev in enumerate(devices):
|
|
38
|
+
assert dev.index == i, f"device {i} reported index {dev.index}"
|
|
39
|
+
assert dev.device_type in {"cpu", "gpu", "igpu", "accel", "unknown"}, (
|
|
40
|
+
f"device {i} device_type {dev.device_type!r}"
|
|
41
|
+
)
|
|
42
|
+
assert dev.memory_total >= 0
|
|
43
|
+
assert dev.memory_free >= 0
|
|
44
|
+
assert dev.device_id is None or isinstance(dev.device_id, str)
|
|
45
|
+
assert isinstance(dev.name, str) and dev.name
|
|
46
|
+
assert isinstance(dev.kind, str) and dev.kind
|
|
47
|
+
|
|
48
|
+
|
|
28
49
|
def test_cpu_always_available():
|
|
29
50
|
# Every shipped configuration includes a CPU backend (compiled in or as
|
|
30
51
|
# the baseline module); a process without one is mispackaged.
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"""Model-gated device-selection tests.
|
|
2
|
+
|
|
3
|
+
These take the ``model_path`` / ``transcribe_cpp`` fixtures, which ``skip``
|
|
4
|
+
when the default whisper-tiny.en asset is absent (override with
|
|
5
|
+
``TRANSCRIBE_SMOKE_MODEL``). They pin the device-selection surface added
|
|
6
|
+
alongside the per-device ``index`` field: ``Model.device`` reports where the
|
|
7
|
+
model landed (its ``.index`` is ``None`` because it did not come from
|
|
8
|
+
enumeration), and an out-of-range / negative ``gpu_device`` is rejected with
|
|
9
|
+
``InvalidArgument``.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
import pytest
|
|
15
|
+
|
|
16
|
+
import transcribe_cpp as t
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def test_model_device_matches_enumeration(transcribe_cpp, model_path):
|
|
20
|
+
# The model lands on some registered device. Model.device does not come
|
|
21
|
+
# from enumeration, so its .index is None; correlate it back to backends()
|
|
22
|
+
# by name (and by device_id when that is reported).
|
|
23
|
+
with transcribe_cpp.Model(model_path) as model:
|
|
24
|
+
dev = model.device
|
|
25
|
+
assert isinstance(dev, transcribe_cpp.BackendDevice)
|
|
26
|
+
assert dev.index is None, "Model.device should not carry a registry index"
|
|
27
|
+
|
|
28
|
+
devices = transcribe_cpp.backends()
|
|
29
|
+
by_name = [d for d in devices if d.name == dev.name]
|
|
30
|
+
assert by_name, (
|
|
31
|
+
f"model device {dev.name!r} not found among backends() "
|
|
32
|
+
f"{[d.name for d in devices]}"
|
|
33
|
+
)
|
|
34
|
+
if dev.device_id is not None:
|
|
35
|
+
assert any(d.device_id == dev.device_id for d in by_name), (
|
|
36
|
+
f"model device_id {dev.device_id!r} matched no enumerated device"
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def test_negative_gpu_device_rejected(transcribe_cpp, model_path):
|
|
41
|
+
with pytest.raises(transcribe_cpp.InvalidArgument):
|
|
42
|
+
transcribe_cpp.Model(model_path, gpu_device=-1)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def test_out_of_range_gpu_device_rejected(transcribe_cpp, model_path):
|
|
46
|
+
bad = len(transcribe_cpp.backends()) + 1000
|
|
47
|
+
with pytest.raises(transcribe_cpp.InvalidArgument):
|
|
48
|
+
transcribe_cpp.Model(model_path, gpu_device=bad)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def test_cpu_backend_with_gpu_index_rejected(transcribe_cpp, model_path):
|
|
52
|
+
# Hardware-independent: a CPU backend has no GPU to select, so a non-zero
|
|
53
|
+
# gpu_device is invalid regardless of what hardware is present.
|
|
54
|
+
with pytest.raises(transcribe_cpp.InvalidArgument):
|
|
55
|
+
transcribe_cpp.Model(model_path, backend="cpu", gpu_device=1)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|