Нет, это не ругательное слово (для тех, кто не в курсе). Транскрибация это перевод голоса в текст.
На протяжении нескольких лет я подрабатывал этим делом. Титры для видео (использовал subtitle editor), интервью, доклады, проповеди и т. п. По заказам речь переводил в текст.
Долго пытался автоматизировать этот процесс. Сейчас существует много сервисов, которые могли бы в этом помочь. Но, как выяснилось, в реальной работе эти сервисы не могут быть полезны. На записях шум, необычный выговор докладчика, качество самой записи не позволяли применить методы автоматического распознавания голоса и перевода речи в текст.
Тем не менее существенно облегчить труд может творческое отношение к процессу.
Во время транскрибации можно использовать любой аудио проигрыватель, который управляется с клавиатуры и показывает тайминг.
При записи текста обычно требуется указывать этот самый тайминг.
Если текст большой, хотелось бы иметь некоторую форму для записи этого текста, в которой тайминги уже указаны с некоторым периодом.
Это существенно помогает ориентироваться в тексте и в аудио записи.
При необходимости по тексту легко определить место в записи, чтобы перейти к нему для уточнения.
Обычно работа по транскрибации оплачивается по времени записи. Было бы удобно сразу после завершения работы видеть и сумму, которую вам должен будет заплатить заказчик.
Оказалось, что в Linux есть простое средство позволяющее создать небольшой скрипт, который может просмотреть аудио файл, определить его продолжительность и создать текстовый файл с указанием интервалов по 15 секунд. В конце файла может быть указана цена работы.
Это средство обыкновенный терминал и bash (Одна из наиболее популярных современных разновидностей командной оболочки UNIX).
Я далеко не программист. Но мне потребовалось всего пара дней для создания такого файла. А теперь, когда я уже давно не занимаюсь транскрибацией регулярно, мне пришёл случайный заказ. Достав из закромов свой файл скрипта, я оперативно этот заказ исполнил.
Вот фрагмент работы:
0:15:30 !
Дадим же Богу возможность в нашей жизни действовать. Действовать через нас, через нашу жизнь, через наши слова, через наши поступки.
0:15:45 !
Сделаемся и мы его орудием для того чтобы ещё хоть кого-то обратить к Богу. Во всём этом пусть каждому из нас Господь поможет
0:16:00 !
и укрепит в наших желаниях. Аминь.
0:16:15 !
- - -
=282.75 ₽.
Скрипт определяет стоимость работы исходя из расценки 17 р/мин. Эта цена настраивается в строке 65 указанием цены за 15 секунд.
MON1=$(bc <<< "$TIMING*0.26016")
Содержание файла:
#!/bin/bash
##Создание формы для транскрибации
## 15 р / мин 0,216666667 р/ сек.
#
#
echo "Запускается перетаскиванием исполняемого файла и акдиофайла в окно терминала, открытого в рабочем каталоге."
echo "Из исходного видео или аудио извлекает фрагменты в формата opus по 15 сек."
echo "и записывает пустые строки [имя аудио].txt"
echo "Временные файлы удаляются автоматически"
F_NAME_FULL1=$1
echo $F_NAME_FULL1
##sleep 5
EXT=${F_NAME_FULL1##*.}
BNAME=`basename "$F_NAME_FULL1" ".$EXT"`
F_NAME_FULL="./"$BNAME"."$EXT
echo $BNAME
##sleep 2
TIME_R=15
######################################
## Преобразование входного файла в формат OPUS для расшифровки
ffmpeg -i $F_NAME_FULL -vn -c:a libopus audio.opus && ffmpeg -i ./audio.opus -f segment -segment_time $TIME_R -acodec copy "%03d.ogg"
##sleep 1
rm ./audio.opus
## Проверка наличия файла для расшифровки
RASH=".ogg"
NNN=0
FILE1=$F_NAME_PREF$(printf '%03d' $NNN)$RASH
echo $FILE1
while [ -f "$FILE1" ]
do
## echo $FILE1
echo "Есть"
## Распознавание
################################
PREF="@"
FILE2=$PREF$FILE1
echo $FILE2
(echo "X")>>./text_1.txt
## Контролируем процесс
################################
rm $FILE1
NNN=$[1+$NNN]
## Добавляем пустую строку с номером минуты.
TIMING=$(($NNN*$TIME_R))
## расходы
############################################
MON1=$(bc <<< "$TIMING*0.26016")
##MON1=$(bc <<< "$TIMING*0.27")
MON==$(echo "scale=2;$MON1/1" |bc)
printf -v ts '%d:%02d:%02d' `expr $TIMING / 3600` `expr $TIMING / 60` `expr $TIMING % 60`
echo " $ts ! " >> ./text_1.txt
###########################################
FILE1=$F_NAME_PREF$(printf '%03d' $NNN)$RASH
## sleep 1
done
echo " - - - ">>./text_1.txt
echo ${MON} " ₽. ">>./text_1.txt
echo " 0:00:00 !">'./'$BNAME'.txt'
echo -e «\n+++» | cat ./text_1.txt>>'./'$BNAME'.txt'
##echo | cat ./text_1.txt>>'./'$BNAME'.txt'
clear
################################
rm ./text_1.txt
## mm.ss
TIME_CODE="0:00:00"
TIME_CODE_str=$"("$TIME_CODE$")"
Имя файла любое допустимое, например write-speech-form.
Достаточно открыть окно терминала из каталога где лежит аудио файл и скрипт, перетащить мышью файл скрипта и аудио файл в окно терминала, нажать <Enter>. Имя аудио файла не должно содержать пробелов и лишних точек, должны быть установлены права на выполнение. Я именую обычно датой или временем 20_59_19.mp3.
Через несколько секунд в каталоге появится текстовая форма разграфка с ценой работы.
При необходимости автоматически проставленные тайминги можно удалить или заменить на более редкие.
В процессе работы скрипт разбирает исходный файл на фрагменты. Это можно использовать для анализа фрагментов и решении других задач автоматизации. Раньше мной это использовалось для отправки фрагментов Яндексу для дешифровки.
Crystal_HMR
Рискую быть обвинен в занудстве, но есть несколько вопросов/предложений:
>Обычно работа по транскрибации оплачивается по времени записи. Было бы удобно сразу после завершения работы видеть и сумму, которую вам должен будет заплатить заказчик.
>Скрипт определяет стоимость работы исходя из расценки 17 р/мин. Эта цена настраивается в строке 65 указанием цены за 15 секунд.
Почему бы сразу не взять длительность файла в минутах (с округлением вверх) и не умножить ее на 17? Весь блок кода будет заменен одной строкой, не будет дробных чисел, и в целом всё будет сильно читабельнее.
>Имя аудио файла не должно содержать пробелов и лишних точек
Так же как и с выходящим файлом - лучше просто разобраться как работать с файлами, содержащими пробелы и другие символы. Было бы и более "юзерфрендли" и больше "защиты от дурака".
Я попробовал запустить скрипт, и получил чистый экран терминала. Предварительно вывалилась какая-то ошибка (ffmpeg вроде). И ничего больше. В целом-то понятно, что ему нужно передать какой-то аргумент, но сам скрипт ничего не ответил на эту тему. Хорошей практикой будет сделать проверку на наличие аргумента, и в случае его отсутствия выдать usage. Вы же сами, если какое-то время не будете пользоваться своей наработкой - забудете/запутаетесь. Придется открывать код и вспоминать. Так вы еще и презентуете это, а раз так - то неплохо бы сделать хорошо :)
В принципе очень много беспорядка в коде. Лишние комментарии, лишние пробелы, отступы, неочевидные конструкции, общая "неоднородность" кода. Например, что делает команда эта команда?
А точнее ее первая часть. Зачем она тут нужна? Зачем столько лишних символов во второй части?
cat text_1.txt >> $BNAME.txt
сработает так же. Аcat file >> "${BNAME}.txt"
еще и без проблем сработает при файле с пробелом.Почему в каких-то случаях использована конструкция
$(command)
а в каких-то`command`
? Рекомендации к использованию парных скобок $() давно описаны, их легче дебажить, чем непарные ``. Почему переменные стилистически используются по-разному? Когда ${var}, когда $var. Есть понимание, или это "от балды"? Зачем конструкции типаF_NAME_FULL="./"$BNAME"."$EXT
, если ее заменитF_NAME_FULL=$BNAME.$EXT
? Если хочется извращаться с точка-слеш перед названием файла (хотя нужно понять зачем это делать) - то хватит"./${BNAME}.${EXT}"
. Возможно ли все "математические" операции привести к одному виду, что бы использовать что-то одно из expr, bc, $(())? Конструкция(echo "X")>>./text_1.txt
вообще феерична :) Зачем грузить во временные файлы всё, если можно грузить в память? В случае если скрипт сломается посредине (или будет остановлен) - хотя бы не останется кучки мусора. В конце концов зачем clear в конце? Может я логи почитать хочу :) без tmux'а я бы этого сделать не смог.Мне кажется, что если навести порядок в коде - статья уже будет иметь большую ценность, хотя бы с точки зрения самообразования автора.
В заключение: при всей моей любви к башу в целом, при тысячах строк написанных мною в собственных баш-портянках - сегодня подобное я бы стал делать только если хочется потренировать непосредственно баш. Если бы мне нужно было решать задачу - я бы, вероятнее, взял пайтон, начал с малого, но двигался бы в сторону автоматического определения наличия разговора в определенном временном диапазоне, динамическое создание таких временных диапазонов, и, возможно, автоматический перевод аудио в текст. После чего просто подредактировать тайминги там, где это нужно и отдать корректору (или самому) на корректирование ошибок автоматического преобразования. А может быть в сторону интерактивности, где после определения временного диапазона этот диапазон проигрывается в цикле, а в окошке есть возможность сразу редактировать временной интервал и "распознанный" текст. На сегодняшний день это звучит вполне реальной задачей.
Beard-56 Автор
Я не программист. Задачи решал по большей части готовыми средствами. Когда начал пробовать яндексовские сервисы по переводу голоса в текст, пришлось создать скрипт по описанию на Яндексе. Позднее выяснилось, что сервисы мало помогают, а доработанный скрипт может быть полезен и без них.
Недавно пришёл случайный заказ (давно уже не занимаюсь этим специально) и скрипт помог его оперативно выполнить. Раз он помог мне, может помочь и другим.
Относительно Python, могу сказать, что иногда обращаюсь и к нему. Но Bash на компах всегда в рабочем состоянии. Не надо ничего подгружать. И если надо решить задачу не программисту, то это вполне годный инструмент.
Если уж вы потратили столько сил на свой комментарий, видимо Вас заинтересовал вопрос. Никто не мешает реализовать ваши идеи на Python или даже на C.
Удачи.
Crystal_HMR
Я лишь пытался намекнуть, что многое можно сделать проще, а многое лучше. Я тоже не программист. Мне понадобилось определенное время, что бы написать тот код, который я приведу ниже. Сделал это исключительно ради освежения своих знаний.
Сделал нарочито просто, без сокращений. Уверен, что можно написать красивее (но понимать "непрограммисту" будет сложнее). Знаю, что можно написать короче. Подозреваю, что мой код тоже не идеален, и его улучшать и улучшать.
Первый блок кода это usage - он не нужен для работы скрипта, но сильно помогает когда им делишься. Потом с помощью ffmpeg (который вы использовали) мы получаем длительность. Не понятно, зачем вы в вашем решении били на отрезки, зачем потом проверяли наличие отрезков. Это всё вычислительные ресурсы, которые не нужны. Дальше используя количество шагов мы просто выводим тайминги с нужным вам форматом. Всё. Если нужно решить конкретно вашу задачу - то даже такое решение уже сильно проще. Имхо, читаемее.
Попробуйте воспринимать это не через призму критики ради вашего оскорбления, а с призмы попытки подсказать вам, что можно сделать лучше в будущем. У меня не было цели вас задеть.
Crystal_HMR
Из обязательного, что нашел через промежуток времени после написания комментария: нужно проверять на наличие файла перед ffmpeg. Если файла нет - выходить с указанием, что файл не найден.
Из необязательного, но было бы правильно: после ffmpeg'а и обрезания вывода проверить переменную dur на соответствие регулярному выражению.
Из вообще мелочей: их много, но больше всего меня беспокоит две. 1) заменить
'%H:%M:%S'
на'%T'
; 2) Всё таки попробовать заменить все bc на $(()), если получится (лень проверять сейчас). Первое визуально сократит код, второе может сделать его быстрее, потому что вызов отдельного приложения - всегда накладные расходы и время. Одна только замена в вызове date после собаки на$(($step * 15))
- уже дает почти двухкратное увеличение скорости выполнения на небольшом файле (длительность 3:23):Кстати, пока писал коммент - обнаружил, что скрипт автора выводит время сверху длительности файла. Т.е. мой файл 3:23, скрипт автора последним таймингом выводит 3:30. Я что бы этому соответствовать - добавил в вычисление steps +1. Его нужно убрать, потому что это, имхо, неверно.