Указываем в скрипте путь на книгу в txt — на выходе получаем папку с озвучкой хорошим синтезом.

Люблю потреблять контент ушами — в это время можно заниматься спортом или давать отдых глазам. Я привык что любая нормальная книга имеет аудио-версию, в худшем случае — любительскую, однако это не всегда так. Сегодня я несколько часов перебирал разные онлайн-сервисы и Андроид-программы для проговаривания русского текста — из приглянувшегося только Pocket который использует Google TTS и Google Books с тем же движком но отчего то другим качеством голоса. Также интересен SpeechKit от Яндекс. Но вроде лучший синтез у Ivona — эту компанию в 2013 году купил Амазон. Гитхаб нашел с десяток скриптов для дергания готового звука, но полностью готового решения для озвучки целой книги не оказалось. Используя неофициальную Go-библиотеку для IVONA Speech Cloud API за несколько часов написал скрипт — впервые использую Go, удобно что все зависимости в одном файле, даже библиотеку с Гитхаба подтягивает автоматически.

Скрипт создает один ogg-файл на абзац — у меня была книга в plaintext, конечно логичнее было бы разбивать по главам, а целиком книгу скормить не получилось — есть лимит на входное количество символов, около десяти минут озвучки на нормальной скорости. Выходной формат можно поменять на mp3. Имена файлов нормально отсортированы по порядку. При работе скрипта в консоли показывается текущий абзац отправленный на озвучку.



Для работы скрипта нужны access key и secret key — я оставил тут свои, но если перестанет работать — вы можете бесплатно получить новые ключи тут.

package main
import (
	"log"
	"fmt"
	"io/ioutil"
	"strings"
	ivona "github.com/jpadilla/ivona-go"
)
func main() {
	client := ivona.New("GDNAICTDMLSLU5426OAA", "2qUFTF8ZF9wqy7xoGBY+YXLEu+M2Qqalf/pSrd9m")
	text, err := ioutil.ReadFile("/home/vitaly/Desktop/test.txt")
	if err != nil {
		log.Fatal(err)
	}

	arrayOfParagraphs := strings.Split(string(text), "\n\n")
	i := 0
	for _,paragraph := range arrayOfParagraphs {
                paragraph = strings.TrimSpace(paragraph)
		if (len(paragraph) < 1) { // against empty lines
			continue
		}
		log.Printf("%v\n", paragraph)
		options := ivona.NewSpeechOptions(paragraph)
		options.Voice.Language = "ru-RU"
		options.Voice.Name = "Maxim"
		options.Voice.Gender = "Male"
		options.OutputFormat.Codec = "OGG"
		r, err := client.CreateSpeech(options)
		if err != nil {
			log.Fatal(err)
		}

		i++
		file := fmt.Sprintf("/home/vitaly/Desktop/ivona/tts%04d.ogg", i) // files like 0001.ogg
		ioutil.WriteFile(file, r.Audio, 0644)
	}
}


После замены пути к книге и пути к выходной папке (а возможно и заменив символ по которому делается сплит файла а также указав английский вместо русского) запускаем скрипт — минут за десять получаем около сотни страниц готового tts:
go run ivona-tts.go

Это мой первый go код, приветствую вашу критику.

P.S.: Первым делом лучше искать уже озвученную человеком версию книги.

Комментарии (34)


  1. Crandel
    21.01.2016 15:52
    +1

    Использую Vocalizer и для русского и для английского языка, очень качественный синтез, рекомендую
    4pda.ru/forum/index.php?showtopic=200728


    1. zdanevich-vitaly
      21.01.2016 15:53

      А можно демо русского и английского?


      1. Crandel
        21.01.2016 15:55

        Да, как замена Google TTS


        1. zdanevich-vitaly
          21.01.2016 16:25
          +2

          Я имел в виду можете ли вы дать линк на Ютуб например который говорит именно тем голосом который вам больше всего нравится?


          1. Crandel
            21.01.2016 16:35
            -3

            www.youtube.com/watch?v=KHxAap53Hd8
            Похоже на это, но у меня Milena Premium-High и звучит на телефоне получше, а для английских книг Ava Premium-High использую
            Профит в том, что не надо ничего кодировать, форматы переводить, стоит только открыть читалку(FBReader к примеру) и есть возможность слушать любые тексты


            1. Ganster41
              21.01.2016 17:42
              +1

              Попробуйте ту же Татьяну из Ivona, можете приятно удивиться. Когда-то сравнивали как раз на книгах, и голоса от Nuance заметно им проигрывали, особенно в витиеватой художественной литературе. В т.ч. на телефоне неплохо работает.


              1. Crandel
                21.01.2016 17:50
                +1

                Спасибо, стоит изучить вопрос, я пользуюсь вокалайзером уже около двух лет, звучит хорошо, поэтому не смотрел за обновлениями


            1. zdanevich-vitaly
              21.01.2016 19:39
              +2

              Мне мужские голоса в любом синтезе кажутся гораздо лучше…


              1. Athari
                22.01.2016 04:12
                +1

                Попробовал Ивону. Таки да, мужской голос лучше.

                Причём что забавно: тестировал на «Белой берёзе», и Максим читает «стоИт берёза», а Татьяна читает «стОит берёза». Это заговор! :D Впрочем, без «ё» они одинаково ошибаются в определении слова.

                Тестовый текст
                Белая берёза
                Под моим окном
                Принакрылась снегом,
                Точно серебром.

                На пушистых ветках
                Снежною каймой
                Распустились кисти
                Белой бахромой.

                И стоит берёза
                В сонной тишине,
                И горят снежинки
                В золотом огне.


  1. lain8dono
    21.01.2016 16:28
    +3

    Это мой первый go код, приветствую вашу критику.

    Не стоит хардкорить пути и ключи прямо в исходники. Для этого есть flag и path/filepath (не стоит обходиться обычной конкатерацией). А в bufio есть сканнер для чтения по словам/строкам/символам, хотя и не принципиально для файлов среднего размера. io/ioutil.WriteFile может возвратить ошибку (например место кончилось или ещё чего) и её стоит обработать.

    Парочка усовершенствований
    package main
    
    import (
    	ivona "github.com/jpadilla/ivona-go"
    
    	"bufio"
    	"flag"
    	"fmt"
    	"io/ioutil"
    	"log"
    	"os"
    	"path/filepath"
    	"strings"
    )
    
    const format = "tts%04d.ogg" // files like 0001.ogg
    
    var dir = flag.String("dir", ".", "like /home/vitaly/Desktop/")
    var textFile = flag.String("text", "", "path to text file, like /home/vitaly/Desktop/test.txt")
    var key = flag.String("key", "GDNAICTDMLSLU5426OAA", "access key for ivona api")
    var secret = flag.String("secret", "2qUFTF8ZF9wqy7xoGBY+YXLEu+M2Qqalf/pSrd9m", "secret key for ivona api")
    
    func main() {
    	flag.Parse()
    
    	conf := os.Stdin // если нет конфига, но читаем стандартный ввод
    	if *textFile != "" {
    		conf, err := os.Open(*textFile)
    		if err != nil {
    			log.Fatal(err)
    		}
    		defer conf.Close()
    	}
    
    	client := ivona.New(*key, *secret)
    	scanner := bufio.NewScanner(conf)
    	for i := 1; scanner.Scan(); i++ {
    		paragraph := strings.TrimSpace(scanner.Text())
    		if paragraph == "" { // пропускаем пустые строки
    			continue
    		}
    		log.Printf("process: %v\n", paragraph)
    
    		options := ivona.NewSpeechOptions(paragraph)
    		options.Voice.Language = "ru-RU"
    		options.Voice.Name = "Maxim"
    		options.Voice.Gender = "Male"
    		options.OutputFormat.Codec = "OGG"
    
    		r, err := client.CreateSpeech(options)
    		if err != nil {
    			log.Fatal(err)
    		}
    
    		file := filepath.Join(*dir, fmt.Sprintf(format, i))
    		err = ioutil.WriteFile(file, r.Audio, 0644)
    		if err != nil {
    			log.Fatalln("writing result file:", err)
    		}
    	}
    
    	if err := scanner.Err(); err != nil {
    		log.Fatalln("reading text file:", err)
    	}
    }
    


    1. neolink
      21.01.2016 16:50
      +1

      у вас только конфиг из файла никогда читаться не будет


      1. lain8dono
        21.01.2016 16:57

        И правда. Вот фикс:

        	var err error
        	if *textFile != "" {
        		conf, err = os.Open(*textFile)
        


    1. zdanevich-vitaly
      21.01.2016 18:25
      +2

      Спасибо.


  1. Stronix
    21.01.2016 17:28
    -3

    Только Go всё-таки не скриптовый язык.


    1. mcleod095
      21.01.2016 18:15

      Сам сейчас периодически пользую go
      и как ни странно, как скриптовый, это позволяет наличие большого количества либ. Да и запуск не такой уж и долгий. Хотя конечно лучше собирать. Но для изучения подойдет и просто go run


      1. Stronix
        21.01.2016 19:32
        -1

        Тогда ждём статьи про C-скрипты, чего уж…


        1. iOrange
          21.01.2016 19:52
          +5

          Вы удивитесь — bellard.org/tcc

          C script supported: just add '#!/usr/local/bin/tcc -run' at the first line of your C source, and execute it directly from the command line.


          1. Stronix
            21.01.2016 20:47

            С Go можно даже так

            //usr/bin/go run $0 $@; exit $?
            package main
            
            import "fmt"
            
            func main() {
            	fmt.Println("Hello world!")
            }
            
            

            Однако, по моему разумению, слово скрипт указывает на скриптовый язык.


  1. niksite
    21.01.2016 17:35
    +4

    Зачем конвертировать если можно сразу читать голосом? На андроиде это умеют многие приложения, например fbreader. На iOS и того проще — чтение текста встроенная системная функция, можно активировать в настройках чтение (в любой программе) по двойному свайпу сверху вниз.


  1. lavkasnov
    21.01.2016 17:40

    Голос так себе, не знаю почему автор его выбрал, есть получше (имею в виду русский)


  1. Neuronix
    21.01.2016 17:58
    +1

    Спасибо за IVONA, не слышал. Наличие Java API радует, заберу к себе в умный дом


  1. yarg
    21.01.2016 18:13
    +1

    Умеют ли современные синтезаторы речи решать проблему с е/ё?


    1. infrapro
      21.01.2016 19:02
      +2

      Попробовал скрипт автора, и могу сказать что в опробованной книге кусочек из фразы: «Я и осел здесь, чтобы отвязаться от вас.» слово осел было прочитано как осёл. Т.е. проблему вроде как решают, но местами неправильно


  1. mcleod095
    21.01.2016 18:36
    +1

    У меня возник вопрос, а если в тексте встречается предложение в котором есть и русский текст и английский?
    Один будет в пролете?


    1. infrapro
      21.01.2016 19:09
      +1

      Будет прочитан весь текст, но не факт, что произношение будет правильным. У API Ivona есть возможность задавать лексиконы, которые позволяют подстроить произношение слова/фразы или произнести сокращения полностью. Я думаю, этим механизмом можно воспользоваться для подобных случаев.


    1. telegamochka
      21.01.2016 19:31
      +1

      Не знаю, как в Ivona, а в RHVoice, который я использовала с «Балаболкой», есть возмощность XML-тегами переключать язык произношения и другие параметры.


    1. Wesha
      21.01.2016 23:02
      +1

      У них на сайте тестовый текст содержит фразы со смесью языков, вроде:

      Я один из голосов программы преобразования текста в речь IVONA. Введите фразу здесь и нажмите Play.
      Произносит без проблем.


  1. telegamochka
    21.01.2016 19:29
    +1

    Спасибо! Две недели назад как раз искала максимально качественный TTS. Пока лучшее из того, что нашла для русского языка — «Балаболка». Попробую поэкспериментировать с Ivona :)


  1. dmbreaker
    21.01.2016 21:35
    +1

    if (len(paragraph) < 1) {
    

    Скобки в Go не нужны.
    log.Printf("%v\n", paragraph)
    

    В принципе ок, особенно для скрипта. Но т.к. точно известно, что у вас строка, то быстрее будет с %s.


  1. degs
    21.01.2016 23:05
    +1

    Наступил на грабли) Для пробы скачал с lib.ru наугад стихотворение Бунина, оказалось в старинной транскрипции, с ятями. Очень неожиданное прочтение получилось. А так — действительно впечатляет, хорошее звучание и интонации естественные (я специально стихи для пробы выбрал). Пожалуй попробую себе в машину что-нибудь сделать послушать.
    Только вот извините, но хардкодить входные/выходные файлы — жуткий моветон. Я тоже go первый раз в жизни вижу, однако если вы разобрались с остальным, то узнать как передать параметры в командной строке уж совсем не проблема. Еще я не понял как оно работает с импортом модулей с гитхаба, мне пришлось руками ставить.


  1. eugenelanda
    22.01.2016 14:29
    +1

    Интересное решение, но не проще ли использовать уже готовое решение с лучшим синтезом для русского языка chitatel.pro
    Попробовать можно синтез от ЦРТ на: voicefabric.ru
    Небольшой отрывок из Достоевского: «в начале июля, в чрезвычайно жаркое время, под вечер, один молодой человек вышел из своей каморки, которую нанимал от жильцов в С — м переулке»
    Ивона: пОд вечер
    Читатель: под вЕчер

    И, ксати, к вопросу о женских голосах, рекомендую попробовать голос Юлия.


    1. zdanevich-vitaly
      24.01.2016 00:18

      Я видел эти сайты и пробовал их до написания своего скрипта — на мой вкус голос Ivona лучше. Хотя логично было бы предположить что русский синтез должен быть лучше у русских компаний вроде Яндекса или Центра Речевых Технологий, наверняка в будущем и те и те улучшат свои продукты.


      1. eugenelanda
        25.01.2016 10:52
        +1

        было бы интересно провести Mos-оценку. Синтезировать один и тот же текст Ivona и ЦРТ и выложить на голосование.


  1. Santacruz
    29.01.2016 21:12

    https://www.ivona.com/us/about-us/voice-portfolio/