Давненько я не писав на hive, і от, сьогодні вирішив поділитись цікавою , як на мене, штукою, яка мені зекономила час, і можливо, вам теж стане в пригоді.
Нещодавно мені мені попався аудіо запис вебінару на важливу для мене тему, але дуже довгий - аж на 2 години. Не хотілось мені витрачати стільки часу на прослуховування, і так за допомогою моїх скромних знань пітона та підказок штучного інтелекту зʼявився такий скрипт:
import subprocess
import os
import wave
import contextlib
import speech_recognition as sr
import stanza
#Завантаження необхідних моделей Stanza для української, російської та англійської мов
stanza.download("uk") # Українська
stanza.download("ru") # Російська
stanza.download("en") # Англійська
#Функція для завантаження NLP-моделі Stanza відповідно до вибраної мови
def load_stanza_pipeline(language):
"""Завантаження NLP-процесора Stanza для вибраної мови."""
language_map = {
"english": "en",
"russian": "ru",
"ukrainian": "uk"
}
lang_code = language_map.get(language.lower(), "en") # Значення за замовчуванням - англійська
#Видаляємо 'sentiment', оскільки він недоступний для російської та української мов
return stanza.Pipeline(lang=lang_code, processors="tokenize,pos")
#Функція для отримання правильного мовного коду для розпізнавання мовлення
def get_language_code(language):
"""Конвертація назви мови у відповідний мовний код для розпізнавання мовлення."""
language_map = {
"english": "en-US",
"russian": "ru-RU",
"ukrainian": "uk-UA"
}
return language_map.get(language.lower(), "en-US") # Значення за замовчуванням - англійська
#Функція для конвертації аудіофайлу у формат WAV за допомогою FFmpeg
def convert_audio_to_wav(input_file):
"""Конвертація аудіофайлу у WAV-формат з використанням FFmpeg."""
output_file = os.path.splitext(input_file)[0] + ".wav"
if os.path.exists(output_file):
print(f"{output_file} вже існує, пропускаємо конвертацію.")
return output_file
try:
subprocess.run(['ffmpeg', '-i', input_file, '-ar', '16000', '-ac', '1', '-sample_fmt', 's16', output_file], check=True)
print(f"Конвертовано {input_file} у {output_file}")
return output_file
except subprocess.CalledProcessError:
print("Помилка конвертації файлу.")
return None
#Функція для розбиття аудіофайлу на шматки (тільки якщо розмір більше 10МБ)
def split_wav(input_file, chunk_size_mb=10):
"""Розбиття WAV-файлу на шматки, якщо його розмір перевищує 10МБ."""
file_size_mb = os.path.getsize(input_file) / (1024 ** 2)
if file_size_mb <= chunk_size_mb:
print(f"{input_file} має розмір {file_size_mb:.2f}МБ, розбиття не потрібне.")
return [input_file] # Повертаємо оригінальний файл у списку
chunks = []
with contextlib.closing(wave.open(input_file, 'rb')) as wf:
frame_rate, num_channels, sample_width, frame_count = wf.getframerate(), wf.getnchannels(), wf.getsampwidth(), wf.getnframes()
bytes_per_second = frame_rate * num_channels * sample_width
max_bytes = chunk_size_mb * (1024 ** 2)
chunk_frames = int((max_bytes / bytes_per_second) * frame_rate)
for i in range(0, frame_count, chunk_frames):
chunk_file = f"chunk_{i // chunk_frames}.wav"
with wave.open(chunk_file, 'wb') as chunk_wf:
chunk_wf.setparams(wf.getparams())
chunk_wf.writeframes(wf.readframes(chunk_frames))
chunks.append(chunk_file)
print(f"Розбито {input_file} на {len(chunks)} шматків.")
return chunks
#Функція для конвертації мовлення у текст
def audio_to_text(audio_chunks, language):
"""Конвертація мовлення у текст для кожного шматка."""
language_code = get_language_code(language)
recognizer = sr.Recognizer()
full_text = ""
for chunk in audio_chunks:
with sr.AudioFile(chunk) as source:
print(f"Обробка {chunk}...")
audio = recognizer.record(source)
try:
text = recognizer.recognize_google(audio, language=language_code)
full_text += text + " "
os.remove(chunk) # Видалення оброблених файлів
except sr.UnknownValueError:
print(f"Попередження: Неможливо розпізнати мовлення в {chunk}.")
except sr.RequestError:
print(f"Помилка підключення до Google API для {chunk}.")
except Exception as e:
print(f"Неочікувана помилка під час обробки {chunk}: {str(e)}")
if full_text:
print("\nОстаточний розпізнаний текст:\n", full_text)
else:
print("\nНе вдалося розпізнати мовлення у наданих шматках.")
return full_text
#Функція для створення короткого резюме тексту за допомогою Stanza
def summarize_text(text, language, sentence_count=5):
"""Створення підсумку ключових точок тексту за допомогою Stanza NLP."""
nlp = load_stanza_pipeline(language)
doc = nlp(text)
sentences = [sent.text for sent in doc.sentences]
summary = " ".join(sentences[:sentence_count]) # Витягуємо кілька перших речень як підсумок
print("\nПідсумок:\n", summary)
return summary
#Функція для збереження оригінального та підсумкового тексту у файл
def save_text(original_text, summarized_text, filename="transcript_summary.txt"):
"""Збереження оригінального та підсумкового тексту у файл."""
with open(filename, "w", encoding="utf-8") as file:
file.write(f"Оригінальний текст:\n{original_text}\n\nПідсумковий текст:\n{summarized_text}")
print(f"\nЗбережено стенограму та підсумок у {filename}")
#
#Головний виконуваний блок
if __name__ == "__main__":
audio_file = input("Введіть назву аудіофайлу: ")
language = input("Введіть мову ('english', 'russian', 'ukrainian'): ").lower()
wav_file = convert_audio_to_wav(audio_file)
if wav_file:
audio_chunks = split_wav(wav_file)
original_text = audio_to_text(audio_chunks, language)
if original_text:
summarized_text = summarize_text(original_text, language)
save_text(original_text, summarized_text)
Коментар до коду:
Данний код використовує утиліту ffmpeg для конвертації аудіофайлу в wav формат, бо саме він потрібен для розпізнавання голосу та конвертації його в текст за допомогою Google Api. На практиці виявилось що розпізнавання не працює для великих за розміром файлів, тому за потреби аудіо розбивається на шматки, які відправляються гуглу по черзі. Далі, для створення резюме тексту використовується NLP бібліотека Стенфордського університету - stanza (https://stanfordnlp.github.io/stanza/) і результат зберігається у файлі transcript_summary.txt . Хочу зазначити, що ця бібліотека досить масивна - більше 1 гб, але вона здатна працювати з українським та російським текстом, то її й вибрав.
На цьому все, якщо цікаві пости на тему пітона, напишіть у коменті про що б ви хотіли почитати. Гарного вам дня!