Kiotaを使って、ずんだもんにしゃべってもらおう!

はじめに

こんにちは、ecbeingのカミーユです!

早くも2024年度も半分が過ぎ、毎年 時が過ぎるのが早くなっているなぁと感じる今日この頃です。

さて、世の中はAIブーム真っ只中。
弊 ecbeing labs でもAI系の話題が取り上げられるようになりました。

しかし、前回に引き続きまして OpenAPI についてのプロダクトを取り上げたいと思います。

OpenAIのAPIの仕様もOpenAPI仕様で策定されていますし、名前も似てるので実質AIの話題ですよAI(強引)

冗談はさておき、今回は

  • Microsoftが2023年に発表した OpenAPI クライアント作成ツール Kiota の紹介
  • Kiota製ソースの具体的な利用方法(C# ハンズオン形式)

を皆さんと一緒に見ていこうと思います。

よろしくお願いします!

前回の記事はこちら(OpenAPI仕様とOpenAPI Generatorについて触れています)

blog.ecbeing.tech

Kiotaの紹介

Kiotaとは?

Kiotaは、Microsoftが開発したオープンソースのコード生成ツールです。
OpenAPI仕様を基に、APIを利用したクライアントライブラリを自動生成できます。

主な特徴は以下の通りです。

  • 多言語対応
    • C#、CLI、Go、Java、PHP、Python、Ruby、TypeScriptといった多言語をサポート
  • カスタマイズ可能
    • 利用するプロダクトにあわせて、名前空間や生成されるAPIクライアントクラス名を調整可能
  • コアライブラリが分離されている
    • 実際の通信を行うコア処理が外部ライブラリとして分離されており、生成されるソースコード量が比較的少ない

OpenAPI Generatorとの比較

前回の記事で取り上げたOpenAPI Generatorとの比較は以下の通りです。

特徴 Kiota OpenAPI Generator
主要用途 APIクライアントの生成 APIクライアントおよびサーバースタブの生成
サポート言語 C#, TypeScript, Java, Python, Goなど 多数の言語をサポート(Java, Kotlin, Swift, TypeScript, Python, C#, Ruby, Goなど)
カスタマイズ性 オプションは少なめ、生成テンプレートのカスタマイズは不可 mustacheテンプレートファイルを利用して自由度の高いカスタマイズが可能
ライセンス MIT Licence Apache-2.0 license
開発元 Microsoft コミュニティー
リリース頻度 定期的だが、OpenAPI Generatorほど頻繁ではない 頻繁なリリースとアップデート
URL learn.microsoft.com openapi-generator.tech

このように並べてみると OpenAPI Generator の方が自由度が高い印象がありますが、
Kiota は Microsoft 製ということもあり、一定の信頼が置けるのではないかと思います。

実践

紹介は以上としまして、次は実際に利用したアプリケーションを作成してみようと思います。
例として C# を利用した実装をご紹介します。

今回は、OpenAPI スキーマが公開されている VOICEVOX を利用し、
音声ファイルを生成する簡単なアプリケーションを作成して、Kiota 製ソースの使い方を見ていきましょう。

VOICEVOX は ヒホ(ヒロシバ)氏が開発しているフリーのテキスト読み上げ・歌声合成ソフトウェアです。
皆さんも一度は YouTube などで VOICEVOX で生成されたずんだもんの声を聞いたことがあるかと思います。

ずんだもん

1. 環境のセットアップ

用意するものは以下の3つです。
すべて公式ページからインストーラーをダウンロードし、インストールを行いましょう。

2. OpenAPIスキーマの取得

まずは元となる OpenAPI スキーマを取得しましょう。

  1. インストールした VOICEVOX を起動します

    VOICEVOX ウィンドウ

  2. VOICEVOXを立ち上げたまま、ブラウザで http://localhost:50021/docs にアクセスします。
    すると、OpenAPI仕様が表示されます。(裏側でHTTPサーバーが動作しています)

    OpenAPI仕様

    画像上でマークしている /openapi.json を右クリックし、「名前をつけて保存」をクリックすることで、JSON ファイルがダウンロードできます。
    こちらを利用して、コード生成を行いましょう。

3. コード生成

ソースコードを生成するためには様々な方法がありますが、
今回は .NET SDK に同梱されている .NET tool を利用します。

その他の方法は公式ページを参照ください。

  1. ターミナルを開き、dotnet コマンドを利用して Kiota をインストールします。

     dotnet tool install --global Microsoft.OpenApi.Kiota
    

    これで Kiota の準備は完了です。 簡単ですね!

  2. 任意のフォルダ(例:voicevox)を作成します。
    そこに先ほど DL した JSON ファイルをコピーしましょう。

      voicevox
        └ openapi.json
    
  3. Kiotaを実行してソースコードを生成してみましょう。
    生成されるソースコードの名前空間やAPIクラス名はこのタイミングで指定します。

      kiota generate --openapi openapi.json -l CSharp --namespace-name "VoiceVoxApiTest.Client" --class-name "VoiceVoxApiClient"
    

    今回は 名前空間を 「VoiceVoxApiTest.Client」、APIクライアントのクラス名を「VoiceVoxApiClient」と設定してみました。

  4. 実行すると、フォルダ内にoutputというフォルダが作成され、中にソースコードが生成されています!

     voicevox
       └ output
         └ Accent_phrases
            ︙
       └ openapi.json
    

※注意: DLした JSON ファイルそのままでは動作しない箇所があったため、生成前に一部修正を行いました。

Kiota側がAPIバージョン 3.1.0 に対応していないため、下記2点の修正を行いました。

  1. APIバージョンを 3.1.03.0.3 に変更
    • 修正前:"openapi": "3.1.0"
    • 修正後:"openapi": "3.0.3"
  2. anyOfの記述を3.0.3準拠に修正
    明示的に{"type": "null"}を含められないため、記述を削除しました。
    • 修正前:"anyOf": [{"type": "number"},{"type": "null"}],
    • 修正後:"anyOf": [{"type": "number"}],

4. Kiotaクライアントの設定

続いて、生成したソースコードを実際に呼び出せるようにしましょう。

Visual Studio を開いて、APIを呼び出すコンソールアプリケーションを作成します。

  1. 新しいプロジェクトの作成
  2. コンソールアプリ
  3. 新しいプロジェクトを構成
    • 生成したソースコードにあわせてプロジェクト名は 「VoiceVoxApiTest」と指定
    • 場所は、先ほどソースコードを生成したフォルダを指定
  4. 追加情報
    • インストールしたSDKにあわせ「.NET 8.0」を選択
  5. 作成ボタンをクリック

これでプロジェクトが作成できました。
次に、自動生成したソースコードをプロジェクトに反映していきます。

「[C#] VoiceVoxApiTest」 を右クリック > 「追加」 > 「新しいフォルダ」を選択し、「Client」というフォルダを作成しましょう。

その後、先ほど生成した output フォルダの中身をClientフォルダにコピーします。

voicevox
  └ output
    └ Accent_phrases
       ︙
  └VoiceVoxApiTest
    └VoiceVoxApiTest
      └Client ← output フォルダの中身をここにコピーする
        └ Accent_phrases
           ︙
  └ openapi.json

するとこのように、Visual Studioにソースコードが反映されます。

しかし、これだけでは実際に利用することができません。
コア部分のライブラリを NuGet を利用してプロジェクトにインストールすることで利用可能になります。

「[C#]VoiceVoxApiTest」 > 「依存関係」 を右クリック > NuGet パッケージの管理 を開き

参照タブから Microsoft.Kiota.Bundle をインストールします。

これで、実際に生成されたソースコードが呼び出せるようになりました。

5. VOICEVOXの呼び出し

あともう一踏ん張りです。
実際にAPIを呼び出してみましょう。

「[C#]VoiceVoxApiTest」> Program.cs を開き、

下のC#ソースを貼り付けて、実行してみてください。

using Microsoft.Kiota.Abstractions.Authentication;
using Microsoft.Kiota.Http.HttpClientLibrary;
using System.Text.Json;
using VoiceVoxApiTest.Client;
using VoiceVoxApiTest.Client.Models;

// HTTPの認証を設定しない
var authProvider = new AnonymousAuthenticationProvider();

// 認証設定を引数にVoiceVoxApiClientが利用するアダプタークラスを生成
using var adapter = new HttpClientRequestAdapter(authProvider)
{
    BaseUrl = "http://localhost:50021/" // アダプターにVOICEVOXの接続先URLを指定する
};

// APIクライアントを作成
var client = new VoiceVoxApiClient(adapter);

var text = "ぼくはずんだもんなのだ。"; // しゃべらせたいテキスト
var speaker = 3; // 話者(3がずんだもんに相当)

Console.WriteLine("/audio_queryにリクエストします。");
// /audio_query テキストを元に、音声合成のパラメータを作成する
// URL例:http://localhost:50021/audio_query?text=ぼくはずんだもんなのだ。&speaker=3
AudioQuery audioQuery = await client.Audio_query
                                    .PostAsync(param =>
                                    {
                                        // URLパラメータにテキストと話者を指定する
                                        param.QueryParameters.Text = text;
                                        param.QueryParameters.Speaker = speaker;
                                    }) ?? throw new InvalidOperationException("/audioQueryのリクエストに失敗しました。");

// 取得したAudioQueryの中身を出力
Console.WriteLine("取得したAudioQuery");
Console.WriteLine(JsonSerializer.Serialize(audioQuery, new JsonSerializerOptions
{
    WriteIndented = true,
    Encoder = JavaScriptEncoder.Create(UnicodeRanges.All)
}));

Console.WriteLine("/synthesisにリクエストします。");
// /synthesis audio_queryで生成したパラメータを元に音声データを生成する
// URL例:http://localhost:50021/synthesis?speaker=3
using Stream audioStream = await client.Synthesis
                                       .PostAsync(audioQuery, param =>
                                       {
                                           // URLパラメータに話者を指定する
                                           param.QueryParameters.Speaker = speaker;
                                       }) ?? throw new InvalidOperationException("/synthesisのリクエストに失敗しました。");

// 書き出すファイルを作成し、ストリームを開く
using FileStream fileStream = File.OpenWrite(@"..\..\..\..\..\zundamon.wav");

// VOICEVOXから取得した音声ストリームをファイルに書き出す。
await audioStream.CopyToAsync(fileStream);

// ファイルを閉じる
fileStream.Close();
Console.WriteLine($"{fileStream.Name}に出力しました。");

すると、zundamon.wavという音声ファイルが、openapi.jsonと同じ階層に出力されます。

再生してみると、プログラムで指定したとおりの音声が生成されているはずです。

「ぼくはずんだもんなのだ。」と聞こえてくる気がしませんか?

こちらの波形表示には「Sazanami」を利用しています

ソースコードの詳細

このプログラムの処理としては大きく3つに分かれています。

  1. APIクライアントの初期化
  2. APIクライアントから2度リクエストを行い、音声データを取得する
  3. ファイルに保存

このうち、Kiotaに関係する1と2のみピックアップして解説します。

1. APIクライアントの初期化

このブロックでは、APIクライアントの初期化を行います。 接続情報を設定したアダプタークラスを引数にAPIクライアントを生成しています。

var authProvider = new AnonymousAuthenticationProvider(); // HTTPの認証を設定しない
using var adapter = new HttpClientRequestAdapter(authProvider) // 認証設定を引数にクライアントが利用するアダプターインスタンスを生成
{
    BaseUrl = "http://localhost:50021/" // アダプターにVOICEVOXのURLを指定する
};
var client = new VoiceVoxApiClient(adapter); // APIクライアントを作成

実際の通信はインストールした NuGet パッケージに含まれている HttpClientRequestAdapter が担当しており、
このオブジェクトに各種接続情報を設定する仕組みになっているようです。

また、OpenAPI Generator で生成されたAPIクライアントと比較すると、生成されるクラス数に差がありました。

  • Kiota: クライアントクラスは一つのみ
  • OpenAPI Generator: OpenAPI 定義の tagsごとにAPIクライアントが分かれる
2. APIクライアントから2度リクエストを行い、音声データを取得する

このブロックでは、生成したAPIクライアントを利用してリクエストを行い、レスポンスを取得しています。

APIクライアントは、OpenAPI 定義の /paths と同じ名前のプロパティを持っており、そのプロパティ内の関数を呼び出すことで通信を行います。

AudioQuery audioQuery = await client.Audio_query
                                    .PostAsync(param =>
                                    {
                                        param.QueryParameters.Text = text; // URLパラメータにテキストを指定する
                                        param.QueryParameters.Speaker = speaker; // URLパラメータに話者を指定する
                                    });

using Stream audioStream = await client.Synthesis
                                       .PostAsync(audioQuery, param =>
                                       {
                                           param.QueryParameters.Speaker = speaker; // URLパラメータに話者を指定する
                                       });

この仕様はかなり直感的ですし、IDEのインテリセンス機能とうまく融合しているなと感じました。

また、レスポンスデータは自動的に Model クラスにデシリアライズされますので、 非常に取り回しがよいです。

このあたりの仕様は、OpenAPI Generator で生成されるソースコードもあまり変わらないかと思います。

注意すべき点としては、URLパラメータの指定がデリゲート処理での指定になっている点です。
.NET の 汎用ホスト や ビルダーパターン のソースコードを書き慣れていない方には、少しとっつきにくく感じるかもしれません。

まとめ

今回は「Kiotaを使って、ずんだもんにしゃべってもらおう!」と題し、

  • Kiota のご紹介
  • 簡単な Kiota の利用方法(C# ハンズオン形式)

の2つをお送りしました。

もしこの記事を読んで Kiota に興味を持たれた方は、お好きな言語で実際に触れてみてください。

C# 以外の言語でも利用できますので、Kiota を活用してAPIクライアントを生成することで、効率的に開発ができるはずです。

この記事が皆さんのライブラリ選定の一助となれば幸いです。

ecbeingでは新進気鋭なエンジニアを募集しております!
careers.ecbeing.tech


こちらの記事は、下記の利用規約に則って執筆しています。