Add multi-format output support (docx + md simultaneously)

This commit is contained in:
Кирилл Блинов 2026-05-29 11:39:13 +03:00
parent 25f45ae7de
commit c771f83351
3 changed files with 64 additions and 17 deletions

View File

@ -155,24 +155,27 @@ python run.py -i meeting.wav -o meeting.docx
| Аргумент | Описание |
|----------|----------|
| `-i, --input` | Путь к аудиофайлу (обязательный) |
| `-o, --output` | Путь к выходному файлу (docx/md/txt) |
| `-o, --output` | Путь к выходному файлу (если один формат) |
| `-p, --profile` | Профиль: `mac_m4`, `gpu_8gb`, `cpu_best` |
| `-c, --config` | Путь к `config.yaml` |
| `-d, --device` | Принудительно: `cpu`, `cuda`, `mps` |
| `-m, --model` | Модель: `tiny`, `base`, `small`, `medium`, `large-v3` |
| `-l, --language` | Язык: `ru`, `en`, ... |
| `-f, --format` | Формат: `docx`, `md`, `txt` |
| `-f, --format` | Форматы через запятую: `docx,md,txt` |
### Примеры
**Аудио файлы:**
```bash
# Базовый запуск
# Базовый запуск (по умолчанию: docx + md)
python run.py -i meeting.wav
# Быстрый тест на маленькой модели
python run.py -i meeting.wav -m base
# Только один формат
python run.py -i meeting.wav -f docx
# Markdown выход
python run.py -i meeting.wav -f md -o meeting.md
```
@ -189,6 +192,22 @@ python run.py -i zoom_meeting.mp4 -o protocol.docx
python run.py -i teams_recording.mkv
```
**Вывод в несколько форматов одновременно:**
```bash
# docx + md (по умолчанию из конфига)
python run.py -i meeting.wav
# docx + md + txt — все сразу
python run.py -i meeting.wav -f docx,md,txt
# Только docx и md
python run.py -i meeting.wav -f docx,md
# Явно указать выход только для одного формата, остальные рядом
python run.py -i meeting.wav -f docx,md -o output/meeting.docx
# Создаст: output/meeting.docx и output/meeting.md
```
**Продвинутые опции:**
```bash
# Сменить профиль
@ -234,9 +253,9 @@ profiles:
compute_type: int8
model: large-v3
language: ru
output:
format: docx
formats: [docx, md] # Можно указать один или несколько
include_timestamps: true
paragraph_pause_sec: 2.0
```

View File

@ -37,7 +37,7 @@ hf_token: null # HuggingFace токен для pyannote. Установите
# Настройки выходного документа
output:
format: docx # docx | md | txt
formats: [docx, md] # Список форматов: docx, md, txt. Можно указать один или несколько.
include_timestamps: true
speaker_label_style: name # name | id | none
paragraph_pause_sec: 2.0 # новый абзац, если пауза > N секунд

50
run.py
View File

@ -37,19 +37,26 @@ def print_first_run_info():
print("")
def parse_formats(fmt_arg: str | None, config_formats: list) -> list[str]:
"""Парсит строку форматов в список."""
if fmt_arg:
return [f.strip().lower() for f in fmt_arg.split(",")]
return config_formats
def main():
parser = argparse.ArgumentParser(
description="Транскрибация совещаний с диаризацией и таймкодами. "
"Поддерживает аудио (wav, mp3, m4a, ogg, flac) и видео (mp4, avi, mkv, mov, etc.)."
)
parser.add_argument("--input", "-i", required=True, help="Путь к аудио или видео файлу")
parser.add_argument("--output", "-o", default=None, help="Путь к выходному файлу (docx/md/txt)")
parser.add_argument("--output", "-o", default=None, help="Путь к выходному файлу (если указан, переопределяет формат)")
parser.add_argument("--profile", "-p", default=None, help="Профиль конфигурации (mac_m4, gpu_8gb, cpu_best)")
parser.add_argument("--config", "-c", default=None, help="Путь к config.yaml")
parser.add_argument("--device", "-d", default=None, help="Принудительно: cpu/cuda/mps")
parser.add_argument("--model", "-m", default=None, help="Принудительно: tiny/base/small/medium/large-v3")
parser.add_argument("--language", "-l", default=None, help="Язык (ru, en, ...)")
parser.add_argument("--format", "-f", default=None, help="Формат выхода: docx, md, txt")
parser.add_argument("--format", "-f", default=None, help="Форматы через запятую: docx,md,txt (по умолчанию из конфига)")
args = parser.parse_args()
@ -90,14 +97,28 @@ def main():
profile["language"] = args.language
output_cfg = config.get("output", {})
fmt = args.format or output_cfg.get("format", "docx")
config_formats = output_cfg.get("formats", ["docx"])
formats = parse_formats(args.format, config_formats)
# Определение путей выходных файлов
output_paths: list[str] = []
if args.output:
output_path = args.output
# Если указан --output, используем его для первого формата
# Остальные форматы — рядом с тем же именем
base = Path(args.output)
output_dir = base.parent
stem = base.stem
first_ext = base.suffix.lstrip(".")
# Первый файл с явным путём
output_paths.append(str(base))
# Остальные форматы рядом
for fmt in formats[1:]:
output_paths.append(str(output_dir / f"{stem}.{fmt}"))
else:
stem = input_path.stem
output_dir = Path(config.get("paths", {}).get("output_dir", "./output"))
output_path = str(output_dir / f"{stem}.{fmt}")
for fmt in formats:
output_paths.append(str(output_dir / f"{stem}.{fmt}"))
# Проверка HF токена
hf_token = os.environ.get("HF_TOKEN") or config.get("hf_token")
@ -118,22 +139,29 @@ def main():
print(f"Модель: {profile['model']}")
print(f"Язык: {profile['language']}")
print(f"Вход: {args.input}")
print(f"Выход: {output_path}")
print(f"Форматы: {', '.join(formats)}")
print(f"Выход: {', '.join(output_paths)}")
print("-" * 40)
# Запуск пайплайна
# Запуск пайплайна (один раз для всех форматов)
result = run_pipeline(
input_path=args.input,
profile_name=args.profile,
config_path=args.config,
output_path=output_path,
output_path=output_paths[0] if output_paths else None,
)
# Генерация документа
build_document(result["segments"], output_path, config)
# Генерация документов для всех форматов
print("-" * 40)
print("Генерация документов...")
for out_path in output_paths:
build_document(result["segments"], out_path, config)
print(f"{out_path}")
print("-" * 40)
print(f"Готово! Сохранено: {output_path}")
print(f"Готово! Сохранено {len(output_paths)} файл(а):")
for p in output_paths:
print(f"{p}")
if __name__ == "__main__":