Add multi-format output support (docx + md simultaneously)
This commit is contained in:
parent
25f45ae7de
commit
c771f83351
29
README.md
29
README.md
@ -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
|
||||
```
|
||||
|
||||
@ -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
50
run.py
@ -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__":
|
||||
|
||||
Loading…
Reference in New Issue
Block a user