feat(config): добавлена настройка диаризации в TOML #52
No files matched your search
@@ -11,7 +11,13 @@ import typer
|
|||||||
from rich.console import Console
|
from rich.console import Console
|
||||||
from rich.status import Status
|
from rich.status import Status
|
||||||
|
|
||||||
from .config import ConfigValue, apply_device_defaults, load_config, resolve_defaults
|
from .config import (
|
||||||
|
CliValues,
|
||||||
|
ResolvedConfig,
|
||||||
|
apply_device_defaults,
|
||||||
|
load_config,
|
||||||
|
resolve_defaults,
|
||||||
|
)
|
||||||
from .context_menu import install_menu as install_context_menu
|
from .context_menu import install_menu as install_context_menu
|
||||||
from .context_menu import uninstall_menu as uninstall_context_menu
|
from .context_menu import uninstall_menu as uninstall_context_menu
|
||||||
from .diarization import build_speaker_transcript
|
from .diarization import build_speaker_transcript
|
||||||
@@ -337,7 +343,7 @@ def main(
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
config = load_config()
|
config = load_config()
|
||||||
cli_values = {
|
cli_values: CliValues = {
|
||||||
"model": model,
|
"model": model,
|
||||||
"language": language,
|
"language": language,
|
||||||
"device": device,
|
"device": device,
|
||||||
@@ -417,7 +423,7 @@ def main(
|
|||||||
|
|
||||||
def _run_single(
|
def _run_single(
|
||||||
file: Path,
|
file: Path,
|
||||||
defaults: dict[str, ConfigValue],
|
defaults: ResolvedConfig,
|
||||||
output: Path | None,
|
output: Path | None,
|
||||||
verbose: bool,
|
verbose: bool,
|
||||||
compute_type_explicit: bool = False,
|
compute_type_explicit: bool = False,
|
||||||
@@ -561,7 +567,7 @@ def _run_single(
|
|||||||
|
|
||||||
def _run_batch(
|
def _run_batch(
|
||||||
files: list[Path],
|
files: list[Path],
|
||||||
defaults: dict[str, ConfigValue],
|
defaults: ResolvedConfig,
|
||||||
verbose: bool,
|
verbose: bool,
|
||||||
force: bool,
|
force: bool,
|
||||||
compute_type_explicit: bool = False,
|
compute_type_explicit: bool = False,
|
||||||
|
|||||||
@@ -3,10 +3,43 @@
|
|||||||
import tomllib
|
import tomllib
|
||||||
import warnings
|
import warnings
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from typing import TypedDict, TypeVar, cast
|
||||||
|
|
||||||
type ConfigValue = str | bool
|
type ConfigValue = str | bool
|
||||||
|
_T = TypeVar("_T")
|
||||||
|
|
||||||
HARDCODED_DEFAULTS: dict[str, ConfigValue] = {
|
|
||||||
|
class ConfigValues(TypedDict, total=False):
|
||||||
|
"""Проверенные значения из TOML-конфига."""
|
||||||
|
|
||||||
|
model: str
|
||||||
|
language: str
|
||||||
|
device: str
|
||||||
|
compute_type: str
|
||||||
|
diarize: bool
|
||||||
|
|
||||||
|
|
||||||
|
class CliValues(TypedDict, total=False):
|
||||||
|
"""Явные значения CLI до разрешения каскада."""
|
||||||
|
|
||||||
|
model: str | None
|
||||||
|
language: str | None
|
||||||
|
device: str | None
|
||||||
|
compute_type: str | None
|
||||||
|
diarize: bool | None
|
||||||
|
|
||||||
|
|
||||||
|
class ResolvedConfig(TypedDict):
|
||||||
|
"""Полная конфигурация после разрешения каскада."""
|
||||||
|
|
||||||
|
model: str
|
||||||
|
language: str
|
||||||
|
device: str
|
||||||
|
compute_type: str
|
||||||
|
diarize: bool
|
||||||
|
|
||||||
|
|
||||||
|
HARDCODED_DEFAULTS: ResolvedConfig = {
|
||||||
"model": "medium",
|
"model": "medium",
|
||||||
"language": "ru",
|
"language": "ru",
|
||||||
"device": "auto",
|
"device": "auto",
|
||||||
@@ -49,7 +82,7 @@ def find_config_file() -> Path | None:
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def load_config(path: Path | None = None) -> dict[str, ConfigValue]:
|
def load_config(path: Path | None = None) -> ConfigValues:
|
||||||
"""Загружает и валидирует TOML-конфиг.
|
"""Загружает и валидирует TOML-конфиг.
|
||||||
|
|
||||||
Неизвестные ключи вызывают предупреждение (а не ошибку) для forward
|
Неизвестные ключи вызывают предупреждение (а не ошибку) для forward
|
||||||
@@ -99,31 +132,53 @@ def load_config(path: Path | None = None) -> dict[str, ConfigValue]:
|
|||||||
raise ValueError(f"Значение 'language' в {path} не может быть пустым")
|
raise ValueError(f"Значение 'language' в {path} не может быть пустым")
|
||||||
result[key] = value
|
result[key] = value
|
||||||
|
|
||||||
return result
|
return cast(ConfigValues, result)
|
||||||
|
|
||||||
|
|
||||||
def resolve_defaults(
|
def resolve_defaults(cli_values: CliValues, config: ConfigValues) -> ResolvedConfig:
|
||||||
cli_values: dict[str, ConfigValue | None], config: dict[str, ConfigValue]
|
|
||||||
) -> dict[str, ConfigValue]:
|
|
||||||
"""Каскад приоритетов: CLI > конфиг-файл > hardcoded-дефолты."""
|
"""Каскад приоритетов: CLI > конфиг-файл > hardcoded-дефолты."""
|
||||||
result: dict[str, ConfigValue] = {}
|
return {
|
||||||
for key in HARDCODED_DEFAULTS:
|
"model": _resolve_value(
|
||||||
cli_val = cli_values.get(key)
|
cli_values.get("model"), config.get("model"), HARDCODED_DEFAULTS["model"]
|
||||||
if cli_val is not None:
|
),
|
||||||
result[key] = cli_val
|
"language": _resolve_value(
|
||||||
elif key in config:
|
cli_values.get("language"),
|
||||||
result[key] = config[key]
|
config.get("language"),
|
||||||
else:
|
HARDCODED_DEFAULTS["language"],
|
||||||
result[key] = HARDCODED_DEFAULTS[key]
|
),
|
||||||
return result
|
"device": _resolve_value(
|
||||||
|
cli_values.get("device"),
|
||||||
|
config.get("device"),
|
||||||
|
HARDCODED_DEFAULTS["device"],
|
||||||
|
),
|
||||||
|
"compute_type": _resolve_value(
|
||||||
|
cli_values.get("compute_type"),
|
||||||
|
config.get("compute_type"),
|
||||||
|
HARDCODED_DEFAULTS["compute_type"],
|
||||||
|
),
|
||||||
|
"diarize": _resolve_value(
|
||||||
|
cli_values.get("diarize"),
|
||||||
|
config.get("diarize"),
|
||||||
|
HARDCODED_DEFAULTS["diarize"],
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def _resolve_value(cli_value: _T | None, config_value: _T | None, default: _T) -> _T:
|
||||||
|
"""Выбирает первое явно заданное значение каскада."""
|
||||||
|
if cli_value is not None:
|
||||||
|
return cli_value
|
||||||
|
if config_value is not None:
|
||||||
|
return config_value
|
||||||
|
return default
|
||||||
|
|
||||||
|
|
||||||
def apply_device_defaults(
|
def apply_device_defaults(
|
||||||
defaults: dict[str, ConfigValue],
|
defaults: ResolvedConfig,
|
||||||
resolved_device: str,
|
resolved_device: str,
|
||||||
cli_values: dict[str, ConfigValue | None],
|
cli_values: CliValues,
|
||||||
config: dict[str, ConfigValue],
|
config: ConfigValues,
|
||||||
) -> dict[str, ConfigValue]:
|
) -> ResolvedConfig:
|
||||||
"""Применяет device-aware дефолты для model и compute_type,
|
"""Применяет device-aware дефолты для model и compute_type,
|
||||||
если они не были явно заданы через CLI или конфиг."""
|
если они не были явно заданы через CLI или конфиг."""
|
||||||
device_defs = DEVICE_DEFAULTS.get(resolved_device, {})
|
device_defs = DEVICE_DEFAULTS.get(resolved_device, {})
|
||||||
@@ -135,4 +190,4 @@ def apply_device_defaults(
|
|||||||
if cli_values.get(key) is None and key not in config:
|
if cli_values.get(key) is None and key not in config:
|
||||||
if key in device_defs:
|
if key in device_defs:
|
||||||
result[key] = device_defs[key]
|
result[key] = device_defs[key]
|
||||||
return result
|
return cast(ResolvedConfig, result)
|
||||||
@@ -1,4 +1,3 @@
|
|||||||
from pathlib import Path
|
|
||||||
from unittest.mock import patch
|
from unittest.mock import patch
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|||||||
Reference in new issue
Block a user