Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion .github/workflows/gigaam.yml
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,10 @@ jobs:
run: |
pytest -v tests/test_onnx.py --tb=short
- name: Run timestamps tests
run: |
pytest -v tests/test_timestamps.py --tb=short
- name: Run all tests with coverage
if: matrix.python-version == '3.10'
env:
Expand Down Expand Up @@ -126,7 +130,7 @@ jobs:
- name: Install linters
run: |
pip install --upgrade pip
pip install flake8 black isort mypy types-requests
pip install .[lint]
- name: Check code formatting with black
run: |
Expand Down
14 changes: 9 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ git clone https://github.com/salute-developers/GigaAM.git
cd GigaAM

# Install the package requirements
pip install -e .
pip install -e .[torch]

# (optionally) Verify the installation:
pip install -e ".[tests]"
Expand Down Expand Up @@ -108,13 +108,17 @@ model = gigaam.load_model(model_name)
transcription = model.transcribe(audio_path)
print(transcription)

# ASR with word-level timestamps
result = model.transcribe(audio_path, word_timestamps=True)
for word in result.words:
print(f" [{word.start:.2f} - {word.end:.2f}] {word.text}")

# and long-form ASR
import os
os.environ["HF_TOKEN"] = <HF_TOKEN with read access to "pyannote/segmentation-3.0">
utterances = model.transcribe_longform(long_audio_path)
for utt in utterances:
transcription, (start, end) = utt["transcription"], utt["boundaries"]
print(f"[{gigaam.format_time(start)} - {gigaam.format_time(end)}]: {transcription}")
result = model.transcribe_longform(long_audio_path)
for segment in result:
print(f"[{gigaam.format_time(segment.start)} - {gigaam.format_time(segment.end)}]: {segment.text}")

# Emotion recognition
model = gigaam.load_model("emo")
Expand Down
14 changes: 9 additions & 5 deletions README_ru.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ git clone https://github.com/salute-developers/GigaAM.git
cd GigaAM

# Установить зависимости
pip install -e .
pip install -e .[torch]

# (опционально) Проверить установку:
pip install -e ".[tests]"
Expand Down Expand Up @@ -107,13 +107,17 @@ model = gigaam.load_model(model_name)
transcription = model.transcribe(audio_path)
print(transcription)

# Распознавание речи с таймстемпами на уровне слов
result = model.transcribe(audio_path, word_timestamps=True)
for word in result.words:
print(f" [{word.start:.2f} - {word.end:.2f}] {word.text}")

# Распознавание на длинном аудио
import os
os.environ["HF_TOKEN"] = "<HF_TOKEN с доступом на чтение к 'pyannote/segmentation-3.0'>"
utterances = model.transcribe_longform(long_audio_path)
for utt in utterances:
transcription, (start, end) = utt["transcription"], utt["boundaries"]
print(f"[{gigaam.format_time(start)} - {gigaam.format_time(end)}]: {transcription}")
result = model.transcribe_longform(long_audio_path)
for segment in result:
print(f"[{gigaam.format_time(segment.start)} - {gigaam.format_time(segment.end)}]: {segment.text}")

# Распознавание эмоций
model = gigaam.load_model("emo")
Expand Down
104 changes: 23 additions & 81 deletions colab_example.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -150,26 +150,7 @@
"id": "D8vK2SEWVq0o",
"outputId": "7f87497e-de4e-44a1-8394-6f735c292a34"
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Embeds: tensor([[[-0.2824, 0.3641, 0.4503, ..., -0.4728, -0.4027, -0.2415],\n",
" [ 0.1607, -0.4995, -0.0565, ..., -0.6242, -0.2318, -0.2053],\n",
" [-1.1857, -1.0032, -0.6091, ..., -0.5142, -0.3736, -0.2652],\n",
" ...,\n",
" [ 0.0187, -0.3757, -0.8965, ..., 0.1718, 0.0567, 0.1307],\n",
" [ 0.2691, -0.0672, -0.5010, ..., -1.4433, -1.4832, -1.4515],\n",
" [-1.5648, -1.6692, -1.2828, ..., 0.5110, 0.4826, 0.0133]]],\n",
" device='cuda:0', grad_fn=<TransposeBackward0>)\n",
"\n",
"Transcription: Ничьих не требуя похвал, Счастлив уж я надеждой сладкой, Что дева с трепетом любви Посмотрит, может быть, украдкой На песни грешные мои. У лукоморья дуб зелёный.\n",
"\n",
"Emotions: angry: 0.000, sad: 0.002, neutral: 0.923, positive: 0.075\n"
]
}
],
"outputs": [],
"source": [
"# Load test audio\n",
"audio_path = gigaam.utils.download_short_audio()\n",
Expand All @@ -186,6 +167,12 @@
"transcription = model.transcribe(audio_path)\n",
"print(\"\\nTranscription:\", transcription)\n",
"\n",
"# ASR with word-level timestamps\n",
"result = model.transcribe(audio_path, word_timestamps=True)\n",
"print(\"\\nWord timestamps:\")\n",
"for word in result.words:\n",
" print(f\" [{word.start:.2f} - {word.end:.2f}] {word.text}\")\n",
"\n",
"# Emotion recognition\n",
"model = gigaam.load_model(\"emo\")\n",
"emotion2prob = model.get_probs(audio_path)\n",
Expand Down Expand Up @@ -299,7 +286,7 @@
},
"outputs": [],
"source": [
"! pip install -e .[longform]"
"! pip install pyannote.audio==4.0"
]
},
{
Expand Down Expand Up @@ -374,19 +361,7 @@
"id": "ZFlpV4VXapk7",
"outputId": "17a36be8-d1db-4ce8-cf33-5812b93c5f14"
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[00:00:00 - 00:16:80]: Вечерня отошла давно, Но в кельях тихо и темно; Уже и сам игумен строгий Свои молитвы прекратил И кости ветхие склонил, Перекрестясь на одр убогий. Кругом и сон, и тишина; Но церкви дверь отворена.\n",
"[00:17:07 - 00:32:54]: Трепещет луч лампады, И тускло озаряет он И тёмную живопись икон, и возглащённые оклады. И раздаётся в тишине То тяжкий вздох, то шёпот важный, И мрачно дремлет в тишине старинный свод.\n",
"[00:32:95 - 00:49:30]: Глухой и влажный Стоят за клиросом чернец и грешник, Неподвижны оба. И шёпот их — Как глаз из гроба, И грешник бледен, как мертвец — Монах. Несчастный! Полно, перестань!\n",
"[00:49:81 - 01:05:65]: Ужасна исповедь злодея, Заплачена тобою дань Тому, Кто в злобе пламенея Лукавого грешника блюдёт И к вечной гибели ведёт. Смирись, опомнись. Время, время. Раскаянье, покров\n",
"[01:05:94 - 01:10:88]: Я разрешу тебя, грехов сложи мучительное бремя.\n"
]
}
],
"outputs": [],
"source": [
"import os\n",
"import warnings\n",
Expand All @@ -399,10 +374,9 @@
"long_audio_path = gigaam.utils.download_long_audio()\n",
"model = gigaam.load_model(\"v3_e2e_rnnt\")\n",
"\n",
"utterances = model.transcribe_longform(long_audio_path)\n",
"for utt in utterances:\n",
" transcription, (start, end) = utt[\"transcription\"], utt[\"boundaries\"]\n",
" print(f\"[{gigaam.format_time(start)} - {gigaam.format_time(end)}]: {transcription}\")"
"result = model.transcribe_longform(long_audio_path)\n",
"for segment in result:\n",
" print(f\"[{gigaam.format_time(segment.start)} - {gigaam.format_time(segment.end)}]: {segment.text}\")"
]
},
{
Expand Down Expand Up @@ -433,15 +407,7 @@
"id": "fmwFIE9qaf7y",
"outputId": "9d85b25e-0346-4306-cf3c-131a6a63af1f"
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"['Ничьих не требуя похвал, Счастлив уж я надеждой сладкой, Что дева с трепетом любви Посмотрит, может быть, украдкой На песни грешные мои. У лукоморья дуб зелёный.', 'Ничьих не требуя похвал, Счастлив уж я надеждой сладкой, Что дева с трепетом любви Посмотрит, может быть, украдкой На песни грешные мои. У лукоморья дуб зелёный.']\n"
]
}
],
"outputs": [],
"source": [
"import librosa\n",
"import torch\n",
Expand All @@ -459,7 +425,9 @@
" encoded, encoded_len = model(\n",
" wav_tns.to(model._device).to(model._dtype), lengths.to(model._device)\n",
" )\n",
" print(model.decoding.decode(model.head, encoded, encoded_len))\n",
" results = model.decoding.decode(model.head, encoded, encoded_len)\n",
" for token_ids, _ in results:\n",
" print(model.decoding.tokenizer.decode(token_ids))\n",
"\n",
"# outputs expected to be equal"
]
Expand Down Expand Up @@ -530,19 +498,7 @@
"id": "xGeCADORttRY",
"outputId": "2cff3399-663c-497a-d41a-2d028a3de65c"
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[00:00:00 - 00:16:80]: Вечерня отошла давно, Но в кельях тихо и темно; Уже и сам игумен строгий Свои молитвы прекратил И кости ветхие склонил, Перекрестясь на одр убогий. Кругом и сон, и тишина; Но церкви дверь отворена.\n",
"[00:17:07 - 00:32:54]: Трепещет луч лампады, И тускло озаряет он И тёмную живопись икон, и возглащённые оклады. И раздаётся в тишине То тяжкий вздох, то шёпот важный, И мрачно дремлет в тишине старинный свод.\n",
"[00:32:95 - 00:49:30]: Глухой и влажный Стоят за клиросом чернец и грешник, Неподвижны оба. И шёпот их — Как глаз из гроба, И грешник бледен, как мертвец — Монах. Несчастный! Полно, перестань!\n",
"[00:49:81 - 01:05:65]: Ужасна исповедь злодея, Заплачена тобою дань Тому, Кто в злобе пламенея Лукавого грешника блюдёт И к вечной гибели ведёт. Смирись, опомнись. Время, время. Раскаянье, покров\n",
"[01:05:94 - 01:10:88]: Я разрешу тебя, грехов сложи мучительное бремя.\n"
]
}
],
"outputs": [],
"source": [
"import torch\n",
"\n",
Expand All @@ -557,7 +513,8 @@
" wav_tns, lengths = wav_tns.to(model._device).to(model._dtype), lengths.to(model._device)\n",
" with torch.no_grad():\n",
" encoded, encoded_len = model(wav_tns, lengths)\n",
" pred_texts.extend(model.decoding.decode(model.head, encoded, encoded_len))\n",
" results = model.decoding.decode(model.head, encoded, encoded_len)\n",
" pred_texts.extend(model.decoding.tokenizer.decode(ids) for ids, _ in results)\n",
"\n",
"for (start, end), text in zip(boundaries, pred_texts):\n",
" print(f\"[{gigaam.format_time(start)} - {gigaam.format_time(end)}]: {text}\")"
Expand Down Expand Up @@ -810,31 +767,16 @@
"id": "Ek1gKS6_cW-G",
"outputId": "39308dfb-f63d-4eb5-d944-30bcf6d7e462"
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Longform transcription:\n",
"\n",
"[0.0000 - 16.8047]: Вечерня отошла давно, Но в кельях тихо и темно; Уже и сам игумен строгий Свои молитвы прекратил И кости ветхие склонил, Перекрестясь на одр убогий. Кругом и сон, и тишина; Но церкви дверь отворена.\n",
"[17.0747 - 32.5491]: Трепещет луч лампады, И тускло озаряет он И тёмную живопись икон, и возглащённые оклады. И раздаётся в тишине То тяжкий вздох, то шёпот важный, И мрачно дремлет в тишине старинный свод.\n",
"[32.9541 - 49.3060]: Глухой и влажный Стоят за клиросом чернец и грешник, Неподвижны оба. И шёпот их — Как глаз из гроба, И грешник бледен, как мертвец — Монах. Несчастный! Полно, перестань!\n",
"[49.8122 - 65.6578]: Ужасна исповедь злодея, Заплачена тобою дань Тому, Кто в злобе пламенея Лукавого грешника блюдёт И к вечной гибели ведёт. Смирись, опомнись. Время, время. Раскаянье, покров\n",
"[65.9447 - 70.8891]: Я разрешу тебя, грехов сложи мучительное бремя.\n"
]
}
],
"outputs": [],
"source": [
"import os\n",
"os.environ[\"HF_TOKEN\"] = \"<HF_TOKEN with read access to `pyannote/segmentation-3.0`>\"\n",
"\n",
"model = AutoModel.from_pretrained(repo_name, revision=\"e2e_rnnt\", trust_remote_code=True)\n",
"utterances = model.transcribe_longform(\"long_example.wav\")\n",
"result = model.transcribe_longform(\"long_example.wav\")\n",
"print(\"Longform transcription:\\n\")\n",
"for utt in utterances:\n",
" transcription, (start, end) = utt[\"transcription\"], utt[\"boundaries\"]\n",
" print(f\"[{start:.4f} - {end:.4f}]: {transcription}\")"
"for segment in result:\n",
" print(f\"[{segment.start:.4f} - {segment.end:.4f}]: {segment.text}\")"
]
},
{
Expand Down
Loading
Loading