適当な日本語文章を形態素解析し、英語に翻訳して音声読み上げさせる

適当な日本語文章を形態素解析し、英語に翻訳して音声読み上げさせる:

表題のままです

Elasticsearchで日本語文章をバラバラの単語に分解して、そいつを AWS Translate で翻訳。

翻訳した単語を今度は AWS Polly で読み上げさせる(音声ファイル出力)サンプルです。

環境・コードは以下に置いてます

https://github.com/satooon/elasticsearch-test

軽くリポジトリ内の説明を

elasticsearch-test 
├── README.md 
├── docker 
│   └── elasticsearch      # Elasticsearchコンテナイメージ定義 
│        ├── Dockerfile 
│        └── config 
├── docker-compose.yml     # dockerコンテナ定義 
└── php 
    ├── composer.json 
    ├── composer.lock 
    ├── composer.phar 
    └── test               # テストコードディレクトリ 
ついでにdocker-compose.ymlも

検証目的のための構成です

docker-compose.yml
version: '3' 
services: 
  elasticsearch: 
    build: ./docker/elasticsearch 
    volumes: 
    - ./docker/elasticsearch/config:/usr/share/elasticsearch/config 
    ports: 
    - 9200:9200 
    expose: 
    - 9300 
    environment: 
    - discovery.type=single-node 
    ulimits: 
      nofile: 
        soft: 65536 
        hard: 65536 
  kibana: 
    image: docker.elastic.co/kibana/kibana:6.4.2 
    depends_on: 
    - elasticsearch 
    ports: 
    - 5601:5601 
コンテナ立てた後はcomposerインストールを実行して、 .env ファイルも作成しておいてください

.env にはご自身のAWSユーザーの access_key と secret_access_key を設定してください。


Elasticsearchのアナライザの設定

日本語の形態素解析にはkuromojiを利用しますが、辞書の更新が止まっているので今回はneologdを使用します。

プラグインは docker/elasticsearch/Dockerfile 内ですでにインストールしてますので、後は設定だけです。

今回は以下のように設定しました。

curl -H 'Content-Type: application/json' -XPUT 'http://localhost:9200/neologd/?pretty' -d' 
{ 
    "settings": { 
        "index":{ 
            "analysis":{ 
                "analyzer" : { 
                    "default" : { 
                        "tokenizer" : "kuromoji_neologd_tokenizer" 
                    } 
                } 
            } 
        } 
    } 
}' 
※設定されているかの確認はkibanaで行いました


動作確認

PHPUnitでテストコードを書いてます

php/test/ElasticsearchTest.php
<?php 
 
require dirname(__DIR__) . '/vendor/autoload.php'; 
 
class ElasticsearchTest extends PHPUnit\Framework\TestCase 
{ 
    public function test_neologdA() 
    { 
        $client = new \GuzzleHttp\Client([ 
            'base_uri' => 'http://localhost:9200' 
        ]); 
        $response = $client->request('GET', '/neologd/_analyze', [ 
            'json' => ['text' => 'こんにちは世界'], 
        ]); 
 
        self::assertEquals(200, $response->getStatusCode()); 
        $expected = '{"tokens":[{"token":"こんにちは","start_offset":0,"end_offset":5,"type":"word","position":0},{"token":"世界","start_offset":5,"end_offset":7,"type":"word","position":1}]}'; 
        self::assertJsonStringEqualsJsonString($expected, $response->getBody()->getContents()); 
    } 
 
... 以下略 
『こんにちは世界』が 『こんにちは』『世界』 で別々の単語で返ってたらテストOK

で、テスト実行...

$ ./php/vendor/bin/phpunit php/test/ElasticsearchTest.php 
PHPUnit 7.4.0 by Sebastian Bergmann and contributors. 
 
....                                                                4 / 4 (100%) 
 
Time: 84 ms, Memory: 4.00MB 
 
OK (4 tests, 16 assertions) 
\(^o^)/トオタ


AWS Translate の確認

ドキュメント: Class Aws\Translate\TranslateClient | AWS SDK for PHP 3.x

php/test/TranslateTest.php
<?php 
 
require dirname(__DIR__) . '/vendor/autoload.php'; 
 
class TranslateTest extends PHPUnit\Framework\TestCase 
{ 
    public static function setUpBeforeClass() 
    { 
        parent::setUpBeforeClass(); 
 
        (new Dotenv\Dotenv(dirname(__DIR__)))->load(); 
    } 
 
... 略 ... 
 
    public function test_translateTextC() 
    { 
        $client = new \GuzzleHttp\Client([ 
            'base_uri' => 'http://localhost:9200' 
        ]); 
        $response = $client->request('GET', '/neologd/_analyze', [ 
            'json' => ['text' => 'こんにちは世界'], 
        ]); 
        self::assertEquals(200, $response->getStatusCode()); 
        $json = json_decode($response->getBody()->getContents()); 
 
        $credentials = new Aws\Credentials\Credentials( 
            getenv('aws_access_key'), 
            getenv('aws_secret_access_key') 
        ); 
        $client = new Aws\Translate\TranslateClient([ 
            'region' => 'us-east-1', 
            'version' => 'latest', 
            'credentials' => $credentials, 
        ]); 
 
        foreach ($json->tokens as $token) { 
            $result = $client->translateText([ 
                'SourceLanguageCode' => 'ja', 
                'TargetLanguageCode' => 'en', 
                'Text' => $token->token, 
            ]); 
            self::assertNotEmpty($result->get('TranslatedText')); 
            echo sprintf("\n%s => %s", $token->token, $result->get('TranslatedText')); 
        } 
    } 
} 
↓で対象の言語に翻訳

$result = $client->translateText([ 
    'SourceLanguageCode' => 'ja', 
    'TargetLanguageCode' => 'en', 
    'Text' => $token->token, 
]); 
テストを実行すると

こんにちは => Hello

世界 => World

が表示されるはず


AWS Polly の確認

ドキュメント: Class Aws\Polly\PollyClient | AWS SDK for PHP 3.x

php/test/PollyTest.php
<?php 
 
require dirname(__DIR__) . '/vendor/autoload.php'; 
 
class PollyTest extends PHPUnit\Framework\TestCase 
{ 
    public static function setUpBeforeClass() 
    { 
        parent::setUpBeforeClass(); 
 
        (new Dotenv\Dotenv(dirname(__DIR__)))->load(); 
    } 
 
... 略 ... 
 
    public function test_pollyB() 
    { 
        $client = new \GuzzleHttp\Client([ 
            'base_uri' => 'http://localhost:9200' 
        ]); 
        $response = $client->request('GET', '/neologd/_analyze', [ 
            'json' => ['text' => 'こんにちは世界'], 
        ]); 
        self::assertEquals(200, $response->getStatusCode()); 
        $json = json_decode($response->getBody()->getContents()); 
 
        $credentials = new Aws\Credentials\Credentials( 
            getenv('aws_access_key'), 
            getenv('aws_secret_access_key') 
        ); 
        $translateClient = new Aws\Translate\TranslateClient([ 
            'region' => 'us-east-1', 
            'version' => 'latest', 
            'credentials' => $credentials, 
        ]); 
        $pollyClient = new Aws\Polly\PollyClient([ 
            'region' => 'us-east-1', 
            'version' => 'latest', 
            'credentials' => $credentials, 
        ]); 
 
        foreach ($json->tokens as $token) { 
            $text = $translateClient->translateText([ 
                'SourceLanguageCode' => 'ja', 
                'TargetLanguageCode' => 'en', 
                'Text' => $token->token, 
            ]); 
            self::assertNotEmpty($text->get('TranslatedText')); 
 
            $speech = $pollyClient->synthesizeSpeech([ 
                'LanguageCode' => 'en-US', 
                'OutputFormat' => 'mp3', 
                'Text' => $text->get('TranslatedText'), 
                'TextType' => 'text', 
                'VoiceId' => 'Salli', 
            ]); 
 
            /** @var \GuzzleHttp\Psr7\Stream $stream */ 
            $stream = $speech->get('AudioStream'); 
            self::assertTrue($stream instanceof \GuzzleHttp\Psr7\Stream); 
            self::assertNotFalse(file_put_contents(sprintf("%s/test_pollyB_%s.mp3", __DIR__, $text->get('TranslatedText')), $stream)); 
        } 
    } 
} 
↓で音声に変換

$speech = $pollyClient->synthesizeSpeech([ 
    'LanguageCode' => 'en-US', 
    'OutputFormat' => 'mp3', 
    'Text' => $text->get('TranslatedText'), 
    'TextType' => 'text', 
    'VoiceId' => 'Salli', 
]); 
VoiceIdLanguageCodeで使用可能なものが決まっている模様

テストを実行するとphp/test配下にmp3ファイルが出力されるので、再生して確認



68747470733a2f2f71696974612d696d6167652d



Pollyで再生した音声はキャッシュしてる

追加コストなしで再生できるのは良い

コメント

このブログの人気の投稿

投稿時間:2021-06-17 22:08:45 RSSフィード2021-06-17 22:00 分まとめ(2089件)

投稿時間:2021-06-20 02:06:12 RSSフィード2021-06-20 02:00 分まとめ(3871件)

投稿時間:2021-06-17 05:05:34 RSSフィード2021-06-17 05:00 分まとめ(1274件)