前言说明

在数字化浪潮席卷全球的时代,语音交互正以前所未有的速度融入我们的生活与工作场景,从智能客服到有声内容创作,从导航语音播报再到教育场景的语言学习,优质、高效的语音合成技术成为了推动行业创新发展的关键力量。云音智联深度洞察市场需求,依托 Fish Speech 先进的语音合成技术,致力于为用户提供专业、精准且极具表现力的语音合成功能。我们凭借强大的技术研发实力,基于 Fish Speech 技术开发了专属 API 接口,不仅能满足用户多样化的语音合成需求,还为开发者提供了便捷接入的渠道,助力各行业轻松实现语音交互升级,解锁智能语音应用的无限可能。

Fish Speech 语音合成服务API接口使用说明 1

FishSpeech 语音合成 API接口文档

接口概述

本接口提供语音克隆服务,支持将文本转换为特定声音模型的语音。接口支持多种参数配置,包括语速、音量、版本选择、音频格式等。

接口地址

POST https://www.yuntts.com/api/v1/fishspeech-generate

请求方法

  • POST

认证方式

需要在请求头中添加API密钥:

Authorization: Bearer YOUR_API_KEY

Content-Type

  • application/json

请求参数

请求参数采用JSON格式,以下是所有可用参数的详细说明:

参数名 类型 是否必填 默认值 取值范围 说明
reference_id string - - 声音模型ID,语音克隆的唯一标识符
model_id string - - 兼容旧版本的声音模型ID参数(优先级低于reference_id)
text string - - 要转换为语音的文本内容
speed float 1.0 0.1-3.0 语速设置
volume int 0 -20-20 音量设置(单位:dB)
version string v1 v1, v2, s1, v3-turbo, v3-hd TTS版本选择
format string mp3 mp3, wav, pcm 音频输出格式
cache boolean false true, false 是否启用缓存模式(true返回音频URL,false返回二进制音频流)
emotion string auto auto, happy, sad, angry, fearful, disgusted, surprised, calm, fluent 情绪控制(V3版本专用)
language string auto auto, zh, en 语言增强(V3版本专用)

请求示例

以下是一个完整的请求示例,包含了主要参数:

{
    "reference_id": "fb215435-9cf1-4141-a938-d05e85c064ee",
    "text": "你好,这是一段测试文本",
    "speed": 1.0,
    "volume": 0,
    "version": "v3-turbo",
    "format": "mp3",
    "cache": false,
    "emotion": "happy",
    "language": "zh"
}

响应格式

接口支持两种响应模式:缓存模式和非缓存模式。

成功响应

缓存模式(cache=true)

缓存模式下,接口返回JSON格式的数据,包含音频文件的URL和相关信息:

{
    "code": 0,
    "msg": "合成成功",
    "data": {
        "audio_url": "https://www.yuntts.com/wp-content/uploads/2025/01/fish-audio-api-abc123_1234567890.mp3",
        "format": "mp3",
        "char_count": 10,
        "cost": 0.01,
        "balance": 99.99
    }
}
非缓存模式(cache=false)

非缓存模式下,接口直接返回二进制音频数据,Content-Type为audio/mpeg:

[二进制音频数据]

错误响应

当请求失败时,接口返回以下格式的错误信息:

{
    "code": 400,
    "error": "invalid_parameters",
    "msg": "缺少必要参数"
}

错误码说明

错误码 HTTP状态码 错误类型 说明
json_decode_failed 400 请求格式错误 JSON解析失败
invalid_parameters 400 参数错误 缺少必要参数
invalid_volume 400 参数错误 音量值超出范围
invalid_version 400 参数错误 无效的TTS版本
invalid_format 400 参数错误 无效的音频格式
invalid_emotion 400 参数错误 无效的情绪值(仅V3版本)
invalid_language 400 参数错误 无效的语言值(仅V3版本)
insufficient_balance 403 权限错误 余额不足
api_connection_error 500 服务器错误 语音引擎连接超时
server_config_error 500 服务器错误 服务端配置异常

计费说明

接口采用按字符计费的方式,具体规则如下:

  • 计费单位:元/字符
  • 基础价格:由系统配置的字符兑换比例决定
  • 折扣规则:根据用户类型应用不同折扣
  • 四舍五入:保留两位小数
  • 最低扣费:当扣除金额小于0.01元时,按0.01元扣除

cURL 请求示例

以下是使用cURL命令调用接口的示例代码:

缓存模式示例

curl -X POST "https://www.yuntts.com/api/v1/fishspeech-generate" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"reference_id":"fb215435-9cf1-4141-a938-d05e85c064ee","text":"你好,这是一段测试文本","speed":1.0,"volume":0,"version":"v3-turbo","format":"mp3","cache":true,"emotion":"happy","language":"zh"}'

非缓存模式示例(保存到文件)

curl -X POST "https://www.yuntts.com/api/v1/fishspeech-generate" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"reference_id":"fb215435-9cf1-4141-a938-d05e85c064ee","text":"你好,这是一段测试文本","speed":1.0,"volume":0,"version":"v3-turbo","format":"mp3","cache":false,"emotion":"happy","language":"zh"}' \
  -o output.mp3

参数验证规则

接口对所有参数进行严格验证,确保请求的合法性:

  • 必填参数验证:reference_id和text为必填项,缺少则返回错误
  • 数值范围验证:音量必须在-20到20之间
  • 枚举值验证:version、format、emotion、language等参数必须在指定的取值范围内
  • V3版本专用参数:emotion和language参数仅在version为v3-turbo或v3-hd时有效

注意事项

  • 请确保提供有效的Bearer Token进行认证
  • 对于长文本,建议分批次调用接口
  • 缓存模式下,音频文件会保存在服务器上,请注意及时下载
  • 非缓存模式下,需要正确处理二进制响应数据
  • V3版本提供更多高级功能,建议优先使用

调试工具

可以使用以下调试工具测试API接口:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>语音克隆API调试工具</title>
    <!-- Bootstrap 5 CSS -->
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
    <!-- Bootstrap Icons -->
    <link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.5/font/bootstrap-icons.css" rel="stylesheet">

</head>
<body>
    <div class="container">
        <div class="row">
            <!-- 左侧表单区域 (8列) -->
            <div class="col-md-8">
                <div class="card shadow-lg">
                    <div class="card-header bg-primary text-white text-center">
                        <h1 class="h3 mb-0">语音克隆API调试工具</h1>
                    </div>
                    <div class="card-body p-4">
                        <form id="apiForm">
                            <div class="mb-4">
                                <label for="reference_id" class="form-label">声音模型ID <span class="text-danger">*</span></label>
                                <select class="form-control" id="reference_id" name="reference_id" required>
                                    <option value="fb215435-9cf1-4141-a938-d05e85c064ee">奶龙</option>
                                </select>
                                <div style="font-size: 12px; color: #6c757d; margin-top: 5px;">必填参数,声音模型的唯一标识符</div>
                            </div>
                            <div class="mb-4">
                                <label for="auth_token" class="form-label">认证令牌 <span class="text-danger">*</span></label>
                                <input type="text" class="form-control" id="auth_token" name="auth_token" placeholder="输入Bearer令牌" required>
                                <div style="font-size: 12px; color: #6c757d; margin-top: 5px;">必填参数,格式为Bearer YOUR_TOKEN</div>
                            </div>
                            <div class="mb-4">
                                <label for="text" class="form-label">文本内容 <span class="text-danger">*</span></label>
                                <textarea class="form-control" id="text" name="text" placeholder="输入要合成的文本" rows="5" required></textarea>
                                <div style="font-size: 12px; color: #6c757d; margin-top: 5px;">必填参数,要转换为语音的文本内容</div>
                            </div>
                            
                            <div class="row mb-4">
                                <div class="col-md-6">
                                    <label for="speed" class="form-label">语速</label>
                                    <input type="number" class="form-control" id="speed" name="speed" min="0.1" max="3" step="0.1" value="1.0">
                                    <div style="font-size: 12px; color: #6c757d; margin-top: 5px;">可选参数,默认值为1.0,范围0.1-3.0</div>
                                </div>
                                
                                <div class="col-md-6">
                                    <label for="volume" class="form-label">音量</label>
                                    <input type="number" class="form-control" id="volume" name="volume" min="-20" max="20" value="0">
                                    <div style="font-size: 12px; color: #6c757d; margin-top: 5px;">可选参数,默认值为0,范围-20到20</div>
                                </div>
                            </div>
                            
                            <div class="row mb-4">
                                <div class="col-md-6">
                                    <label for="version" class="form-label">版本号</label>
                                    <select class="form-select" id="version" name="version">
                                        <option value="v1" selected>v1</option>
                                        <option value="v2">v2</option>
                                        <option value="s1">s1(传统版本)</option>
                                        <option value="v3-turbo">v3-turbo(V3版本)</option>
                                        <option value="v3-hd">v3-hd(V3版本)</option>
                                    </select>
                                    <div style="font-size: 12px; color: #6c757d; margin-top: 5px;">可选参数,默认值为v1,可选值:"v1"、"v2"、"s1"(传统版本),"v3-turbo"、"v3-hd"(V3版本)</div>
                                </div>
                                
                                <div class="col-md-6">
                                    <label for="format" class="form-label">音频格式</label>
                                    <select class="form-select" id="format" name="format">
                                        <option value="mp3" selected>mp3</option>
                                        <option value="wav">wav</option>
                                        <option value="pcm">pcm</option>
                                    </select>
                                    <div style="font-size: 12px; color: #6c757d; margin-top: 5px;">可选参数,默认值为mp3,可选值:"mp3"、"wav"、"pcm"</div>
                                </div>
                            </div>
                            
                            <div class="row mb-4">
                                <div class="col-md-6">
                                    <div class="form-check pt-3">
                                        <input class="form-check-input" type="checkbox" id="cache" name="cache" value="true">
                                        <label class="form-check-label" for="cache">启用缓存</label>
                                    </div>
                                    <div style="font-size: 12px; color: #6c757d; margin-top: 5px;">可选参数,默认值为false,启用缓存后会保存音频文件</div>
                                </div>
                            </div>
                            
                            <!-- V3版本专用参数 -->
                            <div class="row mb-4 v3-params" style="display: none;">
                                <div class="col-md-6">
                                    <label for="emotion" class="form-label">情绪控制</label>
                                    <select class="form-select" id="emotion" name="emotion">
                                        <option value="auto" selected>auto</option>
                                        <option value="happy">happy</option>
                                        <option value="sad">sad</option>
                                        <option value="angry">angry</option>
                                        <option value="fearful">fearful</option>
                                        <option value="disgusted">disgusted</option>
                                        <option value="surprised">surprised</option>
                                        <option value="calm">calm</option>
                                        <option value="fluent">fluent</option>
                                    </select>
                                    <div style="font-size: 12px; color: #6c757d; margin-top: 5px;">仅V3版本支持,默认值为auto</div>
                                </div>
                                
                                <div class="col-md-6">
                                    <label for="language" class="form-label">语言增强</label>
                                    <select class="form-select" id="language" name="language">
                                        <option value="auto" selected>auto</option>
                                        <option value="zh">中文</option>
                                        <option value="en">英文</option>
                                    </select>
                                    <div style="font-size: 12px; color: #6c757d; margin-top: 5px;">仅V3版本支持,默认值为auto</div>
                                </div>
                            </div>

                            <div class="d-flex gap-3">
                                <button type="submit" class="btn btn-success btn-lg">
                                    <i class="bi bi-send"></i> 发送请求
                                </button>
                                <button type="reset" class="btn btn-danger btn-lg">
                                    <i class="bi bi-arrow-counterclockwise"></i> 重置
                                </button>
                            </div>
                        </form>
                    </div>
                </div>
            </div>
            
            <!-- 右侧响应和音频区域 (4列) -->
            <div class="col-md-4">
                <div class="card">
                    <div class="card-header bg-secondary text-white d-flex justify-content-between align-items-center">
                        <h3 class="h5 mb-0">响应结果</h3>
                        <span id="statusCode" class="badge bg-info">等待请求</span>
                    </div>
                    <div class="card-body">
                        <div id="responseBody" style="background-color: #f8f9fa; padding: 15px; border-radius: 4px; border: 1px solid #dee2e6; font-family: monospace; font-size: 13px; overflow-x: auto; white-space: pre-wrap; min-height: 150px;">请发送请求查看响应</div>
                    </div>
                </div>
                
                <div id="audioSection" class="mt-4 card" style="display: none;">
                    <div class="card-header bg-success text-white">
                        <h3 class="h5 mb-0">音频播放</h3>
                    </div>
                    <div class="card-body">
                        <audio id="audioPlayer" class="form-control" controls></audio>
                    </div>
                </div>
            </div>
        </div>
    </div>
    
    <script>
        // 版本选择事件监听器,用于显示/隐藏V3专用参数
        document.getElementById('version').addEventListener('change', function() {
            const v3Params = document.querySelectorAll('.v3-params');
            const isV3 = this.value === 'v3-turbo' || this.value === 'v3-hd';
            v3Params.forEach(param => {
                param.style.display = isV3 ? 'flex' : 'none';
            });
        });
        
        // 初始化时检查版本,显示/隐藏V3专用参数
        document.addEventListener('DOMContentLoaded', function() {
            const versionSelect = document.getElementById('version');
            const v3Params = document.querySelectorAll('.v3-params');
            const isV3 = versionSelect.value === 'v3-turbo' || versionSelect.value === 'v3-hd';
            v3Params.forEach(param => {
                param.style.display = isV3 ? 'flex' : 'none';
            });
        });
        
        document.getElementById('apiForm').addEventListener('submit', function(e) {
            e.preventDefault();
            
            const formData = {
                reference_id: document.getElementById('reference_id').value,
                text: document.getElementById('text').value,
                speed: parseFloat(document.getElementById('speed').value),
                volume: parseInt(document.getElementById('volume').value),
                version: document.getElementById('version').value,
                cache: document.getElementById('cache').checked,
                format: document.getElementById('format').value
            };
            
            // 仅在V3版本时添加emotion和language参数
            const version = document.getElementById('version').value;
            if (version === 'v3-turbo' || version === 'v3-hd') {
                formData.emotion = document.getElementById('emotion').value;
                formData.language = document.getElementById('language').value;
            }
            
            let authToken = document.getElementById('auth_token').value;
            
            // 确保Authorization头包含Bearer前缀
            if (authToken && !authToken.startsWith('Bearer ')) {
                authToken = 'Bearer ' + authToken;
            }
            
            // 显示加载状态
            document.getElementById('statusCode').className = 'badge bg-info';
            document.getElementById('statusCode').textContent = '加载中...';
            document.getElementById('responseBody').textContent = '正在发送请求...';
            document.getElementById('audioSection').style.display = 'none';
            
            // 释放旧的音频URL,避免内存泄漏
            const audioPlayer = document.getElementById('audioPlayer');
            if (audioPlayer.src && audioPlayer.src.startsWith('blob:')) {
                URL.revokeObjectURL(audioPlayer.src);
            }
            
            // 添加更多调试信息
            console.log('发送请求:', {
                url: 'https://www.yuntts.com/api/v1/fishspeech-generate',
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                    'Authorization': authToken ? 'Bearer [隐藏]' : '未提供'
                },
                body: formData
            });
            
            // 发送请求
            fetch('https://www.yuntts.com/api/v1/fishspeech-generate', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                    'Authorization': authToken
                },
                body: JSON.stringify(formData)
            })
            .then(response => {
                // 添加响应调试信息
                console.log('响应状态:', response.status);
                console.log('响应头部:', {
                    'content-type': response.headers.get('content-type'),
                    'content-length': response.headers.get('content-length'),
                    'access-control-allow-origin': response.headers.get('access-control-allow-origin')
                });
                
                // 检查是否是缓存模式(cache=true)
                if (formData.cache) {
                    // 缓存模式下返回JSON
                    return response.json().then(data => {
                        return {
                            status: response.status,
                            data: data,
                            isBinary: false
                        };
                    });
                } else {
                    // 非缓存模式下返回二进制数据
                    return response.blob().then(blob => {
                        return {
                            status: response.status,
                            data: blob,
                            isBinary: true
                        };
                    });
                }
            })
            .then(result => {
                // 更新状态码
                const statusCode = document.getElementById('statusCode');
                statusCode.textContent = `状态码: ${result.status}`;
                
                if (result.status >= 200 && result.status < 300) {
                    statusCode.className = 'badge bg-success';
                } else {
                    statusCode.className = 'badge bg-danger';
                }
                
                // 处理响应内容
                const responseBody = document.getElementById('responseBody');
                
                // 处理音频播放
                const audioPlayer = document.getElementById('audioPlayer');
                
                if (result.isBinary) {
                    // 处理非缓存模式:直接返回二进制音频数据
                    try {
                        // 使用二进制数据创建Blob对象
                        const blob = result.data;
                        
                        // 创建音频URL
                        const audioURL = URL.createObjectURL(blob);
                        
                        // 设置音频播放器事件
                        audioPlayer.onerror = function(e) {
                            console.error('音频加载错误:', e);
                            responseBody.textContent += '\n\n音频加载失败: ' + (e.target.error ? e.target.error.message : '未知错误');
                        };
                        
                        audioPlayer.oncanplaythrough = function() {
                            console.log('音频可以正常播放了');
                        };
                        
                        audioPlayer.onended = function() {
                            console.log('音频播放完毕');
                        };
                        
                        // 设置音频源并加载
                        audioPlayer.src = audioURL;
                        audioPlayer.load(); // 确保音频正确加载
                        
                        // 显示音频播放区域
                        document.getElementById('audioSection').style.display = 'block';
                        
                        // 显示响应信息
                        responseBody.textContent = '成功获取音频数据!\n\n';
                        responseBody.textContent += '音频格式: ' + blob.type + '\n';
                        responseBody.textContent += '音频大小: ' + blob.size + ' bytes\n';
                        
                        // 添加调试信息
                        console.log('音频格式:', blob.type);
                        console.log('音频大小:', blob.size + ' bytes');
                        console.log('音频URL:', audioURL);
                    } catch (error) {
                        console.error('处理音频数据失败:', error);
                        responseBody.textContent = '处理音频数据失败: ' + error.message;
                    }
                } else {
                    // 处理缓存模式:返回JSON格式
                    responseBody.textContent = JSON.stringify(result.data, null, 2);
                    
                    if (result.data && result.data.audio_url) {
                        // 处理缓存模式:有音频URL
                        // 添加音频加载错误处理
                        audioPlayer.onerror = function(e) {
                            console.error('音频加载错误:', e);
                            // 只显示有用的错误信息,避免显示事件对象的默认字符串
                            responseBody.textContent += '\n\n音频加载失败,请检查控制台错误信息。';
                        };
                        
                        audioPlayer.oncanplaythrough = function() {
                            console.log('音频可以正常播放了');
                        };
                        
                        audioPlayer.src = result.data.audio_url;
                        audioPlayer.load(); // 确保音频正确加载
                        document.getElementById('audioSection').style.display = 'block';
                    }
                }
            })
            .catch(error => {
                // 处理错误
                const statusCode = document.getElementById('statusCode');
                statusCode.className = 'status-code bg-danger text-white';
                statusCode.textContent = '请求失败';
                
                const responseBody = document.getElementById('responseBody');
                responseBody.textContent = `请求失败: ${error.message}`;
            });
        });
    </script>
</body>
</html>

FishSpeech 语音克隆 API接口文档

接口概述

本接口提供语音克隆模型创建服务,支持多文件上传创建声音模型。

接口地址

POST https://www.yuntts.com/api/v1/fishspeech-cloning

请求方法

  • POST

Content-Type

  • multipart/form-data

认证方式

需要在请求头中添加API密钥:

Authorization: Bearer YOUR_API_KEY

请求参数

请求参数采用multipart/form-data格式,以下是所有可用参数的详细说明:

参数名 类型 是否必填 说明
name string 模型名称
description string 模型描述
audioFiles file 音频文件,支持多文件上传,格式:WAV/MP3,最大4MB

请求示例

单文件上传示例

curl -X POST "https://www.yuntts.com/api/v1/fishspeech-cloning" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -F "name=我的声音模型" \
  -F "description=个人语音克隆模型" \
  -F "audioFiles=@sample1.wav"

多文件上传示例

curl -X POST "https://www.yuntts.com/api/v1/fishspeech-cloning" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -F "name=我的声音模型" \
  -F "description=个人语音克隆模型" \
  -F "audioFiles=@sample1.wav" \
  -F "audioFiles=@sample2.mp3" \
  -F "audioFiles=@sample3.wav"

响应格式

成功响应

{
    "code": 200,
    "msg": "模型创建成功",
    "data": {
        "model_id": "fb215435-9cf1-4141-a938-d05e85c064ee",
        "name": "我的声音模型"
    }
}

错误响应

当请求失败时,接口返回以下格式的错误信息:

{
    "code": 400,
    "error": "invalid_parameters",
    "msg": "模型名称不能为空"
}

错误码说明

错误码 HTTP状态码 错误类型 说明
invalid_parameters 400 参数错误 缺少必要参数(如模型名称)
invalid_file 400 文件错误 未选择音频文件
invalid_file_type 400 文件类型错误 音频格式不支持
file_too_large 400 文件大小错误 音频文件超过4MB限制
api_connection_error 500 服务器错误 连接第三方服务失败
json_decode_failed 500 服务器错误 解析响应失败

调试工具

可以使用以下调试工具测试API接口:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>语音模型创建</title>
    <link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/5.3.0/css/bootstrap.min.css" rel="stylesheet">
    <style>
        .file-upload {
            border: 2px dashed #dee2e6;
            border-radius: 0.375rem;
            padding: 2rem;
            text-align: center;
        }
        .progress {
            height: 1.5rem;
            margin-top: 1rem;
        }
    </style>
</head>
<body>
<div class="container py-5">
    <div class="row justify-content-center">
        <div class="col-md-8 col-lg-6">
            <h2 class="mb-4">创建语音克隆模型</h2>
            
            <!-- 错误提示 -->
            <div class="alert alert-danger d-none" id="errorAlert"></div>
            
            <form id="modelForm">
                <!-- 模型名称 -->
                <div class="mb-3">
                    <label class="form-label">模型名称 *</label>
                    <input type="text" class="form-control" name="name" required>
                </div>

                <!-- 模型描述 -->
                <div class="mb-3">
                    <label class="form-label">模型描述</label>
                    <textarea class="form-control" name="description" rows="3"></textarea>
                </div>

                <!-- 文件上传 -->
                <div class="mb-3">
                    <label class="form-label">音频文件 *</label>
                    <div class="file-upload">
                        <input type="file" class="form-control" name="audioFiles" accept=".wav,.mp3" required>
                        <small class="text-muted d-block mt-2">支持格式:WAV/MP3,最大4MB</small>
                        <div class="invalid-feedback" id="fileError"></div>
                    </div>
                </div>

                <button type="submit" class="btn btn-primary w-100">
                    <span class="spinner-border spinner-border-sm d-none" role="status"></span>
                    提交创建
                </button>
            </form>

            <!-- 结果展示 -->
            <div class="mt-4 card d-none" id="resultCard">
                <div class="card-body">
                    <h5 class="card-title">创建成功</h5>
                    <ul class="list-unstyled">
                        <li>模型ID: <span id="modelId"></span></li>
                        <li>创建时间: <span id="createdAt"></span></li>
                    </ul>
                </div>
            </div>
        </div>
    </div>
</div>

<script src="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/5.3.0/js/bootstrap.bundle.min.js"></script>
<script>
document.getElementById('modelForm').addEventListener('submit', async (e) => {
    e.preventDefault();
    
    const form = e.target;
    const submitBtn = form.querySelector('button[type="submit"]');
    const spinner = submitBtn.querySelector('.spinner-border');
    const fileInput = form.querySelector('input[type="file"]');
    
    // 重置状态
    document.getElementById('errorAlert').classList.add('d-none');
    spinner.classList.remove('d-none');
    submitBtn.disabled = true;

    try {
        // 前端验证
        if (!fileInput.files[0]) {
            throw new Error('请选择音频文件');
        }

        const file = fileInput.files[0];
        if (!['audio/wav', 'audio/mpeg', 'audio/mp3'].includes(file.type)) {
            throw new Error('仅支持WAV/MP3格式');
        }

        if (file.size > 4 * 1024 * 1024) {
            throw new Error('文件大小超过4MB限制');
        }

        // 构建FormData
        const formData = new FormData();
        formData.append('name', form.name.value);
        formData.append('description', form.description.value);
        formData.append('audioFiles', file);

        // 添加请求参数日志
        console.log('提交表单参数:', {
            name: form.name.value,
            description: form.description.value,
            audioFile: file.name
        });

        // 发送请求
        const response = await fetch('https://www.yuntts.com/api/v1/fishspeech-cloning', {
            method: 'POST',
            headers: {
                'Authorization': `Bearer sk-1f5041702bf69aff59e1f18027a2dac4`,
                // 移除手动设置的Content-Type头,浏览器会自动生成正确的boundary
            },
            body: formData
        });

        const result = await response.json();

        if (!response.ok) {
            throw new Error(result.msg || '请求失败');
        }

        // 显示结果
        document.getElementById('resultCard').classList.remove('d-none');
        document.getElementById('modelId').textContent = result.modelId;
        document.getElementById('createdAt').textContent = result.createdAt;
        form.reset();
    } catch (error) {
        const errorAlert = document.getElementById('errorAlert');
        errorAlert.textContent = error.message;
        errorAlert.classList.remove('d-none');
    } finally {
        spinner.classList.add('d-none');
        submitBtn.disabled = false;
    }
});

</script>
</body>
</html>

 

FishSpeech音色查询 API接口文档

接口地址

https://www.yuntts.com/api/v1/fishspeech-query

请求头

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

请求参数

 {
  "page": 1,//页面
  "page_size": 20,//每页条数
  "includePersonal": false//是否包含个人模型
}

返回参数

{
    "total": 65,
    "page": 1,
    "pageSize": 70,
    "totalPages": 1,
    "data": [
        {
            "modelId": "fb215435-9cf1-4141-a938-d05e85c064ee",
            "modelName": "奶龙",
            "description": "小朋友们,准备好迎接奶龙的魔法了吗?",
            "gender": "male",
            "scene_type": "general",
            "demoAudioUrl": "https://www.yuntts.com/audio/nailong.mp3",
            "avatarUrl": "/wp-content/themes/360mb-v5/assets/tts/avatar/nailong.webp",
            "createdAt": "2024-10-09 02:44:08",
            "updatedAt": "2025-05-09 22:25:53",
            "isPersonal": false
        },
        {
            "modelId": "ff66d8d5-818f-43a8-9b6b-7936b6e75900",
            "modelName": "女主播大白兔",
            "description": "大家好,我是大白兔,欢迎进入我的直播间!",
            "gender": "male",
            "scene_type": "general",
            "demoAudioUrl": "https://www.yuntts.com/audio/nvzhubodabaitu.mp3",
            "avatarUrl": "/wp-content/themes/360mb-v5/assets/tts/avatar/dabaitu.webp",
            "createdAt": "2025-01-16 12:28:39",
            "updatedAt": "2025-05-09 22:24:57",
            "isPersonal": true
        }
    ]
}

返回参数说明

克隆语音模型接口响应参数说明
字段名 类型 描述 示例值
total int 总记录数 65
page int 当前页码 1
pageSize int 每页记录数 70
totalPages int 总页数 1
data[].modelId string 模型唯一标识(UUID格式) fb215435-9cf1-4141-a938-d05e85c064ee
data[].modelName string 模型显示名称 奶龙
data[].description string 模型描述文本 小朋友们,准备好迎接奶龙的魔法了吗?
data[].gender string 语音性别类型(male/female) male
data[].demoAudioUrl string 演示音频URL地址 mp3地址
data[].avatarUrl string 模型头像路径(相对/绝对) 头像地址
data[].isPersonal bool 是否个人模型 false

参考代码

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>模型查询接口调试</title>
    <link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/5.3.0/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div class="container py-4">
    <h3 class="mb-4">克隆模型查询接口调试</h3>
    
    <form id="queryForm" class="mb-4">
        <div class="row g-3">
            <div class="col-md-3">
                <label class="form-label">页码</label>
                <input type="number" class="form-control" id="page" name="page" min="1" value="1" required>
                <div class="invalid-feedback">页码必须≥1</div>
            </div>
            
            <div class="col-md-3">
                <label class="form-label">每页条数</label>
                <input type="number" class="form-control" id="page_size" name="page_size" min="1" max="100" value="20" required>
                <div class="invalid-feedback">1-100之间</div>
            </div>
            
            <div class="col-md-6">
                <div class="form-check form-switch mt-4 pt-2">
                    <input class="form-check-input" type="checkbox" role="switch" id="includePersonal">
                    <label class="form-check-label" for="includePersonal">包含个人模型</label>
                </div>
            </div>
        </div>
        
        <button type="submit" class="btn btn-primary mt-3">查询</button>
    </form>

    <div class="card">
        <div class="card-header">响应结果</div>
        <div class="card-body p-0">
            <textarea id="responseArea" class="form-control" style="height:400px; font-family: monospace" readonly></textarea>
        </div>
    </div>
</div>

<script src="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/5.3.0/js/bootstrap.bundle.min.js"></script>
<script>
document.getElementById('queryForm').addEventListener('submit', async (e) => {
    e.preventDefault();
    
    const formData = {
        page: parseInt(document.getElementById('page').value),
        page_size: parseInt(document.getElementById('page_size').value),
        includePersonal: document.getElementById('includePersonal').checked
    };
    console.log('请求参数:', JSON.stringify(formData, null, 2));

    try {
        const response = await fetch('https://www.yuntts.com/api/v1/fishspeech-query', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
                'Authorization': `Bearer 68985a242e655fb2d0194dfb478f1f76`,
            },
            body: JSON.stringify(formData)
        });

        const result = await response.json();
        document.getElementById('responseArea').value = JSON.stringify(result, null, 4);
        
        if (!response.ok) {
            alert(`请求失败: ${result.error || result.msg}`);
        }
    } catch (error) {
        console.error('请求失败:', error);
        document.getElementById('responseArea').value = `网络错误: ${error.message}`;
    }
});
</script>
</body>
</html>

curl -X POST "https://www.yuntts.com/api/v1/fishspeech-query" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer your_api_key_here" \
-d '{
    "page": 2,
    "pageSize": 30,
    "includePersonal": true
}'

FishSpeech 删除模型 API接口文档

接口地址

https://www.yuntts.com/wp-json/api/v1/fishspeech-delete

请求头

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

请求参数

{
  "modelId": string  // 必填,要删除的模型ID
}

返回数据

{
    "code": 200,
    "msg": "模型删除成功",
    "modelId": "7ef46f62-fe18-4c47-9948-d8861134e649",
    "quota_remaining": 184.6015
}

参考代码

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>删除语音模型</title>
    <link href="https://cdn.bootcdn.net/ajax/libs/bootstrap/5.3.3/css/bootstrap.min.css" rel="stylesheet">
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
</head>
<body class="bg-light">
    <div class="container py-5">
        <div class="card shadow-sm">
            <div class="card-header bg-danger text-white">
                <h3 class="mb-0">删除语音模型</h3>
            </div>
            <div class="card-body">
                <form id="deleteForm">
                    <div class="mb-3">
                        <label for="modelId" class="form-label">模型ID</label>
                        <input type="text" class="form-control" id="modelId" required>
                        <div class="form-text text-muted">请输入要删除的模型ID</div>
                    </div>
                    <button type="submit" class="btn btn-danger">删除模型</button>
                </form>
                
                <div id="resultAlert" class="mt-4 d-none">
                    <div class="alert alert-dismissible fade show">
                        <button type="button" class="btn-close" data-bs-dismiss="alert"></button>
                        <span class="alert-message"></span>
                    </div>
                </div>
            </div>
        </div>
    </div>

    <script>
    $(document).ready(function() {
        $('#deleteForm').submit(function(e) {
            e.preventDefault();
            
            const modelId = $('#modelId').val().trim();
            if (!modelId) {
                showAlert('请输入有效的模型ID', 'danger');
                return;
            }

            $.ajax({
                url: '/wp-json/api/v1/fishspeech-delete',
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                    'Authorization': `Bearer 68985a242e655fb2d0194dfb478f1f76`,
                },
                data: JSON.stringify({ modelId: modelId }),
                success: function(response) {
                    if (response.code === 200) {
                        showAlert(`${response.message} 剩余额度:${response.quota_remaining}`, 'success');
                    } else {
                        showAlert(response.msg || '操作失败', 'warning');
                    }
                },
                error: function(xhr) {
                    const error = xhr.responseJSON || {};
                    showAlert(error.msg || '服务器错误,请稍后再试', 'danger');
                }
            });
        });

        function showAlert(message, type) {
            const $alert = $('#resultAlert').removeClass('d-none').find('.alert');
            $alert.removeClass('alert-success alert-danger alert-warning')
                 .addClass(`alert-${type}`)
                 .find('.alert-message').text(message);
        }
    });
    </script>
</body>
</html>

curl -X POST https://fishspeech.net/api/open/fishspeech-delete \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -d '{
    "modelId": "your_model_id"
  }

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。