TTS について
z-ai-web-dev-sdk でテキストから音声を生成する開発者向けの TTS 実装スキルです。コマンドラインとバックエンド SDK、音声設定、形式の制約、統合例を扱います。
主な機能
- 01z-ai-web-dev-sdk によるテキスト読み上げ
- 02音声や速度を指定したコマンドライン変換
- 03WAV、MP3、PCM の出力
- 04ストリーミング出力は PCM のみ
- 05入力制限とパラメーター範囲の案内
活用シーン
- 01学習コンテンツのナレーション生成
- 02文章の音声版の作成
- 03API 駆動アプリ向けの音声生成
- 04コマンドラインでの音声や形式のテスト
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ answerzhao/ agent-skills --skill ttsインストール後、Claude Code で/ttsを入力して読み込まれたか確認します。
同梱ファイルtts.tsLICENSE.txt
詳細
TTS (Text to Speech) スキル
このスキルは、z-ai-web-dev-sdk パッケージを使用したテキスト読み上げ (TTS) 機能の実装をガイドし、テキストを自然な音声に変換できるようにします。
スキルのパス
スキルの場所: {project_path}/skills/TTS
このスキルは、プロジェクト内の上記のパスにあります。
参照スクリプト: 簡単なテストと参照用のサンプルテストスクリプトが {Skill Location}/scripts/ ディレクトリにあります。動作する例については {Skill Location}/scripts/tts.ts を参照してください。
概要
Text-to-Speech を使用すると、テキスト入力から音声を生成するアプリケーションを構築でき、さまざまなユースケースに対応するために、多様な音声、速度、出力形式をサポートします。
重要: z-ai-web-dev-sdk はバックエンドコードでのみ使用する必要があります。クライアントサイドのコードでは決して使用しないでください。
API の制限と制約
TTS 機能を実装する前に、これらの重要な制限を認識してください:
入力テキストの制約
- 最大長: リクエストごとに 1024 文字
- この制限を超えるテキストは、より小さなチャンクに分割する必要があります
音声パラメータ
- 速度範囲: 0.5 ~ 2.0
- 0.5 = 半分の速度 (遅い)
- 1.0 = 通常の速度 (デフォルト)
- 2.0 = 2 倍の速度 (速い)
- 音量範囲: 0 より大きく、最大 10
- デフォルト: 1.0
- 値は 0 より大きい (排他的) かつ 10 以下 (包含的) である必要があります
フォーマットとストリーミング
- ストリーミングの制限:
stream: trueを有効にすると、pcmフォーマットのみがサポートされます - 非ストリーミング:
wav、pcm、mp3フォーマットをサポートします - サンプルレート: 24000 Hz (推奨)
長いテキストのベストプラクティス
function splitTextIntoChunks(text, maxLength = 1000) {
const chunks = [];
const sentences = text.match(/[^.!?]+[.!?]+/g) || [text];
let currentChunk = '';
for (const sentence of sentences) {
if ((currentChunk + sentence).length <= maxLength) {
currentChunk += sentence;
} else {
if (currentChunk) chunks.push(currentChunk.trim());
currentChunk = sentence;
}
}
if (currentChunk) chunks.push(currentChunk.trim());
return chunks;
}
前提条件
z-ai-web-dev-sdk パッケージはすでにインストールされています。以下の例に示すようにインポートしてください。
CLI の使用法 (簡単なタスク向け)
簡単なテキスト読み上げ変換には、コードを書く代わりに z-ai CLI を使用できます。これは、素早い音声生成、音声のテスト、または簡単な自動化に最適です。
基本的な TTS
# Convert text to speech (default WAV format)
z-ai tts --input "Hello, world" --output ./hello.wav
# Using short options
z-ai tts -i "Hello, world" -o ./hello.wav
さまざまな音声と速度
# Use specific voice
z-ai tts -i "Welcome to our service" -o ./welcome.wav --voice tongtong
# Adjust speech speed (0.5-2.0)
z-ai tts -i "This is faster speech" -o ./fast.wav --speed 1.5
# Slower speech
z-ai tts -i "This is slower speech" -o ./slow.wav --speed 0.8
さまざまな出力フォーマット
# MP3 format
z-ai tts -i "Hello World" -o ./hello.mp3 --format mp3
# WAV format (default)
z-ai tts -i "Hello World" -o ./hello.wav --format wav
# PCM format
z-ai tts -i "Hello World" -o ./hello.pcm --format pcm
ストリーミング出力
# Stream audio generation
z-ai tts -i "This is a longer text that will be streamed" -o ./stream.wav --stream
CLI パラメータ
--input, -i <text>: 必須 - 読み上げるテキスト (最大 1024 文字)--output, -o <path>: 必須 - 出力音声ファイルのパス--voice, -v <voice>: オプション - 音声の種類 (デフォルト: tongtong)--speed, -s <number>: オプション - 読み上げ速度、0.5 ~ 2.0 (デフォルト: 1.0)--format, -f <format>: オプション - 出力フォーマット: wav、mp3、pcm (デフォルト: wav)--stream: オプション - ストリーミング出力を有効化 (pcm フォーマットのみサポート)
CLI と SDK の使い分け
CLI を使用する場合:
- 素早いテキスト読み上げ変換
- さまざまな音声と速度のテスト
- 簡単なバッチ音声生成
- コマンドライン自動化スクリプト
SDK を使用する場合:
- アプリケーション内での動的な音声生成
- Web サービスとの統合
- カスタム音声処理パイプライン
- 複雑な要件を持つ本番アプリケーション
基本的な TTS 実装
シンプルなテキスト読み上げ
import ZAI from 'z-ai-web-dev-sdk';
import fs from 'fs';
async function textToSpeech(text, outputPath) {
const zai = await ZAI.create();
const response = await zai.audio.tts.create({
input: text,
voice: 'tongtong',
speed: 1.0,
response_format: 'wav',
stream: false
});
// Get array buffer from Response object
const arrayBuffer = await response.arrayBuffer();
const buffer = Buffer.from(new Uint8Array(arrayBuffer));
fs.writeFileSync(outputPath, buffer);
console.log(`Audio saved to ${outputPath}`);
return outputPath;
}
// Usage
await textToSpeech('Hello, world!', './output.wav');
複数の音声オプション
import ZAI from 'z-ai-web-dev-sdk';
import fs from 'fs';
async function generateWithVoice(text, voice, outputPath) {
const zai = await ZAI.create();
const response = await zai.audio.tts.create({
input: text,
voice: voice, // Available voices: tongtong, chuichui, xiaochen, jam, kazi, douji, luodo
speed: 1.0,
response_format: 'wav',
stream: false
});
// Get array buffer from Response object
const arrayBuffer = await response.arrayBuffer();
const buffer = Buffer.from(new Uint8Array(arrayBuffer));
fs.writeFileSync(outputPath, buffer);
return outputPath;
}
// Usage
await generateWithVoice('Welcome to our service', 'tongtong', './welcome.wav');
調整可能な速度
import ZAI from 'z-ai-web-dev-sdk';
import fs from 'fs';
async function generateWithSpeed(text, speed, outputPath) {
const zai = await ZAI.create();
// Speed range: 0.5 to 2.0 (API constraint)
// 0.5 = half speed (slower)
// 1.0 = normal speed (default)
// 2.0 = double speed (faster)
// Values outside this range will cause API errors
const response = await zai.audio.tts.create({
input: text,
voice: 'tongtong',
speed: speed,
response_format: 'wav',
stream: false
});
// Get array buffer from Response object
const arrayBuffer = await response.arrayBuffer();
const buffer = Buffer.from(new Uint8Array(arrayBuffer));
fs.writeFileSync(outputPath, buffer);
return outputPath;
}
// Usage - slower narration
await generateWithSpeed('This is an important announcement', 0.8, './slow.wav');
// Usage - faster narration
await generateWithSpeed('Quick update', 1.3, './fast.wav');
調整可能な音量
import ZAI from 'z-ai-web-dev-sdk';
import fs from 'fs';
async function generateWithVolume(text, volume, outputPath) {
const zai = await ZAI.create();
// Volume range: greater than 0, up to 10 (API constraint)
// Values must be > 0 (exclusive) and <= 10 (inclusive)
// Default: 1.0 (normal volume)
const response = await zai.audio.tts.create({
input: text,
voice: 'tongtong',
speed: 1.0,
volume: volume, // Optional parameter
response_format: 'wav',
stream: false
});
// Get array buffer from Response object
const arrayBuffer = await response.arrayBuffer();
const buffer = Buffer.from(new Uint8Array(arrayBuffer));
fs.writeFileSync(outputPath, buffer);
return outputPath;
}
// Usage - louder audio
await generateWithVolume('This is an announcement', 5.0, './loud.wav');
// Usage - quieter audio
await generateWithVolume('Whispered message', 0.5, './quiet.wav');
高度なユースケース
バッチ処理
import ZAI from 'z-ai-web-dev-sdk';
import fs from 'fs';
import path from 'path';
async function batchTextToSpeech(textArray, outputDir) {
const zai = await ZAI.create();
const results = [];
// Ensure output directory exists
if (!fs.existsSync(outputDir)) {
fs.mkdirSync(outputDir, { recursive: true });
}
for (let i = 0; i < textArray.length; i++) {
try {
const text = textArray[i];
const outputPath = path.join(outputDir, `audio_${i + 1}.wav`);
const response = await zai.audio.tts.create({
input: text,
voice: 'tongtong',
speed: 1.0,
response_format: 'wav',
stream: false
});
// Get array buffer from Response object
const arrayBuffer = await response.arrayBuffer();
const buffer = Buffer.from(new Uint8Array(arrayBuffer));
fs.writeFileSync(outputPath, buffer);
results.push({
success: true,
text,
path: outputPath
});
} catch (error) {
results.push({
success: false,
text: textArray[i],
error: error.message
});
}
}
return results;
}
// Usage
const texts = [
'Welcome to chapter one',
'Welcome to chapter two',
'Welcome to chapter three'
];
const results = await batchTextToSpeech(texts, './audio-output');
console.log('Generated:', results.length, 'audio files');
動的コンテンツ生成
import ZAI from 'z-ai-web-dev-sdk';
import fs from 'fs';
class TTSGenerator {
constructor() {
this.zai = null;
}
async initialize() {
this.zai = await ZAI.create();
}
async generateAudio(text, options = {}) {
const {
voice = 'tongtong',
speed = 1.0,
format = 'wav'
} = options;
const response = await this.zai.audio.tts.create({
input: text,
voice: voice,
speed: speed,
response_format: format,
stream: false
});
// Get array buffer from Response object
const arrayBuffer = await response.arrayBuffer();
return Buffer.from(new Uint8Array(arrayBuffer));
}
async saveAudio(text, outputPath, options = {}) {
const buffer = await this.generateAudio(text, options);
if (buffer) {
fs.writeFileSync(outputPath, buffer);
return outputPath;
}
return null;
}
}
// Usage
const generator = new TTSGenerator();
await generator.initialize();
await generator.saveAudio(
'Hello, this is a test',
'./output.wav',
{ speed: 1.2 }
);
Next.js API ルートの例
import { NextRequest, NextResponse } from 'next/server';
export async function POST(req: NextRequest) {
try {
const { text, voice = 'tongtong', speed = 1.0 } = await req.json();
// Import ZAI SDK
const ZAI = (await import('z-ai-web-dev-sdk')).default;
// Create SDK instance
const zai = await ZAI.create();
// Generate TTS audio
const response = await zai.audio.tts.create({
input: text.trim(),
voice: voice,
speed: speed,
response_format: 'wav',
stream: false,
});
// Get array buffer from Response object
const arrayBuffer = await response.arrayBuffer();
const buffer = Buffer.from(new Uint8Array(arrayBuffer));
// Return audio as response
return new NextResponse(buffer, {
status: 200,
headers: {
'Content-Type': 'audio/wav',
'Content-Length': buffer.length.toString(),
'Cache-Control': 'no-cache',
},
});
} catch (error) {
console.error('TTS API Error:', error);
return NextResponse.json(
{
error: error instanceof Error ? error.message : '生成语音失败,请稍后重试',
},
{ status: 500 }
);
}
}
ベストプラクティス
1. テキストの準備
function prepareTextForTTS(text) {
// Remove excessive whitespace
text = text.replace(/\s+/g, ' ').trim();
// Expand common abbreviations for better pronunciation
const abbreviations = {
'Dr.': 'Doctor',
'Mr.': 'Mister',
'Mrs.': 'Misses',
'etc.': 'et cetera'
};
for (const [abbr, full] of Object.entries(abbreviations)) {
text = text.replace(new RegExp(abbr, 'g'), full);
}
return text;
}
2. エラー処理
import ZAI from 'z-ai-web-dev-sdk';
import fs from 'fs';
async function safeTTS(text, outputPath) {
try {
// Validate input
if (!text || text.trim().length === 0) {
throw new Error('Text input cannot be empty');
}
if (text.length > 1024) {
throw new Error('Text input exceeds maximum length of 1024 characters');
}
const zai = await ZAI.create();
const response = await zai.audio.tts.create({
input: text,
voice: 'tongtong',
speed: 1.0,
response_format: 'wav',
stream: false
});
// Get array buffer from Response object
const arrayBuffer = await response.arrayBuffer();
const buffer = Buffer.from(new Uint8Array(arrayBuffer));
fs.writeFileSync(outputPath, buffer);
return {
success: true,
path: outputPath,
size: buffer.length
};
} catch (error) {
console.error('TTS Error:', error);
return {
success: false,
error: error.message
};
}
}
3. SDK インスタンスの再利用
import ZAI from 'z-ai-web-dev-sdk';
// Create a singleton instance
let zaiInstance = null;
async function getZAIInstance() {
if (!zaiInstance) {
zaiInstance = await ZAI.create();
}
return zaiInstance;
}
// Usage
const zai = await getZAIInstance();
const response = await zai.audio.tts.create({ ... });
一般的なユースケース
- オーディオブックとポッドキャスト: 書かれたコンテンツを音声フォーマットに変換
- E ラーニング: 教育コンテンツのナレーションを作成
- アクセシビリティ: テキストコンテンツの音声版を提供
- 音声アシスタント: 動的な応答を生成
- アナウンス: 自動音声通知を作成
- IVR システム: 電話システムのプロンプトを生成
- コンテンツのローカライズ: 異なる言語で音声を作成
統合の例
Express.js API エンドポイント
import express from 'express';
import ZAI from 'z-ai-web-dev-sdk';
import fs from 'fs';
import path from 'path';
const app = express();
app.use(express.json());
let zaiInstance;
const outputDir = './audio-output';
async function initZAI() {
zaiInstance = await ZAI.create();
if (!fs.existsSync(outputDir)) {
fs.mkdirSync(outputDir, { recursive: true });
}
}
app.post('/api/tts', async (req, res) => {
try {
const { text, voice = 'tongtong', speed = 1.0 } = req.body;
if (!text) {
return res.status(400).json({ error: 'Text is required' });
}
const filename = `tts_${Date.now()}.wav`;
const outputPath = path.join(outputDir, filename);
const response = await zaiInstance.audio.tts.create({
input: text,
voice: voice,
speed: speed,
response_format: 'wav',
stream: false
});
// Get array buffer from Response object
const arrayBuffer = await response.arrayBuffer();
const buffer = Buffer.from(new Uint8Array(arrayBuffer));
fs.writeFileSync(outputPath, buffer);
res.json({
success: true,
audioUrl: `/audio/${filename}`,
size: buffer.length
});
} catch (error) {
res.status(500).json({ error: error.message });
}
});
app.use('/audio', express.static('audio-output'));
initZAI().then(() => {
app.listen(3000, () => {
console.log('TTS API running on port 3000');
});
});
トラブルシューティング
問題: 「Input text exceeds maximum length」
- 解決策: テキスト入力は 1024 文字に制限されています。長いテキストは、API の制限事項セクションに示されている
splitTextIntoChunks関数を使用してチャンクに分割してください
問題: 「Invalid speed parameter」または予期しない速度の動作
- 解決策: 速度は 0.5 から 2.0 の間である必要があります。速度の値がこの範囲内にあることを確認してください
問題: 「Invalid volume parameter」
- 解決策: 音量は 0 より大きく、最大 10 である必要があります。音量の値が範囲 (0, 10] 内にあることを確認してください
問題: WAV/MP3 で「Stream format not supported」
- 解決策: ストリーミングモードは PCM 形式のみをサポートします。ストリーミングでは
response_format: 'pcm'を使用するか、WAV/MP3 出力ではストリーミングを無効化 (stream: false) してください
問題: 「SDK must be used in backend」
- 解決策: z-ai-web-dev-sdk がサーバーサイドのコードでのみインポートされていることを確認してください
問題: 「TypeError: response.audio is undefined」
- 解決策: SDK は標準の Response オブジェクトを返します。
response.audioにアクセスする代わりにawait response.arrayBuffer()を使用してください
問題: 生成された音声ファイルが空、または破損している
- 解決策:
await response.arrayBuffer()を呼び出し、適切に Buffer に変換していることを確認してください:Buffer.from(new Uint8Array(arrayBuffer))
問題: 音声が不自然に聞こえる
- 解決策: テキストを適切に準備してください (特殊文字を削除し、略語を展開する)
問題: 処理時間が長い
- 解決策: 長いテキストをより小さなチャンクに分割し、並列で処理してください
問題: Next.js が古い API ルートをキャッシュする
- 解決策: 新しい API ルートエンドポイントを作成するか、開発サーバーを再起動してください
パフォーマンスのヒント
- SDK インスタンスを再利用する: ZAI インスタンスを一度作成して再利用してください
- キャッシュを実装する: 繰り返し使用されるテキストの生成済み音声をキャッシュしてください
- バッチ処理: 複数のテキストを効率的に処理してください
- テキストを最適化する: 生成前に不要な内容を削除してください
- 非同期処理: 複数のリクエストを処理するためにキューを使用してください
重要な注意事項
API の制約
入力テキストの長さ: リクエストあたり最大 1024 文字です。より長いテキストの場合:
// Split long text into chunks
const longText = "..."; // Your long text here
const chunks = splitTextIntoChunks(longText, 1000);
for (const chunk of chunks) {
const response = await zai.audio.tts.create({
input: chunk,
voice: 'tongtong',
speed: 1.0,
response_format: 'wav',
stream: false
});
// Process each chunk...
}
ストリーミング形式の制限: stream: true を使用する場合、pcm 形式のみがサポートされます。wav または mp3 出力には、stream: false を使用してください。
サンプルレート: 音声は 24000 Hz のサンプルレートで生成されます (再生に推奨される設定)。
Response オブジェクトの形式
zai.audio.tts.create() メソッドは標準の Response オブジェクトを返します (audio プロパティを持つカスタムオブジェクトではありません)。常に次を使用してください:
// ✅ CORRECT
const response = await zai.audio.tts.create({ ... });
const arrayBuffer = await response.arrayBuffer();
const buffer = Buffer.from(new Uint8Array(arrayBuffer));
// ❌ WRONG - This will not work
const response = await zai.audio.tts.create({ ... });
const buffer = Buffer.from(response.audio); // response.audio is undefined
利用可能な音声
tongtong- 温暖で親しみやすいchuichui- 活発でかわいいxiaochen- 落ち着いたプロフェッショナルjam- イギリス英語の紳士kazi- 明瞭で標準的douji- 自然で流暢luodo- 感情豊か
速度の範囲
- 最小:
0.5(半分の速度) - デフォルト:
1.0(通常の速度) - 最大:
2.0(2 倍の速度)
重要: 範囲 [0.5, 2.0] 外の速度の値は API エラーの原因となります。
音量の範囲
- 最小:
0より大きい (排他的) - デフォルト:
1.0(通常の音量) - 最大:
10(包括的)
注意: 音量パラメータは省略可能です。指定しない場合、デフォルトは 1.0 です。
覚えておくこと
- z-ai-web-dev-sdk は常にバックエンドのコードでのみ使用してください
- 入力テキストは最大 1024 文字に制限されています - 長いテキストはチャンクに分割してください
- 速度は 0.5 から 2.0 の間である必要があります - この範囲外の値はエラーの原因となります
- 音量は 0 より大きく、最大 10 である必要があります - 省略可能なパラメータで、デフォルトは 1.0 です
- ストリーミングは PCM 形式のみをサポートします - WAV または MP3 出力には非ストリーミングを使用してください
- SDK は標準の Response オブジェクトを返します -
await response.arrayBuffer()を使用してください - ArrayBuffer は
Buffer.from(new Uint8Array(arrayBuffer))を使用して Buffer に変換してください - ファイルに保存する際は音声バッファを適切に処理してください
- 本番アプリケーションにはエラーハンドリングを実装してください
- 頻繁に生成されるコンテンツにはキャッシュを検討してください
- ストレージを管理するために古い音声ファイルを定期的にクリーンアップしてください