Scrapbox ChatGPT Connector
Scrapbox ChatGPT Connectorは、ScrapboxとChatGPTを接続するためのシンプルなスクリプトです。
このスクリプトは、開発者が簡単に全体像を把握し、自分のニーズに合わせてカスタマイズできるように設計されています。またこのプロジェクトの目的は、シンプルな実装を示すことであり、多様なニーズを満たすことではありません。皆さんには、ソースコードを理解し、ご自身のニーズに合わせてカスタマイズすることをお勧めします。
インストール方法
GitHubリポジトリをcloneします。
$ git clone git@github.com:nishio/scrapbox_chatgpt_connector.git
zipでdownloadでもOK
以下のコマンドを実行して、必要なライブラリをインストールします。
$ pip install -r requirements.txt
使い方
OpenAI APIトークンを取得し、.envファイルに保存します。
.envOPENAI_API_KEY=sk-...
インデックスを作る
サンプルに入れてある tiny_sample.json
を元にインデックスが作られます
$ python make_index.py
下記のような出力が出ればOK
:% python make_index.py
100%|███████████████████████████████████████████████████| 1/1 [00:08<00:00, 8.83s/it]
質問をする
$ python ask.py
下記のような出力が出ればOK
:% python ask.py
100%|███████████████████████████████████████████████████| 7/7 [00:00<00:00, 5819.65it/s]
THINKING...
ANSWER:
>>>> Scrapbox ChatGPT Connectorって何?
> Scrapbox ChatGPT Connectorは、ScrapboxとChatGPTを接続するためのシンプルなスクリプトです。
100%|███████████████████████████████████████████████████| 7/7 [00:00<00:00, 6488.43it/s]
THINKING...
ANSWER:
>>>> クオリアさん、日本語で自己紹介して
> はじめまして、私はクオリアと申します。私は人工知能の一種で、このページの管理人でもあります。よろしくお願いします。
自分のScrapboxのデータを使う
自分のScrapboxのデータをJSONにエクスポートする
Include metadata such as line.created and line.updated.のチェックを外してExportする必要がある
コードのここの部分を書き換える
make_index.pyif __name__ == "__main__":
# Sample default arguments for update_from_scrapbox()
JSON_FILE = "from_scrapbox/tiny_sample.json"
INDEX_FILE = "tiny_sample.pickle"
update_from_scrapbox(JSON_FILE, INDEX_FILE)
ask.pyif __name__ == "__main__":
ask("Scrapbox ChatGPT Connectorって何?", "tiny_sample.pickle")
ask("クオリアさん、日本語で自己紹介して", "tiny_sample.pickle")
ライセンス
Scrapbox ChatGPT Connectorは、
MITライセンスの下で配布されています。詳細については、LICENSEファイルをご覧ください。
Ver.3に向けて
.envのサンプルを作るといい
venvを使うことを説明する?
埋め込み部分は遅い
Omoikane Embedでもっと速い実装を作ったが、置き換えるか?シンプルな今の形の方がいいか?
Ver.2 2023-03-22
小さいサンプルを追加
updated サンプルに入れてある[/qualia-san]のデータを元にインデックスが作られます
→ サンプルに入れてある
tiny_sample.json を元にインデックスが作られます
初めて試すユーザが1秒1リクエスト程度に制限されているせいで動作チェックだけで時間が掛かっていた
そこで1ページだけの小さいJSONを用意しておいた
テストの質問内容も変更した
2023/3/27 main branchにはまだtiny_sample.jsonが追加されていないが、make_index.pyではtiny_sample.jsonを使うように指定されているのでエラーが出る模様
fixed
埋め込みリクエストごとにファイルに保存していたのをやめて最後に保存する形に変更した
自分は実験過程で止めたり再開したり色々していたので前者の実装が都合が良かったのだが、大部分のユーザはそうではないので速い方が良いかと。
今までは中断をすると「たまたま書き込み中ならファイルが壊れる、リクエスト中なら壊れない」だった。developブランチにsignalのハンドラを書き換えてファイルが壊れないようにした実装も使ってみたが「理解しやすい短いコードを作る」という方針に反しているのでやめた
既存のインデックスを使ったアップデートに対応
すでに作られてる埋め込みベクトルを再度API呼び出しすることなく再利用できるようにした
askの本体を関数にくくりだして、パラメータとしてインデックスファイルを渡せるようにした
複数のインデックスから仮想人格を作って座談会などの形式をすることをやりやすくした
NEWS
2023-03-09 OpenAI APIを初めて使う人には厳しいレートリミットがかかっているので、エラーだらけになることを防ぐために1リクエストごとに1秒待つようにしました
結構時間が掛かります
リミットの掛かっていない人には関係ないので削ってもよい
差分2023-03-10 「ScrapboxとつながったChatGPTと話す経験」を早く試したい人のために
/nishioのデータで作ったインデックスを公開しました
これって、このデータをダウンロードして
$ python ask.py
だけしたらOpenAIに課金しなくても
nishio(のScrapbox)と対話できるってことですか?
学習はしなくてもいいけど、クエリ自体は課金が必要な気がする(まだそこまで行ってない…)
APIトークンを得て無料試用枠を使えば無料
1回2円くらいで、無料枠を使い切ったら課金が必要
バッチ処理したら早くなるはずだけど僕は自分のを作り終わっちゃったから今のところやるインセンティブがない
インデックス公開神!
みんなのデータが増えてきたから一つの質問を何人もに投げるとか、パネルディスカッションみたいに順繰りに回すとかをやりやすくしたくなってきた
GPT4に質問したかったのでAPIを叩かずにプロンプトをクリップボードに入れるだけのスクリプトを作った
Q&Aとか雑談
ここに何でも書いて(ユーザが加筆できるREADME面白くない?)
ver.2 released
「理解しやすい短いコードを作る」方針にそって、入力をクレンジングするコードと、参照したページの表示を削った
有用性が微妙なので〜
後者は、回答を再度embedしてそれとの類似度で並び替えた方が良いと思うが、追加の時間とコストを要求することになるのでデフォルトにすることはないかなーといあ判断
ver.1~~~
Q&Aに書くにはオフトピックな気がするので、やってみたいことやアイデアをここに書く
Q&Aではなく雑談のセクションにしたのでマージしていい?
👍
✅
「質問文で
ベクトルサーチ」ではなく「質問文の回答を一度知識0で生成させて、その回答文を元に
ベクトルサーチ」した方が精度が上がる、みたいな話をどこかでみた
>「HyDE」では文書を読ませず仮想的な応答を生成し、その応答を埋め込みにして文書を検索します。
上がりそう
要するに質問文が大体の場合は短すぎて「良い」埋め込みベクトルにならないのだと思う
埋め込みに使われるのは
Adaなのでそれほど頭良くないし
ベクトルサーチは単なる内積なので「答え」を検索するのではなく「似ているもの(関連ありそうなもの)」を検索している
一度回答文を作らせてから、それに似ているものを探すことで「ChatGPTが生成する回答文に似たことを書いている僕のScrapboxのページを参考にして回答を作る」になる
それが良いのかどうかはニーズ次第だなぁ
すでに回答が世の中にあるものに関してはそれを使えるから質が上がる
自分のScrapboxを学習させたキャラを作る上では最初にChatGPTが回答しちゃうのでそれに引きずられて「ありきたりなことばかり言うようになるのでは」が心配
これを応用して、
1. 質問文でベクトルサーチして、多少関連度高いページを元に回答させる
2. その回答を元にベクトルサーチして、もっと関連度高いページを元に回答させる
みたいな2 stepでやることで回答のクオリティ上がったりしないかな
実験
step 1
>>>> 自分の知的生産性を高めるにはどうすればいいか?
>新しい知識を生み出す能力を向上させるような知識を身につけることが必要である。他人に伝えるために、未来の自分にも理解できるような具体的な言語化とアウトプットをすることも大切である。また、生産物が時と共に価値を失わないよう、知識を生み出す能力に焦点を合わせた情報を生産することが重要である。
> [知的生産術は自分で作らねばならない] [知的生産性の向上] [知的生産] [知識労働者の生産性は計測できない] [未来の自分にわかるようにする] [KJ法の表札をいつ変更するのか] [知的生産に専念するために楽な手法を使う] [知識労働者の生産性向上] [BMOT特別授業第1回「知的生産」] [老害化しない技術が人生全体での知的生産性向上に有益]
これを元にして新しい質問をしてみた
step-2 query新しい知識を生み出す能力を向上させるような知識を身につけることが必要である。他人に伝えるために、未来の自分にも理解できるような具体的な言語化とアウトプットをすることも大切である。また、生産物が時と共に価値を失わないよう、知識を生み出す能力に焦点を合わせた情報を生産することが重要である。
ネクストアクションは?
>新しい知識を生み出す能力を向上させるために、具体的な言語化とアウトプットをすることが必要。また、知識を生み出す能力に焦点を合わせた情報を生産することが重要。これらを実践することで、生産物が時と共に価値を失わないようにすることができる。
[知識の生成と利用] [エンジニアの知的生産術を若い人に渡す] [知的生産] [Hatena2011-05-04] [未来の自分にわかるようにする] [知識の生産者] [エンジニアの知的生産術 ビフォー・アフター] [なぜ知的生産術に投資するのか]
回答は(そもそも抽象的すぎる話題のせいか)あんまり変わってないけど、参考にしてるリスト(ベクトル検索結果上位)はかなり変わってるな
やってから思ったけど質問文を変えない方が良かったか
質問文を変えないversion
step-2 query>>>> 新しい知識を生み出す能力を向上させるような知識を身につけることが必要である。他人に伝えるために、未来の自分にも理解できるような具体的な言語化とアウトプットをすることも大切である。また、生産物が時と共に価値を失わないよう、知識を生み出す能力に焦点を合わせた情報を生産することが重要である。
自分の知的生産性を高めるにはどうすればいいか?
>自分の知識の量を増やすことと、他人の知識の量を増やすことの両方が必要である。自分の知識を増やすためには、新しい知識を習得する速度を上げたり、新しい知識を発見することが重要である。他人の知識を増やすためには、教えることが資産の生産であるため、効率的に教える知識を身につけることが重要である。また、未来の自分にも理解できるような具体的な言語化とアウトプットをすることも大切である。
> [未来の自分にわかるようにする] [知的生産] [知識の生成と利用] [エンジニアの知的生産術を若い人に渡す] [なぜ知的生産術に投資するのか] [知識の生産者] [「成果に焦点を合わせた情報」の「成果」とは何] [知的生産性の向上] [ポスト資本主義社会]
step-3もやってみたけど同じ回答だった
タイムアウト
「APIを叩いてるけどタイムアウトしまくり」みたいな話、そもそも無料トライアルや、課金して48時間以内の新参者にはキツいリミット掛けられてるんだよね
Rate Limit
>
たぶんこのスクリプトで初めてChatGPT APIを試す人はこの罠にハマりまくる
一応、失敗したら1秒待ってやり直すコードにはしてあるけど、僕の環境では再現しないので試せない
無課金枠だと一瞬でrate limitに達した
>limit reached for default-global-with-image-limits in organization org-xxx on requests per min. Limit: 60 / min. Current: 70 / min. Contact support@openai.com if you continue to have issues. Please add a payment method to your account to increase your rate limit. Visit https://platform.openai.com/account/billing to add a payment method.
リクエストごとに1秒待つ挙動にしました
値段
みんなが心配するのは値段だと思う
LangChain Chatのingest.pyの処理は3000ページが15秒くらいで終わった気がする
時間かかるよねえ
どれくらい掛かるかREADMEに書きたいけど、時間測らずに放置して寝たのでどれくらい掛かるのかわからないな
テキストそれぞれAPIを叩くのではなくバルクで叩く方法があるのではと思ったんだがパッと見つけられず、とりあえず「まあ/nishioでも寝てる間に終わるからいいだろう」的な感じでリリースした
なるほど
Scrapboxが更新された時のアップデートをどうするのかも悩みどころ
この件、現状でも「キャッシュにないときだけAPIを叩く」という実装なので単純に新しいJSONと既存のpickleでやれば更新された分だけ追加される
ただし「消えたもの」もpickleには残り続けるから…
これ言葉で書くよりコードで書く方が楽だが「機能追加ではなくシンプルであることを最優先」ってポリシーには反するんだよな、どうしようかな
やっぱまとめて埋め込む方法あるっぽい
Scrapboxが更新された時のアップデートを実装したついでに、何もアップデート必要ないケースの実験をしてわかったんだけどデータをpickleで保存してるのが遅い
途中で止めた時に途中経過が失われないように毎回保存してるからw
というわけでこの保存をコメントアウトして最後に一回だけ保存するように変えたらいいと思う
類似度検索を素朴に実装しているので/nishioの39000チャンクに対して検索すると1秒に22000チャンクくらいの速度で1秒ちょい掛かる(Macbook Pro)
これの数倍大きい人は高速化を考える必要が出てくるだろうね
テキストの似ている順を計算するときにもOpenAIが利用できるというのを知った
memとかはそういう事をやっていそう
ちなみにChatGPTが4000トークンしか受け付けないので500トークンに刻んでインデックスを使ってるんだけど、埋め込みAPI自体は8000トークン取れる
僕のプロジェクトの99%のページは刻まずに埋め込める
自分のでも計算してみたい
まあ確かに実行前におおよその見積もりが出ると安心だよね
一度ベクトルを計算してしまえば、あとはOpenAIに聞く必要はないので、API利用のためのお金もかからない
既存のライブラリはTop KのKが固定のものばっかりで、僕はChatGPT APIの上限いっぱいまで詰め込みたかったので自前実装にしました
チャンクの結合機能はありません、今のところつける気もありません
その場合「一番関係あるところ」でスタートして、関係がだんだん減っていく流れをコンテキストとして与えることになる
逆では?
一番関係あるところで終わる流れを与えた方がいいのでは?
「前に読むのと後ろに読むのとどっちがいいかな?」と周囲を見て判断した方がいい?
理想を言うとスライドウィンドウの中で最も関連度の高いものを選ぶのが良さそうな
Scrapboxの構造を踏まえたインデックス作成について
✅長いページは500トークン弱(行単位)で区切り、
✅検索時に同じページから複数取らないようにする
…という感じの設計思想です
500トークンのチャンクは50%ずつオーバーラップしている、これがスライディングウィンドウに相当する
類似度が高いものばかり取って共通点が多くなったらイマイチだから、同じページからいくつも取らない
一つのページからはベストな500トークンだけを取り出す
AIに「関係のありそうないくつものページを読んで考える」という活動をさせている
対象がScrapboxでない場合(例えば一冊の書籍とか)の場合には、オーバーラップしないように選んでからドキュメント内位置でソートするとかがいいかな
内積を使ってる点に関して
>OpenAI embeddings are normalized to length 1, which means that:
> Cosine similarity can be computed slightly faster using just a dot product
> Cosine similarity and Euclidean distance will result in the identical rankings --- doc
区別する意味はない
>gpt-3.5-turbo $0.002 / 1K tokens
Embeddingはこっちかな?
Yes
対話的にやり取りできるようにしてみたい
Q&A以外が結構混じっていたので切り出した
試してみた (Windows環境)
Pythonを入れてなかったのでインストールから
インデックスができるまで待機中
終わっていた
うまく動いた
めちゃくちゃ楽しいな......
これって毎回、ask.pyを編集しててるけどそれよりいい方法あります?
「いい方法」はニーズによって決まるので、例えば上記のような方法が使いやすいならそうしてもいい
僕はVSCodeの画面分割でコードとターミナルが一画面に並んでる状態にしてる
ターミナルのコマンド引数で質問文を取るスタイルだとこういう複数行の入力が試しづらくなると思う
サーバを用意するのが面倒でなければUserScriptで呼び出せるAPIを作ると良いと思う
UserScriptの案
Herokuの無料枠がなくなった的な話を聞いたけど今だと何がいいのかな?
この件、UserScriptにAPIサーバの情報を書いてしまうと誰でも呼び出せてしまうと気づいた
APIサーバをローカルで建てるか
そんなことをしなくてもAPIキーをlocalstorageに入れれば良い
しかしそれ以外の問題がたくさんあった
自分が書いていないことを新しく考えさせたい
> >>>> ParallelTalkというプロダクトの概要を説明した上で、より独創的なプロダクト名を10個挙げてください。
> > ParallelTalkは、非ターン制の音声コミュニケーションツールであり、将来的には様々なメディアの半同期的コミュニケーションを目指している。独創的なプロダクト名の例:1. SyncSphere 2. TimeWarp 3. CoSync 4. MetaComm 5. FlowTalk 6. Synapse 7. TimeBlend 8. MindMeld 9. SyncHive 10. TimeEcho
いくつか普通に好きなのあるな
> >>>> ParallelTalkというプロダクトの概要を説明した上で、プロダクトの課題を挙げてください。
> > ParallelTalkは、時間を超越した存在のためのコミュニケーションツールであり、同期と非同期の間にある時間共有のあり方を目指している。課題としては、コミュニケーションが本当に成立するかどうか不明であり、実装方法や音声配信などの技術的な問題もある。また、時間軸のannotationが必要であり、人間の労働力と自然言語処理の両方が必要とされている。
回答は完璧だけど、全部自分が考えたこと
新しく考えさせるにはどうすれば良いのだろう
Promptいじくり回していればできそう
AIクオリアさんでは「Say your opinion」ってやってる
「Aiは自分の意見持てないので無理」と言ってくるので、これを突破する必要がありそう
あー、そうなんだ、クオリアさんでそんなことになったことがない
「あなたは何々です」の役割指定が機能してるのか?
ある質問に対してthe text does not provide a specific answer to this questionばっかり言う
ハルシネーション対策でAIが想像でものを書かないようにチューニングされて、想像力を失ってしまったのか
「もっと自由に書け」ってパラメータが欲しいなぁ
2 stepでやらせたら出来た
> >>>> 1. Summarize issue about ParallelTalk. 2. Think and explain issues of ParallelTalk not written in the text. Say something unique, not only cliches.
「最初に文章に書かれていることを言わせて、その後にそれ以外の事を言わせる」のが上手くいった
> 1. The issue with ParallelTalk is the need to create an interface that allows for semi-synchronous communication using elastic synchronization and annotations on a virtual timeline. The goal is to create an environment where pseudo-synchronous and synchronous communication can coexist. The implementation of this interface is still uncertain, and there are concerns about smooth branch branching and the ability to add audio later. The text also mentions previous research on computer-mediated communication and the use of CRDTs to address conflicts in parallel communication.
> 2. One potential issue with ParallelTalk could be the difficulty in achieving a balance between synchronous and pseudo-synchronous communication. It may be challenging to create an interface that allows for both types of communication to coexist without causing confusion or frustration for users. Additionally, there may be concerns about the privacy and security of the communication, especially if it involves sensitive or confidential information. Another issue could be the potential for miscommunication or misunderstandings due to the lack of nonverbal cues in virtual communication.
おお、これは普通に良いこと言ってるな
自分が書いたことがないことを言い出しているので、普通に有益だ
仕組み解説
>全くわからない。「埋め込みベクトル」「クエリー」「ベクトル」「ベクトル検索」あたり
描いた
たすかります
>自然言語処理(NLP)における一連の言語モデリングおよび特徴学習手法の総称であり、単語や語句が実ベクトル空間上に位置づけられる。単語の数だけの次元を持つ空間から、はるかに低い次元を持つ連続ベクトル空間へと数学的な埋め込みが行われる
そう。1トークン1万種類くらいあるので、8000トークンの文字列は8000万次元空間の点とみなせるわけだが、これをたった1000次元程度の空間にギュッと詰め込んでしまうのが「埋め込み」
自分も理解できてないので図を見てふわっと考えてみる
質問だけだとChatGPTはあまりその内容を理解してくれないのでそれを補強しようという試み?
どう補強するかと言うと、短い質問を膨らませた上でChatGPTに問い合わせる
どう膨らませると言うとあるScrapboxプロジェクトに記載された文書で、今回の質問と類似したものも一緒に質問とする
合ってるのだろうか?
「あまり内容を理解してくれない」というよりも、知ってて欲しいことを知らない
ChatGPTの学習時に使われていないデータを参考資料としてプロンプトに含めることで「これを読んで答えて」ができる
そうするとChatGPTにできない下記のデータを参考にしたやり取りができる
学習時に存在しなかった最新の情報
電子書籍などの著作権的にインターネット上でアクセス可能にできないデータ
グループウェアの中の顧客コンタクト履歴のデータなど社外に公開できないもの
なるほど
「この質問に回答してください。なお、回答の生成に利用するデータに、このScrapboxの内容も含んで良いです」といったことをやっているのか
似てる順Textが用意できるならOpenAPIを利用せずとも似たような仕組みが作れるということだろうか?
意味を加味したテキスト類似度を出すのって大変だろうからOpenAPIを使うのは妥当だとは思いつつ、理解のために質問
できる
「似てる順」である必然性はないので、例えばScrapboxのURLを渡して「このページと関連リンクのページを更新順に読んで」でもいい
そうすると人間がScrapboxのリンクによって明示した「関連」を使って参考にする文章を選ぶようになる
英語ブログの要約RSS生成の仕組みに関連した話だと、例えばRSSの新着全部がChatGPTの4000トークンに収まるなら、全部を読ませて「最近何がホットな話題?」とか聞くことができるけど、4000トークンを超えてくると何らかの方法で選抜することが必要になる。この選抜の方法はいろいろあり得るけど、その一つの方法として埋め込みベクトルの類似度を使う方法があるというだけの話
「埋め込みベクトルの類似度を使う」はテキストの情報しか使わないのでテキストならなんでも使える、対象のデータ構造の知識があればもっと工夫のしようがある
対象テキストが日本語であるなら、日本語の得意なモデルを使うのもあり
これはプロンプトを相当工夫しなきゃいけない、ということですか?
たとえば
「今与えたjsonファイルの仕様を説明します。pagesにpageという概念がn件入っています。pageという概念は……」「Scrapboxでは []
で囲った文字列をリンクとして扱います。リンクとは……」みたいな感じで読み方を説明していく
Scrapboxのjsonを解析するコードを与えた上で、「このコードから、今与えたjsonファイルの仕様を理解しなさい」みたいな命令を与える etc
そもそもChatGPTは4000トークンしか読めないのでScrapboxからエクスポートしたJSONを直接読ませることは不可能
プロンプトで頑張るのではなく、Pythonとかで「読む対象を選ぶコード」を書いて、選んでからChatGPTに渡す必要がある
なるほど!
OpenAIが提供しているAPIの中にEmbedding APIと、ChatGPT APIがある
そこの区別が曖昧なせいで混乱したのだと思う
これでした。二つあったのか
OpenAI APIの仕様が「埋め込みベクトルのみ受け付けられる」になっている はFalse
どっちのAPIも自然言語しか受け取らない
>「俺のsta.json 26MBを全部与える」ことはできるのか?
小分けにしてEmbedding APIに全部与える
この結果を使って26MBの中から厳選したものをChatGPT APIに与える
(mizchi)
chatgpt に任意のドキュメントを調べさせる方法、これで理解あってる?
事前に関連資料群を embedding APIで検索ベクトル化
プロンプトも一旦検索ベクトル化して↑の文書群とのコサイン類似度で近いものを列挙
最終的なプロンプトとして関連ドキュメントをテキストとして埋め込んで実行
(自分の最初の理解だった)検索エンジン作るのと何が違うかというと、word2vec 的な?検索ベクトル作る作業を OpenAI のモデル側で行ってて、自分で検索エンジン作るのと違って、文書の発見はそのコサイン類似度を使えばいいと最初から手段が示されてる
ただそれらすべて8192トークン内で済ませるテクニックみたいなもので、今変なテクニックを頑張って覚えなくても有料APIの拡充等で普通にやれそうな気配もあるな
(nishio)
検索がベクトル検索であるかどうかはChatGPTと無関係なので「手前に検索エンジン作る」の理解で良いように思う。例えば社内に顧客とのコンタクト履歴DBがある場合に、顧客IDで検索してプロンプトに積めばChatGPTは過去のコンタクト履歴を踏まえた回答ができるようになる。本質的にはそういう仕組み
ベクトル検索は文字列の完全一致で検索する従来の検索と違って表記揺れなどに強いなどの特徴がある「新しい検索」で、それ自体が独立でChatGPTと無関係に価値のある技術。
これは未来の普通かな
この記事が2019年だから埋め込みベクトルの類似度に基づく検索がChatGPTのためのハックではなくChatGPTより前からある技術だということは明らか
てっきり、ベクトルそのままChatGPTにわたすのかと思ってたが違うのか
そう考えると、どちらかというとChatGPT側のほうが、前段の検索結果のテキストから欲しい内容を説明させるグルーコード(コード?)的な役割だな
体験談
別の実装
Discord
関連話題
Scrapbox ChatGPT Connector
過去のブログとかTwitterとかも全部ChatGPTに食わせたいなと思ったけどScrapboxにぶちこめばいいのか
(ver.1)これを呼ぶたびに追加されるだけなのでScrapboxを介さずに直接追加してもいいよ
Githubなるほど