fix(cli): приведён в порядок вывод предупреждений и ONNX #29
No files matched your search
@@ -413,10 +413,10 @@ device-aware дефолт недоступен для выбранной мод
|
||||
# Транскрипт: meeting.mp4
|
||||
|
||||
- **Дата транскрипции**: 2026-03-17 14:30:05
|
||||
- **Модель**: large-v3
|
||||
- **Модель**: gigaam-v3-e2e-rnnt
|
||||
- **Язык**: ru (задан явно)
|
||||
- **Длительность**: 01:23:45
|
||||
- **Устройство**: CUDA (NVIDIA GeForce RTX 3060)
|
||||
- **Устройство**: ONNX (CPU)
|
||||
|
||||
---
|
||||
|
||||
|
||||
+3
-3
@@ -63,10 +63,10 @@ transcribe <путь_к_файлу> [опции]
|
||||
# Транскрипт: meeting-2026-03-17.mp4
|
||||
|
||||
- **Дата транскрипции**: 2026-03-17 14:30:05
|
||||
- **Модель**: large-v3
|
||||
- **Язык**: ru (задан явно) / ru (определён автоматически)
|
||||
- **Модель**: gigaam-v3-e2e-rnnt
|
||||
- **Язык**: ru (задан явно)
|
||||
- **Длительность**: 01:23:45
|
||||
- **Устройство**: CUDA (NVIDIA GeForce RTX 3060)
|
||||
- **Устройство**: ONNX (CPU)
|
||||
|
||||
---
|
||||
|
||||
|
||||
+9
-1
@@ -10,7 +10,8 @@ dependencies = [
|
||||
"faster-whisper>=1.2.1,<2",
|
||||
"httpx>=0.28,<1",
|
||||
"socksio>=1.0.0,<2",
|
||||
"sherpa-onnx>=1.13.5,<2",
|
||||
# При обновлении сверить блок tool.uv.dependency-metadata ниже.
|
||||
"sherpa-onnx==1.13.5",
|
||||
"nvidia-cublas-cu12>=12.4,<13; sys_platform == 'linux' and platform_machine == 'x86_64'",
|
||||
"openvino-genai>=2026.3.0.0,<2026.4; sys_platform != 'darwin' and (platform_machine == 'x86_64' or platform_machine == 'AMD64')",
|
||||
"onnx-asr[cpu,hub]>=0.12,<0.13",
|
||||
@@ -34,3 +35,10 @@ testpaths = ["tests"]
|
||||
|
||||
[tool.hatch.build.targets.wheel]
|
||||
packages = ["src/local_transcriber"]
|
||||
|
||||
[[tool.uv.dependency-metadata]]
|
||||
# Метаданные wheel-файлов sherpa расходятся, поэтому зависимость от core задана для uv явно.
|
||||
# Версии sherpa, override и core меняются вместе; проверка: uv tree --locked --package sherpa-onnx
|
||||
name = "sherpa-onnx"
|
||||
version = "1.13.5"
|
||||
requires-dist = ["sherpa-onnx-core==1.13.5"]
|
||||
@@ -2,6 +2,9 @@
|
||||
|
||||
import sys
|
||||
import time
|
||||
import warnings
|
||||
from collections.abc import Callable
|
||||
from functools import wraps
|
||||
from pathlib import Path
|
||||
|
||||
import typer
|
||||
@@ -56,6 +59,29 @@ app = typer.Typer()
|
||||
console = Console(stderr=True)
|
||||
|
||||
|
||||
def _show_cli_warning(
|
||||
message: Warning | str,
|
||||
*_args: object,
|
||||
**_kwargs: object,
|
||||
) -> None:
|
||||
"""Печатает предупреждение в пользовательском формате CLI."""
|
||||
console.print(f"Внимание: {message}", style="yellow", soft_wrap=True, markup=False)
|
||||
|
||||
|
||||
def _with_cli_warning_renderer(
|
||||
command: Callable[..., None],
|
||||
) -> Callable[..., None]:
|
||||
"""Устанавливает CLI-рендер предупреждений на время одного запуска."""
|
||||
|
||||
@wraps(command)
|
||||
def wrapped(*args: object, **kwargs: object) -> None:
|
||||
with warnings.catch_warnings():
|
||||
warnings.showwarning = _show_cli_warning
|
||||
command(*args, **kwargs)
|
||||
|
||||
return wrapped
|
||||
|
||||
|
||||
def _format_device_info(device_used: str) -> str:
|
||||
"""Формирует строку устройства для шапки транскрипта."""
|
||||
if device_used == "cuda":
|
||||
@@ -66,6 +92,8 @@ def _format_device_info(device_used: str) -> str:
|
||||
return f"OpenVINO ({gpu_name or 'Intel GPU'})"
|
||||
if device_used in ("openvino", "openvino-cpu"):
|
||||
return "OpenVINO (CPU)"
|
||||
if device_used == "onnx":
|
||||
return "ONNX (CPU)"
|
||||
return "CPU"
|
||||
|
||||
|
||||
@@ -193,6 +221,7 @@ def _print_diarization_report(
|
||||
|
||||
|
||||
@app.command()
|
||||
@_with_cli_warning_renderer
|
||||
def main(
|
||||
files: list[Path] | None = typer.Argument(None, help="Пути к аудио/видеофайлам"),
|
||||
model: str | None = typer.Option(
|
||||
|
||||
+70
-1
@@ -1,3 +1,4 @@
|
||||
import warnings
|
||||
from pathlib import Path
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
@@ -118,6 +119,49 @@ def test_cli_happy_path_exit_code_zero(tmp_path):
|
||||
assert out.exit_code == 0
|
||||
|
||||
|
||||
@pytest.mark.parametrize("file_count", [1, 2])
|
||||
def test_cli_renders_runtime_warning_without_python_details(tmp_path, file_count):
|
||||
files = [tmp_path / f"test-{index}.mp3" for index in range(file_count)]
|
||||
for file in files:
|
||||
file.write_bytes(b"fake")
|
||||
|
||||
result = _make_result()
|
||||
model = _make_model()
|
||||
backend = _make_backend()
|
||||
tfr = _make_tfr(result=result, model=model, backend=backend)
|
||||
warning_message = (
|
||||
"Тестовое [bold]предупреждение[/bold] с длинным текстом, который "
|
||||
"должен остаться одной логической строкой без служебных подробностей Python"
|
||||
)
|
||||
|
||||
def transcribe_with_warning(**_kwargs):
|
||||
warnings.warn(warning_message, stacklevel=2)
|
||||
return tfr
|
||||
|
||||
original_showwarning = warnings.showwarning
|
||||
with (
|
||||
patch("local_transcriber.cli.load_config", return_value={}),
|
||||
patch("local_transcriber.cli.validate_input_file", side_effect=lambda p: p),
|
||||
patch("local_transcriber.cli.detect_device", return_value="cpu"),
|
||||
patch(
|
||||
"local_transcriber.cli.load_model",
|
||||
return_value=(model, "cpu", backend, "/models/medium"),
|
||||
),
|
||||
patch(
|
||||
"local_transcriber.cli._transcribe_file",
|
||||
side_effect=transcribe_with_warning,
|
||||
),
|
||||
patch("local_transcriber.cli.write_transcript"),
|
||||
):
|
||||
out = runner.invoke(app, [str(file) for file in files])
|
||||
|
||||
warning_lines = [line for line in out.output.splitlines() if "Тестовое" in line]
|
||||
assert warning_lines == [f"Внимание: {warning_message}"]
|
||||
assert "UserWarning" not in out.output
|
||||
assert "warnings.warn" not in out.output
|
||||
assert warnings.showwarning is original_showwarning
|
||||
|
||||
|
||||
def test_cli_default_options_passed_to_transcribe(tmp_path):
|
||||
audio = tmp_path / "test.mp3"
|
||||
audio.write_bytes(b"fake")
|
||||
@@ -149,6 +193,30 @@ def test_cli_default_options_passed_to_transcribe(tmp_path):
|
||||
assert "Устройство: onnx" in out.output
|
||||
|
||||
|
||||
def test_cli_identifies_onnx_backend_in_transcript_header(tmp_path):
|
||||
audio = tmp_path / "test.mp3"
|
||||
audio.write_bytes(b"fake")
|
||||
result = _make_result(device_used="onnx")
|
||||
model = _make_model()
|
||||
backend = _make_backend()
|
||||
tfr = _make_tfr(result=result, model=model, actual_device="onnx", backend=backend)
|
||||
|
||||
with (
|
||||
patch("local_transcriber.cli.load_config", return_value={}),
|
||||
patch("local_transcriber.cli.detect_device", return_value="onnx"),
|
||||
patch(
|
||||
"local_transcriber.cli.load_model",
|
||||
return_value=(model, "onnx", backend, "/models/gigaam-v3-e2e-rnnt"),
|
||||
),
|
||||
patch("local_transcriber.cli._transcribe_file", return_value=tfr),
|
||||
):
|
||||
out = runner.invoke(app, [str(audio)])
|
||||
|
||||
content = (tmp_path / "test-transcript.md").read_text(encoding="utf-8")
|
||||
assert out.exit_code == 0
|
||||
assert "- **Устройство**: ONNX (CPU)" in content
|
||||
|
||||
|
||||
def test_cli_custom_options(tmp_path):
|
||||
audio = tmp_path / "test.mp3"
|
||||
audio.write_bytes(b"fake")
|
||||
@@ -1380,7 +1448,8 @@ def test_format_device_info_openvino_legacy():
|
||||
assert _format_device_info("openvino") == "OpenVINO (CPU)"
|
||||
|
||||
|
||||
def test_format_device_info_cpu():
|
||||
def test_format_device_info_distinguishes_onnx_from_faster_whisper_cpu():
|
||||
assert _format_device_info("onnx") == "ONNX (CPU)"
|
||||
assert _format_device_info("cpu") == "CPU"
|
||||
|
||||
|
||||
|
||||
@@ -2,6 +2,13 @@ version = 1
|
||||
revision = 3
|
||||
requires-python = ">=3.13"
|
||||
|
||||
[manifest]
|
||||
|
||||
[[manifest.dependency-metadata]]
|
||||
name = "sherpa-onnx"
|
||||
version = "1.13.5"
|
||||
requires-dist = ["sherpa-onnx-core==1.13.5"]
|
||||
|
||||
[[package]]
|
||||
name = "annotated-doc"
|
||||
version = "0.0.4"
|
||||
@@ -284,7 +291,7 @@ requires-dist = [
|
||||
{ name = "onnxruntime", specifier = ">=1.28,<2" },
|
||||
{ name = "openvino-genai", marker = "(platform_machine == 'AMD64' and sys_platform != 'darwin') or (platform_machine == 'x86_64' and sys_platform != 'darwin')", specifier = ">=2026.3.0.0,<2026.4" },
|
||||
{ name = "rich", specifier = ">=14.3.3,<15" },
|
||||
{ name = "sherpa-onnx", specifier = ">=1.13.5,<2" },
|
||||
{ name = "sherpa-onnx", specifier = "==1.13.5" },
|
||||
{ name = "socksio", specifier = ">=1.0.0,<2" },
|
||||
{ name = "typer", specifier = ">=0.24.1,<1" },
|
||||
]
|
||||
@@ -601,6 +608,9 @@ wheels = [
|
||||
name = "sherpa-onnx"
|
||||
version = "1.13.5"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "sherpa-onnx-core" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/6d/a1/8a7d8751bc71a0814f3b9332717909512a5ff919d07ed53e4baa861ef8c7/sherpa_onnx-1.13.5.tar.gz", hash = "sha256:14bebfe71365a2c678dd94cd08efa8e79df06318b17fe8e97b2e802a7881fd5a", size = 1037285, upload-time = "2026-08-11T08:17:31.817Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/61/6f/b70ae4c7e367e3d2dca99efc65152d22ad5d942619add19172d24267c14b/sherpa_onnx-1.13.5-cp313-cp313-linux_armv7l.whl", hash = "sha256:15a02d9d74143f336156cb8b4da826bc65c11daa28bd5c9099e9397b3660e7df", size = 11999210, upload-time = "2026-08-11T09:26:07.356Z" },
|
||||
@@ -623,6 +633,22 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/28/5e/9a9c63e1dcd646c5f21df6d16e6770fedd956f8a54241f3382343c6289af/sherpa_onnx-1.13.5-cp314-cp314-win_arm64.whl", hash = "sha256:a7e97d8457a51725ffa3fcb44cb1d57bfdb780bc390a9460a65e05bf3d2851b4", size = 2303336, upload-time = "2026-08-11T07:33:25.917Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sherpa-onnx-core"
|
||||
version = "1.13.5"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/8b/fe/2a972bc05bc1c674275a97d16d387545c6efa811bf2a8dc1b6ac573f9fe1/sherpa_onnx_core-1.13.5-py3-none-macosx_10_15_universal2.whl", hash = "sha256:a5380f4f8ec609e1c68f2052e34a55862098fa0efa0bba0af33adbdc0231fc4c", size = 19850412, upload-time = "2026-08-11T07:15:17.913Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/27/cd/5730372ce10ba08fda03a3e3dad4ec8bc2a62607530a8f32c44e63258c51/sherpa_onnx_core-1.13.5-py3-none-macosx_10_15_x86_64.whl", hash = "sha256:6bb5c460cd432293a290c861fbd519e30ac290ca84b5acd1c4447c22aef03351", size = 10614601, upload-time = "2026-08-11T07:00:58.916Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/91/54/b753e2dbd2b0f09aed2d2082f35c41606af9712457278ff99d13eaae92d3/sherpa_onnx_core-1.13.5-py3-none-macosx_11_0_arm64.whl", hash = "sha256:899e88916efd96ee1eabc512e9ceaf2fdb711b20b2512cf40358b623e90b5ded", size = 9282744, upload-time = "2026-08-11T07:09:47.547Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e6/58/505668cedd7036bcba305c1a1f5424a3340f4701297a628de83d61e8ed58/sherpa_onnx_core-1.13.5-py3-none-manylinux2014_aarch64.whl", hash = "sha256:4cd751063a378a49f0c72eba5ba959fe375397f5baf93a53f3db64097d00e2aa", size = 13051193, upload-time = "2026-08-11T07:00:47.526Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/8f/61/2cf3aee64c280c830ca4fa25584eb87f8acf04787152744a29d576323977/sherpa_onnx_core-1.13.5-py3-none-manylinux2014_x86_64.whl", hash = "sha256:485b20188ddf905ffbd7504ed456a05d0ff84d10c592a16c0adb7d69bb845f82", size = 10371666, upload-time = "2026-08-11T07:19:12.791Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/24/08/c04236fdf7825c4149b8b28b24d5a26f9e3fdca879aa24b8f1c65e96745b/sherpa_onnx_core-1.13.5-py3-none-manylinux_2_35_armv7l.whl", hash = "sha256:12697ff5745e225157b3257fe638e8b6305b1860366b6387e7a586ee6de2b18b", size = 9920766, upload-time = "2026-08-11T08:48:07.866Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/44/c0/6d19a5b4be1541e2bd17ec045d0c48a641055d290007826ddee3a081a905/sherpa_onnx_core-1.13.5-py3-none-win32.whl", hash = "sha256:6b2f19b7559ad278aa17af0b9f3917a90a37fef4501c04afb14e722f4848c9b7", size = 14534505, upload-time = "2026-08-11T08:22:22.047Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/2a/67/61611b5b945d7ac860387283a352860df8ab0431e3cc0868c1d5291e9f86/sherpa_onnx_core-1.13.5-py3-none-win_amd64.whl", hash = "sha256:fb48f5b7b4596bb745e5dcbb04616d841712224cba652717a71a4551d8ee5b63", size = 16522273, upload-time = "2026-08-11T07:09:46.3Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/28/b2/d7ee13aba3fc40316e2363a5ac0780be7b0112050f7e8821bcd00d6af024/sherpa_onnx_core-1.13.5-py3-none-win_arm64.whl", hash = "sha256:7e24d3ddbcb1e6447467b214ff1235dced21fa4107de5c55125fb3c95ff10501", size = 15683505, upload-time = "2026-08-11T07:11:03.608Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "socksio"
|
||||
version = "1.0.0"
|
||||
|
||||
Reference in new issue
Block a user