基于Bluemix云平台的一个文本转语音应用

          林炳文Evankaka原创作品。转载请注明出处http://blog.csdn.net/evankaka

          摘要:Text to Speech 服务提供的应用程序编程接口 (API) 使用 IBM 的语音合成功能将文本转换成音频信号。此服务提供了具象状态传输 (REST) 接口,支持将各种语言、口音和语音的文本合成自然语音。此服务目前可将英语或西班牙语的书面文本合成男声(英语和西班牙语)或女声(仅限英语)朗读的音频信号。音频可通过流式方法传输回客户机,延迟时间最短。

本文工程下载:http://download.csdn.net/detail/evankaka/9427964

本文实例访问:http://texttospeechtest.eu-gb.mybluemix.net/

BluxMix账号注册:https://apps.admin.ibmcloud.com/manage/trial/bluemix.html?cm_mmc=CMDeveloperGCG-_-Bluemix-_-CSDN-_-onlineeventQ2


一、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>
demo.js,引用的js文件内容:

'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>
另外,要发布到bluemix中去,本工程还配置了初始的参数

---
declared-services:
  text-to-speech-service:
    label: text_to_speech
    plan: standard
applications:
- services:
  - text-to-speech-service
  name: TextToSpeechTest  #改成你的Bluxmix中心上对应的web工程名
  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


最后如果出现如下内容,表明上传成功且运行成功
当然,也可以到bluxmix中心去看


最后,打开网址:http://texttospeechtest.eu-gb.mybluemix.net/

点击Speak按钮,即可!注意,等待语音返回比较慢,请耐心等待!注意,等待语音返回比较慢,请耐心等待!注意,等待语音返回比较慢,请耐心等待!



本文工程下载:http://download.csdn.net/detail/evankaka/9427964

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值