ネイティブスピーカーなsaykanji作り

前回までのsaykanjiコマンドの能力は、漢字・仮名・英単語混じりの文章を辛うじて棒読みするレベルであった。はっきり言ってかなり不自然だ。言葉のもつアクセントはすべて無視されている。まるで、お経を読み上げるような感じ。

saykanaコマンドの性能を引き出すべく、より自然な日本語での読み上げを目指してみた!

数字の読み上げ

  • 数字をNUMKタグに変換することにした。
  • COUNTER属性を利用するため、助数詞辞書を作成した。
  • これで「10分」が「じゅっぷん」と発音される。(今までは「いちぜろふん」だった)

アクセントの付与

  • アクセント付きの読みに変換するため、発音辞書を作成した。
  • 項目は「"原文","発音"」の2項目のみ。
  • 発音は、AquesTalk音声記号列仕様書の書き方
"Rails","れ'いるず"
"準備","じゅ'んび"
"今度","こ'んど"
"もう少し","もうすこ'し"
"アクセント","あ'_クせんと"
"(","、か'っこ、"
")","、か'っこ/とじ'る、"
...

カタカナ語のアクセントのルール

  • カタカナ語の後ろから3拍目がアクセントになるルールを適用した。
コンピュ'ータ
キーボ'ード
スクリ'プト
    • NADのカタカナ英語辞書の結果を変換する場合のコード
REG_HIRA="(.*[^っー])([っー]?)([^ぁぃぅぇぉゃゅょ][ぁぃぅぇぉゃゅょ]?[^ぁぃぅぇぉゃゅょ][ぁぃぅぇぉゃゅょ]?)$"
add_accent_to()
{
  ruby -e "require 'jcode';\$KCODE='u';print('$1'.sub(/$REG_HIRA/, '\1\'\2\3'));"
}
    • 上記辞書にヒットしないカタカナ語を変換する場合のコード
REG_KATA="(.*[^ッー])([ッー]?)([^ァィゥェォャュョ][ァィゥェォャュョ]?[^ァィゥェォャュョ][ァィゥェォャュョ]?)$"
add_accent_to_if_need()
{
  ruby -e "require 'jcode';\$KCODE='u';print('$1'.sub(/$REG_KATA/, '\1\'\2\3')) if /[ァ-ンー]{3,}/=~'$1';"
}

カタカナ → ひらがな変換

  • 発音情報を全てひらがなで(saykanaに)渡した方が発音が良くなる(良きに計らってくれる)ようなので、ひらがなに変換した。
kata_to_hira()
{
  ruby -e "require 'jcode';\$KCODE='u';print('$1'.tr('ァ-ン', 'ぁ-ん'));"
}

アクセントと区切り

  • アクセントは「/」で区切る文節に1つだけ設定する必要がある。
  • もし、一文節に二つ以上のアクセントがあっても、最後のアクセントしか有効にならない。
  • アクセントを利用するためには、必然的に文章をいくつもの「/」で区切ることになる。
  • 発音辞書には品詞レベルで発音情報が登録している。
  • mecabも品詞レベルに形態素解析した結果を返してくれる。
$ <span style="font-weight:bold;">echo "日本語を話そう"|mecab -O wakati</span>
日本語 を 話そ う 
  • ところが、自然な日本語で発音するためには、主要な品詞 + 助詞類を含めた、意味の通じる単位に区切る必要がある。
にほんごを/はなそ'う
  • 最適な区切りを導き出すために、mecabコマンドはオプション無しで実行して、品詞等の詳細情報も利用することにした。
$ <span style="font-weight:bold;">echo "日本語を話そう"|mecab</span>
日本語	名詞,一般,*,*,*,*,日本語,ニホンゴ,ニホンゴ
を	助詞,格助詞,一般,*,*,*,を,ヲ,ヲ
話そ	動詞,自立,*,*,五段・サ行,未然ウ接続,話す,ハナソ,ハナソ
う	助動詞,*,*,*,不変化型,基本形,う,ウ,ウ
EOS

区切りの基本方針

  • 基本的に、助詞または助動詞で区切る。
  • アクセントがない場合は、無駄に区切らない。
  • 助詞、助動詞以外でもアクセントが連続する場合は区切る。

名詞が連続する場合の取り扱い

  • 名詞は連続すると、アクセントが後ろの単語の最初に変化する場合が多い。
速度(そ'くど)
 +
制限(せいげ'ん)
 =
速度制限(そくどせ'いげん)
  • よって、名詞が連続する場合は、例えアクセントが連続しても区切らない。
  • アクセントが連続した場合、後ろのアクセントが有効になるので、結果OK。
そくどせ'いげん = そ'くどせ'いげん

以上を踏まえたコードは...

  • 名詞が連続しない時だけ区切る処理(=名詞が連続する時は区切らない処理)
add_kugiri_if_need()
{
  if [ "$kind_stock" = '名詞,副詞可能,*,*' -o "$hinsi_stock" != '名詞' -o "$hinsi" != '名詞' ]
  then
    res="$res$kugiri"
  fi
}
  • 後に続く単語のアクセントを再設定する処理
reset_top_accent_if_need()
{
  if [ "$kind_stock" != '名詞,副詞可能,*,*' -a "$hinsi_stock" = '名詞' -a "$hinsi" = '名詞' ]
  then
    ruby -e "require 'jcode';\$KCODE='u';print(\"$1\".gsub(/\'/, '').sub(/^(.)(.*)/, '\1\'\2'));"
  fi
}

連続する助詞・助動詞の取り扱い

  • 助詞、助動詞にもアクセントが必要なときがある。
  • 多くの助詞は1文字であることが多い。
  • アクセントは助詞、助動詞が連続する時に発生する。

そこで、連続する助詞は一つのフレーズとして扱うことにした。

  • 助詞は、発音情報と関係ない( )で囲うことにした。
  • 以下の例では、(なので) が連続したフレーズとして扱われている。
$ saykanji "シンプルなスクリプトなので、"
 	記号,空白,*,*,*,*, , , 
シンプル	名詞,形容動詞語幹,*,*,*,*,シンプル,シンプル,シンプル
な	助動詞,*,*,*,特殊・ダ,体言接続,だ,ナ,ナ
スクリプト	名詞,一般,*,*,*,*,スクリプト,スクリプト,スクリプト
な	助動詞,*,*,*,特殊・ダ,体言接続,だ,ナ,ナ
ので	助詞,接続助詞,*,*,*,*,ので,ノデ,ノデ
、	記号,読点,*,*,*,*,、,、,、
EOS
 し'んぷる(な)/すくり'ぷと/(な'ので)、
  • もし、フレーズとして扱わないと、アクセント無しの"しんぷる「な」"と区別できなくて困る。

動詞,非自立,*,*の取り扱い

  • 動詞の中でも「動詞,非自立,*,*」で区別される品詞は、助動詞のような性格と感じた。

そこで、上記については助詞、助動詞と同等に扱うことにした。

句読点での区切りの取り扱い

  • 句読点「、。」= 区切り「/」+ ポーズ(無音の待機時間)である。
  • 句読点の手前に区切りが入ると、直前の音声が途切れてしまう。

そこで、句読点の手前では区切りは不要なので、強制的に排除することにした。

連体詞、感動詞

下記の品詞は独立性が高いと感じ、アクセントの有無に関わらず区切ることにした。

  • 連体詞:あらゆる、たいした
  • 感動詞:はい、もしもし、わあ

同字・同音、ところが異アクセントな場合

  • 発音辞書は、原文と発音のcsvファイル。
  • アクセントは「'」で設定する。
"理解","り'かい"  
  • 原文は漢字、ひらがな、カタカナ、英語の可能性がある。
  • 漢字の場合、複数の読みを持っている可能性がある。
  • 同じ漢字を区別する必要がある場合は、以下のように原文を「|」で区切って「読み」を続けることにした。
"中|ちゅう","ちゅう"
"中|なか","な'か"
  • 同じ漢字かつ同じ読みだが、アクセントが異なる場合がある。
  • 原文を「|」で区切って「品詞名」を続けることにした。
の気持ち
"今|名詞","い'ま'"

はやり
"今|接頭詞","いま''"

AppleScriptシェルスクリプトと日本語の正規表現について

  • シェルスクリプトからRubyを実行するときの注意。
    • require 'jcode'; $KCODE='u'を忘れずに。
    • $のエスケープが必要。
      • 関数定義の中では...
ruby -e "\$KCODE=..."
`ruby -e "\\\$KCODE=..."`

saykanjiが返す情報

  • saykanjiを実行すると、以下の情報を返すようにした。
$ saykanji "あと30分はかかりそうです。"
 	記号,空白,*,*,*,*, , , 
あと	名詞,一般,*,*,*,*,あと,アト,アト
30	名詞,数,*,*,*,*,*
分	名詞,接尾,助数詞,*,*,*,分,フン,フン
は	助詞,係助詞,*,*,*,*,は,ハ,ワ
かかり	動詞,自立,*,*,五段・ラ行,連用形,かかる,カカリ,カカリ
そう	名詞,接尾,助動詞語幹,*,*,*,そう,ソウ,ソー
です	助動詞,*,*,*,特殊・デス,基本形,です,デス,デス
。	記号,句点,*,*,*,*,。,。,。
EOS
 あ'と/(わ)/かかりそ'う(です)。
$ saykanji "速度と制限で速度制限。"
 	記号,空白,*,*,*,*, , , 
速度	名詞,一般,*,*,*,*,速度,ソクド,ソクド
と	助詞,格助詞,一般,*,*,*,と,ト,ト
制限	名詞,サ変接続,*,*,*,*,制限,セイゲン,セイゲン
で	助詞,格助詞,一般,*,*,*,で,デ,デ
速度	名詞,一般,*,*,*,*,速度,ソクド,ソクド
制限	名詞,サ変接続,*,*,*,*,制限,セイゲン,セイゲン
。	記号,句点,*,*,*,*,。,。,。
EOS
 そ'くど(と)/せいげ'ん(で)/そ'くどせ'いげん。

上記情報をもとに、不足している情報を発音辞書に追加して行けば、いつかは流暢な日本語で読み上げてくれるのではないかと期待している。

所感

  • 思うがままに条件を追加していったら、コードがグチャグチャな状態になてってしまった。
  • Rubyを使い始めたなら、シェルスクリプトは止めて、全てRubyで書き直した方が良いのではないか...。
  • 発音辞書の登録で日本語力が決まる。現在の登録単語数は300語未満。(過去3回分の日記を読み上げる過程で入力した状態)
  • 未だ、助詞のアクセントの変化には、ちゃんと対応できていない気がする。