javaのcommand lineアプリケーションでもサクッとChatGPTのようなやり取りをするアプリケーションが作れるようです。

準備

今回使うJavaやそのライブラリをインストールします。

SDKMAN

このコマンドでインストール

curl -s "https://get.sdkman.io" | bash

参考:https://sdkman.io/

Java

sdkmanを利用してインストールします。今回利用するのはこのバージョン

  • GraalVM 22.3.1.r17
sdk install java 22.3.1.r17-grl

Micronaut

  • 4系だと、m1macでもnativeコンパイルして動かせたので4系を選択
sdk install micronaut 4.0.0-M4 

native image

  • GraalVMでコマンドとしてビルドするならこれも。
gu install native-image

プロジェクトの作成

続いて、プロジェクトを作成します。

mn create-cli-app  example.micronaut.chatfunc --build=gradle --lang=java

こんな感じのコマンドを入力すると、chatfuncというフォルダにベースアプリが生成されます。

gradleに依存ライブラリのインストール

OpenAIのAPIを呼ぶために今回は、ライブラリ「azure-ai-openai」をbuild.gradleに追加します。

  • build.gradle
dependencies {
... 省略
    implementation("com.azure:azure-ai-openai:1.0.0-beta.2")
... 省略
}

参考:https://github.com/Azure/azure-sdk-for-java/tree/main/sdk/openai/azure-ai-openai

プログラミング

今回はこのファイルを編集するだけです。OPENAI_API_KEYは環境変数から渡す想定で、@Valueで変数に紐付けしています。あとは、azure-ai-openaiのgithubのサンプルを参考に chat completionsを呼び出しています。

CHATの質問だけ切り出すと、こんな感じのものをAPIに送っています。

  • ChatRole.SYSTEM: “あなたは親切なITコンサルタントです。”
  • ChatRole.USER: “質問していいですか?”
  • ChatRole.ASSISTANT: “もちろんです、なにかお困り事ですか?”
  • ChatRole.USER: “GraalVMの良さを教えてください。”

コード

  • ChatfuncCommand.java
package example.micronaut;

import java.util.ArrayList;
import java.util.List;

import com.azure.ai.openai.OpenAIClient;
import com.azure.ai.openai.OpenAIClientBuilder;
import com.azure.ai.openai.models.ChatChoice;
import com.azure.ai.openai.models.ChatCompletions;
import com.azure.ai.openai.models.ChatCompletionsOptions;
import com.azure.ai.openai.models.ChatMessage;
import com.azure.ai.openai.models.ChatRole;
import com.azure.ai.openai.models.CompletionsUsage;
import com.azure.ai.openai.models.NonAzureOpenAIKeyCredential;

import io.micronaut.configuration.picocli.PicocliRunner;
import io.micronaut.context.annotation.Value;
import picocli.CommandLine.Command;

@Command(name = "chatfunc", description = "...", mixinStandardHelpOptions = true)
public class ChatfuncCommand implements Runnable {

    @Value("${openai.api.key}")
    private String openaiKey;

    public static void main(String[] args) throws Exception {
        PicocliRunner.run(ChatfuncCommand.class, args);
    }

    public void run() {

        OpenAIClient client = new OpenAIClientBuilder()
                .credential(new NonAzureOpenAIKeyCredential(openaiKey))
                .buildClient();

        List<ChatMessage> chatMessages = new ArrayList<>();
        chatMessages.add(new ChatMessage(ChatRole.SYSTEM)
                .setContent("あなたは親切なITコンサルタントです。"));
        chatMessages.add(new ChatMessage(ChatRole.USER).setContent("質問していいですか?"));
        chatMessages.add(new ChatMessage(ChatRole.ASSISTANT).setContent("もちろんです、なにかお困り事ですか?"));
        chatMessages.add(new ChatMessage(ChatRole.USER).setContent("GraalVMの良さを教えてください。"));

        ChatCompletions chatCompletions = client.getChatCompletions("gpt-3.5-turbo-0613", new ChatCompletionsOptions(chatMessages));

        System.out.printf("Model ID=%s is created at %d.%n", chatCompletions.getId(), chatCompletions.getCreated());
        for (ChatChoice choice : chatCompletions.getChoices()) {
            ChatMessage message = choice.getMessage();
            System.out.printf("Index: %d, Chat Role: %s.%n", choice.getIndex(), message.getRole());
            System.out.println("Message:");
            System.out.println(message.getContent());
        }

        System.out.println();
        CompletionsUsage usage = chatCompletions.getUsage();
        System.out.printf("Usage: number of prompt token is %d, "
                + "number of completion token is %d, and number of total tokens in request and response is %d.%n",
            usage.getPromptTokens(), usage.getCompletionTokens(), usage.getTotalTokens());
    }
}

参考:https://github.com/Azure/azure-sdk-for-java/blob/main/sdk/openai/azure-ai-openai/README.md

実行

環境変数にOPENAI_API_KEYを設定した後に、作ったコマンドCLIを実行していきます。

環境変数の設定

export OPENAI_API_KEY="あなたのAPIKEY"

実行コマンドはこれ

./gradlew run 

結果

GraalVMは、Java仮想マシン(JVM)と共通のランタイム環境を提供するオープンソースのユニバーサル仮想マシンです。以下に、GraalVMの主な利点をいくつか紹介します。

  1. パフォーマンス: GraalVMは、高速なJIT(Just-in-Time)コンパイラを備えており、Javaアプリケーションの実行速度を向上させることができます。また、GraalVMはネイティブイメージコンパイラも提供しており、アプリケーションをネイティブバイナリにコンパイルすることでさらなるパフォーマンスの向上が期待できます。
  2. 言語の統合: GraalVMは、Javaの他にJavaScript、Python、Ruby、R言語などの多くのプログラミング言語をサポートしています。これにより、複数の言語を1つのアプリケーションで組み合わせることが容易になります。
  3. ポリグロット開発: GraalVMの特徴的な機能の1つは、異なるプログラミング言語のコードを統合して同じ実行環境で処理できることです。これにより、異なる言語で書かれたコンポーネントを効率的に組み合わせて開発することができます。
  4. クラウドネイティブ: GraalVMは、クラウド環境でのアプリケーション開発をサポートしています。ネイティブイメージコンパイラにより、アプリケーションのスタートアップ時間を短縮し、コンテナイメージのサイズを削減することができます。
  5. 柔軟性: GraalVMはモジュラーアーキテクチャを採用しており、必要なコンポーネントのみを選択してインストールすることができます。また、GraalVMは、既存のツールやエコシステムとの互換性も高いです。

これらは、GraalVMが優れた性能、言語の統合、柔軟性などの観点で注目されている理由の一部です。しかし、具体的な要件や使用ケースによって、GraalVMの利点は異なるかもしれません。

Usage: number of prompt token is 78, number of completion token is 747, and number of total tokens in request and response is 825.