Bootstrap

скрипт получения из видеофайла, двух файлов, звуковая дорожка wav, и текст txt распознанной речи

скрипт получения из видеофайла, двух файлов, звуковая дорожка wav, и текст txt распознанной речи

Напишем скрипт на python, который из видеофайла, по пути указанного через атрибуты на вход, создаст два файла, один аудиофайл в формате wav, это звук из этого видео, а второй txt файл, в котором будет текст из распознанных из этого звукового файла слов. Причём видео может быть на одном из 142 возможных языков для распознавания.

Предисловие, зачем это может быть нужно. У меня например возникло желание узнать что говорится в одном видео с Youtube, вот ссылка https://www.youtube.com/watch?v=xoHPnwuyIJc

Но проблема в том что у видео нет субтитров, и у него язык Хинди, я об этом просто догадался. Поэтому я скачал его себе на компьютер, и обработал следующим скриптом, чтобы получить хоть какую-то информацию по данной теме. Если у кого-то похожая задача, то этот скрипт может быть им использован тоже, потому что довольно универсален и достаточно прост.

Язык, который нужно распознать из видео, пользователь указывает самостоятельно при запуске скрипта. Использована библиотека следующих языков https://cloud.google.com/speech-to-text/docs/speech-to-text-supported-languages.

Для создания виртуального окружения, перейдите в каталог своего проекта и выполните:


python -m venv venv

### Активация


source venv/bin/activate

обновить менеджер пакетов pip


pip install -U pip

установите следующие пакеты

speech_recognition argparse moviepy.editor googletrans pydub numpy

С помощью этой команды:


pip install speech_recognition argparse moviepy.editor googletrans pydub numpy

создайте файл, например pars_video.py, это и будет скрипт со следующим содержимым:

Terminal:

try:
    import speech_recognition as sr
    import sys
    import argparse
    from moviepy.editor import *
    import os
    from googletrans import Translator
    from pydub import AudioSegment
    import numpy as np
    import re


    # Определим словарь из возможных кодов взятых на сайте https://cloud.google.com/speech-to-text/docs/speech-to-text-supported-languages
    codes = {'Afrikaans (South Africa)':'af-ZA','Albanian (Albania)': 'sq-AL','Amharic (Ethiopia)': 'am-ET ','Arabic (Algeria)': 'ar-DZ','Arabic (Bahrain)': 'ar-BH','Arabic (Egypt)': 'ar-EG','Arabic (Iraq)': 'ar-IQ','Arabic (Israel)': 'ar-IL','Arabic (Jordan)': 'ar-JO','Arabic (Kuwait)': 'ar-KW','Arabic (Lebanon)': 'ar-LB','Arabic (Mauritania)': 'ar-MR','Arabic (Oman)': 'ar-OM','Arabic (Qatar)': 'ar-QA','Arabic (Saudi Arabia)': 'ar-SA','Arabic (State of Palestine)': 'ar-PS','Arabic (Tunisia)': 'ar-TN','Arabic (United Arab Emirates)': 'ar-AE','Arabic (Yemen)': 'ar-YE','Armenian (Armenia)': 'hy-AM','Azerbaijani (Azerbaijan)': 'az-AZ','Basque (Spain)': 'eu-ES','Bengali (Bangladesh)': 'bn-BD','Bengali (India)': 'bn-IN','Bosnian (Bosnia and Herzegovina)': 'bs-BA','Bulgarian (Bulgaria)': 'bg-BG','Burmese (Myanmar)': 'my-MM','Catalan (Spain)': 'ca-ES','Chinese, Cantonese (Traditional Hong Kong)': 'yue-Hant-HK','Chinese, Mandarin (Simplified, China) ': 'zh','Chinese, Mandarin (Traditional, Taiwan)': 'zh-TW','Croatian (Croatia)': 'hr-HR','Czech (Czech Republic)': 'cs-CZ','Danish (Denmark)': 'da-DK','Dutch (Belgium)': 'nl-BE','Dutch (Netherlands)': 'nl-NL','English (Australia)': 'en-AU','English (Canada)': 'en-CA','English (Ghana)': 'en-GH','English (Hong Kong)': 'en-HK','English (India)': 'en-IN','English (Ireland)': 'en-IE','English (Kenya)': 'en-KE','English (New Zealand)': 'en-NZ','English (Nigeria)': 'en-NG','English (Pakistan)': 'en-PK','English (Philippines)': 'en-PH','English (Singapore)': 'en-SG','English (South Africa)': 'en-ZA','English (Tanzania)': 'en-TZ','English (United Kingdom)': 'en-GB','English (United States)': 'en-US','Estonian (Estonia)': 'et-EE','Filipino (Philippines)': 'fil-PH','Finnish (Finland)': 'fi-FI','French (Belgium)': 'fr-BE','French (Canada)': 'fr-CA','French (France)': 'fr-FR','French (Switzerland)': 'fr-CH','Galician (Spain)': 'gl-ES','Georgian (Georgia)': 'ka-GE','German (Austria)': 'de-AT','German (Germany)': 'de-DE','German (Switzerland)': 'de-CH','Greek (Greece)': 'el-GR','Gujarati (India)': 'gu-IN','Hebrew (Israel)': 'iw-IL','Hindi (India)': 'hi-IN','Hungarian (Hungary)': 'hu-HU','Icelandic (Iceland)': 'is-IS','Indonesian (Indonesia)': 'id-ID','Italian (Italy)': 'it-IT','Italian (Switzerland)': 'it-CH','Japanese (Japan)': 'ja-JP','Javanese (Indonesia)': 'jv-ID','Kannada (India)': 'kn-IN','Kazakh (Kazakhstan)': 'kk-KZ','Khmer (Cambodia)': 'km-KH','Korean (South Korea)': 'ko-KR','Lao (Laos)': 'lo-LA','Latvian (Latvia)': 'lv-LV','Lithuanian (Lithuania)': 'lt-LT','Macedonian (North Macedonia)': 'mk-MK','Malay (Malaysia)': 'ms-MY','Marathi (India)': 'mr-IN','Mongolian (Mongolia)': 'mn-MN','Nepali (Nepal)': 'ne-NP','Norwegian Bokmål (Norway)': 'no-NO','Persian (Iran)': 'fa-IR','Polish (Poland)': 'pl-PL','Portuguese (Brazil)': 'pt-BR','Portuguese (Portugal)': 'pt-PT','Punjabi (Gurmukhi India)': 'pa-Guru-IN','Romanian (Romania)': 'ro-RO','Russian (Russia)': 'ru-RU','Kinyarwanda (Rwanda)': 'rw-RW','Serbian (Serbia)': 'sr-RS','Sinhala (Sri Lanka)': 'si-LK','Slovak (Slovakia)': 'sk-SK','Slovenian (Slovenia)': 'sl-SI','Swati (South Africa)': 'ss-latn-za','Southern Sotho (South Africa)': 'st-ZA','Spanish (Argentina)': 'es-AR','Spanish (Bolivia)': 'es-BO','Spanish (Chile)': 'es-CL','Spanish (Colombia)': 'es-CO','Spanish (Costa Rica)': 'es-CR','Spanish (Dominican Republic)': 'es-DO','Spanish (Ecuador)': 'es-EC','Spanish (El Salvador)': 'es-SV','Spanish (Guatemala)': 'es-GT','Spanish (Honduras)': 'es-HN','Spanish (Mexico)': 'es-MX','Spanish (Nicaragua)': 'es-NI','Spanish (Panama)': 'es-PA','Spanish (Paraguay)': 'es-PY','Spanish (Peru)': 'es-PE','Spanish (Puerto Rico)': 'es-PR','Spanish (Spain)': 'es-ES','Spanish (United States)': 'es-US','Spanish (Uruguay)': 'es-UY','Sundanese (Indonesia)': 'su-ID','Swahili (Kenya)': 'sw-KE','Swahili (Tanzania)': 'sw-TZ','Swedish (Sweden)': 'sv-SE','Tamil (India)': 'ta-IN','Tamil (Malaysia)': 'ta-MY','Tamil (Singapore)': 'ta-SG','Tamil (Sri Lanka)': 'ta-LK','Telugu (India)': 'te-IN','Thai (Thailand)': 'th-TH','Setswana (South Africa)': 'tn-latn-za','Turkish (Turkey)': 'tr-TR','Tsonga (South Africa)': 'ts-ZA','Ukrainian (Ukraine)': 'uk-UA','Urdu (India)': 'ur-IN','Urdu (Pakistan)': 'ur-PK','Uzbek (Uzbekistan)': 'uz-UZ','Venda (South Africa)': 've-ZA','Vietnamese (Vietnam)': 'vi-VN','isiXhosa (South Africa)': 'xh-ZA','Zulu (South Africa)': 'zu-ZA'}
  
#тригер если есть хотябы один фрагмент резульата, то будет больше нуля
    n = 0

    for i, (language, code) in enumerate(codes.items()):
        print(f"{i+1}. {language}: {code}")
    print('показан список доступных языков, которые могут быть в источнике звука. выбирайте тот который считаете нужным. скрипт будет искать слова на этом языка в вашем входящем видео файле и вносить их в текст.')
    print('Укажите на каком языке речь в вашем видео. Напишите только номер:')



    # регулярным выражение отсекаем со входа прочие символы кроме числа

    inp = re.findall(r'\d+', input("Enter a number: "))
    choice = int(inp[0])

    selected_language = list(codes.keys())[choice-1]
    selected_code = codes[selected_language]
    print(f"You selected '{selected_language}' with code '{selected_code}'.")

    def createParser ():
        parser = argparse.ArgumentParser(description='Process some input.')
        #Определить аргументы, которые мы принимаем
        parser.add_argument('-p', '--path', type=str, help='the path to process')
        args = parser.parse_args()
        return args

    if __name__ == '__main__':
        args = createParser()

        def get_audio(args=args):
            # аргумент физический адрес файла видео
            if args.path:
                print ("Получаем аудио из видео по адресу, {}!".format (args.path) )

                # создать объект видеоклипа из входного файла
                clip = VideoFileClip(args.path)

                # Извлечь имя файла из пути
                file_name = os.path.basename(args.path)

                # Распечатать имя файла
                print(file_name)
                new_wav=file_name+'.wav'

                # извлечь звук из клипа
                audio = clip.audio

                # сохранить аудио как новый файл
                audio.write_audiofile(new_wav, codec='pcm_s16le')

                print('Первая часть скрипта успешно отработана. Звук записан в созданный аудио файл: '+new_wav)
                # создать объект распознавателя
                r = sr.Recognizer()

                try:
                    # Загрузим аудиофайл
                    audio_file = AudioSegment.from_file(new_wav)

                    # Установите продолжительность сегмента в миллисекундах (177 seconds = 177000 milliseconds)
                    segment_duration = 177000

                    # Рассчитать количество сегментов
                    num_segments = int(np.ceil(audio_file.duration_seconds / (segment_duration/1000)))

                    print('Приступили ко второй части скрипта, процесс идёт, ждите завершения.')
                    print(f'Всего предстоит обработать {num_segments} сегментов по {segment_duration/1000} секунд каждый.')

                    # Разделить аудиофайл на сегменты, создаём словарь сегметов
                    segments = []
                    for i in range(num_segments):
                        start = i * segment_duration
                        end = min((i+1) * segment_duration, len(audio_file))
                        #учитываем что последний сегмент может быть другого размера
                        if i == num_segments - 1:
                            segment = audio_file[start:]
                        else:
                            segment = audio_file[start:end]
                        segments.append(segment)
                except Exception as err:
                    print('разбивка', err)


                #Обрабатывать каждый сегмент отдельно
                for i, segment in enumerate(segments):
                    # Сохраним каждый сегмент во временный новый файл
                    print(f'начало обработки {i+1} сегмента')
                    filename = f'segment_{i+1}.wav'
                    segment.export(filename, format='wav')
                    n=int(i+1)
                    # откройте аудиофайл с помощью класса Recognizer
                    with sr.AudioFile(filename) as source:
                        # прослушать данные (загрузить аудио в память)
                        audio_data = r.record(source)

                    #удаляем временный файл фрагмента
                    os.remove(filename)

                    # транскрибировать аудиоданные в текст
                    if audio_data is not None:
                        try:
                            text = r.recognize_google(audio_data, language=selected_code)
                            print('УСПЕХ!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!')
                            file=file_name+'.txt'

                            # Записать текст фрагмента в конец файла. внимание файл будет создан, но если вы запустите скрипт с теми же параметрами ещё раз, то файл будет дописывать результы не удаляя предыдущих
                            with open(file, 'a') as f:
                                f.write(text)
                            print(f'содержимое {i+1} сегмента {text}') # печатает содержимое файла на данный момент
                            print(f'сегмент № {i+1} обработан и добавлен в файл результата {file}:')
                        except Exception as e:
                            print(f"Error: {str(e)}")
                    else:
                        if n<num_segments:
                            print("Работа скрипта не завершена, из-за ошибки в данных аудиопотока")
                        else:
                            print("Работа скрипта завершена")
                return file

        print(f'Результат заключительной части скрипта, находится в файле: {get_audio()}')
#обернули всё try - except, чтобы выбросить исключение и понять в чём ошибка в случае таковой
except Exception as err:
    if n<1:
        print('Ничего не получилось, ибо: '+str(err))
    else:
        print("Работа скрипта завершена, с ошибками")


Так, как необходимый адрес вместе с именем входного видеофайла path мы будем добавлять через именованный параметр (-p,--path), прямо в командной строке при вызове срипта, то наша команда в итоге будет иметь примерно следующий вид:

не забывая, что мы уже находимся в активированном окружении

python pars_video.py -p /home/username/Videos/dhvid2.mp4

Далее просто выбираем язык и ждём завершения работы программы.

код скрипта также можно взять и здесь https://gitlab.com/pub_ramanzes/pars_video

Копирование материалов разрешается только с указанием автора Roman Sakhno и индексируемой прямой ссылкой на сайт (http://itdid.ru)!

Добавляйтесь ко мне в друзья ВКонтакте: http://vk.com/sahroman.
Если Вы хотите дать оценку мне и моей работе, то напишите её в моей группе: http://vk.com/sahroman.

Если у Вас остались какие-либо вопросы, либо у Вас есть желание высказаться по поводу этой статьи, то Вы можете оставить свой комментарий внизу страницы.

Порекомендуйте эту статью друзьям:

Если Вам понравился сайт, то разместите ссылку на него (у себя на сайте, на форуме, в контакте):

  1. Кнопка:

    Она выглядит вот так: Как настроить свой компьютер

  2. Текстовая ссылка:

    Она выглядит вот так: Как настроить свой компьютер

  3. BB-код ссылки для форумов (например, можете поставить её в подписи):

Комментарии (0):

Для добавления комментариев надо войти в систему.
Если Вы ещё не зарегистрированы на сайте, то сначала зарегистрируйтесь.

крипто-донат, на развитие сайта itdid.ru:

В новом окне с терминалом itdid.ru, введите любую сумму: