fix(cli): приведён в порядок вывод предупреждений и ONNX #29

Merged
ddmitry merged 3 commits from feature/7-cli-output into master 2026-08-29 08:51:21 +03:00
6 changed files with 140 additions and 8 deletions

No files matched your search

+2 -2
View File
@@ -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
View File
@@ -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
View File
@@ -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"]
+29
View File
@@ -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
View File
@@ -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"
Generated
+27 -1
View File
@@ -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"