Как вы проверяете момент завершения, при stdin вводе? Если отправляю на stdin сразу весь фрагмент текста, всё работает отлично. Если отправляю построчно, до момента заполнения буфера (python Popen) balcon запущен и ожидает данных. По достижении лимита, данные из буфера сбрасываются balcon и отлично обрабатываются. Но. После их обработки, balcon сразу закрывается. Хотя по логике должен ожидать следующей порции данных из буфера и закрываться только по отправке команды stdin.close() Раньше с такой бедой не сталкивался, хотя с stdin работаю часто. Поэтому грешу скорее на balcon.
Код
from subprocess import Popen, PIPE from time import sleep
test = 'Тестовая строка для озвучки' test_b = test.encode('cp1251')
i = 0 while True: i += 1 stdin.write(test_b) stdin.write(b'\n') print(i, prc.poll()) # None — программа запущена, 0 - закрыта. sleep(0.2) # замедление для удобства отслеживания процесса глазами
Lecron При запуске моя программа считывает все данные, которые на тот момент есть в STDIN, и на этом работа со входным потоком завершается. Не думаю, что это "баг" - так и было задумано, здесь нет ошибки в реализации.
Не уверен, что смогу реализовать то, что Вам нужно: например, сомневаюсь, что моя программа сможет узнать о выполнении внешней команды stdin.close(). Это будет уже какая-то другая консольная программа: она должна будет ждать в цикле, когда в STDIN появятся новые данные, чтобы прочитать их (конвейер, pipe); изначально это не входило в мои планы. Обещаю подумать еще на эту тему; пока ничем не могу помочь.
Не сомневайтесь, может. Для примера, посмотрите на утилиты iConv и 7z. Сейчас специально проверил. Работают ожидаемо. Кмк, это вообще штатное поведение утилит принимающих stdin. В тестовом скрипте строки запуска, соответственно args = ['iconv.exe', '-f', 'CP1251', '-t', 'UTF-8'] args = ['7z.exe', 'a', '-si', '_test.7z']
У меня встречный вопрос: зачем это нужно именно в случае "Балаболки"? Почему так важно посылать текст по частям, а не подготовить его предварительно и отправить целиком? Это же не какие-нибудь "тяжелые" видео данные формата HD, это просто текст - мегабайты текста можно подготовить за секунды. Что именно Вы делаете в своей программе?
Другой вопрос: какого поведения Вы ждете от моей консольной программы? Она должна сначала забрать из входного потока все фрагменты текста и затем преобразовать текст в речь? Или каждый фрагмент текста надо преобразовывать в речь по отдельности?
Озвучка многопоточная. 4+ запуска balcon. Каждая строка обрабатывается корректором, работающем в отдельном потоке, общем на всё. Если нужно готовить полный фрагмент, то произойдет задержка озвучки на обработку ~4 фрагментов, с загрузкой 1 ядра. Если напитывать по строкам, озвучка пойдет практически сразу (размер буфера 2 кБ) с 100% загрузкой CPU. Плюс эстетическая составляющая. Привык работать итераторами. Плюс это просто правильно. Долго не мог понять, почему падает обработка. За всю жизнь ни разу не сталкивался с таким подходом работы с stdin — 1 буфер и всё!
Поведение обычное. Один запуск — один файл. Только не "забрать все фрагменты и преобразовать в речь", а преобразовать буфер и отправить аудио дальше, дождаться следующего, преобразовать буфер и отправить дальше, дождаться.... Сейчас программа после запуска спокойно дожидается данных. Надо чтобы после завершения порции, точно также дожидалась следующих данных. Лучший пример — архиватор 7z.
За всю жизнь ни разу не сталкивался с таким подходом работы с stdin — 1 буфер и всё!
Просто я не ставил себе задачу реализовать поддержку конвейера (pipe): это избавило от многих проблем. Например, проще применять правила ко всему тексту сразу, тогда не возникнет сложностей с тем, что правила не будут применены к "стыкам" фрагментов. Ведь даже из Вашего объяснения нет полной ясности, сколько именно текста содержит один фрагмент ("строка" - это один абзац, как я понял). А вдруг найдется другой программист, который будет присылать по одному слову в STDIN и требовать, чтобы программа читала всё предложение целиком. И если отправляются в буфер абзацы, надо следить за тем, чтобы на конце каждого фрагмента был перевод каретки: если не делать этого, фрагменты "склеятся" друг с другом. Вроде бы мелочь, но может превратиться в проблему.
Сейчас программа нормально работает с такой командной строкой (это именно то, что я собирался реализовать изначально):
Код
balcon -i -n Alyona < test.txt
Но нет полной поддержки конвейера (pipe):
Код
7z.exe e -so test.zip | balcon -i -n Alyona
Обещать не стану, работа эта не столько сложная, сколько трудоемкая. Если дойдут руки - хорошо, нет - значит, нет. Спасибо за описание проблемы, буду думать дальше.
Обнаружил еще один момент достойный улучшения. Программа автоматически цепляет конфиг с параметрами. Это удобно, для самого ходового варианта. Но нужно установить приоритет командной строки, позволяющей их перекрыть. Возможно для некоторых команд оно так и работает. Но для например --silence-end, значения параметра конфига и командной строки складываются.
Но нужно установить приоритет командной строки, позволяющей их перекрыть.
Сейчас это именно так: параметр сначала будет взят из файла конфигурации, а затем из командной строки, и использоваться будет последнее из значений параметра.
Параметр --silence-end превращается в тег SAPI 5:
Код
Конец документа.<silence msec="2000">
и он чувствителен к тому, как каждый конкретный голос обрабатывает тег тишины. Возможно, поэтому может казаться, что пауза длиннее или короче, чем требуется. Надо бы, конечно, заменить вставку тегов тишины в текст на вставку собственных аудиоданных с тишиной непосредственно в аудиопоток, но руки до этого никак не дойдут.
P.S. Сейчас обратил внимание, что пауза для --silence-end вставляется и при сохранении звукового файла, и при чтении вслух, хотя в документации я написал лишь про звуковой файл. Это моя ошибка; спасибо, что помогли обнаружить ее.
При отсутствии конфига дает аудио длиной 7 сек. При наличии, также содержащим параметр --silence-end 4000, дает аудио 12 сек Они именно разные, а не отличающиеся от заданного по капризу движка.
Сообщение отредактировал Lecron - Воскресенье, 21.05.2023, 14:49
Дата: Понедельник, 22.05.2023, 02:23 | Сообщение #15
V.I.P.
Группа: Модераторы
Сообщений: 139
Статус: Offline
ЦитатаLecron ()
значения параметра конфига и командной строки складываются
Действительно, складываются.
Не знаю, почему я так сделал: наверное, хотел предусмотреть добавление не только тега тишины, но и какого-либо текста в начало или конец аудиофайла. Исправлю в следующей версии, спасибо за замечание.