こんにちは、依然としてNostrに入り浸っているひゅうがです。
ついにNostrでbotまで作ってしまいました。「へんしんbot」と「迫るショッカーbot」です。暇か。


いや、無職とはいえそこまで暇じゃないはずなんだけど。あっという間に2週間潰れちゃったよ。俺はいったい何をやっているんだ……。

以下、bot運用までの悪戦苦闘記録です。


【事の起こりはNostr本の演習】

技術書典に出されたNostrの解説書『Hello Nostr! 先住民が教えるNostrの歩き方』
この本の中に、「手を動かして学ぶ Nostrプロトコル」という項目があってですね。自分でJavaScriptでプログラムを書いてNostrリレーに投稿したり、botを動かしたりしてみよう、それによってNostrプロトコルの理解を深めよう!という「演習問題」になっている。

もちろん私はJavaScriptなんか触ったことはなく、「難しそう」「私には無理だろう」と思っていたんだけど。

フォロイーさん達が演習で作ったbotが実際に動いているのを見てるとなんだかとっても面白そうで、楽しそうで、「一からプログラムを書くわけはでなく“???”となっている部分を穴埋めするだけ」なら私にもできるのでは?とチャレンジしてみることに。


【まずは環境構築】

演習を始めるには準備が要ります。

1.Node.jsとやらをインストール
2.演習環境のGitリポジトリをクローンする
3.依存パッケージ(npm)をインストール
1は簡単。Node.js公式サイトからWindows用をダウンロードしてインストールするだけ。
2をそのままやろうとするとまず「Git」というのをインストールしなければいけない。「えー、めんどくさそう」と思っていたら「対象ファイルをZip形式でダウンロードするのもできるよ」と教えてもらい、そちらで対応。
3はすっかり素っ飛ばしていて、後から「npm入れた?」と言われて「は?npm???」となりました。

Nostr本の説明には
git clone https://github.com/XXXX/yyyyyyy.git
cd aaaa-bbbbb
npm install
を実行すること、と書いてあったんだけど、1行目の「git」の部分を使用しないから全部要らないと思い込んで、読み飛ばしてたんですねぇ。
2行目と3行目は必要なんだよ、よく見ろ! 2行目の「cd」は「チェンジディレクトリ」だ! 知ってるだろ!


【演習にとりかかるも、実行の仕方を間違える】

ともあれせっかちなひゅうが、早速演習1-1に取りかかります。秀丸エディタでコードを開いて「???」部分をなんとか穴埋めして、いざ!

しかし動かない。
うーん? なんで?? 1行目の1文字目が間違ってるってどういうこと? そんなとこいじってないぞ?


はい、賢明なる読者諸君はもうおわかりですね。ひゅうがはエクスプローラーから直接jsファイルをダブルクリックして動かそうとしていました。

違う!そうじゃない!!!

コマンドプロンプトから「node 1-1.js」と入れて実行するんです。何のためにNode.js入れたと思ってるんだ! いや、Node.jsが何なのか知らんし……。

実はちゃんとダウンロードしたファイルに「README」が入ってて、そこに「実装が完了したら、“node 1-1_fetch_posts_raw_ws.js” のようにして実行してください。」
って書いてあったんですけどね。1行も読んでなかったんですよね……。

フォロイーさんに教えてもらってやっと正しい方法で実行、でももちろんすぐには動かず、エラーが出たり、予想と違う動きをしたり。

ちなみに1-1は「リレーからWebsocketで“kind1”のデータを読み込んで、コンソールに“いわゆる投稿本文”を表示してみよう」というお題です。
うまく動くとコンソールにどんどんNostr民の投稿が表示されていく。おおおおおおお、すごい。

1-2は1-1と同じことをnostr-toolsというのを使ってやってみようというもので、んーーー? なんとなくはわかるけど、なんとなくしかわからん。
ちょっと直しては動かし、またちょっと直しては動かしを繰り返していたら2時間や3時間あっという間に溶ける。
TLの皆さんの助力を仰ぎながらなんとか1-2もクリアして、いよいよ1-3。なにが「いよいよ」かというと、演習1-3は「投稿してみよう」だからです。


【コマンドライン引数がわからない】

JavaScript全然わからないながらも、「この辺でこんなことをしている」という流れはなんとなくわかる。一から書くわけじゃなく「穴埋め」なので、「これで行けるのでは?」と思って試すのだけどなかなか動いてくれない。

文法エラーはなくなったはずなのに「投稿内容をコマンドライン引数として設定してください」というエラーが出る、何これどういうこと!? 全然わからん、むきーっ!

嘆いていると親切なNostr民が教えてくれるわけですが、「node 1-3.js 投稿内容」と入力するんだよ、と言われてもまだピンと来ない。はぁ?投稿内容?それプログラムの中に書くんでしょ、「content」のとこに。

……違ったんだよね。
中に書くんじゃないの。
「node 1-3.js なんとかかんとか」って入力して実行したら、「なんとかかんとか」の部分が「content」にセットされて、それがNostrに投稿される。

えええええ、そんなん知らんがな、聞いてへんがな!

実はこれもちゃんと「README」に書いてあった。「一部のプログラムは実行時にコマンドライン引数を渡す必要がありますのでご注意ください」って。

お ま え が 「README」 を 読 ん で な い だ け !
ま ず 「README」 を 読 め !

まぁでも読んでても「コマンドライン引数」が何のことかわからないまま、同じミスをしてたんじゃないかな。実際につまずいてみないことにはピンと来ない。
まさに「手を動かして学ぶJavaScript」。

READMEだけでなく、プログラムをよく見れば――そのエラーを出している箇所をちゃんと見ればわかるはずでもあるんだけど、1-3をやってる時にはまだまださっぱり命令文や関数の意味がわかっていなくて、本当にただ勘で穴埋めしていたので、実際の処理の順番がどうなっているかも理解しておらず。

「なんでこれ時系列順じゃないの? なんでそっちを先にするの?」と思ってた。

「どこまで合ってるか」を確かめるためにところどころ「console.log」でコンソールに「Q-1まで合ってる」と表示させてたら、順番がテレコになるところがあって、今は「なるほど」と思うけども、当時は「んんん???」だった。

何もわかってなくてもちゃんと動いて投稿できてしまう。演習プログラムの元の出来が素晴らしすぎますね、うん。

演習1-4は「誰かの投稿にリプライしてみよう」というお題。
リプライしたい「誰かの投稿」のアカウントIDとイベントIDを指定して返信するプログラム。これは比較的早く、しかも自力でクリアしたんだけど、実は「クリアできてなかった」。間違ってた。
自分でも「あれ?動いたけどなんか釈然としないな」とは思ったんだよ。思ったんだけど、「まぁいっか、次行こ!」


【はい、やっとbot作りです】

演習2に入りました。やっとbot作成&運用の部分です。
ちなみに演習1-1に取りかかったのが5月31日水曜日。1-4と2-1がたぶん6月2日金曜日。

演習2-1はbotのプロフィールを作成するお題
Nostrには「アカウント」という概念がなく、「秘密鍵と公開鍵のペア」を作って、その鍵ペアに名前を付けてリレーに流せば、それでめでたく「botの誕生」です。

鍵ペアは先ほどの「npm」というやつですぐ生成できる。いくらでも生成できる。botのためにメールアドレスだのなんだの設定する必要はありません。
なんてお手軽なんでしょうか。

botのIDは「@botV3」にしました。私(@showV3)のbotだから「V3」、演習2-2で返信できるようになる&「仮面ライダーV3」から表示名は「へんしんbot」。うん、いいんじゃないかい。

2-1ではアイコンまでは設定しないんだけど、たまたま昔描いたV3のイラストがあったので、後から設定しました。


【2-2でどつぼ。マンツーマン指導を受ける】

2-1のプロフィール設定があっさりできたので、意気揚々と2-2のソースを開いたら。

何もわからない。

えーっと、突然難易度上がってない? 2-2は「特定の単語を含む投稿に自動で“いいね”してみよう」というお題なんですが……、そして「ある文字列に指定の単語が含まれているかを判定するには、includes()メソッドを使うとよいでしょう」というヒントもちゃんと書かれてはいるんですが。

わからない、何もわからない。

「includes」の使い方をググってどうにか「指定の単語が含まれているかどうか」部分は書けた気がする、しかし動かない。動かないぞ~~~~~!

(ちなみに「includes」メソッド、「includes(調べたいデータ、検索したい文字列)」という使い方じゃなかったのでびっくりした。「調べたいデータ(が入っている変数など).includes(検索したい文字列)」という形。この「.」で繋げて色々するやり方がこう、いまだにピンときてないところある。いや、まぁほとんどのことがピンときてないけれども)

あちこちちょっとずついじって動かしてみるものの動かない。
全然“いいね”してくれない。

ううう、何が間違っとるんじゃぁぁぁぁぁぁ。

理屈(ロジック)としては「ifで引っかけて対象ポストのアカウントIDとイベントIDをセットして“いいね”ポストをリレーに流す」で、流れ自体はそもそも演習ソースに書いてあるし、「???」を埋めるだけ、埋めるだけなのに……。

うぇーんと泣いていると天の助け。
優しいフォロイーさんがマンツーマンで指導してくださり

「ここはこう」「このくだりはこう」と丁寧に一つ一つ教えてもらって、やっと、やっと。

動いたーーーーーーー!!!!!!!!

お母さん、僕のへんしんbotが動いたよ、動いた、うわぁぁぁぁぁん。

忘れもしない、6月4日日曜日の夕方。あと少しで『水星の魔女』が始まるよ、という時間に、へんしんbotは「初いいね」を遂げたのであった。

――完――


【まだだ、まだ終わらんよ!】

演習は2-3まであります。

その前に、「釈然としなかった1-4」を見返しました。マンツーマン指導のおかげで関数とか引数のことがちょっとだけ、ちょっとだけ理解できたからです。

演習1-4、「リアクション対象のアカウントIDとイベントID」をセットするところと、それを引数として受け取って実際にリプライポストを組み立てる部分とがあるんだけど、何もわからないひゅうが、力業で直にアカウントIDとイベントIDを書き込んでた。

「セットするところ」と「ポスト組み立て」のところに別々のイベントIDを書き込むと「ポスト組み立て」に書いた方のポストにリプライされる。じゃあ「セットするところ」要らんやん?と思ってたんですねぇ、ははは。

しかしここで1-4をおさらいしたことがある意味2-3で苦労する原因ではあった。

演習2-3は「自分宛てのリプライにリプライを返してみよう」というお題。1-4も「誰かの投稿にリプライ」するプログラムなので、1-4をコピーすればできるだろうと考えた。

やってみた。

動かなかった。

なんでやーーーーー、どう見ても合うてるやろーーーーーーーーーーーーー!

かなり長い時間を溶かして、「1-4じゃなくて2-2を」というヒントをもらい、まっさらな元ソースに一から2-2をコピーして実行してみたら。

あっさり動いた。

え?
なんで?
動いたの嬉しいけど釈然としない……。

後から「そーか」と気がついたんですが、1-4と2-2だとイベントの署名に使う関数が違っていて、2-3は2-2方式の関数を使っているので、1-4をコピーすると「定義されていない関数を使って署名しようとしている」になってしまう。

そんなとこ全然見てなかったよ。てかそれなら「undefined」って言ってくれればいいのに、なんで構文エラー出ないの……。


【調子に乗ってもう1つbotを作り、暴走させる】

2-3が動いたらそれで演習はおしまいなんですが。

演習を一つこなすごとにフォロイーの皆さんが「偉い」「すごい」と褒めそやして持ちあげてくださるので、ひゅうがは調子に乗ってさらに別のbotを作りました。

前述の通り、鍵ペアはいくらでも生成できます。作った鍵ペアに演習2-1でプロフィールを作ってあげれば存在自体はすぐできる。

へんしんbotが「自分宛の返信に自動で返信する」――つまり「話しかけられないと動かない」botなので、もう一つの方は「対象となるキーワードを含む投稿に勝手に返信する」botにしようと考えました。

たまたま昔描いたショッカー戦闘員の絵があったこともあり、その名も「迫るショッカーbot」。キーワードを含む投稿があると自動で「イーっ!」しに行く。

演習2-2の「特定のキーワードを含む投稿に“いいね”する」を改造すればできるはずなので、比較的すんなり動いたんですが。

動きすぎた。

いくらなんでも迫りすぎ。

「演習」という言葉を見つけたら「演習やってる、イーっ!」と返す、というふうにしたわけですよ、バカですね。そんなことしたら自分の「演習やってる」に反応してまた「イーっ!」して無限ループになる。ちょっと考えればわかるだろ! でもわかんないで動かしちゃった!!!

だだだだだだーっとコンソールにすごい勢いでログが流れて「は?」と思って慌てて止めましたが、ショッカーbot、何連続イーっ!したんだろう……。TLの皆さん、その節はすいませんでした。お騒がせしました……。

でも皆さん優しいんですよね。怒るどころか「なんぼでも暴走させたらいい」とか言ってくださったりして。
ここで「バカじゃないの?」「素人のくせに嬉しがって作るから」などと言われたら、もうbot動かすのやめよう、ってなりますもん。

「自分の投稿は除外する」ロジックを入れることでループを回避、ショッカーbotもちゃんと動くようになりました。ほっ。


【楽しいbot育て】

botたち、動くようになると大変楽しいです。そして「あんなこともさせたい」「こんなことも」と欲が出て来る。単純に「話しかけられたら返信する」「キーワードに反応しておうむ返しする」だったのを、現在進行形でちょこちょこ改修し続けています。

《ショッカーbotの進化》

・コマンドライン引数を二つ使うことによって、キーワードと返信の語句を変える。
 (キーワード「演習」を含む投稿に対して「演習やってる、イーっ!」と返すだけだったのを、「演習」に対して「プログラムやってる、イーっ!」などと返すように)
・コマンドラインで指定する以外に、デフォルトで反応するキーワードと返信の組を設定する。その際正規表現を使って「a、b、c」という語句を見つけたら「A」を返すよう、キーワードをグループ化する。
・特定のbotに反応しないよう改修。
・自分に言及されると「いいね」する機能を追加。

《へんしんbotの進化》

・乱数を使って返信文のバリエーションを6種類まで増やす。
・switch文でいちいち6パターンに場合分けしていたものを配列を使ったシンプルなものに変更。

(今後実装したい機能 ※2023/06/18夕方実装済み
・起動時に自動で何か一言投稿する機能。
・「占って」と言われたら「仮面ライダー占い」を返す機能。
両botともNIP-05認証もつけました。身元のしっかりしたショッカー戦闘員と仮面ライダーです。

ちなみに乱数の部分は図書館で借りてきたこの本を丸写し。配列の説明もわかりやすかった。

【私が動かしている間だけ動くbotたち】

botというと「サーバーに置いてあって24時間ずっと動いている」というイメージですが、もちろんひゅうがはサーバーもドメインも持っていないので、へんしんbotもショッカーbotも、「ひゅうがが自分のPCで起動している間」だけしか動いていません。

てか普通にPCで動くんだ、っていうのがまず驚きではありました。もっと大変だと思ってた。

旧Vostroちゃんの電源入れっぱなしにして、24時間botを稼働させることもできなくはないらしい。やらないけど。

思ったように動かないと泣きそうになるけど、その分動いた時の喜びは格別。「こうすればいいのでは?」と閃いてうまく行った時のエウレカ感は異常。
へんしんbotのロジック、「これ配列にすれば良くね?」と気づいた時には「最っ高でしょ、天っ才でしょ!」とつい戦兎くんになってしまったほど。

なのでもうしばらくbot育てに没頭する日々が続きそうです。
botだけに!!!(ズコーっ)

(※ちなみに両botともに日本語リレー wss://relay-jp.nostr.wirednet.jp しか読み書きしていません。botに会いたい方はぜひ日本語リレーに繋いでNostrしてくださいませ)


【関連記事】
Nostr本演習のアンチョコ(JavaScript覚え書き)~その1~
Nostr本演習のアンチョコ(JavaScript覚え書き)~その2~
Nostr本演習のアンチョコ(JavaScript覚え書き)~その3・延長戦~
Nostr本演習のアンチョコ(JavaScript覚え書き)~その4・ファイル出力とか~
Nostrで検索ツールを作った話
Nostrに手を出して時間を溶かしている話
Nostr初心者のためのFAQ【日本語ユーザーはここにいる!】
お空の色はどんな色?~Blueskyで遊んでみた~