Gaucheでも日本語を喋らせる(3)
最近のテレビは、朝30分程見ると、夜見て欲しい番組の主演者が出てきて、 どうでもいいような事を、べらべら喋ってる。
朝だけかと思うと、昼も出てきて、まだ喋ってる。ひどいのになると、夕方の けだるい時間帯にも(TV局もけだるいようで、ひたすら再放送してる)、その人が 昔出てた番組をひたすら、流している。
TVは終わったな。キー局全部だぞ。その点、12CHは、旅行とグルメに徹していて 偉いぞ。いつ、見始めて、見終わっても、後悔なんて、ちっとも無いから。
Gaucheで喋らせる、一応完成
;; say japanse (using extarnal application mecab and gsay) ;; -*- coding: utf-8 -*- ;; Usage: gosh say.scm sjis-text-file (use gauche.process) (use gauche.charconv) (define MECAB ;; wakati and yomi mode '("mecab" "--eos-format=\n" "--unk-format=\\s%m" "--node-format=\\s%pS%f[7]" )) (define ALPHA '((#\a . "えー") (#\b . "びー") (#\c . "しー") (#\d . "でー") (#\e . "いー") (#\f . "えふ") (#\g . "じー") (#\h . "えっち") (#\i . "あい") (#\j . "じぇい") (#\k . "けー") (#\l . "える") (#\m . "えむ") (#\n . "えぬ") (#\o . "おー") (#\p . "ぴー") (#\q . "きゅー") (#\r . "あーる") (#\s . "えす") (#\t . "てー") (#\u . "ゆー") (#\v . "ぶい") (#\w . "だぶる") (#\x . "えくす") (#\y . "わい") (#\z . "ぜっと") )) (define PUNCT '((#\. . "どっと") (#\/ . "すら") (#\? . "はてな") (#\: . "ころん") (#\- . "まいなす") (#\+ . "ぷらす") (#\> . "さんかくこっか") (#\@ . "あっと") (#\& . "あんど") (#\( . "かっこ") (#\) . "こっか") (#\! . "びっくり") (#\< . "さんかくかっこ") (#\$ . "だら") (#\% "ぱーせんと") (#\~ . "ちるだ") (#\* . "こめ") (#\^ . "はっと") )) (define MECABTMP "_mecab.tmp") ; Quick hack for mecab input (define (j->k str) (with-output-to-file MECABTMP (lambda () (display str))) ; (display (ces-convert str 'utf-8 'sjis)))) ; for inner debug (let1 p (run-process MECAB :input MECABTMP :output :pipe) (cdr (string-split (ces-convert (read-line (process-output p) #t) 'sjis) "\\s")))) (define (say str) (let1 for-gsay (ces-convert str 'utf-8 'sjis) (sys-putenv "AquesTalk" for-gsay) (print for-gsay) ; monitor (process-output->string `("gsay")))) (define (csub cl tbl) (string-join (map (lambda (c) (cond ((assoc (char-downcase c) tbl) => (lambda (v) (cdr v))) (else "しらないもじよー"))) cl) ",")) (define (conv li) (map (lambda (str) (let1 cl (string->list str) (cond ((char-set-contains? #[[:digit:]] (car cl)) #`"<NUMK VAL=,|str|>") ((char-set-contains? #[[:alpha:]] (car cl)) (csub cl ALPHA)) ((char-set-contains? #[[:punct:]] (car cl)) (csub cl PUNCT)) (else str)))) li)) (define (speak str) (let1 li (j->k str) (say (string-join (conv li) ",")))) (define (main args) (define (scan-line line p) (if (eof-object? line) (sys-unlink MECABTMP) (begin (print line) ; monitor (speak line) (scan-line (read-line p #t) p)))) (call-with-input-file (cadr args) (lambda (p) (scan-line (read-line p #t) p))))
使い方
上記が、say.scm とすると
c:\sakae\gsay>gosh say.scm smpl.txt 7月22日(水)に、eclispeがありました。 <NUMK VAL=7>,ツキ,<NUMK VAL=22>,ニチ,かっこ,スイ,こっか,ニ,、,いー,しー,える,あ い,えす,ぴー,いー,ガ,アリ,マシ,タ,。 次回は、イースター島で、見られます。 ジカイ,ハ,、,イースター,トウ,デ,、,ミ,ラレ,マス,。
2行づつペアになっていて、先の行は、原稿。後の行は、gsay経由で、AquesTalk に渡す データだ。これぐらいになってると、あの人でも、読めるだろう。喋りも棒読みだし。
この子は、まだひ弱です。変なものを食べさせると、即死してしまいますので、鍛えて 頂けたら幸いです。
ちょっとはまった事
最初、PUNCHの定義を、rubyっぽく
(define PUNCT '((:. . "どっと") (:/ . "すら") (:? . "はてな") (:: . "ころん") (:- . "まいなす") (:+ . "ぷらす") (:' . "くぉーと") (:@ . "あっと") (:& . "あんど") (:( . "かっこ") (:) . "こっか") (:! . "びっくり") (:# . "いげた") (:$ . "だら") (:% "ぱーせんと") (:~ . "ちるだ") (:* . "こめ") (:^ . "はっと") ))
にしてたんだ。この状態で起動すると
c:\sakae\gsay\old>gosh say.scm ../smpl.txt gosh: "read-error": Read error at "./say.scm":line 25: dot in wrong context
こんなエラーを喰らってしまう。":'" とか、":(" の部分が、お気にめさない らしい。emacsから見ると、:? は、灰色で表示され、いかにも認識しましたよって 風になるんだけど、:( の部分は、普通のテキストの扱い。
早く、手を打つべきでしたね。