Administrator
Administrator
Published on 2025-04-26 / 13 Visits
1
0

景音随行:低资源服务器上快速落地 TTS(文本转语音)服务实践

背景介绍

在我们的项目 「景音随行」 中,需要为每个景点提供自动语音讲解功能。即将景点的文字描述即时转成自然流畅的语音,让游客能够沉浸式体验景区文化。

项目背景有几个关键限制条件:

  • 服务器资源有限(1核2G)

  • 支持多语种:简体中文、繁体中文、英文

  • 语音质量高:尽量自然,不要太电子感

  • 调用简洁:Java Web 系统集成

  • 延迟低:适合同步播放或快速生成音频文件


开源 TTS 框架调研与对比

我们初步调研了以下几个主流开源 TTS 项目:

项目

优点

缺点

Coqui-TTS

模型多,自定义强

资源占用极大,需要 GPU

ChatTTS

音质优秀,接近 SOTA

推理慢,需要大内存

CosyVoice

微调版小模型

支持语言少,中文一般

Spark-TTS

高性能推理引擎

依赖复杂,需要训练模型

edge-tts

轻量、开箱即用、微软云音色

云接口模拟,完全本地推理

Kokoro-FastAPI

封装服务化简单

底层仍依赖大型模型


最终选择:edge-tts

经过测试,edge-tts音质、速度、资源占用 之间达到了非常好的平衡:

  • 📦 体积小:仅依赖 Python + edge-tts 库

  • 🎤 音质好:微软官方 Neural 系列音色

  • 🌍 多语言支持:中文、英文、甚至更多小语种

  • 🚀 启动快:冷启动 < 1s

  • 💻 低资源运行:无 GPU 要求,1G 内存也能跑


技术实现方案

我们的整体思路是:
Java Web 项目调用Python脚本,动态生成语音 MP3 二进制流,直接返回前端播放。

整体架构图:

[Java Controller] 
     ↓
[PythonTTSBridge (ProcessBuilder)]
     ↓
[Python 脚本 (edge-tts)]
     ↓
[MP3字节流输出]
     ↓
[浏览器或小程序播放]

核心代码实现

1. Java 调用 Python:PythonTTSBridge.java

package com.xxx.integration;

import java.io.*;
import java.util.concurrent.*;

public class PythonTTSBridge {

    private static final ExecutorService pool = Executors.newFixedThreadPool(10);
    private static final String PYTHON_PATH = "/usr/bin/python3";
    private static final String SCRIPT_PATH = "/opt/soundJourney/tts/tts.py";

    public static Future<byte[]> generateSpeech(String text, String langCode) {
        return pool.submit(() -> {
            ProcessBuilder pb = new ProcessBuilder(
                PYTHON_PATH, SCRIPT_PATH, text, langCode
            );
            Process process = pb.start();

            try (InputStream in = process.getInputStream()) {
                byte[] audio = in.readAllBytes();
                process.waitFor(10, TimeUnit.SECONDS);
                return audio;
            } catch (Exception e) {
                throw new RuntimeException("TTS生成失败", e);
            } finally {
                process.destroy();
            }
        });
    }
}

2. Controller 层暴露接口

@RestController
@RequestMapping("/api/tts")
public class TTSController {

    @PostMapping(produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
    public ResponseEntity<byte[]> tts(@RequestParam String text, @RequestParam String langCode) throws Exception {
        byte[] mp3Bytes = PythonTTSBridge.generateSpeech(text, langCode).get(12, TimeUnit.SECONDS);
        return ResponseEntity.ok()
                .header(HttpHeaders.CONTENT_DISPOSITION, "inline; filename=\"speech.mp3\"")
                .contentType(MediaType.APPLICATION_OCTET_STREAM)
                .body(mp3Bytes);
    }
}

3. Python TTS 脚本:/opt/soundJourney/tts/tts.py

#!/usr/bin/env python3
import sys
import asyncio
import edge_tts
import tempfile
import os

def log(*args):
    print("[TTS LOG]", *args, file=sys.stderr)

if len(sys.argv) != 3:
    log("参数错误,应为:文本 langCode")
    sys.exit(1)

text, lang_code = sys.argv[1], sys.argv[2]

voice_map = {
    "1": "zh-CN-XiaoxiaoNeural",
    "2": "zh-TW-HsiaoChenNeural",
    "3": "en-US-JennyNeural",
}

voice = voice_map.get(lang_code)
if not voice:
    log(f"不支持的语言类型: {lang_code}")
    sys.exit(1)

async def synthesize():
    try:
        with tempfile.NamedTemporaryFile(delete=False, suffix=".mp3") as tmp_file:
            tmp_path = tmp_file.name
        communicate = edge_tts.Communicate(text=text, voice=voice)
        await communicate.save(tmp_path)
        with open(tmp_path, "rb") as f:
            sys.stdout.buffer.write(f.read())
            sys.stdout.flush()
        os.remove(tmp_path)
    except Exception as e:
        log("语音合成失败:", str(e))
        sys.exit(1)

asyncio.run(synthesize())

现有成果

  • 支持简体中文、繁体中文、英文三种语言

  • 端到端延迟稳定在 1-2秒

  • 服务器资源占用率低于 15% CPU / 200MB内存

  • 支持高并发请求,后台线程池统一管理


下一步优化建议

优化方向

具体措施

备注

缓存机制

对常用文本加缓存,避免重复生成

Redis 或本地缓存

流式输出

分段推送音频流,边播边合成

降低首音延迟

多音色扩展

根据场景动态切换不同 speaker

丰富听觉体验

错误重试机制

Python 脚本异常时自动重试一次

提升稳定性

Docker 容器化

封装 Python 运行环境,提升部署一致性

特别适合微服务体系


最后总结

edge-tts 给了我们一个快速、轻量、易集成的文本转语音方案,尤其适合资源受限的场景。

整个方案没有引入任何重量级模型,不需要GPU,却依然可以做到效果自然、体验良好。

希望这篇文章能帮到同样想在项目中引入 TTS 功能的开发者们!


Comment