废话不多说,咋们先注册好百度智能云账号,创建好语音合成的应用
1.配置依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
2.application.properties文件\application.yml文件配置
baidu.tts.api-key=应用的API Key
baidu.tts.secret-key=应用的 Secret Key
3.服务层
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.Map;
@Service
public class BaiduTtsService {
@Value("${baidu.tts.api-key}")
private String apiKey;
@Value("${baidu.tts.secret-key}")
private String secretKey;
private final RestTemplate restTemplate = new RestTemplate();
// 获取Access Token(有效期30天)
private String getAccessToken() {
String authUrl = "https://aip.baidubce.com/oauth/2.0/token" +
"?grant_type=client_credentials" +
"&client_id=" + apiKey +
"&client_secret=" + secretKey;
ResponseEntity<Map> response = restTemplate.getForEntity(authUrl, Map.class);
return (String) response.getBody().get("access_token");
}
// 调用语音合成API
public byte[] textToSpeech(String encodedText, String voiceType, String pitch) {
try {
// 解码前端传递的URL编码文本
String decodedText = URLDecoder.decode(encodedText, "UTF-8");
String accessToken = getAccessToken();
String ttsUrl = "https://tsn.baidu.com/text2audio" +
"?tex=" + encodeText(decodedText) + // 重新编码给百度API
"&lan=zh" +
"&cuid=123" +
"&ctp=1" +
"&tok=" + accessToken +
"&per=" + voiceType + // 音色
"&pit=" + pitch; // 音调
return restTemplate.getForObject(ttsUrl, byte[].class);
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("解码失败", e);
}
}
// 处理中文编码
private String encodeText(String text) {
try {
return URLEncoder.encode(text, "UTF-8");
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("文本编码失败", e);
}
}
}
(该案例用的短文本在线合成+基础音库)
4.Controller层
import com.lxy.other.service.BaiduTtsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class TttsController {
@Autowired
private BaiduTtsService ttsService;
@GetMapping("/generate-audio")
public ResponseEntity<ByteArrayResource> generateAudio(
@RequestParam String text,
@RequestParam(defaultValue = "0") String voiceType, // 默认音色
@RequestParam(defaultValue = "5") String pitch // 默认音调
) {
byte[] audioData = ttsService.textToSpeech(text, voiceType, pitch);
return ResponseEntity.ok()
.contentType(MediaType.parseMediaType("audio/mp3"))
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"audio.mp3\"")
.body(new ByteArrayResource(audioData));
}
}
前端代码我也一块提供测试:
样式:
<style>
.container {
max-width: 800px;
margin: 20px auto;
padding: 20px;
font-family: "Microsoft YaHei";
}
.control-panel {
margin: 20px 0;
padding: 15px;
border: 1px solid #e4e7ed;
border-radius: 8px;
}
.slider-container {
display: flex;
align-items: center;
margin: 15px 0;
}
.voice-type {
margin-top: 15px;
padding: 10px;
border-top: 1px solid #ebeef5;
}
audio {
width: 30%;
margin: 15px 0;
}
button {
background: #409eff;
color: white;
border: none;
padding: 10px 25px;
border-radius: 4px;
cursor: pointer;
}
button:disabled {
background: #a0cfff;
cursor: not-allowed;
}
</style>
<div id="app" class="container">
<audio :src="audioUrl" controls id="player"></audio>
<input type="text" v-model="inputText" placeholder="输入要朗读的内容">
<div class="voice-type">
<label>选择音色:</label>
<el-select v-model="voiceType" placeholder="请选择音色">
<el-option label="标准女声" value="0"></el-option>
<el-option label="标准男声" value="1"></el-option>
<el-option label="情感男声" value="3"></el-option>
<el-option label="情感女声" value="5"></el-option>
</el-select>
</div>
<div class="slider-container">
<label>音调:</label>
<el-slider v-model="pitch" :min="0" :max="15" show-input></el-slider>
</div>
<button
@click="playAudio"
:disabled="isLoading"> <!-- 防止重复点击 -->
{{ isLoading ? '生成中...' : '播放' }}
</button>
<p v-if="errorMessage" style="color: red;">{{ errorMessage }}</p>
</div>
<script>
var vue = new Vue({
el: "#app",
data: {
inputText: "", // 绑定输入框内容
audioUrl: "", // 存储音频URL
errorMessage: "", // 错误信息
audioElement: null, // 新增音频元素引用
isLoading:false,
voiceType: "0", // 默认音色
pitch: 5 // 默认音调
},
mounted() {
// 初始化时获取音频元素引用
this.audioElement = document.getElementById("player");
// 添加音频加载完成监听
this.audioElement.addEventListener('canplaythrough', () => {
this.audioElement.play().catch(error => {
console.log('自动播放被阻止:', error);
});
});
},
methods: {
async playAudio() {
try {
this.isLoading = true;
this.errorMessage = "";
this.audioUrl = ""; // 清空旧地址
// 验证输入
if (!this.inputText.trim()) {
this.errorMessage = "请输入要朗读的内容";
return;
}
// 暂停当前播放并重置
this.audioElement.pause();
this.audioElement.currentTime = 0;
// 编码并发送请求
const encodedText = encodeURIComponent(this.inputText);
const response = await fetch(`/generate-audio?text=${encodedText}&voiceType=${this.voiceType}&pitch=${this.pitch}`);
if (!response.ok) throw new Error('网络响应异常');
const blob = await response.blob();
// 生成新地址(需先释放旧地址)
if(this.audioUrl) URL.revokeObjectURL(this.audioUrl);
this.audioUrl = URL.createObjectURL(blob);
} catch (error) {
console.error('播放失败:', error);
this.errorMessage = "音频播放失败:" + error.message;
} finally {
this.isLoading = false;
}
}
}
});
</script>
对于更多音色的探索可查看百度智能云AI开放平台
地址:语音技术https://ai.baidu.com/ai-doc/SPEECH/Rluv3uq3d
对于长文本在线语音合成技术可移步另一篇文章:简单集成百度智能云语音合成技术之长文本语音在线合成-CSDN博客