前言说明

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

OpenAudio(前身为知名开源 TTS 项目 Fish Speech)是由 Fish Audio 团队打造的顶尖AI 文本转语音(TTS)技术体系,专注于提供高自然度、多语言、零样本语音克隆的合成解决方案。

API接口插图

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接口文档

接口概述

本接口提供语音克隆模型创建服务,支持多文件上传创建声音模型,为防止接口滥用,接口已做克隆数量限制。

Fish Speech插图

克隆数量限制

用户类型 可创建模型数量
普通用户 2
VIP会员 10
永久会员 无限制

 接口地址

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"

响应格式

成功响应

{
  "modelId": "f18680d3-caa2-4e65-bc9e-b1265cba9d15",
  "title": "测试模型",
  "description": "这是一个测试模型",
  "createdAt": "2026-03-19T14:27:19.525+00:00",
  "message": "模型创建成功"
}

错误响应

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

{
    "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>

                <!-- API 密钥 -->
                <div class="mb-3">
                    <label class="form-label">API 密钥 *</label>
                    <input type="text" class="form-control" id="apiKey" required placeholder="请输入 API 密钥">
                </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="modelTitle"></span></li>
                        <li>模型描述: <span id="modelDescription"></span></li>
                        <li>创建时间: <span id="createdAt"></span></li>
                        <li>提示信息: <span id="modelMessage"></span></li>
                    </ul>
                    <div class="mt-3">
                        <h6 class="text-muted">完整响应日志:</h6>
                        <pre class="bg-light p-2 rounded text-sm" id="responseLog"></pre>
                    </div>
                </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
        });

        // 获取 API 密钥
        const apiKey = document.getElementById('apiKey').value;
        if (!apiKey) {
            throw new Error('请输入 API 密钥');
        }

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

        const result = await response.json();

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

        // 显示结果
        document.getElementById('resultCard').classList.remove('d-none');
        document.getElementById('modelId').textContent = result.modelId;
        document.getElementById('modelTitle').textContent = result.title;
        document.getElementById('modelDescription').textContent = result.description || '无';
        document.getElementById('createdAt').textContent = result.createdAt;
        document.getElementById('modelMessage').textContent = result.message || '模型创建成功';
        document.getElementById('responseLog').textContent = JSON.stringify(result, null, 2);
        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-delete

请求头

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

请求参数

{
  "modelId": "b210a45b-2e09-4730-be18-7963c8054cf1"
}

返回数据

{
    "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"
  }

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