これまではAquestalkで音声合成するためのテキストデータを直接記述していましたが、これではtwitter等からとってきた任意のテキストを喋らせられませんので、自動的に通常の日本語テキストをAquestalk用のテキストに変換する方法を考えてみました。本家のサイトには日本語テキストを変換してくれるWebサービスがありますが、これはブラウザからしか使ってはいけない、と書いてありましたので、自前で作ることにしました。
ざっくりとした流れとしては、mecabで形態素解析(辞書はnaist-jdicを使用)して、得られた各単語の読み仮名(カタカナ)をAquestalk用の文字に変換(ローマ字に変換する処理に近い)、です。下記がそのモジュールのソースです。mecabはサーバ上にインストールされているものを使用しますが、coffeescriptから利用するためにmecab-asyncというモジュールを使わせていただきました(同期実行しています)。Aquestalk picoのローマ字に変換する部分はここを参考に実装しました。アクセント句とかアクセントの位置とかはどう付ければいいのかまだわかっていないので、対応できていません。あと、数字とかアルファベットで書かれた名称等はmecabで変換できないので、現在のところは「ピー」で置き換えてます。
Mecab = require 'mecab-async'
class RomanGenerator
constructor: ->
@dmap = {}
@maxlen = 0
put: (kana, alpha) ->
@dmap[kana] = alpha.toLowerCase()
if kana.length > @maxlen
@maxlen = kana.length
setup: ->
@dmap = {}
@put("ア", "A")
@put("イ", "I")
@put("ウ", "U")
@put("エ", "E")
@put("オ", "O")
@put("カ", "KA")
@put("キ", "KI")
@put("ク", "KU")
@put("ケ", "KE")
@put("コ", "KO")
@put("サ", "SA")
@put("シ", "SHI")
@put("ス", "SU")
@put("セ", "SE")
@put("ソ", "SO")
@put("タ", "TA")
@put("チ", "CHI")
@put("ツ", "TU")
@put("テ", "TE")
@put("ト", "TO")
@put("ナ", "NA")
@put("ニ", "NI")
@put("ヌ", "NU")
@put("ネ", "NE")
@put("ノ", "NO")
@put("ハ", "HA")
@put("ヒ", "HI")
@put("フ", "FU")
@put("ヘ", "HE")
@put("ホ", "HO")
@put("マ", "MA")
@put("ミ", "MI")
@put("ム", "MU")
@put("メ", "ME")
@put("モ", "MO")
@put("ヤ", "YA")
@put("ユ", "YU")
@put("ヨ", "YO")
@put("ラ", "RA")
@put("リ", "RI")
@put("ル", "RU")
@put("レ", "RE")
@put("ロ", "RO")
@put("ワ", "WA")
@put("ヲ", "WO")
@put("ン", "NN")
@put("ガ", "GA")
@put("ギ", "GI")
@put("グ", "GU")
@put("ゲ", "GE")
@put("ゴ", "GO")
@put("ザ", "ZA")
@put("ジ", "ZI")
@put("ズ", "ZU")
@put("ゼ", "ZE")
@put("ゾ", "ZO")
@put("ダ", "DA")
@put("ヂ", "DI")
@put("ヅ", "DU")
@put("デ", "DE")
@put("ド", "DO")
@put("バ", "BA")
@put("ビ", "BI")
@put("ブ", "BU")
@put("ベ", "BE")
@put("ボ", "BO")
@put("パ", "PA")
@put("ピ", "PI")
@put("プ", "PU")
@put("ペ", "PE")
@put("ポ", "PO")
@put("キャ", "KYA")
@put("キュ", "KYU")
@put("キョ", "KYO")
@put("シャ", "SYA")
@put("シュ", "SYU")
@put("ショ", "SYO")
@put("チャ", "TYA")
@put("チュ", "TYU")
@put("チョ", "TYO")
@put("ニャ", "NYA")
@put("ニュ", "NYU")
@put("ニョ", "NYO")
@put("ヒャ", "HYA")
@put("ヒュ", "HYU")
@put("ヒョ", "HYO")
@put("リャ", "RYA")
@put("リュ", "RYU")
@put("リョ", "RYO")
@put("ギャ", "GYA")
@put("ギュ", "GYU")
@put("ギョ", "GYO")
@put("ジャ", "ZYA")
@put("ジュ", "ZYU")
@put("ジョ", "ZYO")
@put("ヂャ", "DYA")
@put("ヂュ", "DYU")
@put("ヂョ", "DYO")
@put("ビャ", "BYA")
@put("ビュ", "BYU")
@put("ビョ", "BYO")
@put("ピャ", "PYA")
@put("ピュ", "PYU")
@put("ピョ", "PYO")
@put("ッカ", "KKA")
@put("ッキ", "KKI")
@put("ック", "KKU")
@put("ッケ", "KKE")
@put("ッコ", "KKO")
@put("ッサ", "SSA")
@put("ッシ", "SSI")
@put("ッス", "SSU")
@put("ッセ", "SSE")
@put("ッソ", "SSO")
@put("ッタ", "TTA")
@put("ッチ", "CCHI")
@put("ッツ", "TTSU")
@put("ッテ", "TTE")
@put("ット", "TTO")
@put("ッパ", "PPA")
@put("ッピ", "PPI")
@put("ップ", "PPU")
@put("ッペ", "PPE")
@put("ッポ", "PPO")
@put("ッキャ", "KKYA")
@put("ッキュ", "KKYU")
@put("ッキョ", "KKYO")
@put("ッシャ", "SSHA")
@put("ッシュ", "SSHU")
@put("ッショ", "SSHO")
@put("ッチャ", "CCHA")
@put("ッチュ", "CCHU")
@put("ッチョ", "CCHO")
@put("ー", "-")
@put("?", "?")
@put("。", ".")
@put("、", ",")
@put("-", ",")
trans: (str) ->
out_str = ""
in_str = str
while in_str.length > 0
l = Math.min in_str.length, @maxlen
while l > 0
k = in_str.substring 0, l
if k in Object.keys(@dmap)
out_str = out_str + @dmap[k]
in_str = in_str.substr l
break
l--
if l == 0
console.log "変換不可:" + in_str
return false
out_str
rgen = new RomanGenerator()
rgen.setup()
mecab = new Mecab()
Mecab.command = "mecab -d /usr/local/lib/mecab/dic/naist-jdic/"
module.exports.textToAques = (str) ->
res = mecab.parseSync str
sentence = ""
for token in res
if typeof token[9] != "undefined"
sentence += token[9]
else
sentence += "ピー"
rgen.trans sentence