AITalk WebAPIを使ってwavを生成してs3に保存するaws lambda

LINE BOT AWARDSのハッカソンに参加した。ぷ◯きゅあがタスクの終了や寝る時間などを通知すると同時に音声合成でしゃべってくれる、という(いちおう)親子向けのBOTを作った。

LINE apiはeventに応じてwebhookが飛んでくる仕様になっているため、serverlessのアーキテクチャでシステムを作った。つまりlambda、step functionsをはじめとしたaws漬けだったのだが簡単に優れた設計のアプリが作れて僕スゴいじゃなくてawsマジすごい。

そのソースコードも公開する予定なのだが、スポンサー企業でもあったAITalkさんのAPIを呼んで音声合成したWAVEファイルをs3に保存するところは汎用性が高そうなのでgithubにrepositoryを作った。

https://github.com/Drunkar/aitalk_webapi_wav_generator_lambda

中身もいちおうここに貼っておく。めんどくさかったのは、jsのaws-sdkにはs3にファイルをアップロードする方法がなかった(rubyにはあるみたい)ので、jsのオブジェクトとしてメモリに保持した状態でputObject()することでI got Kotonaki. たぶんstreamを理解している人ならば一時ファイルとして/tmp以下に保存することなくs3にアップロードするコードが書けると思う。


var http = require("http");
var fs = require("fs");
var aws = require("aws-sdk");

var api_url = "http://webapi.aitalk.jp/webapi/v2/ttsget.php";

exports.handler = function(event, context) {
    var request_url = api_url +
        "?username=" + encodeURI(event.aitalk_username) +
        "&password=" + encodeURI(event.aitalk_password) +
        "&text=" + encodeURI(event.text) +
        "&speaker_name=" + encodeURI(event.aitalk_speaker_name) +
        "&volume=" + encodeURI(event.aitalk_volume) +
        "&speed=" + encodeURI(event.aitalk_speed) +
        "&pitch=" + encodeURI(event.aitalk_pitch) +
        "&range=" + encodeURI(event.aitalk_range) +
        "&ext=wav&use_wdic=1";

    var outFile = fs.createWriteStream("/tmp/" + event.filename);
    // start download
    http.get(request_url, function(res) {

        // output as a file
        res.pipe(outFile);

        // download end
        res.on("end", function() {
            outFile.close();

            // open the wav file as a js object and putObject to S3
            var s3 = new aws.S3();
            fs.readFile("/tmp/" + event.filename, function(err, data) {
                if (err) {
                    return console.log(err);
                }
                var params = {
                    Bucket: event.bucket,
                    Key: event.filename,
                    Body: data,
                    ContentType: "audio/wav",
                    ACL: "public-read"
                };
                s3.putObject(params, function(err, data) {
                    console.log(err, data);
                });
            });

        });
    }).on("error", function(e) {
        context.done("error", e);
    });
};

テストイベントを以下のように飛ばせばおk。


{
  "aitalk_username": "",
  "aitalk_password": "",
  "aitalk_speaker_name": "nozomi_emo",
  "aitalk_volume": "2.00",
  "aitalk_speed": "1.20",
  "aitalk_pitch": "0.90",
  "aitalk_range": "2.00",
  "text": "戦争に負けたから堕ちるのではないのだ。人間だから堕ちるのであり、生きているから堕ちるだけだ。",
  "filename": "voice.wav",
  "bucket": ""
}

Leave a Comment

Your email address will not be published. Required fields are marked *