以下の内容はhttps://redhologerbera.hatenablog.com/entry/2025/02/16/223751より取得しました。


ZyphraのZonosのAPIに関して調べる

本日はAI枠です。

先日新型のTextToSpeechサービスのZyphraのZonosを触っていました。

redhologerbera.hatenablog.com

サイドメニューを見るとSettingsの中にAPIKeysおよびAPI Documentationが存在しました。

今回はこのAPIを使用すれば何ができるのか?見ていきます。

API DocumentにはPythonとTypeScriptのサンプルコードが掲載されています。

https://playground.zyphra.com/settings/docs

このドキュメントを見るにhttp://api.zyphra.com/v1/audio/text-to-speechというエンドポイントにHTTPリクエストを使用して送信することで処理結果が返ってくるようです。

BASE64形式で音源をアップロードすることでCloneVoiceも行えるようです。

〇Unityで実行(失敗)

Unityで

using System.Collections;
using UnityEngine;
using UnityEngine.Networking;
using System.IO;

public class ZonosAPIClient : MonoBehaviour
{
    private string apiKey = "zsk-"; // APIキーをここに入力
    private string apiUrl = "https://api.zonos.com/v1/audio";
    public AudioSource audioSource; // AudioSourceコンポーネントをアタッチ

    void Start()
    {
        string textData = "こんにちは!";
        string audioFilePath = Application.dataPath + "/youmiyahina.wav"; // 音声ファイルのパス
        StartCoroutine(SendRequest(textData, audioFilePath));
    }

    IEnumerator SendRequest(string text, string audioPath)
    {
        // 音声ファイルをバイト配列として読み込む
        byte[] audioData = File.ReadAllBytes(audioPath);

        // フォームデータを作成
        WWWForm form = new WWWForm();
        form.AddField("text", text);
        form.AddBinaryData("audio", audioData, "audio.wav", "audio/wav");

        // POSTリクエストを作成
        UnityWebRequest request = UnityWebRequest.Post(apiUrl, form);
        request.SetRequestHeader("Authorization", "Bearer " + apiKey);

        // リクエストを送信し、レスポンスを待機
        yield return request.SendWebRequest();

        if (request.result != UnityWebRequest.Result.Success)
        {
            Debug.LogError("リクエストエラー: " + request.error);
        }
        else
        {
            Debug.Log("レスポンス受信");
            byte[] responseData = request.downloadHandler.data;
            // レスポンスデータをAudioClipに変換して再生
            StartCoroutine(PlayAudioClip(responseData));
        }
    }

    IEnumerator PlayAudioClip(byte[] audioData)
    {
        // WAVデータをAudioClipに変換
        AudioClip clip = WavUtility.ToAudioClip(audioData, 0, "ProcessedAudio");
        if (clip != null)
        {
            audioSource.clip = clip;
            audioSource.Play();
        }
        else
        {
            Debug.LogError("AudioClipの作成に失敗しました。");
        }
        yield return null;
    }
}

using UnityEngine;
using System.IO;

public static class WavUtility
{
    public static AudioClip ToAudioClip(byte[] wavFile, int offsetSamples = 0, string name = "wav")
    {
        using (MemoryStream memStream = new MemoryStream(wavFile))
        using (BinaryReader reader = new BinaryReader(memStream))
        {
            // WAVヘッダーの読み込み
            reader.ReadBytes(22);
            ushort channels = reader.ReadUInt16();
            int sampleRate = reader.ReadInt32();
            reader.ReadBytes(6);
            ushort bitDepth = reader.ReadUInt16();
            reader.ReadBytes(4);
            int dataSize = reader.ReadInt32();

            // PCMデータの読み込み
            byte[] pcmData = reader.ReadBytes(dataSize);

            // AudioClipの作成
            AudioClip audioClip = AudioClip.Create(name, dataSize / (bitDepth / 8), channels, sampleRate, false);
            float[] floatData = ConvertByteToFloat(pcmData, bitDepth);
            audioClip.SetData(floatData, offsetSamples);

            return audioClip;
        }
    }

    private static float[] ConvertByteToFloat(byte[] byteArray, int bitDepth)
    {
        int bytesPerSample = bitDepth / 8;
        int floatArrayLength = byteArray.Length / bytesPerSample;
        float[] floatArray = new float[floatArrayLength];

        for (int i = 0; i < floatArrayLength; i++)
        {
            if (bitDepth == 16)
            {
                short value = System.BitConverter.ToInt16(byteArray, i * bytesPerSample);
                floatArray[i] = value / 32768f;
            }
            else if (bitDepth == 32)
            {
                int value = System.BitConverter.ToInt32(byteArray, i * bytesPerSample);
                floatArray[i] = value / (float)int.MaxValue;
            }
        }

        return floatArray;
    }
}

これを実行することで通信ができるはずですが以下のようなエラーが発生しました。

InvalidOperationException: Insecure connection not allowed UnityEngine.Networking.UnityWebRequest.BeginWebRequest () (at :0) UnityEngine.Networking.UnityWebRequest.SendWebRequest () (at :0) ZonosAPIClient+d__4.MoveNext () (at Assets/HoloMoto/tts/ZonosAPIClient.cs:34) UnityEngine.SetupCoroutine.InvokeMoveNext (System.Collections.IEnumerator enumerator, System.IntPtr returnValueAddress) (at <44f3679c53d1477a9c6e72f269e3a3a9>:0) UnityEngine.MonoBehaviour:StartCoroutine(IEnumerator)

これはUnityがHTTP(非SSL)接続をデフォルトで許可していないために発生しています。

 これはセキュリティ面の問題なので、つまりHTTPSのURLを指定する必要があるのですが、https://api.zonos.com/v1/audioを使用した場合404が出ています。

 これはZyphra側がHTTPのみを提供しているためと思われます。

 実行するためにはHTTPの通信をUnityで使用する必要があります。

 この辺りは次回見ていきたいと思います。

 本日は以上です。




以上の内容はhttps://redhologerbera.hatenablog.com/entry/2025/02/16/223751より取得しました。
このページはhttp://font.textar.tv/のウェブフォントを使用してます

不具合報告/要望等はこちらへお願いします。
モバイルやる夫Viewer Ver0.14