PacoFYM commited on
Commit
13fe256
·
verified ·
1 Parent(s): be2f1d0

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +87 -85
app.py CHANGED
@@ -1,98 +1,100 @@
1
  import os
2
  import tempfile
 
 
 
3
  import torch
4
  import whisperx
5
- from pyannote.audio import Pipeline
6
- import gradio as gr
7
 
8
- # Загружаем модели один раз при старте
9
  device = "cuda" if torch.cuda.is_available() else "cpu"
10
- asr_model = whisperx.load_model("small", device) # модель WhisperX
11
- diar_model = Pipeline.from_pretrained(
12
- "pyannote/speaker-diarization-3.1",
13
- use_auth_token=os.getenv("HF_TOKEN", "")
14
- ).to(device)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
15
 
16
  def transcribe_with_diarization(audio_path):
17
- # 1) транскрипция
18
- result = asr_model.transcribe(
19
- audio_path,
20
- language="ru", # фиксируем русский, чтобы не тратить время на детект
21
- compute_type="float32", # CPU-friendly
22
- diarize=False
23
- )
24
- # 2) выравнивание (alignment)
25
- result = whisperx.align(
26
  result["segments"],
27
- asr_model.audio,
28
- asr_model.tokenizer,
 
29
  device
30
  )
31
- # 3) диаризация
32
- diar = diar_model({"uri": "audio", "audio": audio_path})
33
- # вплетаем спикер-теги
34
- segments = whisperx.diarize(result["segments"], diar)
35
-
36
- # 4) готовим текст для raw_output (объединяем, без спикеров)
37
- full_text = "\n".join(f"[{seg['start']:.2f}-{seg['end']:.2f}] {seg['text']}"
38
- for seg in segments)
39
-
40
- # сохраняем в temp-файл для кнопки "Сохранить"
41
- tmp = tempfile.NamedTemporaryFile(delete=False, suffix=".txt", mode="w", encoding="utf-8")
42
- for seg in segments:
43
- tmp.write(f"{seg['speaker']}: {seg['start']:.2f}-{seg['end']:.2f}\t{seg['text']}\n")
44
- tmp.close()
45
-
46
- return full_text, tmp.name
47
-
48
- def create_app():
49
- with gr.Blocks(
50
- title="Транскрипция и диаризация аудио",
51
- css="""
52
- @media(max-width:600px) {
53
- .gradio-container { padding: 0.5rem; }
54
- .gr-button { width: 100% !important; }
55
- }
56
- """
57
- ) as app:
58
- gr.Markdown("# 🎙️ Транскрипция и диаризация аудио")
59
- gr.Markdown(
60
- "Загрузите аудиофайл, нажмите **Транскрибировать**, "
61
- "прослушайте сегменты, отредактируйте текст и присвойте имена спикерам."
62
- )
63
-
64
- audio_input = gr.Audio(
65
- label="Аудиофайл",
66
- type="filepath"
67
- )
68
-
69
- transcribe_btn = gr.Button("▶️ Транскрибировать")
70
-
71
- # ПОЛЕ для «сырого» текста сразу после транскрипции
72
- raw_output = gr.Textbox(
73
- label="Результат транскрипции",
74
- placeholder="Здесь появится текст после транскрибации",
75
- lines=6
76
- )
77
-
78
- save_btn = gr.Button("💾 Сохранить результат")
79
- output_file = gr.File(
80
- label="Скачать .txt",
81
- file_count="single"
82
- )
83
-
84
- transcribe_btn.click(
85
- fn=transcribe_with_diarization,
86
- inputs=audio_input,
87
- outputs=[raw_output, output_file]
88
- )
89
-
90
- return app
91
 
92
- if __name__ == "__main__":
93
- create_app().launch(
94
- server_name="0.0.0.0",
95
- server_port=7860,
96
- share=False,
97
- inbrowser=False
 
98
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  import os
2
  import tempfile
3
+ import datetime
4
+
5
+ import gradio as gr
6
  import torch
7
  import whisperx
8
+ from whisperx.diarize import DiarizationPipeline
 
9
 
10
+ # Определяем устройство: CUDA если доступна, иначе CPU
11
  device = "cuda" if torch.cuda.is_available() else "cpu"
12
+
13
+ # Загружаем модель WhisperX с compute_type="float32" и русским языком
14
+ asr_model = whisperx.load_model(
15
+ "small",
16
+ device=device,
17
+ compute_type="float32" # принудительная настройка, убирает float16
18
+ )
19
+
20
+ # Загружаем модель выравнивания для русского
21
+ align_model, metadata = whisperx.load_align_model(
22
+ language_code="ru",
23
+ device=device
24
+ )
25
+
26
+ # Инициализируем пайплайн диаризации (Pyannote) с токеном HF
27
+ hf_token = os.getenv("HUGGINGFACEHUB_API_TOKEN", None)
28
+ diarization_pipeline = DiarizationPipeline(
29
+ use_auth_token=hf_token,
30
+ device=device
31
+ )
32
 
33
  def transcribe_with_diarization(audio_path):
34
+ # 1) ASR без детекции языка (принудительно ru)
35
+ result = asr_model.transcribe(audio_path, language="ru")
36
+
37
+ # 2) Выравнивание субтитров по аудио
38
+ aligned = whisperx.align(
 
 
 
 
39
  result["segments"],
40
+ align_model,
41
+ metadata,
42
+ audio_path,
43
  device
44
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
45
 
46
+ # 3) Диаризация
47
+ diarization = diarization_pipeline(audio_path)
48
+
49
+ # 4) Объединяем текстовые сегменты и спикеров
50
+ merged = whisperx.merge_text_with_diarization(
51
+ aligned["segments"],
52
+ diarization["segments"]
53
  )
54
+
55
+ # 5) Формируем текст для вывода
56
+ lines = []
57
+ for seg in merged:
58
+ spk = seg.get("speaker", "Speaker")
59
+ txt = seg.get("text", "").strip()
60
+ lines.append(f"[{spk}] {txt}")
61
+ return "\n".join(lines)
62
+
63
+ def export_to_txt(text):
64
+ # Сохраняем результат во временный файл и возвращаем путь
65
+ timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
66
+ filename = f"transcript_{timestamp}.txt"
67
+ path = os.path.join(tempfile.gettempdir(), filename)
68
+ with open(path, "w", encoding="utf-8") as f:
69
+ f.write(text)
70
+ return path
71
+
72
+ # Собираем интерфейс Gradio
73
+ app = gr.Blocks(title="🎙️ DiarAI: Транскрибация и диаризация (RU)")
74
+
75
+ with app:
76
+ gr.Markdown("""
77
+ ## Транскрибация и диаризация (русский язык)
78
+ - Фиксированный язык распознавания: **ru** для повышения скорости.
79
+ - Диаризация спикеров через Pyannote.
80
+ """)
81
+
82
+ audio_input = gr.Audio(type="filepath", label="Загрузите аудио (только RU)")
83
+ transcribe_btn = gr.Button("▶️ Транскрибировать")
84
+ output_txt = gr.Textbox(label="Результат транскрипции", lines=20)
85
+ save_btn = gr.Button("💾 Экспорт в .txt")
86
+ download_file = gr.File(label="Скачать результат")
87
+
88
+ transcribe_btn.click(
89
+ fn=transcribe_with_diarization,
90
+ inputs=audio_input,
91
+ outputs=output_txt
92
+ )
93
+ save_btn.click(
94
+ fn=export_to_txt,
95
+ inputs=output_txt,
96
+ outputs=download_file
97
+ )
98
+
99
+ if __name__ == "__main__":
100
+ app.launch()