前言说明
在数字化浪潮席卷全球的时代,语音交互正以前所未有的速度融入我们的生活与工作场景,从智能客服到有声内容创作,从导航语音播报再到教育场景的语言学习,优质、高效的语音合成技术成为了推动行业创新发展的关键力量。云音智联深度洞察市场需求,依托 Fish Speech 先进的语音合成技术,致力于为用户提供专业、精准且极具表现力的语音合成功能。我们凭借强大的技术研发实力,基于 Fish Speech 技术开发了专属 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接口文档
接口概述
本接口提供语音克隆模型创建服务,支持多文件上传创建声音模型。
接口地址
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"
}


评论(0)