前言说明

云音工坊依托 Edge TTS 技术,为用户提供免费语音合成功能。我们基于该技术开发了专属 API 接口,目前该接口仅对会员用户开放,普通用户暂不支持调用接口服务,会员使用接口服务不会二次扣费,也无其他限制。若您需要免费合成语音,可直接通过本站在线工具操作,无需额外权限。如需使用 API 功能,欢迎升级为本站会员,会员可解锁更多高效语音合成场景。

Edge TTS 语音合成服务API接口使用说明 1

使用说明

语音合成接口

接口地址(支持 POST)

https://www.yuntts.com/api/v1/edge_tts

请求头

字段名 类型 必填 描述
Authorization string Bearer Token
Content-Type string application/json

示例

Content-Type: application/json
Authorization: Bearer API-KEY  // API密钥

注意:秘钥请登录后前往 https://www.yuntts.com/user/api/ 生成,接口秘钥支持访问本站所有接口服务!

请求参数

参数名 类型 必填 描述 约束条件 示例值
text string 需要合成的文本内容 最大2000个字符 "你好世界"
voice string 语音类型选择 音色名 "zh-CN-XiaoxiaoNeural"
rate integer 语速调节 -100 ~ 100 0
pitch integer 音调调节 -100 ~ 100 0
volume integer 音量调节 -100 ~ 100 0
stream boolean 是否启用流式传输 true/false true

请求示例

{
  "text": "欢迎使用Edge TTS语音合成服务,这是一个测试文本。",
  "voice": "zh-CN-XiaoxiaoNeural",
  "rate": 5,
  "pitch": 0,
  "volume": 10,
  "stream": true
}

返回参数说明

字段名 类型 说明 示例
code Integer 状态代码 200
status String 执行状态 success
msg String 状态信息 合成成功
audio_url URL 音频文件地址 https://www.yuntts.com/.../68269e2ea4595_1747361326.mp3
format String 音频格式 mp3

返回示例

{
    "code": 200,
    "status": "success",
    "msg": "合成成功",
    "audio_url": "https://www.yuntts.com/wp-content/uploads/2025/05/68268f6256c69_1747357538.mp3",
    "format": "mp3"
}

秘钥错误

{
    "code": 401,
    "msg": "API密钥无效或已过期!"
}

权限不足

{
    "code": 403,
    "error": "insufficient_privileges",
    "message": "合成失败:权限不足,请升级为会员或永久会员!"
}

参数错误

{
    "code": 404,
    "msg": "无效的 voice 参数"
}

合成失败

{
    "code": 201,
    "msg": "合成失败"
}

参考代码

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Edge TTS 合成</title>
    <link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/5.3.3/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
    <div class="container">
        <div class="row">
            <div class="col-md-12">
                <div class="text-center pricing-header px-3 py-3 pt-md-5 pb-md-4 mx-auto">
                    <h3>Edge TTS 合成</h3>
                    <p class="text-muted mb-0">请输入相关信息进行合成</p>
                </div>
                <div class="row mb-4">
                    <div class="col-md-12">
                        <div class="accordion" id="paramsAccordion">
                            <div class="accordion-item">
                                <h2 class="accordion-header">
                                    <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseParams">
                                        接口参数说明
                                    </button>
                                </h2>
                                <div id="collapseParams" class="accordion-collapse collapse" data-bs-parent="#paramsAccordion">
                                    <div class="accordion-body">
                                        <table class="table table-striped table-bordered">
                                            <thead class="table-light">
                                                <tr>
                                                    <th>参数名</th>
                                                    <th>类型</th>
                                                    <th>必填</th>
                                                    <th>说明</th>
                                                    <th>示例值</th>
                                                </tr>
                                            </thead>
                                            <tbody>
                                                <tr>
                                                    <td>text</td>
                                                    <td>String</td>
                                                    <td>是</td>
                                                    <td>需要合成的文本内容</td>
                                                    <td>"你好世界"</td>
                                                </tr>
                                                <tr>
                                                    <td>voice</td>
                                                    <td>String</td>
                                                    <td>是</td>
                                                    <td>语音类型选择</td>
                                                    <td>"zh-CN-XiaoxiaoNeural"</td>
                                                </tr>
                                                <tr>
                                                    <td>rate</td>
                                                    <td>Integer</td>
                                                    <td>否</td>
                                                    <td>语速调节(-100~100)</td>
                                                    <td>0</td>
                                                </tr>
                                                <tr>
                                                    <td>pitch</td>
                                                    <td>Integer</td>
                                                    <td>否</td>
                                                    <td>音调调节(-100~100)</td>
                                                    <td>0</td>
                                                </tr>
                                                <tr>
                                                    <td>volume</td>
                                                    <td>Integer</td>
                                                    <td>否</td>
                                                    <td>音量调节(-100~100)</td>
                                                    <td>0</td>
                                                </tr>
                                                <tr>
                                                    <td>stream</td>
                                                    <td>Boolean</td>
                                                    <td>否</td>
                                                    <td>是否启用流式传输</td>
                                                    <td>true</td>
                                                </tr>
                                            </tbody>
                                        </table>
                                    </div>
                                </div>
                            </div>
                </div>
                <div class="shadow-none p-3 mb-5 card rounded">
                    <form id="ttsForm">
                        <div class="row">
                            <div class="col-md-8 mb-3">
                                <div class="form-group">
                                    <label for="text">文本内容:</label>
                                    <textarea class="form-control" rows="22" id="text" placeholder="请输入要合成的文本..." required></textarea>
                                </div>
                                <div class="d-flex align-items-center justify-content-between mt-2">
                                    <div class="form-check">
                                        <input class="form-check-input" type="checkbox" id="edge-tts-stream" checked>
                                        <label class="form-check-label" for="edge-tts-stream" style="font-size: small">
                                            启用流式传输
                                        </label>
                                    </div>
                                </div>
                            </div>
                            <div class="col-md-4 mb-3">
                                <div class="form-group">
                                    <label for="voice">语音类型:</label>
                                    <select id="voice" name="voice" class="form-select form-select-lg mb-3"> 
                                        <option value="zh-CN-XiaoxiaoNeural">晓晓(Xiaoxiao)-女</option><option value="zh-CN-XiaoyiNeural">晓伊(Xiaoyi)-女</option><option value="zh-CN-YunjianNeural">云健(Yunjian)-男</option><option value="zh-CN-YunxiNeural">云希(Yunxi)-男</option><option value="zh-CN-YunxiaNeural">云霞(Yunxia)-男</option><option value="zh-CN-YunyangNeural">云扬(Yunyang)-男</option><option value="zh-CN-liaoning-XiaobeiNeural">小北(Xiaobei)-女</option><option value="zh-CN-shaanxi-XiaoniNeural">小妮(Xiaoni)-女</option>
                                    </select>
                                </div>
                                <div class="mb-3">
                                    <label for="edge-tts-rateSlider" class="form-label">语速</label>
                                    <input type="range" class="form-range" id="edge-tts-rateSlider" min="-100" max="100" value="0" oninput="document.getElementById('edge-tts-rateValue').textContent = this.value">
                                    <span id="edge-tts-rateValue">0</span>
                                </div>
                                <div class="mb-3">
                                    <label for="edge-tts-pitchSlider" class="form-label">音调</label>
                                    <input type="range" class="form-range" id="edge-tts-pitchSlider" min="-100" max="100" value="0" oninput="document.getElementById('edge-tts-pitchValue').textContent = this.value">
                                    <span id="edge-tts-pitchValue">0</span>
                                </div>
                                <div class="mb-3">
                                    <label for="edge-tts-volumeSlider" class="form-label">音量</label>
                                    <input type="range" class="form-range" id="edge-tts-volumeSlider" min="-100" max="100" value="0" oninput="document.getElementById('edge-tts-volumeValue').textContent = this.value">
                                    <span id="edge-tts-volumeValue">0</span>
                                </div>
                                <div class="d-flex flex-wrap gap-2">
                                    <button class="btn btn-primary flex-grow-1" id="edge-tts-synthesizeBtn" onclick="edgeTtsSynthesize()">
                                        <i class="fa fa-paper-plane" aria-hidden="true"></i> <span id="buttonText">合成</span> <span class="spinner-border spinner-border-sm" id="loadingSpinner" style="display: none;"></span>
                                    </button>
                                    <button class="btn btn-warning flex-grow-1" id="edge-tts-download-edge-tts" disabled onclick="downloadAudio()">
                                        <i class="fa fa-arrow-circle-down" aria-hidden="true"></i> <span id="downloadText">下载音频</span> <span class="spinner-border spinner-border-sm" id="downloadSpinner" style="display: none;"></span>
                                    </button>
                                </div>
                            </div>
                        </div>
                    </form>
                </div>
                <audio id="edge-tts-audioPlayer" controls style="display: none;"></audio>
                <div id="result" class="col-md-12"></div>
            </div>
        </div>
    </div>    </div>    </div>
    <script>
        function downloadAudio() {
            const downloadBtn = document.getElementById('edge-tts-download-edge-tts');
            const downloadText = document.getElementById('downloadText');
            const downloadSpinner = document.getElementById('downloadSpinner');
            const resultDiv = document.getElementById('result');
            
            // 禁用按钮并显示加载状态
            downloadBtn.disabled = true;
            downloadText.textContent = '下载中...';
            downloadSpinner.style.display = 'inline-block';
            resultDiv.textContent = '正在准备下载...';
            
            const audioUrl = document.getElementById('edge-tts-audioPlayer').src;
            
            // 使用fetch API获取音频内容
            fetch(audioUrl, {
                headers: {
                    'Authorization': 'Bearer 68985a242e655fb2d0194dfb478f1f76'
                }
            })
            .then(response => {
                if (!response.ok) {
                    throw new Error(`HTTP error! status: ${response.status}`);
                }
                return response.blob();
            })
            .then(blob => {
                // 创建Blob对象的临时URL
                const url = URL.createObjectURL(blob);
                
                // 创建下载链接并触发点击
                const a = document.createElement('a');
                a.href = url;
                a.download = 'synthesized_audio.mp3';
                a.click();
                
                // 释放临时URL以避免内存泄漏
                setTimeout(() => {
                    URL.revokeObjectURL(url);
                }, 100);
                
                resultDiv.textContent = '下载成功!';
            })
            .catch(error => {
                console.error('下载出错:', error);
                resultDiv.textContent = '下载出错: ' + error.message;
            })
            .finally(() => {
                // 恢复按钮状态
                downloadBtn.disabled = false;
                downloadText.textContent = '下载音频';
                downloadSpinner.style.display = 'none';
            });
        }

        async function edgeTtsSynthesize() {
            const synthesizeBtn = document.getElementById('edge-tts-synthesizeBtn');
            const buttonText = document.getElementById('buttonText');
            const loadingSpinner = document.getElementById('loadingSpinner');
            synthesizeBtn.disabled = true;
            buttonText.textContent = '合成中...';
            loadingSpinner.style.display = 'inline-block';

            const text = document.getElementById('text').value;
            const voice = document.getElementById('voice').value;
            const rate = document.getElementById('edge-tts-rateSlider').value;
            const pitch = document.getElementById('edge-tts-pitchSlider').value;
            const volume = document.getElementById('edge-tts-volumeSlider').value;
            const stream = document.getElementById('edge-tts-stream').checked;
            const resultDiv = document.getElementById('result');
            resultDiv.textContent = '正在合成...';

            const requestBody = {
                text: text,
                voice: voice,
                rate: rate,
                pitch: pitch,
                volume: volume,
                stream: stream
            };

            console.log('========== Edge TTS 请求开始 ==========');
            console.log('请求URL: https://www.yuntts.com/api/v1/edge_tts');
            console.log('请求方法: POST');
            console.log('请求头:');
            console.log('  Authorization: Bearer sk-7896e51c31a71246cbb97e656a0876e7');
            console.log('  Content-Type: application/json');
            console.log('请求体:', JSON.stringify(requestBody, null, 2));
            console.log('==========================================');

            try {
                const response = await fetch('https://www.yuntts.com/api/v1/edge_tts', {
                    method: 'POST',
                    headers: {
                        'Authorization': 'Bearer sk-7896e51c31a71246cbb97e656a0876e7',
                        'Content-Type': 'application/json'
                    },
                    body: JSON.stringify(requestBody)
                });

                console.log('========== Edge TTS 响应结果 ==========');
                console.log('HTTP状态码:', response.status);
                console.log('响应状态:', response.ok ? '成功' : '失败');
                console.log('响应头:');
                for (const [key, value] of response.headers.entries()) {
                    console.log(`  ${key}: ${value}`);
                }

                // 根据stream参数和响应类型处理不同的返回格式
                if (stream) {
                    // 处理流式返回的二进制音频
                    console.log('响应类型: 二进制音频流');
                    console.log('==========================================');
                    
                    if (!response.ok) {
                        throw new Error(`HTTP error! status: ${response.status}`);
                    }
                    
                    // 将响应转换为Blob对象
                    const blob = await response.blob();
                    
                    // 创建Blob对象的临时URL
                    const audioUrl = URL.createObjectURL(blob);
                    
                    // 设置音频播放器
                    const audioPlayer = document.getElementById('edge-tts-audioPlayer');
                    audioPlayer.src = audioUrl;
                    audioPlayer.style.display = 'block';
                    document.getElementById('edge-tts-download-edge-tts').disabled = false;
                    resultDiv.textContent = '合成成功!点击下方播放器试听音频。';
                } else {
                    // 处理非流式返回的JSON数据
                    const responseData = await response.json();
                    console.log('响应体:', JSON.stringify(responseData, null, 2));
                    console.log('==========================================');
                    
                    const data = responseData;
                    if ((data.code && data.code === 200) || (data.status && data.status === 'success')) {
                        const audioPlayer = document.getElementById('edge-tts-audioPlayer');
                        audioPlayer.src = data.audio_url || data.data?.audio_url;
                        audioPlayer.style.display = 'block';
                        document.getElementById('edge-tts-download-edge-tts').disabled = false;
                        resultDiv.textContent = '合成成功!点击下方播放器试听音频。';
                    } else {
                        resultDiv.textContent = data.message || data.msg || '合成失败,请稍后重试';
                        document.getElementById('edge-tts-download-edge-tts').disabled = true;
                    }
                }
            } catch (error) {
                console.error('========== Edge TTS 请求错误 ==========');
                console.error('错误类型:', error.name);
                console.error('错误信息:', error.message);
                console.error('==========================================');
                resultDiv.textContent = '合成出错: ' + error.message;
            } finally {
                synthesizeBtn.disabled = false;
                buttonText.textContent = '合成';
                loadingSpinner.style.display = 'none';
            }
        }
    </script>
</body>
</html>

 

# 基本调用(使用默认参数)
curl -X POST \
     -H "Authorization: Bearer 68985a242e655fb2d0194dfb478f1f76" \
     -H "Content-Type: application/json" \
     -d '{"text":"你好世界","voice":"zh-CN-XiaoxiaoNeural"}' \
     http://your-domain.com/wp-json/api/v1/edge_tts

# 带完整参数调用
curl -X POST \
     -H "Authorization: Bearer 68985a242e655fb2d0194dfb478f1f76" \
     -H "Content-Type: application/json" \
     -d '{"text":"欢迎使用语音合成服务","voice":"zh-CN-YunxiNeural","rate":20,"pitch":-10,"volume":5,"stream":true}' \
     http://your-domain.com/wp-json/api/v1/edge_tts

import requests

url = "http://your-domain.com/wp-json/api/v1/edge_tts"
headers = {
    "Authorization": "Bearer 68985a242e655fb2d0194dfb478f1f76",
    "Content-Type": "application/json"
}

# 基本调用
payload = {
    "text": "你好世界",
    "voice": "zh-CN-XiaoxiaoNeural"
}
response = requests.post(url, json=payload, headers=headers)
print(response.json())

# 带错误处理的高级调用
try:
    payload = {
        "text": "欢迎使用语音合成服务",
        "voice": "zh-CN-YunxiNeural",
        "rate": 20,
        "pitch": -10,
        "volume": 5,
        "stream": True
    }
    response = requests.post(url, json=payload, headers=headers)
    response.raise_for_status()
    audio_data = response.json()
    print("合成成功:", audio_data['audio_url'])
except requests.exceptions.HTTPError as err:
    print(f"HTTP错误:{err}")
except KeyError:
    print("响应数据格式异常")

音色查询接口

提供底层的音色查询功能
接口地址(支持 POST)
https://www.yuntts.com/api/v1/edge_voices

请求头

字段名 类型 必填 描述
Authorization string Bearer Token
Content-Type string application/json

示例

Content-Type: application/json
Authorization: Bearer API-KEY  // API密钥

请求参数

该接口支持空请求体,也可以传递额外参数来过滤音色列表。

参数名 类型 必填 描述 示例值
[custom_param] any 自定义过滤参数 {"language": "zh-CN"}

返回数据

{
  "code": 200,
  "message": "获取音色列表成功",
  "data": {
    "voices": [
      {
        "name": "Microsoft Server Speech Text to Speech Voice (zh-CN, XiaoxiaoNeural)",
        "short_name": "zh-CN-XiaoxiaoNeural",
        "locale": "zh-CN",
        "gender": "Female",
        "sample_rate_hertz": "24000",
        "voice_type": "Neural",
        "status": "GA"
      },
      {
        "name": "Microsoft Server Speech Text to Speech Voice (zh-CN, YunxiNeural)",
        "short_name": "zh-CN-YunxiNeural",
        "locale": "zh-CN",
        "gender": "Male",
        "sample_rate_hertz": "24000",
        "voice_type": "Neural",
        "status": "GA"
      }
      // 更多音色...
    ],
    "count": 2  // 音色总数
  }
}

参考代码

curl -X POST "https://www.yuntts.com/api/v1/edge_voices" \
  -H "Authorization: Bearer sk-7896exxxxxxxxxcbb97e656a0876e7" \
  -H "Content-Type: application/json"

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Edge TTS 音色查询测试</title>
    <!-- Bootstrap 5 CSS -->
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
    <style>
        body {
            background-color: #f8f9fa;
        }
        .card {
            box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
            transition: transform 0.2s;
        }
        .card:hover {
            transform: translateY(-2px);
            box-shadow: 0 6px 12px rgba(0, 0, 0, 0.15);
        }
        .filter-section {
            background-color: white;
            padding: 20px;
            border-radius: 8px;
            margin-bottom: 20px;
            box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
        }
        .voice-card {
            height: 100%;
        }
        .loading {
            display: none;
        }
        .stats {
            background-color: white;
            padding: 15px;
            border-radius: 8px;
            margin-bottom: 20px;
            box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
        }
    </style>
</head>
<body>
    <div class="container mt-5">
        <h1 class="text-center mb-5">Edge TTS 音色查询测试</h1>
        
        <!-- 统计信息 -->
        <div class="stats">
            <div class="row">
                <div class="col-md-4">
                    <h5 class="text-muted">总音色数</h5>
                    <h3 id="totalVoices" class="text-primary">0</h3>
                </div>
                <div class="col-md-4">
                    <h5 class="text-muted">已筛选</h5>
                    <h3 id="filteredVoices" class="text-success">0</h3>
                </div>
                <div class="col-md-4">
                    <h5 class="text-muted">API状态</h5>
                    <h3 id="apiStatus" class="text-danger">未连接</h3>
                </div>
            </div>
        </div>
        
        <!-- API密钥输入区域 -->
        <div class="filter-section">
            <h3 class="mb-4">API认证</h3>
            <div class="row g-3 align-items-end">
                <div class="col-md-9">
                    <label for="apiKey" class="form-label">API密钥 (Bearer Token)</label>
                    <input type="text" id="apiKey" class="form-control" placeholder="请输入您的API密钥">
                </div>
                <div class="col-md-3">
                    <button id="saveApiKey" class="btn btn-primary btn-lg w-100">保存密钥</button>
                </div>
            </div>
        </div>
        
        <!-- 筛选区域 -->
        <div class="filter-section">
            <h3 class="mb-4">音色筛选</h3>
            <div class="row g-3">
                <div class="col-md-4">
                    <label for="country" class="form-label">国家/地区</label>
                    <select id="country" class="form-select">
                        <option value="">全部</option>
                    </select>
                </div>
                <div class="col-md-4">
                    <label for="language" class="form-label">语言</label>
                    <select id="language" class="form-select">
                        <option value="">全部</option>
                    </select>
                </div>
                <div class="col-md-4">
                    <label for="gender" class="form-label">性别</label>
                    <select id="gender" class="form-select">
                        <option value="">全部</option>
                        <option value="Female">女性</option>
                        <option value="Male">男性</option>
                    </select>
                </div>
                <div class="col-md-12">
                    <button id="searchBtn" class="btn btn-primary btn-lg">查询音色</button>
                    <button id="resetBtn" class="btn btn-secondary btn-lg ms-2">重置筛选</button>
                    <div class="spinner-border spinner-border-sm text-primary loading" id="loading" role="status">
                        <span class="visually-hidden">加载中...</span>
                    </div>
                </div>
            </div>
        </div>
        
        <!-- 结果展示区域 -->
        <div class="row" id="voicesContainer">
            <!-- 音色卡片将在这里动态生成 -->
        </div>
    </div>
    
    <!-- Bootstrap 5 JS -->
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
    
    <script>
        // 全局变量存储所有音色数据
        let allVoices = [];
        let apiKey = '';
        
        // API 端点配置
        const API_CONFIG = {
            // 线上地址
            url: 'https://www.yuntts.com/api/v1/edge_voices'
        };
        
        // 初始化页面
        document.addEventListener('DOMContentLoaded', function() {
            // 绑定事件
            document.getElementById('searchBtn').addEventListener('click', fetchVoices);
            document.getElementById('resetBtn').addEventListener('click', resetFilters);
            document.getElementById('saveApiKey').addEventListener('click', saveApiKey);
            
            // 绑定筛选条件变化事件
            document.getElementById('country').addEventListener('change', filterVoices);
            document.getElementById('language').addEventListener('change', filterVoices);
            document.getElementById('gender').addEventListener('change', filterVoices);
            
            // 从localStorage加载保存的API密钥
            loadApiKey();
        });
        
        // 保存API密钥到localStorage
        function saveApiKey() {
            const apiKeyInput = document.getElementById('apiKey');
            const key = apiKeyInput.value.trim();
            
            if (key) {
                apiKey = key;
                localStorage.setItem('edgeTtsApiKey', key);
                
                // 显示保存成功消息
                const saveBtn = document.getElementById('saveApiKey');
                const originalText = saveBtn.textContent;
                saveBtn.textContent = '已保存!';
                saveBtn.classList.remove('btn-primary');
                saveBtn.classList.add('btn-success');
                
                // 2秒后恢复按钮状态
                setTimeout(() => {
                    saveBtn.textContent = originalText;
                    saveBtn.classList.remove('btn-success');
                    saveBtn.classList.add('btn-primary');
                }, 2000);
                
                // 自动查询音色
                fetchVoices();
            } else {
                alert('请输入有效的API密钥');
            }
        }
        
        // 从localStorage加载API密钥
        function loadApiKey() {
            const savedKey = localStorage.getItem('edgeTtsApiKey');
            if (savedKey) {
                apiKey = savedKey;
                document.getElementById('apiKey').value = savedKey;
                // 自动查询音色
                fetchVoices();
            }
        }
        
        // 获取音色列表
        async function fetchVoices() {
            if (!apiKey) {
                showError('请先保存有效的API密钥');
                return;
            }
            
            showLoading();
            try {
                const response = await fetch(API_CONFIG.url, {
                    method: 'POST',
                    headers: {
                        'Authorization': `Bearer ${apiKey}`,
                        'Content-Type': 'application/json'
                    }
                });
                
                if (!response.ok) {
                    throw new Error(`HTTP error! status: ${response.status}`);
                }
                
                const data = await response.json();
                
                // 处理WordPress插件返回的响应格式
                // WordPress插件返回的格式: {code: 200, message: "success", data: {voices: [...], count: 100}}
                if (data.code === 200 && data.data && data.data.voices) {
                    allVoices = data.data.voices;
                    updateStats(allVoices.length, allVoices.length);
                    updateApiStatus('已连接', 'success');
                    
                    // 提取唯一的国家和语言选项
                    populateFilterOptions(allVoices);
                    
                    // 渲染音色列表
                    renderVoices(allVoices);
                } else {
                    // 处理错误响应
                    const errorMsg = data.message || 'Invalid API response';
                    throw new Error(errorMsg);
                }
            } catch (error) {
                console.error('Error fetching voices:', error);
                updateApiStatus('连接失败', 'danger');
                showError(`获取音色失败: ${error.message}`);
            } finally {
                hideLoading();
            }
        }
        
        // 填充筛选选项
        function populateFilterOptions(voices) {
            const countries = new Set();
            const languages = new Set();
            
            // 提取国家和语言
            voices.forEach(voice => {
                const localeParts = voice.locale.split('-');
                if (localeParts.length >= 2) {
                    countries.add(localeParts[1]);
                }
                if (localeParts.length >= 1) {
                    languages.add(localeParts[0]);
                }
            });
            
            // 填充国家选项
            const countrySelect = document.getElementById('country');
            // 清空现有选项(保留第一个"全部"选项)
            countrySelect.innerHTML = '<option value="">全部</option>';
            Array.from(countries).sort().forEach(country => {
                const option = document.createElement('option');
                option.value = country;
                option.textContent = country;
                countrySelect.appendChild(option);
            });
            
            // 填充语言选项
            const languageSelect = document.getElementById('language');
            // 清空现有选项(保留第一个"全部"选项)
            languageSelect.innerHTML = '<option value="">全部</option>';
            Array.from(languages).sort().forEach(language => {
                const option = document.createElement('option');
                option.value = language;
                option.textContent = language;
                languageSelect.appendChild(option);
            });
        }
        
        // 筛选音色
        function filterVoices() {
            const country = document.getElementById('country').value;
            const language = document.getElementById('language').value;
            const gender = document.getElementById('gender').value;
            
            let filtered = allVoices.filter(voice => {
                const localeParts = voice.locale.split('-');
                const voiceCountry = localeParts.length >= 2 ? localeParts[1] : '';
                const voiceLanguage = localeParts.length >= 1 ? localeParts[0] : '';
                
                // 应用筛选条件
                const matchCountry = !country || voiceCountry === country;
                const matchLanguage = !language || voiceLanguage === language;
                const matchGender = !gender || voice.gender === gender;
                
                return matchCountry && matchLanguage && matchGender;
            });
            
            // 更新统计信息
            updateStats(allVoices.length, filtered.length);
            
            // 渲染筛选后的音色列表
            renderVoices(filtered);
        }
        
        // 渲染音色列表
        function renderVoices(voices) {
            const container = document.getElementById('voicesContainer');
            
            if (voices.length === 0) {
                container.innerHTML = '<div class="col-12 text-center py-5"><h4>未找到匹配的音色</h4></div>';
                return;
            }
            
            let html = '';
            voices.forEach(voice => {
                // 解析locale为语言和国家
                const localeParts = voice.locale.split('-');
                const language = localeParts[0] || '';
                const country = localeParts.length >= 2 ? localeParts[1] : '';
                
                html += `
                    <div class="col-md-4 col-lg-3 mb-4">
                        <div class="card voice-card h-100">
                            <div class="card-body">
                                <h5 class="card-title">${voice.name}</h5>
                                <h6 class="card-subtitle mb-2 text-muted">${voice.short_name}</h6>
                                <p class="card-text">
                                    <strong>语言:</strong> ${language}<br>
                                    <strong>国家:</strong> ${country}<br>
                                    <strong>性别:</strong> ${voice.gender}<br>
                                    <strong>采样率:</strong> ${voice.sample_rate_hertz} Hz<br>
                                    <strong>类型:</strong> ${voice.voice_type}<br>
                                    <strong>状态:</strong> ${voice.status}
                                </p>
                            </div>
                            <div class="card-footer bg-transparent">
                                <button class="btn btn-sm btn-outline-primary w-100 copy-btn" data-voice="${voice.short_name}">
                                    复制音色名
                                </button>
                            </div>
                        </div>
                    </div>
                `;
            });
            
            container.innerHTML = html;
            
            // 绑定复制按钮事件
            document.querySelectorAll('.copy-btn').forEach(btn => {
                btn.addEventListener('click', function() {
                    const voiceName = this.getAttribute('data-voice');
                    copyToClipboard(voiceName);
                    this.textContent = '已复制!';
                    this.classList.remove('btn-outline-primary');
                    this.classList.add('btn-success');
                    
                    // 2秒后恢复按钮状态
                    setTimeout(() => {
                        this.textContent = '复制音色名';
                        this.classList.remove('btn-success');
                        this.classList.add('btn-outline-primary');
                    }, 2000);
                });
            });
        }
        
        // 复制到剪贴板
        function copyToClipboard(text) {
            navigator.clipboard.writeText(text).catch(err => {
                console.error('Failed to copy text: ', err);
            });
        }
        
        // 重置筛选条件
        function resetFilters() {
            document.getElementById('country').value = '';
            document.getElementById('language').value = '';
            document.getElementById('gender').value = '';
            
            // 重新渲染所有音色
            updateStats(allVoices.length, allVoices.length);
            renderVoices(allVoices);
        }
        
        // 更新统计信息
        function updateStats(total, filtered) {
            document.getElementById('totalVoices').textContent = total;
            document.getElementById('filteredVoices').textContent = filtered;
        }
        
        // 更新API状态
        function updateApiStatus(status, type) {
            const statusElement = document.getElementById('apiStatus');
            statusElement.textContent = status;
            
            // 移除所有状态类
            statusElement.classList.remove('text-success', 'text-danger', 'text-warning');
            
            // 添加对应状态类
            if (type === 'success') {
                statusElement.classList.add('text-success');
            } else if (type === 'danger') {
                statusElement.classList.add('text-danger');
            } else {
                statusElement.classList.add('text-warning');
            }
        }
        
        // 显示加载状态
        function showLoading() {
            document.getElementById('loading').style.display = 'inline-block';
            document.getElementById('searchBtn').disabled = true;
        }
        
        // 隐藏加载状态
        function hideLoading() {
            document.getElementById('loading').style.display = 'none';
            document.getElementById('searchBtn').disabled = false;
        }
        
        // 显示错误信息
        function showError(message) {
            const container = document.getElementById('voicesContainer');
            container.innerHTML = `
                <div class="col-12">
                    <div class="alert alert-danger" role="alert">
                        ${message}
                    </div>
                </div>
            `;
        }
    </script>
</body>
</html>

状态码说明

状态码 错误码 错误信息 描述
200 - 成功 请求成功
400 json_decode_failed JSON解析失败: [具体错误] 请求体JSON格式错误
400 empty_text 请输入有效文本! text参数为空
400 empty_voice 请选择语音类型! voice参数为空
400 text_too_long 文本长度不能超过2000个字符! text参数超过长度限制
400 invalid_voice voice 参数无效,请检查! voice参数格式错误
400 invalid_parameters rate、pitch 或 volume 参数无效,请检查! 音参数格式错误
401 rest_invalid_auth Authorization头格式错误 缺少或无效的Bearer Token
403 insufficient_privileges 合成失败:权限不足,请升级为会员或永久会员! 用户权限不足
500 api_request_failed 合成失败: [具体错误] 请求Edge TTS服务失败
500 api_server_error 合成失败: 服务返回错误[状态码] Edge TTS服务返回错误状态码
500 response_parse_failed 合成失败: 解析响应失败 无法解析Edge TTS服务的响应
500 invalid_response_structure 合成失败: 响应结构无效 Edge TTS服务返回的响应格式不符合预期
500 directory_create_failed 生成失败: 无法创建上传目录 无法创建存储音频的目录
500 directory_not_writable 上传目录不可写 上传目录没有写权限
500 file_create_failed 文件创建失败 无法创建音频文件
500 empty_audio_file 合成失败: 生成的音频文件为空 生成的音频文件大小为0
声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。