关于百度智能云账号的注册移步案例:简单集成百度智能云语音合成技术之短文本语音在线合成-CSDN博客
在之前的短文本合成案例中,应对长文本时,语音合成的速度很慢。所以我在网上找资料实现了长文本语音合成方法。废话不多说直接进入依赖配置。
1.pom文件依赖
<dependency>
<groupId>com.baidu.aip</groupId>
<artifactId>java-sdk</artifactId>
<version>4.16.11</version>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>3.14.9</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.83</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
2.application.yml/application.properties文件配置
baidu.tts.api-key=你的API KEY
baidu.tts.secret-key=你的SECRET KEY
3.service层
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.lxy.Reading.entity.TtsRequest;
import okhttp3.MediaType;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import okhttp3.RequestBody;
import okhttp3.*;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
@Service
public class LongTextTts {
@Value("${baidu.tts.api-key}")
private String apiKey;
@Value("${baidu.tts.secret-key}")
private String secretKey;
private static final OkHttpClient HTTP_CLIENT = new OkHttpClient();
public String createTTS(TtsRequest request) throws IOException {
// 构造 JSON 请求体
JSONObject requestBody = new JSONObject();
requestBody.put("text",request.getText());
requestBody.put("format", "mp3-16k");
requestBody.put("voice", request.getVoiceType());
requestBody.put("lang", "zh");
// 打印请求体
System.out.println("Request Body: " + requestBody.toJSONString());
MediaType mediaType = MediaType.parse("application/json");
RequestBody body = RequestBody.create(mediaType, requestBody.toJSONString());
Request request2 = new Request.Builder()
.url("https://aip.baidubce.com/rpc/2.0/tts/v1/create?access_token=" + getAccessToken())
.post(body)
.addHeader("Content-Type", "application/json")
.build();
try (Response response = HTTP_CLIENT.newCall(request2).execute()) {
if (response.isSuccessful() && response.body() != null) {
String responseBody = response.body().string();
System.out.println("Response Body: " + responseBody); // 打印响应体
JSONObject jsonObject = JSON.parseObject(responseBody);
return jsonObject.getString("task_id");
} else {
if (response.body() != null) {
System.out.println("Error Response: " + response.body().string());
}
throw new RuntimeException("创建TTS任务失败: " + response.code());
}
}
}
public String checkTaskStatus(String taskId) throws IOException {
if (taskId == null || taskId.isEmpty()) {
throw new IllegalArgumentException("任务ID不能为空");
}
String taskStatus = "";
while (!("Success".equals(taskStatus) || "Failed".equals(taskStatus))) {
try {
Thread.sleep(1000); // Sleep for 1 second
} catch (InterruptedException e) {
e.printStackTrace();
}
HashMap<String, Object> map = new HashMap<>();
ArrayList<Object> list = new ArrayList<>();
list.add(taskId);
map.put("task_ids", list);
JSONObject jsonObject = new JSONObject(map);
MediaType mediaType = MediaType.parse("application/json");
RequestBody body = RequestBody.create(mediaType, jsonObject.toString());
Request request = new Request.Builder()
.url("https://aip.baidubce.com/rpc/2.0/tts/v1/query?access_token=" + getAccessToken())
.method("POST", body)
.addHeader("Content-Type", "application/json")
.addHeader("Accept", "application/json")
.build();
try (Response response = HTTP_CLIENT.newCall(request).execute()) {
if (response.isSuccessful()) {
String responseBody = response.body().string();
JSONArray tasksInfo = JSON.parseObject(responseBody).getJSONArray("tasks_info");
if (tasksInfo.size() > 0) {
JSONObject taskInfo = tasksInfo.getJSONObject(0);
taskStatus = taskInfo.getString("task_status");
if ("Success".equals(taskStatus)) {
return taskInfo.getJSONObject("task_result").getString("speech_url");
} else if ("Failed".equals(taskStatus)) {
throw new RuntimeException("任务失败: " + taskStatus);
}
} else {
throw new RuntimeException("未找到任务信息");
}
} else {
throw new RuntimeException("检查任务状态失败: " + response.code());
}
} catch (IOException e) {
e.printStackTrace();
}
}
return "";
}
private String getAccessToken() throws IOException {
MediaType mediaType = MediaType.parse("application/x-www-form-urlencoded");
RequestBody body = RequestBody.create(mediaType, "grant_type=client_credentials&client_id=" + apiKey
+ "&client_secret=" + secretKey);
Request request = new Request.Builder()
.url("https://aip.baidubce.com/oauth/2.0/token")
.method("POST", body)
.addHeader("Content-Type", "application/x-www-form-urlencoded")
.build();
Response response = HTTP_CLIENT.newCall(request).execute();
if (response.isSuccessful() && response.body() != null) {
String responseBody = response.body().string();
JSONObject jsonObject = JSON.parseObject(responseBody);
return jsonObject.getString("access_token");
} else {
throw new IOException("Failed to get access token: " + response.code());
}
}
4.实体类
getter、setter注解大家记得自己加
public class TtsRequest {
private String text;
private String voiceType;
private String pitch;
}
5.controller层
@RestController
public class TttsController {
@Autowired
private LongTextTts longTextTts;
@RequestMapping("/synthesize")
public ResponseEntity<String> synthesizeText(@RequestBody TtsRequest request) {
try {
String taskId = longTextTts.createTTS(request);
System.out.println("taskId = " + taskId);
String audioUrl = longTextTts.checkTaskStatus(taskId);
return ResponseEntity.ok(audioUrl);
} catch (Exception e) {
return ResponseEntity.badRequest().body("语音合成失败: " + e.getMessage());
}
}
}
测试页面一起给大家了
html中需要的axios.js文件和vue.js文件大家得去网上找(这里暂不提供
页面:
<!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 rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
<!-- 引入组件库 -->
<script src="https://unpkg.com/element-ui/lib/index.js"></script>
<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;
}
.settings-panel {
display: none;
margin-top: 20px;
padding: 15px;
border: 1px solid #e4e7ed;
border-radius: 8px;
}
.settings-panel.active {
display: block;
}
</style>
</head>
<body>
<div id="app" class="container">
<audio :src="audioUrl" controls id="player"></audio>
<textarea id="text" v-model="inputText" placeholder="请输入要合成的文本"></textarea>
<button
@click="playAudio"
:disabled="isLoading"> <!-- 防止重复点击 -->
{{ isLoading ? '生成中...' : '播放' }}
</button>
<p v-if="errorMessage" style="color: red;">{{ errorMessage }}</p>
<button @click="isSettingsActive = !isSettingsActive">设置</button>
<!-- 设置面板-->
<div class="settings-panel" :class="{ active: isSettingsActive }" v-if="isSettingsActive == true">
<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="4100"></el-option>
<el-option label="度灵儿-清激女声" value="4119"></el-option>
<el-option label="度有为-磁性男声" value="4176"></el-option>
<el-option label="度小萌-软萌妹子" value="111"></el-option>
<el-option label="度清柔-温柔男神" value="6602"></el-option>
<el-option label="度小夏-甜美女声" value="4148"></el-option>
<el-option label="度云萱-旁白女声" value="6221"></el-option>
<el-option label="度悠然-旁白男声" value="6205"></el-option>
</el-select>
</div>
</div>
</div>
<script>
var vue = new Vue({
el: "#app",
data: {
inputText: "", // 绑定输入框内容
audioUrl: "", // 存储音频URL
errorMessage: "", // 错误信息
audioElement: null, // 新增音频元素引用
isLoading:false,
voiceType: "0", // 默认音色
isSettingsActive: false // 设置面板是否显示
},
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;
// 构造包含参数的 JSON 对象
const requestBody = {
text: this.inputText,
voiceType: this.voiceType, // 默认音色
};
const response = await fetch('/synthesize', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(requestBody) // 发送结构化数据
});
if (response.ok) {
const audioUrl = await response.text();
document.getElementById('player').src = audioUrl;
} else {
alert('语音合成失败: ' + response.statusText);
}
} catch (error) {
alert('请求失败: ' + error.message);
}finally {
this.isLoading = false;
}
}
},
});
</script>
</body>
</html>
只需要这些就可以开始测试了,对于音色的选择可移步语音技术网页自己选择。