项目效果显示页面2017/7月前有效: http://myjavaweb1.mybluemix.net/
摘要:Text to Speech 服务提供的应用程序编程接口 (API) 使用 IBM 的语音合成功能将文本转换成音频信号。此服务提供了具象状态传输 (REST) 接口,支持将各种语言、口音和语音的文本合成自然语音。此服务目前可将英语或西班牙语的书面文本合成男声(英语和西班牙语)或女声(仅限英语)朗读的音频信号。音频可通过流式方法传输回客户机,延迟时间最短。
本文工程下载:http://download.csdn.net/detail/evankaka/9427964
本文实例访问:http://texttospeechtest.eu-gb.mybluemix.net/
一、Bluemix创建web工程并添加文本转语音服务
1、创建Bluemix上的web工程.(如何创建工程可看基于IBM Bluemix部署Java Web项目实战演练)
2、添加文本转语音服务
添加服务
3、最后绑定的服务的工程如下:
二、本地创建工程
这里需要创建一个dynamic 的web工程,本文是直接在https://github.com/watson-developer-cloud/text-to-speech-java这上工程的基础上来做修改的。
最终目录如下:
下面来分析一下关键的代码,这里是以Servlet来实现语音的获取的
(1)DemoServlet.java
这是本工程的核心代码
- package com.ibm.cloudoe.samples;
- import java.io.IOException;
- import java.net.URI;
- import java.util.logging.Level;
- import java.util.logging.Logger;
- import javax.servlet.ServletException;
- import javax.servlet.ServletOutputStream;
- import javax.servlet.annotation.MultipartConfig;
- import javax.servlet.http.HttpServlet;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- import org.apache.http.HttpStatus;
- import org.apache.http.client.fluent.Executor;
- import org.apache.http.client.fluent.Request;
- import org.apache.http.client.fluent.Response;
- import com.ibm.ws.xs.json.java.JSONArray;
- import com.ibm.ws.xs.json.java.JSONObject;
- @MultipartConfig
- public class DemoServlet extends HttpServlet {
- private static Logger logger = Logger.getLogger(DemoServlet.class.getName());
- private static final long serialVersionUID = 1L;
- private String serviceName = "text_to_speech";
- // 此处需要修改成您自己的
- private String baseURL = "https://stream.watsonplatform.net/text-to-speech/api";
- private String username = "bd546fff-2e43-42c9-8c76-71075c257128";
- private String password = "AL7sK4TRu0T0";
- /**
- * 处理前台传过来的请求
- */
- @Override
- protected void doGet(final HttpServletRequest req, final HttpServletResponse resp) throws ServletException, IOException {
- if (req.getParameter("text") == null || req.getParameter("voice") == null) { //如果文本或语音为空,返回到初始界面
- req.getRequestDispatcher("/index.jsp").forward(req, resp);
- } else {
- boolean download = false;
- if (req.getParameter("download") != null && req.getParameter("download").equalsIgnoreCase("true")) { //判断是否下载语音
- download = true;
- }
- req.setCharacterEncoding("UTF-8");
- try {
- String queryStr = req.getQueryString();
- String url = baseURL + "/v1/synthesize";
- if (queryStr != null) {
- url += "?" + queryStr;//连接url
- }
- URI uri = new URI(url).normalize();
- Request newReq = Request.Get(uri); //构造请求头
- newReq.addHeader("Accept", "audio/ogg; codecs=opus"); //设置语音格式,还可以为"audio/wav"或者 "audio/flac"
- Executor executor = Executor.newInstance().auth(username, password);
- Response response = executor.execute(newReq);//发送请求报文,并取得返回
- if (download)
- {
- resp.setHeader("content-disposition", "attachment; filename=transcript.ogg");//下载语音
- }
- ServletOutputStream servletOutputStream = resp.getOutputStream();
- response.returnResponse().getEntity()
- .writeTo(servletOutputStream);//将语音流返回前台
- servletOutputStream.flush();
- servletOutputStream.close();
- } catch (Exception e) {
- // Log something and return an error message
- logger.log(Level.SEVERE, "got error: " + e.getMessage(), e);
- resp.setStatus(HttpStatus.SC_BAD_GATEWAY);
- }
- }
- }
- /**
- * 取得环境变量
- */
- private JSONObject getVcapServices() {
- String envServices = System.getenv("VCAP_SERVICES");
- if (envServices == null) return null;
- JSONObject sysEnv = null;
- try {
- sysEnv = JSONObject.parse(envServices);
- } catch (IOException e) {
- // Do nothing, fall through to defaults
- logger.log(Level.SEVERE, "Error parsing VCAP_SERVICES: "+e.getMessage(), e);
- }
- return sysEnv;
- }
- @Override
- public void init() throws ServletException {
- super.init();
- processVCAP_Services();
- }
- /**
- * 取得环境变量的参数
- */
- private void processVCAP_Services() {
- logger.info("Processing VCAP_SERVICES");
- JSONObject sysEnv = getVcapServices();
- if (sysEnv == null) return;
- logger.info("Looking for: "+ serviceName );
- for (Object key : sysEnv.keySet()) {
- String keyString = (String) key;
- logger.info("found key: " + key);
- if (keyString.startsWith(serviceName)) {
- JSONArray services = (JSONArray)sysEnv.get(key);
- JSONObject service = (JSONObject)services.get(0);
- JSONObject credentials = (JSONObject)service.get("credentials");
- baseURL = (String)credentials.get("url");
- username = (String)credentials.get("username");
- password = (String)credentials.get("password");
- logger.info("baseURL = "+baseURL);
- logger.info("username = "+username);
- logger.info("password = "+password);
- } else {
- logger.info("Doesn't match /^"+serviceName+"/");
- }
- }
- }
- }
这里的原理其实就是前台传文本过来后,在doget方法中再构造request请求头到语音处理中心,它将结果返回到servlet,再返回到前台。
(2)前台关键代码
这是页面的内容:
index.jsp
- <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
- <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <title>文本转语音实例</title>
- <meta charset="utf-8">
- <meta http-equiv="X-UA-Compatible" content="IE=edge">
- <meta name="viewport" content="width=device-width, initial-scale=1">
- <link rel="shortcut icon" href="images/favicon.ico" type="image/x-icon">
- <link rel="icon" href="images/favicon.ico" type="image/x-icon">
- <link rel="stylesheet" href="css/watson-bootstrap-dark.css">
- <link rel="stylesheet" href="css/style.css">
- </head>
- <body>
- <div class="container">
- <div class="row">
- <div class="col-lg-7 col-md-7 col-xs-12">
- <h2>文本转语音</h2>
- <div class="well">
- <form method="get" class="form-horizontal">
- <fieldset>
- <div class="row">
- <div class="col-lg-12 col-xs-12">
- <label for="textArea" class="control-label">请输入或复制要转换成语音的文本:</label>
- <textarea id="textArea" name="text" rows="8" required class="form-control"></textarea><span class="help-block"><small>注意只能输入现一种语言,语音返回会有点慢,请耐心等待</small></span>
- </div>
- </div>
- <div style="margin-bottom:30px;" class="row">
- <label for="voice" class="col-lg-12 col-xs-12 control-label">请选择语音类型:</label>
- <div class="col-lg-12 col-xs-12">
- <select class="select-voice" id="voice" style="width:100%" name="voice" required class="form-control">
- </select>
- </div>
- </div>
- <div class="row">
- <div class="col-lg-4 col-xs-4 download-container">
- <input value="Download" class="btn btn-block download-button">
- </div>
- <div class="col-lg-4 col-xs-4 text-center"></div>
- <div class="col-lg-4 col-xs-4 ie-speak">
- <input value="Speak" class="btn btn-block speak-button">
- <div class="arrow-box">
- <p>请使用谷歌或火狐浏览器</p>
- </div>
- </div>
- </div>
- </fieldset>
- </form>
- </div>
- </div>
- <div class="col-lg-5 col-md-5 col-xs-12">
- <h2>语音输出</h2>
- <div class="row">
- <div class="col-lg-12 col-xs-12">
- <div style="display:none" class="well result">
- <div class="text-center">
- <audio autoplay preload="auto" autobuffer controls class="audio"></audio>
- </div>
- <div><span class="help-block">返回的语音是以<a href="http://www.vorbis.com/">Ogg Vorbis</a> 格式的,它可以使用<a href="http://www.videolan.org/vlc/index.html">VLC</a>, <a href="http://audacity.sourceforge.net/">Audacity</a> 等来播放</span>
- </div>
- </div>
- <div style="display:none" class="well error">
- <div class="form-group row">
- <div class="col-lg-12 col-xs-12">
- <p class="errorMsg">处理请求失败</p>
- </div>
- </div>
- </div>
- </div>
- </div>
- </div>
- </div>
- <div class="row">
- <div class="help-block text-center"><small>请使用谷歌浏览器 <a href="https://www.google.com/intl/en/chrome/browser/desktop/" target="_blank">Chrome </a>火狐浏览器 <a href="https://www.mozilla.org/en-US/firefox/new/" target="_blank">Firefox.</a></small>
- </div>
- </div>
- </div>
- <script type="text/javascript" src="js/browser-detect.js"></script>
- <script type="text/javascript" src="js/jquery-1.11.1.min.js"></script>
- <script type="text/javascript" src="js/constants.js"></script>
- <script type="text/javascript" src="js/demo.js"></script>
- </body>
- </html>
- 'use strict';
- //页面一加载完成就执行
- $(function () {
- var audio = $('.audio').get(0),//语音播放器
- textArea = $('#textArea'); //文本内容
- //为语音选择器添加内容
- Object.keys(VOICES).forEach(function(key) {
- $('<option>', { value : key })
- .appendTo($('.select-voice'))
- .text(VOICES[key]);
- });
- //设置初始文本内容
- function updateSampleText() {
- var lang = $('.select-voice').val().substr(0,5);
- $('#textArea').text(SAMPLE_TEXT[lang]);
- }
- $('.select-voice').change(updateSampleText);
- updateSampleText();
- // IE 和 Safari 不支持此实例语音播放,让speak按钮 无效
- if ($('body').hasClass('ie') || $('body').hasClass('safari')) {
- $('.speak-button').prop('disabled', true);
- }
- if ($('.speak-button').prop('disabled')) {
- $('.ie-speak .arrow-box').show();
- }
- //播放错误信息
- $('.audio').on('error', function () {
- $('.result').hide();
- $('.errorMgs').text('Error processing the request.');
- $('.errorMsg').css('color','red');
- $('.error').show();
- });
- //播放语音
- $('.audio').on('loadeddata', function () {
- $('.result').show();
- $('.error').hide();
- });
- //download点击事件
- $('.download-button').click(function() {
- textArea.focus();
- if (validText(textArea.val())) {
- window.location.href = '?download=true&' + $('form').serialize();
- }
- });
- //speak按钮点击事件
- $('.speak-button').click(function() {
- $('.result').hide();
- audio.pause();
- $('#textArea').focus();
- if (validText(textArea.val())) {
- audio.setAttribute('src','?&' + $('form').serialize());
- }
- });
- //校验文本的输入内容
- function validText(text) {
- $('.error').hide();
- $('.errorMsg').css('color','#5a5a5a');
- if ($.trim(text).length === 0) {
- $('.errorMsg').text('Please enter the text you would like to synthesize in the text window.');
- $('.errorMsg').css('color','#5a5a5a');
- $('.error').show();
- return false;
- }
- if (!containsAllLatin1(text)) {
- $('.errorMsg').text('Language not supported. Please use only ISO 8859 characters');
- $('.error').show();
- return false;
- }
- return true;
- }
- /**
- * Check that the text doesn't contains non latin-1 characters.
- * @param String The string to test
- * @return true if the string is latin-1
- */
- function containsAllLatin1(str) {
- return /^[A-z\u00C0-\u00ff\s?@¿''\.,-\/#!$%\^&\*;:{}=\-_`~()0-9]+$/.test(str);
- }
- });
其它具体的请看工程代码,这里不再做分析。
(3)添加jar包
本地运行需要添加如下jar包,记得!
其中json-org.jar和ogclient.jar可到这里下载ftp://public.dhe.ibm.com/cloud/bluemix/datacache/
同时工程右键设置属性中,编辑的JDK选择1.6,web版本选择2.5
(4)本地发布运行
右键运行即可,
输入http://localhost:8088/app/
测试过后没有问题。下一步发布到个人bluemix中心。
三、发布到个人bluemix中心
(1)打包war包
因为本工程使用了ant.其实内容如下:
build.xml
- <?xml version="1.0" encoding="UTF-8" ?>
- <!DOCTYPE xml>
- <project basedir="." default="build" name="WebApp">
- <property environment="env" />
- <property name="srcDir" value="." />
- <property name="debuglevel" value="source,lines,vars" />
- <property name="target" value="1.6" />
- <property name="source" value="1.6" />
- <property name="ARCHIVE_DIR" value="output" />
- <property name="LIB_DIR" value="./lib" />
- <property name="WEB_INF_LIB_DIR" value="./WebContent/WEB-INF/lib" />
- <property name="warname" value="webApp.war" />
- <path id="classpathDir">
- <pathelement location="build/bin" />
- <fileset dir="${LIB_DIR}">
- <include name="*.jar" />
- </fileset>
- <fileset dir="${WEB_INF_LIB_DIR}">
- <include name="*.jar" />
- </fileset>
- </path>
- <target name="init">
- <mkdir dir="build" />
- <mkdir dir="build/bin" />
- </target>
- <target name="clean">
- <delete dir="build" />
- <delete file="${ARCHIVE_DIR}/${warname}" />
- </target>
- <target name="build" depends="build-project,build-war" />
- <target name="cleanall" depends="clean" />
- <target name="build-project" depends="clean,init">
- <copy todir="${ARCHIVE_DIR}">
- <fileset file="manifest.yml" />
- </copy>
- <echo message="${ant.project.name}: ${ant.file}" />
- <javac debug="true" debuglevel="${debuglevel}" destdir="build/bin" source="${source}" target="${target}" includeantruntime="false">
- <src path="src" />
- <classpath refid="classpathDir" />
- </javac>
- </target>
- <target name="build-war" depends="build-project">
- <war destfile="${ARCHIVE_DIR}/${warname}" webxml="WebContent/WEB-INF/web.xml">
- <webinf dir="WebContent/WEB-INF" />
- <zipfileset dir="src" prefix="WEB-INF/src" />
- <fileset dir="WebContent">
- <include name="**/*" />
- </fileset>
- <lib dir="WebContent/WEB-INF/lib" />
- <classes dir="build/bin" />
- </war>
- </target>
- </project>
- ---
- declared-services:
- text-to-speech-service:
- label: text_to_speech
- plan: standard
- applications:
- - services:
- - text-to-speech-service
- name: TextToSpeechTest <span style="font-family: Arial, Helvetica, sans-serif;">#改成你的Bluxmix中心上对应的web工程名</span>
- path: webApp.war #改成你的war包名,上传时这个注释要去掉
- memory: 512M
现在来打包下:
打包后的输出路径:
(2)上传到个个Bluxmix中心
登陆
- cf login
- 输入用户名、邮箱、选择工程空间(记得选择你此次web项目所在的空间)
上传
- cf push TextToSpeechTest -p D:\marJee-workspace\text-to-speech-java-master\output\webApp.war -m 512M
最后,打开网址:http://texttospeechtest.eu-gb.mybluemix.net/
点击Speak按钮,即可!注意,等待语音返回比较慢,请耐心等待!注意,等待语音返回比较慢,请耐心等待!注意,等待语音返回比较慢,请耐心等待!