recycleactor commited on
Commit
73bb0d9
·
verified ·
1 Parent(s): 047b55f

Upload 2 files

Browse files
Files changed (2) hide show
  1. app.py +55 -18
  2. requirements.txt +0 -1
app.py CHANGED
@@ -1,25 +1,33 @@
 
1
  import os
2
  import subprocess
3
  import tempfile
4
 
 
5
  import gradio as gr
6
- from faster_gigaam import FastGigaAM
7
 
8
- # Модель грузим ОДИН раз при старте контейнера, не на каждый запрос
9
- # иначе каждое голосовое ждало бы полную загрузку весов заново.
10
- # device="cpu" принципиально: этот Space создан на тарифе ZeroGPU (сейчас
11
- # у бесплатных аккаунтов HF нет варианта CPU Basic при создании), но раз мы
12
- # нигде не используем декоратор @spaces.GPU приложение работает на
13
- # обычном CPU этого же контейнера и не трогает дневную квоту GPU-секунд.
14
- # GigaAM компактная (220-240М параметров), GPU ей и не нужен.
15
- MODEL = FastGigaAM(model_name="v3_ctc", device="cpu", batch_size=1)
 
 
 
 
 
 
 
 
16
 
17
 
18
  def _to_wav(src_path: str) -> str:
19
- """Конвертирует присланный файл (у Telegram голосовые — .ogg/opus) в
20
- 16kHz mono WAV через ffmpeg. Модель ожидает конкретный формат, и
21
- предсказуемая конвертация надёжнее, чем полагаться на то, что она сама
22
- разберётся с любым форматом на входе."""
23
  dst_path = tempfile.mktemp(suffix=".wav")
24
  subprocess.run(
25
  ["ffmpeg", "-y", "-i", src_path, "-ar", "16000", "-ac", "1", dst_path],
@@ -29,18 +37,47 @@ def _to_wav(src_path: str) -> str:
29
  return dst_path
30
 
31
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
32
  def transcribe(audio_path: str) -> str:
33
  if not audio_path:
34
  return ""
35
  wav_path = _to_wav(audio_path)
 
36
  try:
37
- # faster-gigaam сам режет длинное аудио на куски с перехлёстом —
38
- # ограничения в 25 секунд (как у нативного gigaam.transcribe) тут
39
- # нет, голосовые любой длины идут одним вызовом.
40
- segments, _info = MODEL.transcribe(wav_path)
41
- return " ".join(seg.text for seg in segments).strip()
42
  finally:
43
  os.remove(wav_path)
 
 
 
 
 
 
 
 
 
 
44
 
45
 
46
  # api_name фиксирует имя эндпоинта — так со стороны бота адрес вызова
 
1
+ import glob
2
  import os
3
  import subprocess
4
  import tempfile
5
 
6
+ import gigaam
7
  import gradio as gr
 
8
 
9
+ # Модель грузим ОДИН раз при старте контейнера, не на каждый запрос.
10
+ # v3_e2e_ctc версия с пунктуацией и нормализацией текста (не голый поток
11
+ # слов без знаков препинания) и CTC-декодер (быстрее RNNT, для транскрибации
12
+ # голосовых в чате этого достаточно).
13
+ # Никакого @spaces.GPU нигде не используем — Space создан на тарифе ZeroGPU
14
+ # (сейчас у бесплатных аккаунтов HF нет варианта CPU Basic при создании),
15
+ # но раз GPU нигде не запрашивается, приложение работает на обычном CPU
16
+ # этого же контейнера и не трогает дневную квоту GPU-секунд. GigaAM
17
+ # компактная (220-240М параметров), GPU ей и не нужен.
18
+ MODEL = gigaam.load_model("v3_e2e_ctc")
19
+
20
+ # Нативный model.transcribe() ограничен 25 секундами аудио за вызов.
21
+ # Официальный обход (.transcribe_longform) тянет за собой pyannote.audio
22
+ # и токен Hugging Face — ради простой последовательной нарезки заводить
23
+ # это не стоит, поэтому режем длинные голосовые сами через ffmpeg.
24
+ CHUNK_SECONDS = 20
25
 
26
 
27
  def _to_wav(src_path: str) -> str:
28
+ """Конвертирует присланный файл (у Telegram голосовые — .ogg/opus, но
29
+ подойдёт любой формат, который понимает ffmpeg — mp3, flac и т.д.) в
30
+ 16kHz mono WAV. Модели нужен предсказуемый формат на входе."""
 
31
  dst_path = tempfile.mktemp(suffix=".wav")
32
  subprocess.run(
33
  ["ffmpeg", "-y", "-i", src_path, "-ar", "16000", "-ac", "1", dst_path],
 
37
  return dst_path
38
 
39
 
40
+ def _split_into_chunks(wav_path: str) -> list[str]:
41
+ """Режет WAV на куски по CHUNK_SECONDS через ffmpeg segment muxer.
42
+ Простая последовательная нарезка без перехлёста — изредка может
43
+ срезать слово ровно на границе куска, но для голосовых в чате это
44
+ приемлемый компромисс против того, чтобы тянуть pyannote+HF-токен
45
+ только ради длинных сообщений."""
46
+ out_dir = tempfile.mkdtemp()
47
+ pattern = os.path.join(out_dir, "chunk_%03d.wav")
48
+ subprocess.run(
49
+ [
50
+ "ffmpeg", "-y", "-i", wav_path,
51
+ "-f", "segment", "-segment_time", str(CHUNK_SECONDS),
52
+ "-c", "copy", pattern,
53
+ ],
54
+ check=True,
55
+ capture_output=True,
56
+ )
57
+ return sorted(glob.glob(os.path.join(out_dir, "chunk_*.wav")))
58
+
59
+
60
  def transcribe(audio_path: str) -> str:
61
  if not audio_path:
62
  return ""
63
  wav_path = _to_wav(audio_path)
64
+ chunks: list[str] = []
65
  try:
66
+ chunks = _split_into_chunks(wav_path)
67
+ parts = [MODEL.transcribe(chunk).strip() for chunk in chunks]
68
+ return " ".join(p for p in parts if p).strip()
 
 
69
  finally:
70
  os.remove(wav_path)
71
+ for c in chunks:
72
+ try:
73
+ os.remove(c)
74
+ except OSError:
75
+ pass
76
+ if chunks:
77
+ try:
78
+ os.rmdir(os.path.dirname(chunks[0]))
79
+ except OSError:
80
+ pass
81
 
82
 
83
  # api_name фиксирует имя эндпоинта — так со стороны бота адрес вызова
requirements.txt CHANGED
@@ -1,5 +1,4 @@
1
  --extra-index-url https://download.pytorch.org/whl/cpu
2
  torch
3
  git+https://github.com/salute-developers/GigaAM.git
4
- git+https://github.com/MishaNyaCopilot/faster-gigaam.git
5
  gradio
 
1
  --extra-index-url https://download.pytorch.org/whl/cpu
2
  torch
3
  git+https://github.com/salute-developers/GigaAM.git
 
4
  gradio