rksoftware

Visual Studio とか C# とかが好きです

AI を Web アプリに組み込む その 4

以前にコンソールアプリで AI を扱うチャットアプリを作りました。

rksoftware.hatenablog.com

今回は Web アプリに組み込んでみます。GitHub のリポジトリはこちら。

github.com

こんな感じに文章要約を AI で行います。

今回はその 4。AI を扱う機能のコントローラーの作り方についてです。

■ 全体の目次です

rksoftware.hatenablog.com

■ Web アプリに追加する、とは?

Web アプリそのものは別途存在していて、アドオン敵に AI 機能を追加する試みです。
簡単に言うと Web アプリのプロジェクトとは別のプロジェクトで AI の機能を実装します。そして、それらのプロジェクトに依存関係はないものの、実行時には AI 機能を持って Web アプリが動く。そういう夢のような構成です。

■ コントローラーのコード

こんな感じです。

[Microsoft.AspNetCore.Mvc.ApiController]
[Microsoft.AspNetCore.Mvc.Route("[controller]")]
public class AIController : Microsoft.AspNetCore.Mvc.ControllerBase
{
    public record PostParameter(string UserMessage) { }
    public record Result(string AIMessage) { }

    // API Key 等。ここでは環境変数から取得。コードに書かなくてよいように
    // DeploymentName は環境変数にしなくてもよいとは思いますが、コピペで検証しやすいように環境変数にしています
    static readonly string openAIEndpoint = Environment.GetEnvironmentVariable("OpenAIEndpoint")!;
    static readonly string openAIAPIKey = Environment.GetEnvironmentVariable("OpenAIAPIKey")!;
    static readonly string openAIDeploymentName = Environment.GetEnvironmentVariable("OpenAIDeploymentName")!;
    // システムプロンプトの文言を用意しておきます
    static readonly string systemPrompt = "ユーザーからのメッセージを要約してください";
    // エンドポイント、キー、デプロイメント名を使って AI のクライアントを生成しておきます
    static readonly Azure.AI.OpenAI.AzureOpenAIClient client = new Azure.AI.OpenAI.AzureOpenAIClient(new Uri(openAIEndpoint), new Azure.AzureKeyCredential(openAIAPIKey));

    [Microsoft.AspNetCore.Mvc.HttpPost()]
    public async Task<Result> Post(PostParameter p)
    {
        // AI と会話する会話履歴オブジェクトを生成。システムプロンプトとユーザーからの質問を保持
        List<OpenAI.Chat.ChatMessage> chatHistory = new() { OpenAI.Chat.ChatMessage.CreateSystemMessage(systemPrompt), OpenAI.Chat.ChatMessage.CreateUserMessage(p.UserMessage) };
        // AI のクライアントを生成し回答を得る
        var aiMessage = (await client.GetChatClient(openAIDeploymentName).CompleteChatAsync(chatHistory)).Value.Content.Last().Text;
        return new Result(aiMessage);
    }
}
[Microsoft.AspNetCore.Mvc.ApiController]
[Microsoft.AspNetCore.Mvc.Route("[controller]")]
public class AIScriptController : Microsoft.AspNetCore.Mvc.ControllerBase
{
    [Microsoft.AspNetCore.Mvc.HttpGet()]
    public string Get() => """
        function addAIClientAPI(idButton, idTextarea, site) {
            document.getElementById(idButton).setAttribute('onclick', `aiClientAPI('${idTextarea}', site);return false;`);
        }
        function aiClientAPI(id, site) {
            alert('要約します');
            var elm = document.getElementById(id);
            fetch(`${site}/AI`, {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ userMessage: elm.value })
            })
            .then(response => response.json())
            .then(data => {
                elm.value = data.aiMessage;
                alert('要約しました');
            })
            .catch(error => {
                alert(error);
            });
        }
    """;
}

コメントを書いているのでコードの中身の詳細の解説は不要でしょう。

■ 環境変数を使う

これは、Web のコントローラーだからというわけではありませんが、AI 関連のキーやエンドポイントを環境変数にしています。こうすることで環境側で設定ができるようになるので例えばクラウドにあげるときや、共同作業時にデバッグは個人ごとの AI を使うなど、やりたいことができます。
逆に独自の設定ファイルなどだと厄介ですね。

■ JavaScript コードを返却する

これは API コントローラーでなくてもよかったかもしれません。要検証。
AI を扱う API を今回作っていますが、その API には当然インターフェイスはあります。リクエストやレスポンス上のパラメータ名などですね。
せっかく API を DLL 読み込みだけで使えるようにしても、このインターフェイスを意識しなくてはならないのはやさしくないです。というわけでラップする JavaScript コードも用意してしまおうというわけです。

■ 使う方

このプロジェクトを使う方、Web アプリ側ではページで次のような JavaScript を書くだけで AI が使えます。

    <script>
        const site = '';
        const script = document.createElement('script'); script.src = `${site}/aiscript?${String(new Date().getTime())}`; document.head.appendChild(script);
        const interal = setInterval(function() { if (typeof addAIClientAPI !== 'undefined') { addAIClientAPI('ボタンのID', '文章入力のテキストエリアのID', site); clearInterval(interal); } }, 33);
    </script>

JavaScript はわからないのでこれがあるべきコードかはわかりませんが、動作します。

■ 次回

次回からは AI を使うコントローラーがきちんと読み込まれて API が使えているかを確認する方法を見ていこうと思います。