この記事が気に入ったら、忘れずにブックマークしてください。
私をフォローして、一緒に Java を学びましょう。
1. ChatGPT APIに基づくPC側ソフトウェア開発プロセスで発生する問題の分析
OpenAI が最近発売した GPT-4.0 モデルは非常に人気があります。もちろん、OpenAIはGPT-4.0 APIを外部に正式に公開していないため、今回はGPT-3.5 APIを使用します。
まずはレンダリングを見てみましょう!
このクライアントは JavaFX を使用して開発されています。JavaFX JavaFX は Swing と比較して CSS スタイルをサポートしているため、Java を使用して GUI ソフトウェアを開発する場合は JavaFX の使用をお勧めします。JavaFX は、Oracle Corporation が 2008 年に開始したプロジェクトです。JavaFX 関連の API は上位バージョンの JDK には含まれていないため、JavaFX を自分でインストールする必要があることに注意してください。私は JDK 8 を開発して使用したため、JavaFX を自分でインストールしなくても JavaFX API を直接呼び出すことができます。
上の図では、JavaFX で書かれた UI インターフェイスがあまり見栄えが良くないことがわかりますが、私のメインのプログラミング言語が Java であるはずがないので、UI インターフェイスを書くには Java しか使えません。
送信、保存、表示、削除という 4 つの主な機能があります。その中でも、送信は中心的な機能です。GPT-3.5 API は送信時に間接的に呼び出されます。ここで直接呼び出しではなく間接呼び出しと呼ばれるのはなぜですか? この OpenAI 会社が中国ではオープンではないことを誰もが知っているはずです。OpenAI の公式 Web サイトに直接アクセスすることはできますが、ただし、OpenAI の製品ChatGPTにはアクセスできません。したがって、ここでは外部サーバーを中継サーバーとして使用する必要があります。トランジット サーバーを使用して GPT API にアクセスできる理由は簡単に理解できます。たとえば、あなたは A で、B にはアクセスできますが、C にはアクセスできませんが、B は C にアクセスできます。その場合、B にCさんへの情報。
ここでは、クライアント ソフトウェアの開発中に遭遇する問題についてのみ説明し、インターフェイスの作成方法については説明しません。
2. 最初に発生する問題は、ユーザーが送信ボタンをクリックした後、スレッドがブロックされることです。
この問題の主な原因は、ユーザーが送信ボタンをクリックした後、Hutool ツール クラスの HttpRequest.post() メソッドが呼び出され、データを独自定義のインターフェイスに送信することです。コードは以下のように表示されます。
sendButton.setOnAction(e -> sendMessage());
private void sendMessage() {
// 获取用户输入的消息并将其添加到聊天区域
String prompt = inputArea.getText();
// 获取当前时间
String nowTime = getNowTime();
chatArea.appendText(nowTime + "\n");
chatArea.appendText("我说:" + prompt + "\n\n");
// 清空输入框
inputArea.setText("");
// 存储上下文语境
messages.add(new Message("user", prompt));
// 获取 ChatGPT 的回复
String reply = httpRequest(messages);
// 机器人回复时间
String replyTime = getNowTime();
chatArea.appendText(replyTime + "\n");
// 把内容显示到 UI 界面上
chatArea.appendText("机器人说:" + reply + "\n\n");
messages.add(new Message("assistant", reply));
}
上記のコードでは、httpRequest(messages) を呼び出すときにスレッドがブロックされるため、ユーザーは実行中に気分が悪くなります。現在のスレッドがネットワーク リクエストを行っているときは、非常に時間がかかる操作であるため、メイン スレッド全体がブロックされ、アプリケーションがフリーズします。ChatGPT が応答しない場合、常にそこでスタックします。
おそらく、新しいスレッドを作成して http リクエストを送信すれば解決すると思われるかもしれませんが、実際はそうではありません。問題の根本は、[送信] ボタンをクリックしたことです。次の場合は、新しいスレッドを作成する必要があります。送信ボタンをクリックします もちろんここにいます httpを送信すると新しいスレッドも作成されます。コードは以下のように表示されます。
sendButton.setOnAction(e -> {
Task<Void> task = new Task<Void>() {
@Override
protected Void call() throws Exception {
// 执行耗时操作,例如发送网络请求或执行计算密集型任务
sendMessage();
// 返回null
return null;
}
};
// 在后台线程上执行Task
new Thread(task).start();
// 将操作提交到JavaFX应用程序线程队列中
Platform.runLater(() -> {
// 在此更新UI或执行其他需要在JavaFX应用程序线程上执行的操作
});
});
private void sendMessage() {
// 获取用户输入的消息并将其添加到聊天区域
String prompt = inputArea.getText();
// 获取当前时间
String nowTime = getNowTime();
chatArea.appendText(nowTime + "\n");
chatArea.appendText("我说:" + prompt + "\n\n");
// 清空输入框
inputArea.setText("");
// 存储上下文语境
messages.add(new Message("user", prompt));
// 获取 ChatGPT 的回复
// String reply = httpRequest(messages);
// 创建新的线程去发送 ChatGPT 请求
FutureTask<String> task = new FutureTask<String>(new Callable<String>() {
@Override
public String call() throws Exception {
return httpRequest(messages);
}
});
new Thread(task).start();
try {
String reply = task.get();
// 机器人回复时间
String replyTime = getNowTime();
chatArea.appendText(replyTime + "\n");
// 把内容显示到 UI 界面上
chatArea.appendText("机器人说:" + reply + "\n\n");
messages.add(new Message("assistant", reply));
} catch (Exception e) {
e.printStackTrace();
}
}
注: UI インターフェイスのコンテンツを更新したい場合は、それを使用できますPlatform.runLater()
。
3. 2番目の問題は、ChatGPTは継続的な対話を実行できない、つまりコンテキストがないことです。
この問題は長い間悩まされてきました。公式の開発ドキュメントにはこれについて具体的に説明されていないようです。GitHub コードを研究し、インターネットで他の人のアイデアを検索した結果、チャット履歴をもう一度 ChatGPT API に送信する必要があることがわかりました。しかし、これではさらに多くの資金が消費されます。OpenAI は実際にはオープンではないからです。
毎回チャット履歴を ChatGPT に送信するだけです。
ここでは、コレクションを使用してチャット レコードを保存し、毎回チャット レコードをコレクションに追加します。次に、List コレクションを ChatGPT API に送信します。
// 存放上下文语境
private List<Message> messages = new ArrayList<>();
// 存储上下文语境
messages.add(new Message("system", "你是一个助手"));
messages.add(new Message("user", prompt));
messages.add(new Message("assistant", reply));
Message クラスのコードは次のとおりです。
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Message {
private String role;
private String content;
}
ChatGPT 開発ドキュメントには、role に 3 つの値があると記載されています。1 つは ChatGPT が果たす役割を示す system で、2 番目の値はユーザーを示す user、そして 3 番目の値は ChatGPT を示す Assistant です。ロールに対応するコンテンツはコンテンツ変数に格納されます。これはマップ コレクションに似ています。つまり、役割がキーであり、コンテンツが値です。
さらに質問がある場合は、ブログを参照してください。