Merge pull request 'fix(cli): приведён в порядок вывод предупреждений и ONNX' (#29) from feature/7-cli-output into master
Reviewed-on: #29
This commit was merged in pull request #29.
This commit is contained in:
commit
95f295c37c
4 files changed
+104
-6
No files matched your search
@@ -413,10 +413,10 @@ device-aware дефолт недоступен для выбранной мод
|
|||||||
# Транскрипт: meeting.mp4
|
# Транскрипт: meeting.mp4
|
||||||
|
|
||||||
- **Дата транскрипции**: 2026-03-17 14:30:05
|
- **Дата транскрипции**: 2026-03-17 14:30:05
|
||||||
- **Модель**: large-v3
|
- **Модель**: gigaam-v3-e2e-rnnt
|
||||||
- **Язык**: ru (задан явно)
|
- **Язык**: ru (задан явно)
|
||||||
- **Длительность**: 01:23:45
|
- **Длительность**: 01:23:45
|
||||||
- **Устройство**: CUDA (NVIDIA GeForce RTX 3060)
|
- **Устройство**: ONNX (CPU)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
+3
-3
@@ -63,10 +63,10 @@ transcribe <путь_к_файлу> [опции]
|
|||||||
# Транскрипт: meeting-2026-03-17.mp4
|
# Транскрипт: meeting-2026-03-17.mp4
|
||||||
|
|
||||||
- **Дата транскрипции**: 2026-03-17 14:30:05
|
- **Дата транскрипции**: 2026-03-17 14:30:05
|
||||||
- **Модель**: large-v3
|
- **Модель**: gigaam-v3-e2e-rnnt
|
||||||
- **Язык**: ru (задан явно) / ru (определён автоматически)
|
- **Язык**: ru (задан явно)
|
||||||
- **Длительность**: 01:23:45
|
- **Длительность**: 01:23:45
|
||||||
- **Устройство**: CUDA (NVIDIA GeForce RTX 3060)
|
- **Устройство**: ONNX (CPU)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,9 @@
|
|||||||
|
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
|
import warnings
|
||||||
|
from collections.abc import Callable
|
||||||
|
from functools import wraps
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
import typer
|
import typer
|
||||||
@@ -56,6 +59,29 @@ app = typer.Typer()
|
|||||||
console = Console(stderr=True)
|
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:
|
def _format_device_info(device_used: str) -> str:
|
||||||
"""Формирует строку устройства для шапки транскрипта."""
|
"""Формирует строку устройства для шапки транскрипта."""
|
||||||
if device_used == "cuda":
|
if device_used == "cuda":
|
||||||
@@ -66,6 +92,8 @@ def _format_device_info(device_used: str) -> str:
|
|||||||
return f"OpenVINO ({gpu_name or 'Intel GPU'})"
|
return f"OpenVINO ({gpu_name or 'Intel GPU'})"
|
||||||
if device_used in ("openvino", "openvino-cpu"):
|
if device_used in ("openvino", "openvino-cpu"):
|
||||||
return "OpenVINO (CPU)"
|
return "OpenVINO (CPU)"
|
||||||
|
if device_used == "onnx":
|
||||||
|
return "ONNX (CPU)"
|
||||||
return "CPU"
|
return "CPU"
|
||||||
|
|
||||||
|
|
||||||
@@ -193,6 +221,7 @@ def _print_diarization_report(
|
|||||||
|
|
||||||
|
|
||||||
@app.command()
|
@app.command()
|
||||||
|
@_with_cli_warning_renderer
|
||||||
def main(
|
def main(
|
||||||
files: list[Path] | None = typer.Argument(None, help="Пути к аудио/видеофайлам"),
|
files: list[Path] | None = typer.Argument(None, help="Пути к аудио/видеофайлам"),
|
||||||
model: str | None = typer.Option(
|
model: str | None = typer.Option(
|
||||||
|
|||||||
+70
-1
@@ -1,3 +1,4 @@
|
|||||||
|
import warnings
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from unittest.mock import MagicMock, patch
|
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
|
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):
|
def test_cli_default_options_passed_to_transcribe(tmp_path):
|
||||||
audio = tmp_path / "test.mp3"
|
audio = tmp_path / "test.mp3"
|
||||||
audio.write_bytes(b"fake")
|
audio.write_bytes(b"fake")
|
||||||
@@ -149,6 +193,30 @@ def test_cli_default_options_passed_to_transcribe(tmp_path):
|
|||||||
assert "Устройство: onnx" in out.output
|
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):
|
def test_cli_custom_options(tmp_path):
|
||||||
audio = tmp_path / "test.mp3"
|
audio = tmp_path / "test.mp3"
|
||||||
audio.write_bytes(b"fake")
|
audio.write_bytes(b"fake")
|
||||||
@@ -1380,7 +1448,8 @@ def test_format_device_info_openvino_legacy():
|
|||||||
assert _format_device_info("openvino") == "OpenVINO (CPU)"
|
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"
|
assert _format_device_info("cpu") == "CPU"
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user