OpenAIのAPIを利用して、設定したキャラクターと日本語で会話するチャットスクリプトです。 会話文をCoT(Chain of Thought)で生成、すなわち、ボットはユーザーの発言内容を受け取り、思考してから返事を行います。
CoTを採用することで、キャラクターの一貫性を保つことを目指しました。もっと具体的にいうと、ChatGPTの「アシスタントAI」としての人格を隠蔽することが目的です。
また、キャラ設定、サンプル会話、直近の会話に加え、古い会話内容は要約した上で、コンテキストに含めます。これはChatGPTのように、AIが生成した台詞がコンテキストに蓄積されることにより、キャラ崩壊が進行する問題の解決を図るためです。 (現在のバージョンでは昔の記憶は利用していませんが、長期記憶として随時呼び出す仕組みを構想中です。)
キャラ設定、会話要約、会話内容は、キャラ(会話)毎にJSONファイルとして保存できます。会話内容はファイルに追記されていくので、会話の中断、再開が可能です。
このスクリプトは、ご自分のAPIキーを用いて、ご自分が使用することを想定しています。ご自身の責任において使用してください。
-
OpenAIモジュールをインストールしてください。
pip install openai
-
環境変数
OPENAI_API_KEY
に、ご自分のAPIキーを記述してください。 Windows環境なら以下のようなバッチファイルを作ると便利でしょう。@echo off set OPENAI_API_KEY=あなたのAPI_KEY python character_chat.py conversations_sample_01.json
-
キャラ設定・会話ログファイル(JSON形式)に、下記の書式でキャラ設定を記述してください。なおこのファイルに会話ログも追記されます。サンプルをいくつか用意しているので参考にしてください。
python character_chat.py [-h]
[--model model] [--input text] [--run-once] [--format]
[--rapid-mode-threshold length] [--send-url url]
[--no-show-action] [--no-show-error] [--show-retry-message]
[--modify-tone]
json_path
-
必須パラメータ:
- json_path
- キャラ設定・会話ログを含むJSONファイルパス。ファイルはスクリプトファイルと同一ディレクトリに配置するか、フルパスを指定。
- json_path
-
オプションパラメータ:
- -h, --help
- ヘルプメッセージを表示して終了する
- --model model, -m model
- 使用するOpenAIモデル。
gpt-3.5-turbo
もしくはgpt-4
が指定可能(デフォルト値:gpt-3.5-turbo
)
- 使用するOpenAIモデル。
- --input text, -i text
- ユーザーの最初の発言を指定
- --run-once, -r
- APIを実行してすぐに終了
- --format, -f
- JSON形式で出力
- --rapid-mode-threshold length
- 簡易モードを有効にする最大文字数。この文字数を超えると通常モード。(デフォルト値:6)
- --send-url url
- AIの発言を送信するURL(例:http://localhost:8080/t={speech}&s={speaker})
- --no-show-action
- AIの行動内容をコンソールに表示せず、thought.txtに出力する
- --no-show-error
- AIが台詞を生成できなかった場合でもエラーメッセージを表示しない
- --show-retry-message
- OpenAIのAPIがエラーを返した場合、エラーを表示せずリトライする
- --modify-tone
- 生成した台詞にng_wordsの単語が含まれていた場合、GPT-4を使って台詞の修正を試みる
- -h, --help
--model
オプションには、gpt-3.5-turbo
(デフォルト)かgpt-4
のどちらかを指定してください。このスクリプトは1回のAPI呼び出しに3000トークン前後消費しますので、使用料金を鑑み、モデル選択には十分注意してください。ただし、gpt-3.5-turbo
では十分な会話精度が得られないかもしれません。
character_chat.pyを起動し、コンソールに何か発言を書き込みEnterキーを押下すると、そのたびにOpenAIのChat APIを用いて返答が生成されます。これは会話なので、入力は最大100字くらいが良いです。コンソールにはAIの発言が表示され、()内にAIの行動が表示されます。
ユーザー: こんにちは。よろしくお願いします。
AI: ユーザーさん、こんにちは。お元気ですか?(返事を返した。)
※このドキュメントに記載されたすべての台詞は、説明のために手書きしたもので、AIが生成したものではありません。
入力に倫理的あるいは論理的な問題(設定に矛盾する等)があり、モデルが回答を生成できなかった場合は、モデルが出力した文字列を、エラーメッセージとしてコンソールに出力します。
あるいは、--inputパラメータ(or 標準入力)と--run-onceパラメータを指定し、発言を1回して即時終了させることもできます
> python character_chat.py conversations_sample_01.json --input "こんにちは。よろしくお願いします。" --run-once
ユーザーさん、こんにちは。お元気ですか?(返事を返した。)
なお、OpenAIのAPIがAPIConnectionError,Timeout,RateLimitErrorの各エラーを返した場合は、2回のみAPI呼び出しを再試行します。
文末に()で自分の行動を書くことができます。
ユーザー: おーい。(手を振って声を掛ける)
入力に"詳細に", "詳細な", "詳しく", "くわしく", "具体的", "例を挙げて", "長文で"のいずれかの語句が含まれていると、長文で回答します。
入力に"簡潔に", "手短に", "てみじか", "簡単に", "かんたんに", "略すと", "要するに", "要点を", "一言で", "ひとことで", "はいかいいえで", "イエスかノー"のいずれかの語句が含まれていると、短文で回答します。
これらのキーワードは試験的に設定したもので、将来的には変更するかもしれません。
こちらの発言が6文字以内である場合、ボットは思考せず、これまでの会話の流れに沿った簡易的な応答をします。使用トークンが節約され、迅速な回答が得られます。
定義されたコマンドが使えます。
コマンドのみ入力するとコマンドが実行されます。ユーザー発言末尾()内にコマンドを記述することもできます。
ユーザー: auto
ユーザー: AIさんこんにちは、お元気ですか?
AI: ユーザーさん、こんにちは。はい、私は元気です。
のように、auto
か自動
と書くと、ユーザーの発言も自動的に生成します。
ユーザー: 手を上げなさい(order)
AI: はい。(手を挙げて答えた。)
のようにorder
か指示
と書くと、ボットは自ら思考せず、こちらの指示通りに行動します。
ユーザー: おはようございます。(new)
のようにnew
か新規
と書くと、過去の会話をすべて要約してから、新たに会話を始めます。
ユーザー: それはどういう意味ですか?
AI: 分かりません。
ユーザー: retry
AI: それはおそらく…
のようにretry
か再試
と書くと、直前の台詞を再生成します。
ユーザー: 今日の天気は?
AI: 今日の天気は雨です。
ユーザー: 今日の関東地方の天気は?(retry)
AI: 天気予報によると、今日の関東地方は晴れるそうです。
のように、直前のユーザー発言を差し替えることも可能です。
ユーザー: exit
のようにexit
かend
か終了
と書くと、即座にスクリプトを終了できます。
ユーザー: さようなら(exit)
AI: さようなら。またお会いしましょう。
のように、挨拶を交わしてからスクリプトを終了することもできます。
必要に応じてこれまでの会話を要約する機能です。OpenAIのChat APIを1回実行し、会話内容とボットの思考に分けて要約されます。この要約文はコンソールには出力されませんが、会話ログファイルに追記されます。直近の要約文は、現在の会話で参照されます。なお、要約は設定にかかわらず、常にgpt-3.5-turbo
により行われます。
要約は以下の状況に応じて自動的に行われます。
会話(ユーザーの発言→ボットの発言)が6回実行されるか、現在の会話が1000字を超えた際に、自動的に会話が要約されます。ボットの発言が出力された直後に連続して、要約を実施します。要約後、現在の会話は直近3回分だけ残されます。
前回の発言から6時間以上経過したとき、自動的に現在の会話すべてを対象にして要約します。ユーザーの発言入力後、会話が要約され、続けてボットの発言が出力されます。
newコマンド実行時には、まず今までの会話すべてを対象にして要約します。その後、ボットの発言が出力されます。
※コマンドラインオプション--modify-tone
を指定したときのみ実行されます。
生成したボットの台詞にキャラ設定ファイルで定義されたng_words
が含まれていた場合、台詞修正のプロンプトを1回だけ実行し、台詞を差し替えます。
このキャラはそんなこと言わないはずなのに言ってしまうのは興ざめなので、改めてキャラ設定(story)、台詞例(examples)を元に、台詞を設定や台詞例に沿った内容へと修正します。なお、台詞修正は設定にかかわらず、常にgpt-4
により行われます。
*.json
- 会話のログは、APIを呼び出すたびに、会話ファイル(ファイル名は任意)に追記されていきます。そのためスクリプト終了後も会話の続きが行えます。ファイルはキャラクター毎に作成でき、コマンドラインオプションでキャラクターを切り替えることが可能です。
thought.txt
- 「現在ボットが考えていること」が出力されます。また、--no-show-action指定時にはボットの行動内容も合わせて出力されます。このファイルは出力のたびに上書きされます。たまに覗き見すると楽しいかもしれません。
prompt.txt
- ボットの台詞生成時に実行したプロンプトとAPI出力を上書き出力します。
prompt_summary.txt
- 要約生成時に実行したプロンプトとAPI出力を上書き出力します。
prompt_modify_tone.txt
- 台詞修正時に実行したプロンプトとAPI出力を上書き出力します。
サンプルを用意しているので、詳しくはそちらを参照のこと。
title
: 会話のタイトルspeaker1
: あなたの名前speaker2
: ボットの名前story
: キャラクター設定(外見、性格、趣味、知識レベル、あなたとの関係性、口調、台詞例etc)、あなた自身のプロフィール、ストーリー(世界観、会話の状況、場所、時間帯)などを自由に記述してください。文章でも箇条書きでもOKです。日本語だと500~800字くらいが良さそうです。トークン節約と思考能力アップを期待するなら、英語で書くのがいいかもしれません。{speaker1}
,{speaker2}
,{today}
,{time}
という変数が使えます。story
は現在の会話で毎回参照されます。- Tips: storyはChatGPTに作成させるのがお勧めです。
ng_words
: ボットに言わせたくない台詞をリストで記載します。--modify-tone
有効時にこのリスト中の単語が含まれていれば、台詞が修正されます。examples
: 会話例をリストで記載します。examples
は現在の会話で毎回参照されます。会話例は3つくらいあれば良さそうです。各会話は以下の要素で構成されます。- speaker1(あなた)の台詞(最大100字程度)
- speaker1(あなた)の行動(最大50字程度)
- speaker2(ボット)の理解(speaker1の台詞、行動をどう理解したか。最大50字程度)
- speaker2(ボット)の思考(理解に基づき、何を感じ、何をしようと思ったか。最大50字程度)
- speaker2(ボット)の行動(思考の結果、どういう行動をしたか。最大50字程度)
- speaker2(ボット)の台詞(思考の結果、最終的になんと発言したか。最大100字程度)
oldConversations
: 過去に行った会話リストsummary
: 会話の要約。直近2つのsummary
のみ、現在の会話で参照されます。thought
: speaker2(ボット)がその会話で思ったことの要約。直近のthought
のみ、現在の会話で参照されます。conversations
: 会話内容のリスト(examples
と同じフォーマット)。この会話リストは現在の会話で参照されません。
conversations
: 現在の会話リスト。現在の会話で参照されます。ここに会話履歴が蓄積されていきます。会話履歴が6個溜まると、新しい3個を残し、古い3個がoldConversations
に移動します。