OpenAI TTS(Text to Speech) を Node.js で試してみた

先日開催された OpenAI Dev Day で新たに発表された、テキストから音声を生成する OpenAI TTS (Text To Speech) API が面白そうだったので、早速ですが Node.js 環境で簡単に試してみました。

先日開催された OpenAI Dev Day では大幅な機能追加に加え、いくつかの新しい API も発表されました。

その中で、テキストから音声を生成する OpenAI TTS (Text To Speech) API が面白そうだったので、早速ですが簡単に試してみることに。

Text to speech の概要や、API の リファレンスは下記にあります。

で、ご丁寧に Python や Node.js でのリクエストサンプルコードも提示してくれているのでこれを使って秒で試せます。

価格とか

なお、API の利用には設定された費用がかかります。価格は下記ページの 「Audio models」 のセクションに書かれています。

具体的には下記のようになっていますので、例えば modeltts-1 を指定して API に、100文字分のリクエストを投げると、0.0015 ドル消費するといったイメージ (で、合ってると思うんですが間違ってたら教えてください)。

  • TTS: 1,000文字あたり $0.015
  • TTS HD: 1,000文字あたり $0.030

ちなみに、ChatGPT で ChatGPT Plus とか、有料プランを使ってる場合でも、それとは別に、OpenAI のアカウントの方で支払い情報を登録して、クレジットをチャージしておかないといけないので注意してください。

私の場合は初期クレジットでとりあえず 20 ドルくらい入れておきましたけど、そんくらいあれば十分色々な API を試しても足りるんじゃないでしょうか。オートチャージ (例えばクレジットの残額が 5 ドルを切ったら、自動で 20 ドルを新たに入金とか) を設定したり、使いすぎるのが怖い場合は、月額上限の設定などもできるので、必要に応じてしておくといいと思います。

なお、Open AI に支払い情報を登録する前に API にリクエストを送ると、429 Too Many Requests ステータスで、エラーメッセージに You exceeded your current quota, please check your plan and billing details. (お金が足りねぇよ(超意訳)) が帰ってきます。

支払い情報の登録直後だとまだデータが反映されていないのか、しばらく (といっても 10 分、15 分の話ですが) これが帰ってくる場合があるので、新たに支払い情報を登録した場合は、少しだけ時間を置いてみるといいと思います。

API キーの取得

API の利用には API キーが必要です。OpenAI アカウントの管理画面にある 「API Keys」 から取得しておきましょう。当たり前ですが、取得した API キーは他人に教えたりしないようにね。

実際に試す

お支払いの準備ができて、API キーの取得までできたら、あとはソースコードを書いて試すだけです。

まず、必要な npm パッケージをインストールしておきます。

npm install openai dotenv --save

openai は、OpenAI 公式のパッケージですが、Node.js で API にアクセスするための機能がまとまっているのでとても便利。もうひとつの dotenv は、.env ファイルから API キーを取得するために使用します。

また、.env ファイルを作成して、下記の設定を記述しておいてください。

OPENAI_API_KEY=[ここに取得した API キー]

実際に使ったソースコードは下記。サンプルをベースに少しいじっただけです。

import 'dotenv/config';
import fs from 'fs';
import path from 'path';
import OpenAI from 'openai';

const openai = new OpenAI();

const inputText = '今日はとてもいい天気ですので、先日、OpenAI Dev Day で発表された OpenAI TTS(Text to Speech)を試してみます。';

// 保存するファイル名で使用する日時(YYYYMMDD-HHMMSS)
const getFormattedDateTime = () => {
    const now = new Date();
    const year = now.getFullYear();
    const month = String(now.getMonth() + 1).padStart(2, '0');
    const day = String(now.getDate()).padStart(2, '0');
    const hours = String(now.getHours()).padStart(2, '0');
    const minutes = String(now.getMinutes()).padStart(2, '0');
    const seconds = String(now.getSeconds()).padStart(2, '0');
    return `${year}${month}${day}-${hours}${minutes}${seconds}`;
}

const main = async () => {
    try {
        const mp3 = await openai.audio.speech.create({
            model: 'tts-1',
            voice: 'alloy',
            input: inputText,
        });
        const buffer = Buffer.from(await mp3.arrayBuffer());
        const speechFile = path.resolve(`./speech_${getFormattedDateTime()}.mp3`);
        await fs.promises.writeFile(speechFile, buffer);

        console.log(`Audio saved to ${speechFile}`);
    } catch (error) {
        console.error('Error:', error);
    }
}

main();

上記、ファイルを index.mjs などとして、実行すれば、ファイルを実行したディレクトリに、.mp3 ファイルが保存されます。

node index.mjs

今回は試しに、

『今日はとてもいい天気ですので、先日、OpenAI Dev Day で発表された OpenAI TTS(Text to Speech)を試してみます。』

のように、英語と日本語が混ざった文章を投げてみましたが、日本語堪能な外国人さんがしゃべってる感は強いけど、かなり自然な音声が帰ってきました。下記にサンプルを置いておくので聞いてみてください。

OpenAI TTS Sample (model: tts-1):

比較のために、上が model: tts-1、下が model: tts-1-hd で生成したものです。これくらいの短い文章だと、ほとんど違いはないですね。ほんの少し、model: tts-1-hd の方が自然に聞こえる気もしますが。

OpenAI TTS Sample (model: tts-1-hd):

あと、実験として、わざと HTML を含めたテキストを input に入れてみたのですが、model: tts-1 で試した場合、普通に HTML は無視して、というか HTML の要素自体を読み上げたりせず、中身のテキストだけをうまく読み上げてくれました。一方で、model: tts-1-hd の時は支離滅裂な英語が帰ってきたりしました。

API リファレンスの方には特にこの辺の言及がなかったのですが、Web ページ本文の HTML を丸ごと投げつけて読み上げてもらう、みたいな雑なことをやった場合でも、場合によってはうまいこと処理してくれそうな予感はありますが、今回は短い文章だったのでたまたまうまくいった可能性もあります。

そもそも、input で渡せる文字列の最大長は 4096 文字なのと、HTML 分も文字数としてカウントされてしまうと思いますので、プレーンテキストに成形してから送るというのが基本になると思います。

記事をここまで御覧頂きありがとうございます。
この記事が気に入ったらサポートしてみませんか?