SVX日記
2026-02-05(Thu) AIに攻略法を聞きながらゲームする
自分はロードスターでドライブする際、ボイスレコーダを携えていることが多い。気になる道路や建造物、思いついたアイデアなんかを、その場で喋って録音しておくのだ。運転中に筆記具でメモするのは難しいが、ボイスメモなら差し支えない。で、自宅に帰ったら聞き返しながらエディタに打ち込み、必要に応じて調べたり、TODOリストに入れたりするのだ。
ちなみに日本製だとこの用途に見合うボイスレコーダが見当たらない。スライドスイッチのワンアクションで録音を開始し、同じくワンアクションで完了したいだけなのだが。それとストラップホールは必須。で、アリエク。なんだかんだで手元に3つもある。紛失したり、買ってみたらワンアクションで録音できなかったりで、4つも買ってしまった。安いけど。小さいのに動画まで撮れたりするのもあるのだが、その機能はいらん。
結局「AIレコーダ」の記事は読まなかったのだが、たぶん録音した内容を文字起こしするというような内容だろう。でも、それってぜんぜんレコーダ関係ない。結局はレコーダをPCに接続して、外部AIサービスに文字起こしを依頼するのだから。そんなの簡単に作れるだろう。
すると、文字起こし専用に「audio-transcriptions API」というものがあるらしい。音声データを渡すと、文字列を返してくれる。逆に音声で読み上げてくれる「audio-speech API」というものもある。文字列を渡すと、音声データを返してくれる。
さらに画像を生成する「images-generations API」というものもある。文字列を渡すと、画像データを返してくれる。ほんじゃ、画像を説明してくれる「images-descriptions API」があるかというと……それはない。それはないが「chat API」に画像データを渡す機能ならある。釈然としないが、音声ならばその用途はほぼ文字起こしに決まっているだろうが、画像の場合には説明以外にも、文字を抜き出したり、場所を聞いたり、画像を編集したりと、目的が千差万別だかららしい。そらそうやな。
ついでにいうと「chat API」には音声データを渡す機能もある。その場合、文字起こしを依頼してもいいし、声質や曲名を聞いてもいいのだろう。要するにAIにおける音声と画像の処理には非対称性があるってことだ。
わかったところで順にライブラリに実装していく。NGSAudioTranscriptionsクラス、NGSAudioSpeechクラス、NGSImagesGenerationsクラス、そして、NGSクラスに画像や音声を渡せる機能を追加していく。
と、そこで気づいたのだが「文字起こし」と「読み上げ」ができれば、音声による指示と、音声による応答が可能になる。要するにAIと会話ができるようになるわけだ。プログラミングしながらキーボードから手を離さずにチョット聞きたい。とか……そうだ! ゲームしながらチョット攻略法を聞きたい、なんて時に使えるのではないだろうか。
ただし「文字起こし」「質問」「読み上げ」を順次行う都合から、応答速度はイマイチ。なので、最近はほぼリアルタイムな会話を実現する専用のAPIもあるらしい。んが、それを使ったらそれ以上に何の工夫もできなさそうだ。別に会話をしたいわけではないからな。
問題は、問合せを開始するトリガ。理想は「アレクサ」のように、特定の音声の発話で開始したいが、これは常時の音声認識が必要なので難しい。コマンド起動やマウス操作はうざったい。そこで、ジョイスティックのボタンをトリガにしてみた。作ってから1年位になるが、常にすぐ横に立てかけてあるので予備挙動なしで「チョン」と押せる。Rubyでの検出処理も意外と容易だった。CPU負荷なしで待機できること。コレ重要。
そして極めて都合の良いことに「ゲームしながらチョット攻略法を聞きたい」状況にも最適なわけだ。自作のジョイスティックは3ボタンなのでアーケード版のグラIIのプレイ中には使えないが、ドルアーガなら大丈夫。プレイ中は「/dev/input/js0」が排他されてしまうかと思ったらそうはならなかった。
早速、プレイ中にボタン3を押して「ドルアーガの塔の16面の宝の出し方を教えて下さい」と聞いてみる。滑舌が悪くて「ドルガーゴの塔」になってしまっているのに、キチンと「16面の宝箱は左右の外周に触れることで出現します」と音声で返ってきた。おいおいマジかよ。そこはトンチンカンな回答を返してオチをつけてくれよ。まぁURLまで発話してしまうというオチはあったけれどさ。
ライブラリには画像を生成させるAPIもあるので、30面のように「特定地点を通過する」のような出現条件の場合、画像で説明させるようにすることも可能だろう。ドラゴンバスターで出口を守っているルームガーダーの位置を聞いたりもできる。いや「/dev/input/js0」を渡しているのだから「ちょっとトイレいくんで進めといて」と、代行プレイを依頼することも……将来的には可能かもしれない。まぁ、オイラはゲーマーなので、宝の出し方も全部覚えているし、AIに頼るなんてアリエないけどな(←なんだよイマサラ)。
#!/usr/bin/env ruby
# coding: utf-8
begin
$LOAD_PATH.unshift('.', '/usr/local/lib/ruby')
require 'libngs'
require 'libjoy'
rescue LoadError
raise
end
begin
$LOAD_PATH.unshift('~', File.dirname(File.expand_path($0)))
load 'ngs.config'
rescue LoadError
raise
end
ngs = {
:CHAT => NGS.new(@configs),
:TRANSCRIBE => NGSAudioTranscriptions.new(@configs),
:SPEAK => NGSAudioSpeech.new(@configs),
}
js = JoyStick.new
loop {
puts('Press button 2 to start.'); js.gets2
thread = Thread.new {
$pid = Process.spawn('rec -c 1 -r 16000 query.wav')
}
puts('Done, press button 2.'); js.gets2
Process.kill(:INT, $pid)
thread.join
# 音声認識
fh = open('query.wav')
query = ngs[:TRANSCRIBE].transcribe(fh)
query += '50文字程度で回答をお願いします。'
puts(query)
# 問合せ
answer = ngs[:CHAT].ask(query)
puts(answer)
# 音声発声
res = ngs[:SPEAK].speak(answer)
open('answer.mp3', 'w') {|fh|
fh.write(res)
}
system('play answer.mp3')
}
__END__


