Pull to refresh

Comments 36

UFO just landed and posted this here
UFO just landed and posted this here
Я имел в виду можете ли вы дать линк на Ютуб например который говорит именно тем голосом который вам больше всего нравится?
UFO just landed and posted this here
Попробуйте ту же Татьяну из Ivona, можете приятно удивиться. Когда-то сравнивали как раз на книгах, и голоса от Nuance заметно им проигрывали, особенно в витиеватой художественной литературе. В т.ч. на телефоне неплохо работает.
UFO just landed and posted this here
Мне мужские голоса в любом синтезе кажутся гораздо лучше…
Попробовал Ивону. Таки да, мужской голос лучше.

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

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

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

И стоит берёза
В сонной тишине,
И горят снежинки
В золотом огне.
Это мой первый 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)
	}
}


diff
4d3
< 	"fmt"
5a5,8
> 
> 	"bufio"
> 	"flag"
> 	"fmt"
7a11,12
> 	"os"
> 	"path/filepath"
10a16,22
> 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")
> 
12,15c24,32
< 	client := ivona.New("GDNAICTDMLSLU5426OAA", "2qUFTF8ZF9wqy7xoGBY+YXLEu+M2Qqalf/pSrd9m")
< 	text, err := ioutil.ReadFile("/home/vitaly/Desktop/test.txt")
< 	if err != nil {
< 		log.Fatal(err)
---
> 	flag.Parse()
> 
> 	conf := os.Stdin // если нет конфига, но читаем стандартный ввод
> 	if *textFile != "" {
> 		conf, err := os.Open(*textFile)
> 		if err != nil {
> 			log.Fatal(err)
> 		}
> 		defer conf.Close()
18,21c35,39
< 	arrayOfParagraphs := strings.Split(string(text), "\n")
< 	i := 0
< 	for _, paragraph := range arrayOfParagraphs {
< 		if len(paragraph) < 4 { // against empty lines
---
> 	client := ivona.New(*key, *secret)
> 	scanner := bufio.NewScanner(conf)
> 	for i := 1; scanner.Scan(); i++ {
> 		paragraph := strings.TrimSpace(scanner.Text())
> 		if paragraph == "" { // пропускаем пустые строки
24c42,43
< 		log.Printf("%v\n", paragraph)
---
> 		log.Printf("process: %v\n", paragraph)
> 
29a49
> 
35,37c55,63
< 		i++
< 		file := fmt.Sprintf("/home/vitaly/Desktop/ivona/tts%04d.ogg", i) // files like 0001.ogg
< 		ioutil.WriteFile(file, r.Audio, 0644)
---
> 		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)

у вас только конфиг из файла никогда читаться не будет
И правда. Вот фикс:
	var err error
	if *textFile != "" {
		conf, err = os.Open(*textFile)
Только Go всё-таки не скриптовый язык.
Сам сейчас периодически пользую go
и как ни странно, как скриптовый, это позволяет наличие большого количества либ. Да и запуск не такой уж и долгий. Хотя конечно лучше собирать. Но для изучения подойдет и просто go run
Тогда ждём статьи про C-скрипты, чего уж…
Вы удивитесь — 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.
С Go можно даже так
//usr/bin/go run $0 $@; exit $?
package main

import "fmt"

func main() {
	fmt.Println("Hello world!")
}


Однако, по моему разумению, слово скрипт указывает на скриптовый язык.
Зачем конвертировать если можно сразу читать голосом? На андроиде это умеют многие приложения, например fbreader. На iOS и того проще — чтение текста встроенная системная функция, можно активировать в настройках чтение (в любой программе) по двойному свайпу сверху вниз.
Голос так себе, не знаю почему автор его выбрал, есть получше (имею в виду русский)
Спасибо за IVONA, не слышал. Наличие Java API радует, заберу к себе в умный дом
Умеют ли современные синтезаторы речи решать проблему с е/ё?
Попробовал скрипт автора, и могу сказать что в опробованной книге кусочек из фразы: «Я и осел здесь, чтобы отвязаться от вас.» слово осел было прочитано как осёл. Т.е. проблему вроде как решают, но местами неправильно
У меня возник вопрос, а если в тексте встречается предложение в котором есть и русский текст и английский?
Один будет в пролете?
Будет прочитан весь текст, но не факт, что произношение будет правильным. У API Ivona есть возможность задавать лексиконы, которые позволяют подстроить произношение слова/фразы или произнести сокращения полностью. Я думаю, этим механизмом можно воспользоваться для подобных случаев.
Не знаю, как в Ivona, а в RHVoice, который я использовала с «Балаболкой», есть возмощность XML-тегами переключать язык произношения и другие параметры.
У них на сайте тестовый текст содержит фразы со смесью языков, вроде:
Я один из голосов программы преобразования текста в речь IVONA. Введите фразу здесь и нажмите Play.
Произносит без проблем.
Спасибо! Две недели назад как раз искала максимально качественный TTS. Пока лучшее из того, что нашла для русского языка — «Балаболка». Попробую поэкспериментировать с Ivona :)
if (len(paragraph) < 1) {

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

В принципе ок, особенно для скрипта. Но т.к. точно известно, что у вас строка, то быстрее будет с %s.
Наступил на грабли) Для пробы скачал с lib.ru наугад стихотворение Бунина, оказалось в старинной транскрипции, с ятями. Очень неожиданное прочтение получилось. А так — действительно впечатляет, хорошее звучание и интонации естественные (я специально стихи для пробы выбрал). Пожалуй попробую себе в машину что-нибудь сделать послушать.
Только вот извините, но хардкодить входные/выходные файлы — жуткий моветон. Я тоже go первый раз в жизни вижу, однако если вы разобрались с остальным, то узнать как передать параметры в командной строке уж совсем не проблема. Еще я не понял как оно работает с импортом модулей с гитхаба, мне пришлось руками ставить.
Интересное решение, но не проще ли использовать уже готовое решение с лучшим синтезом для русского языка chitatel.pro
Попробовать можно синтез от ЦРТ на: voicefabric.ru
Небольшой отрывок из Достоевского: «в начале июля, в чрезвычайно жаркое время, под вечер, один молодой человек вышел из своей каморки, которую нанимал от жильцов в С — м переулке»
Ивона: пОд вечер
Читатель: под вЕчер

И, ксати, к вопросу о женских голосах, рекомендую попробовать голос Юлия.
Я видел эти сайты и пробовал их до написания своего скрипта — на мой вкус голос Ivona лучше. Хотя логично было бы предположить что русский синтез должен быть лучше у русских компаний вроде Яндекса или Центра Речевых Технологий, наверняка в будущем и те и те улучшат свои продукты.
было бы интересно провести Mos-оценку. Синтезировать один и тот же текст Ivona и ЦРТ и выложить на голосование.
Да тут и сравнивать нечего, Ivona пока вне конкуренции
Sign up to leave a comment.

Articles