微软(TTS)文本转语音服务API实现

此博客实现与java实现微软文本转语音(TTS)经验总结_java tts_${简简单单}的博客-CSDN博客之上,首先感谢博客源码的提供,本人在上面添加了一些详细的注释,方便大家跟好的理解和使用,毕竟我已经用原文调试了一下午才调通,一些细节的问题给大家标注出来,免得浪费大家的时间,下面直接开始代码吧!

首先大家需要去微软官网获取到密钥,方便调用时可以使用,大家注意看下图,我们一定要注意给我们分配到的区域,我这里是分配到eastus ,就是east us(美国东部)的意思,大家一定需要注意一下,后面会使用到的,然后终结点里面的地址就是我们获取token的地址

下面我们准备几个类,方便后面使用,大家把代码都复制到自己项目中,不要有遗漏:

package com.daoversal.util;public class ByteArray {private byte[] data;private int length;public ByteArray(){length = 0;data = new byte[length];}public ByteArray(byte[] ba){data = ba;length = ba.length;}/**合并数组*/public  void cat(byte[] second, int offset, int length){if(this.length + length > data.length) {int allocatedLength = Math.max(data.length, length);byte[] allocated = new byte[allocatedLength << 1];System.arraycopy(data, 0, allocated, 0, this.length);System.arraycopy(second, offset, allocated, this.length, length);data = allocated;}else {System.arraycopy(second, offset, data, this.length, length);}this.length += length;}public  void cat(byte[] second){cat(second, 0, second.length);}public byte[] getArray(){if(length == data.length){return data;}byte[] ba = new byte[length];System.arraycopy(data, 0, ba, 0, this.length);data = ba;return ba;}public int getLength(){return length;}
}
package com.daoversal.util;import javax.net.ssl.HttpsURLConnection;
import java.net.URL;public class HttpsConnection {public static HttpsURLConnection getHttpsConnection(String connectingUrl) throws Exception {URL url = new URL(connectingUrl);return (HttpsURLConnection) url.openConnection();}
}
package com.daoversal.util;import lombok.extern.slf4j.Slf4j;
import org.w3c.dom.Document;
import org.w3c.dom.Element;import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.StringWriter;@Slf4j
public class XmlDom {public static String createDom(String locale, String genderName, String voiceName, String textToSynthesize){Document doc = null;Element speak, voice;try {DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();DocumentBuilder builder = dbf.newDocumentBuilder();doc = builder.newDocument();if (doc != null){speak = doc.createElement("speak");speak.setAttribute("version", "1.0");speak.setAttribute("xml:lang", "en-US");voice = doc.createElement("voice");voice.setAttribute("xml:lang", locale);voice.setAttribute("xml:gender", genderName);voice.setAttribute("name", voiceName);voice.appendChild(doc.createTextNode(textToSynthesize));speak.appendChild(voice);doc.appendChild(speak);}} catch (ParserConfigurationException e) {log.error("Create ssml document failed: {}",e.getMessage());return null;}return transformDom(doc);}private static String transformDom(Document doc){StringWriter writer = new StringWriter();try {TransformerFactory tf = TransformerFactory.newInstance();Transformer transformer;transformer = tf.newTransformer();transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");transformer.transform(new DOMSource(doc), new StreamResult(writer));} catch (TransformerException e) {log.error("Transform ssml document failed: {}",e.getMessage());return null;}return writer.getBuffer().toString().replaceAll("\n|\r", "");}
}

 下面这个类我给大家重点讲一下,大家去下面网址看看自己的参数Text to speech API reference (REST) - Speech service - Azure AI services | Microsoft Learn

AUDIO_24KHZ_48KBITRATE_MONO_MP3 :语言类型,这个不重要,那个声音好听用那个,去下图找:

ACCESS_TOKEN_URI :就是本文章的第一张图里面,里面获取token的地址,直接将地址复制进来就好了。

API_KEY :自己的api key,就是密钥。

 TTS_SERVICE_URI : 这个地址一定要对应分配的区域才行,不然会报权限错误

Synthesis tts speech failed Server returned HTTP response code: 401 for URL: https://.........

我这里是 east us(美国东部),所以就使用美国东部里面的地址即可。

package com.daoversal.util;public class TtsConst {/*** 音频合成类型(亲测这种效果最佳,其他的你自己去试试)* 里面有很多类型,可以去里面找自己需要的* https://learn.microsoft.com/en-us/azure/ai-services/speech-service/rest-text-to-speech?tabs=streaming*/public static final String AUDIO_24KHZ_48KBITRATE_MONO_MP3 = "audio-24khz-48kbitrate-mono-mp3";/*** 授权url   获取密钥页面 终结点 里面的地址,我们使用这个获取token*/public static final String ACCESS_TOKEN_URI = "token获取地址";/*** api key*/public static final String API_KEY = "自己的密钥";/*** tts服务url,这里一定要根据自己分配的地区找相应的地址才行*/public static final String TTS_SERVICE_URI = "https://eastus.tts.speech.microsoft.com/cognitiveservices/v1/";}

下面参数给大家讲一下:

textToSynthesize : 传入的合成语音文本内容

locale:语言类型,大家可以参考,中文在嵌入式语音里面,大家可以在两个页面找到自己需要的语言。

Embedded Speech - Speech service - Azure AI services | Microsoft Learn

Language support - Speech service - Azure AI services | Microsoft Learn

gender:为发声人性别,Male表示男性

 voiceName :发声者名称,大家可以去下图找出对应的,比如中文的话:

package com.daoversal.util;import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;import javax.annotation.Resource;
import javax.net.ssl.HttpsURLConnection;
import java.io.DataOutputStream;
import java.io.InputStream;@Slf4j
@Component
public class TtsService {@Resourceprivate Authentication authentication;/*** 合成音频* @param textToSynthesize 传入需要翻译的文本* @param locale    要合成的语言类型* @param gender    性别* @param voiceName 发音者名称* @return*/public byte[] genAudioBytes(String textToSynthesize, String locale, String gender, String voiceName) {String accessToken = authentication.genAccessToken();if (StringUtils.isEmpty(accessToken)) {return new byte[0];}try {HttpsURLConnection webRequest = HttpsConnection.getHttpsConnection(TtsConst.TTS_SERVICE_URI);webRequest.setRequestProperty("Host", "eastus.tts.speech.microsoft.com");webRequest.setRequestProperty("Content-Type", "application/ssml+xml");webRequest.setRequestProperty("X-Microsoft-OutputFormat", TtsConst.AUDIO_24KHZ_48KBITRATE_MONO_MP3);webRequest.setRequestProperty("Authorization", "Bearer " + accessToken);webRequest.setRequestProperty("Ocp-Apim-Subscription-Key", TtsConst.API_KEY);webRequest.setRequestProperty("User-Agent", "Mozilla/5.0");webRequest.setRequestProperty("Accept", "*/*");webRequest.setDoInput(true);webRequest.setDoOutput(true);webRequest.setConnectTimeout(5000);webRequest.setReadTimeout(300000);webRequest.setRequestMethod("POST");String body = XmlDom.createDom(locale, gender, voiceName, textToSynthesize);if (StringUtils.isEmpty(body)) {return new byte[0];}byte[] bytes = body.getBytes();webRequest.setRequestProperty("content-length", String.valueOf(bytes.length));webRequest.connect();DataOutputStream dop = new DataOutputStream(webRequest.getOutputStream());dop.write(bytes);dop.flush();dop.close();InputStream inSt = webRequest.getInputStream();ByteArray ba = new ByteArray();int rn2 = 0;int bufferLength = 4096;byte[] buf2 = new byte[bufferLength];while ((rn2 = inSt.read(buf2, 0, bufferLength)) > 0) {ba.cat(buf2, 0, rn2);}inSt.close();webRequest.disconnect();return ba.getArray();} catch (Exception e) {log.error("Synthesis tts speech failed {}", e.getMessage());}return null;}}

最后就是调用了,大家可以测试了:

package com.daoversal.web;import com.daoversal.framework.http.Response;
import com.daoversal.task.DvWeekCountTask;
import com.daoversal.task.RechargeTask;
import com.daoversal.task.UserGradeCountTask;
import com.daoversal.task.WindControlMsgTask;
import com.daoversal.util.TtsService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import okhttp3.*;
import org.springframework.boot.configurationprocessor.json.JSONException;
import org.springframework.boot.configurationprocessor.json.JSONObject;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.*;/*** <p>* 套餐价值释放记录表 前端控制器* </p>** @author HayDen* @since 03 22 10:44:13*/
@RestController
@RequestMapping("/test")
@Api(value = "test")
public class TestController {@Resourceprivate TtsService testService;@PostMapping("/ttsService")@ApiOperation(value = "获取ttsService", httpMethod = "POST" )public void ttsService(String text) {// byte[] bte = testService.genAudioBytes(res,"en-US","Male","en-US-JennyNeural");byte[] bte = testService.genAudioBytes(text,"zh-CN","Male","zh-CN-YunxiNeural");String value = "hllo.mp3";convertByteArrayToFile(bte,value);System.out.println("213213123");}/*** 此文件是将byte[] 转换成文件存储到指定路径的* @param arr* @param value*/public static void convertByteArrayToFile(byte[] arr,String value) {try (BufferedInputStream bis = new BufferedInputStream(new ByteArrayInputStream(arr));//这里是转换以后的文件存储的路径FileOutputStream fileOutputStream = new FileOutputStream("/Users/recovery/Downloads/"+value);BufferedOutputStream bos = new BufferedOutputStream(fileOutputStream)) {int data;while ((data = bis.read()) != -1) {bos.write(data);}bos.flush();} catch (IOException e) {e.printStackTrace();}}}

最后大家需要注意一下就是如果你选的是英文en-US,但是输入的文本是中文的话他是不会翻译的,所以大家一定要注意自己的语言类型不要弄错了,如果有疑问可以留言哦,我看到肯定会毫无保留的给大家说明的。

​​​​​​​

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/84662.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【LeetCode-中等题】 222. 完全二叉树的节点个数

文章目录 题目方法一&#xff1a;把该题当做一个普通的二叉树来做&#xff08;任何遍历都可以&#xff09;方法二&#xff1a;利用完全二叉树的性质来做 题目 方法一&#xff1a;把该题当做一个普通的二叉树来做&#xff08;任何遍历都可以&#xff09; 例如&#xff1a;二叉树…

【强化学习】02—— 探索与利用

文章目录 1. 探索与利用2. 探索策略3. 多臂老虎机3.1. 形式化描述3.2. 估计期望奖励3.3. 懊悔regret函数 4. 贪心策略和 ϵ − g r e e d y \epsilon-greedy ϵ−greedy策略5. 积极初始化6. 显示地考虑动作的价值分布7. UCB上置信界算法8. 汤普森采样算法总结参考 1. 探索与利用…

Python与数据分析--每天绘制Matplotlib库实例图片3张-第1天

目录 1.实例1--Bar color demo 2.实例2--Bar Label Demo 3.实例3--Grouped bar chart with labels 1.实例1--Bar color demo import matplotlib.pyplot as plt # 支持中文 plt.rcParams[font.sans-serif] [SimHei] # 用来正常显示中文标签 plt.rcParams[axes.unicode_minus…

BCC源码下载

接前一篇文章&#xff1a;BCC介绍 1. GitHub地址 上一篇文章中已提到&#xff0c;BCC的github地址是&#xff1a;https://github.com/iovisor/bcc。 页面如下所示&#xff1a; 2. 源码下载 打开终端&#xff0c;创建好要存放BCC源码的目录&#xff0c;进入此目录。 然后&…

王江涛十天搞定考研词汇

学习目标&#xff1a; 考研词汇 学习内容&#xff1a; 2023-9-17 第一天考研词汇 学习时间&#xff1a; 开始:2023-9-17 结束:进行中 学习产出&#xff1a; 2023-9-17intellect智力&#xff1b;知识分子intellectual智力的&#xff1b;聪明的intellectualize使...理智化&a…

如何使用ArcGIS Pro自动矢量化道路

对于已经制作好的电子地图&#xff0c;我们可以通过像素识别的方式将其中的要素提取出来&#xff0c;比如本教程要讲到的道路数据&#xff0c;这里为大家介绍一下在ArcGIS Pro中如何自动矢量化道路&#xff0c;希望能对你有所帮助。 栅格计算 在工具箱中点击“Spatial Analys…

机器学习(18)---朴素贝叶斯

朴素贝叶斯 一、概述1.1 概率分类器1.2 贝叶斯工作原理1.3 贝叶斯的性质 二、sklearn中的朴素贝叶斯2.1 贝叶斯分类器2.2 高斯朴素贝叶斯GaussianNB2.3 探索贝叶斯&#xff1a;高斯朴素贝叶斯擅长的数据集2.4 探索贝叶斯&#xff1a;高斯朴素贝叶斯的拟合效果与运算速度 一、概…

Go编程规范

文章目录 注释转义符定义变量方法一&#xff1a;指定变量类型&#xff0c;声明后若不赋值&#xff0c;使用默认值方法二&#xff1a;根据值自行判定变量类型(类型推导)方法三&#xff1a;省略var, 注意:左侧的变量不应该是已经声明过的&#xff0c;否则会导致编译错误[推荐]全局…

【Redis】Redis 的学习教程(十一)之使用 Redis 实现分布式锁

1. 分布式锁概念 在多线程环境下&#xff0c;为了保证数据的线程安全&#xff0c;锁保证同一时刻&#xff0c;只有一个可以访问和更新共享数据。在单机系统我们可以使用 synchronized 锁、Lock 锁保证线程安全。 synchronized 锁是 Java 提供的一种内置锁&#xff0c;在单个 …

快速用Python进行数据分析技巧详解

概要 一些小提示和小技巧可能是非常有用的&#xff0c;特别是在编程领域。有时候使用一点点黑客技术&#xff0c;既可以节省时间&#xff0c;还可能挽救“生命”。 一个小小的快捷方式或附加组件有时真是天赐之物&#xff0c;并且可以成为真正的生产力助推器。所以&#xff0…

leetcode543 二叉树的直径

题目 给你一棵二叉树的根节点&#xff0c;返回该树的 直径 。 二叉树的 直径 是指树中任意两个节点之间最长路径的 长度 。这条路径可能经过也可能不经过根节点 root 。 两节点之间路径的 长度 由它们之间边数表示。 示例 输入&#xff1a;root [1,2,3,4,5] 输出&#xff1…

全国职业技能大赛云计算--高职组赛题卷⑤(容器云)

全国职业技能大赛云计算--高职组赛题卷⑤&#xff08;容器云&#xff09; 第二场次题目&#xff1a;容器云平台部署与运维任务2 基于容器的web应用系统部署任务&#xff08;15分&#xff09;任务3 基于容器的持续集成部署任务&#xff08;15分&#xff09;任务4 Kubernetes容器…

web:[HCTF 2018]WarmUp

题目 点进页面&#xff0c;页面只有一张滑稽脸&#xff0c;没有其他的提示信息 查看网页源代码&#xff0c;发现source.php&#xff0c;尝试访问一下 跳转至该页面&#xff0c;页面显示为一段php代码&#xff0c;需要进行代码审计 <?phphighlight_file(__FILE__);class emm…

【Flink】FlinkCDC获取mysql数据时间类型差8小时时区解决方案

1、背景: 在我们使用FlinkCDC采集mysql数据的时候,日期类型是我们很常见的类型,但是FlinkCDC读取出来会和数据库的日期时间不一致,情况如下 FlinkCDC获取的数据中create_time字段1694597238000转换为时间戳2023-09-13 17:27:18 而数据库中原始数据如下,并没有到下午5点…

flink集群与资源@k8s源码分析-回顾

本章是分析系列最后一章,作为回顾,以运行架构图串联起所有分析场景 1 启动集群,部署集群(提交k8s),新建作业管理器组件 2 构建和启动flink master组件 3 提交作业,N/A

多线程的学习上篇

座右铭: 天行健&#xff0c;君子以自强不息;地势坤&#xff0c;君子以厚德载物. 引入进程这个概念的目的 引入进程这个概念,最主要的目的,是为了解决“并发编程"这样的问题. 这是因为CPU进入了多核心的时代 要想进一步提高程序的执行速度,就需要充分的利用CPU 的多核资源…

滑动时间窗口的思想和实现,环形数组,golang

固定时间窗口 在开发限流组件的时候&#xff0c;我们需要统计一个时间区间内的请求数&#xff0c;比如以分钟为单位。所谓固定时间窗口&#xff0c;就是根据时间函数得到当前请求落在哪个分钟之内&#xff0c;我们在统计的时候只关注当前分钟之内的数量&#xff0c;即 [0s, 60…

【大数据之Kafka】十六、Kafka集成外部系统之集成Flume

Flume 是一个在大数据开发中非常常用的组件。可以用于 Kafka 的生产者&#xff0c;也可以用于 Kafka 的消费者。 Flume安装和部署&#xff1a;https://blog.csdn.net/qq_18625571/article/details/131678589?spm1001.2014.3001.5501 1 Flume生产者 &#xff08;1&#xff09…

帆软BI开发-Day2-趋势图的多种变形

前言&#xff1a; 在BI数据展示中&#xff0c;条形图、趋势图无疑是使用场景非常多的两种图形。与条形图不同的是&#xff0c;趋势图更能反馈出一定的客观规律和未来的趋势走向&#xff0c;因此用于作为预警和判异的业务场景&#xff0c;但实际业务场景的趋势图可没你想的那么简…

华为HCIA(三)

链路本地地址接口标识64bit 当STP端口到了Forwarding状态后&#xff0c;会转发流量&#xff0c;也处理报文 在TCP/IP模型中&#xff0c;会话层&#xff0c;表示层和应用层&#xff0c;都规划成了应用层 路由表包含目的地址和掩码&#xff0c;优先级&#xff0c;cost,下一跳和…