文字转语音

This commit is contained in:
spllzh
2025-10-04 19:52:06 +08:00
parent 24c00c22ab
commit 06730b656e
51 changed files with 5157 additions and 8 deletions

View File

@@ -67,6 +67,10 @@ spring:

View File

@@ -135,4 +135,29 @@ dify:
summary-nameplate-token: app-cv5glaYrY4zgjq0XIidSoJea
portrait-3in1-token: app-jlrV6lLDlhy1YDEdUiK4hdVZ
ai-feed-token: app-b6kFOvLvAsAOxB1vDgSNa0OO
top-sales-alldim-token: app-99nVuuKfcRR2vikxgOTiNQm0
top-sales-alldim-token: app-99nVuuKfcRR2vikxgOTiNQm0
classification-token: app-Id1eOuv5yBb1pexpEWVDqSS3
# MinIO 对象存储配置
minio:
# MinIO服务器地址
endpoint: http://101.35.52.237:19005
# 访问密钥
access-key: minioadmin
# 秘密密钥
secret-key: minioadmin
# 默认存储桶名称
bucket-name: car
# SiliconFlow API 配置
siliconflow:
# SiliconFlow API 基础URL
base-url: https://api.siliconflow.cn/v1
# API Token - 请替换为您的实际Token
api-key: ${siliconflow_api_key}
# 默认TTS模型
default-tts-model: FunAudioLLM/CosyVoice2-0.5B
# 请求超时时间(毫秒)
timeout: 30000
# 是否启用SiliconFlow服务
enabled: true

View File

@@ -0,0 +1,254 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>TTS音频转换演示</title>
<style>
body {
font-family: Arial, sans-serif;
max-width: 800px;
margin: 0 auto;
padding: 20px;
background-color: #f5f5f5;
}
.container {
background: white;
padding: 30px;
border-radius: 10px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}
h1 {
color: #333;
text-align: center;
margin-bottom: 30px;
}
.form-group {
margin-bottom: 20px;
}
label {
display: block;
margin-bottom: 5px;
font-weight: bold;
color: #555;
}
textarea {
width: 100%;
padding: 10px;
border: 1px solid #ddd;
border-radius: 5px;
font-size: 14px;
resize: vertical;
min-height: 100px;
}
button {
background-color: #007bff;
color: white;
padding: 12px 24px;
border: none;
border-radius: 5px;
cursor: pointer;
font-size: 16px;
margin-right: 10px;
}
button:hover {
background-color: #0056b3;
}
button:disabled {
background-color: #ccc;
cursor: not-allowed;
}
.result {
margin-top: 20px;
padding: 15px;
background-color: #f8f9fa;
border-radius: 5px;
border-left: 4px solid #007bff;
}
.error {
border-left-color: #dc3545;
background-color: #f8d7da;
}
.success {
border-left-color: #28a745;
background-color: #d4edda;
}
.audio-info {
margin-top: 15px;
padding: 10px;
background-color: #e9ecef;
border-radius: 5px;
}
.audio-controls {
margin-top: 15px;
}
audio {
width: 100%;
margin-top: 10px;
}
.loading {
display: none;
text-align: center;
color: #666;
}
.spinner {
border: 3px solid #f3f3f3;
border-top: 3px solid #007bff;
border-radius: 50%;
width: 30px;
height: 30px;
animation: spin 1s linear infinite;
margin: 0 auto 10px;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
</style>
</head>
<body>
<div class="container">
<h1>🎵 TTS音频转换演示</h1>
<form id="ttsForm">
<div class="form-group">
<label for="textInput">输入要转换的文本:</label>
<textarea id="textInput" placeholder="请输入要转换为语音的文本..." required></textarea>
</div>
<button type="submit" id="convertBtn">🎤 转换为语音</button>
<button type="button" id="clearBtn">🗑️ 清空</button>
</form>
<div class="loading" id="loading">
<div class="spinner"></div>
<p>正在转换中,请稍候...</p>
</div>
<div id="result" class="result" style="display: none;">
<h3>转换结果</h3>
<div id="resultContent"></div>
</div>
</div>
<script>
const form = document.getElementById('ttsForm');
const textInput = document.getElementById('textInput');
const convertBtn = document.getElementById('convertBtn');
const clearBtn = document.getElementById('clearBtn');
const loading = document.getElementById('loading');
const result = document.getElementById('result');
const resultContent = document.getElementById('resultContent');
form.addEventListener('submit', async (e) => {
e.preventDefault();
const text = textInput.value.trim();
if (!text) {
alert('请输入要转换的文本');
return;
}
await convertToSpeech(text);
});
clearBtn.addEventListener('click', () => {
textInput.value = '';
result.style.display = 'none';
});
async function convertToSpeech(text) {
showLoading(true);
hideResult();
try {
const response = await fetch('/api/tts/speech', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
input: text,
model: 'fnlp/MOSS-TTSD-v0.5',
voice: 'fnlp/MOSS-TTSD-v0.5:claire'
})
});
const data = await response.json();
if (data.success) {
showResult(data, text);
} else {
showError(data.message || '转换失败');
}
} catch (error) {
console.error('转换失败:', error);
showError('网络错误:' + error.message);
} finally {
showLoading(false);
}
}
function showLoading(show) {
loading.style.display = show ? 'block' : 'none';
convertBtn.disabled = show;
}
function hideResult() {
result.style.display = 'none';
}
function showResult(data, inputText) {
result.className = 'result success';
result.style.display = 'block';
const audioInfo = `
<div class="audio-info">
<h4>📊 音频信息</h4>
<p><strong>格式:</strong> ${data.format || 'mp3'}</p>
<p><strong>采样率:</strong> ${data.sampleRate || 44100} Hz</p>
<p><strong>时长:</strong> ${data.duration ? data.duration.toFixed(2) : '未知'} 秒</p>
<p><strong>文件大小:</strong> ${data.audioSizeBytes ? (data.audioSizeBytes / 1024).toFixed(2) + ' KB' : '未知'}</p>
<p><strong>Base64长度</strong> ${data.audioLength || '未知'}</p>
</div>
`;
const audioControls = data.audio ? `
<div class="audio-controls">
<h4>🎵 音频播放</h4>
<audio controls>
<source src="data:audio/mp3;base64,${data.audio}" type="audio/mpeg">
您的浏览器不支持音频播放
</audio>
</div>
` : '';
const minioInfo = data.minioUrl ? `
<div class="audio-info">
<h4>☁️ MinIO存储</h4>
<p><strong>访问URL</strong> <a href="${data.minioUrl}" target="_blank">${data.minioUrl}</a></p>
<p><strong>直接播放:</strong> <a href="${data.minioUrl}" target="_blank">点击播放</a></p>
</div>
` : '';
resultContent.innerHTML = `
<p><strong>输入文本:</strong> ${inputText}</p>
${audioInfo}
${audioControls}
${minioInfo}
`;
}
function showError(message) {
result.className = 'result error';
result.style.display = 'block';
resultContent.innerHTML = `<p><strong>错误:</strong> ${message}</p>`;
}
// 页面加载时显示示例文本
window.addEventListener('load', () => {
textInput.value = '你好这是一个TTS语音转换测试。欢迎使用我们的语音合成服务';
});
</script>
</body>
</html>