搭建文字转语音(TTS)服务器

1.试用地址

点击链接进行体验
测试图片

2.开发环境

ASP.NET

3.需求

(1)需要动态将文本转化为语音
(2)实现免费的转换过程
(3)转换成语音后可以直接下载
(4)将语音加载到U3D中试用

3.实现过程

(1)新建ASP.NET空工程
新建工程
(2)创建TextToSpeechController类,用于生成Wav文件
创建TextToSpeechController类
(3)添加Speech类库
添加Speech类库
(4)TextToSpeechController类代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using SpeechLib;
using System.Speech;
using System.Speech.Synthesis;
using System.IO;
using System.Security.Cryptography;
using System.Text;

namespace TextToSpeechServer
{
    public static class TextToSpeechController
    {
        public static string GetSavePath(string speechText)
        {
            //根据录入内容生成唯一文件名
            string fileName = Md5(speechText).ToUpper();
            fileName += ".wav";

            //获取根目录路径
            string path = HttpRuntime.AppDomainAppPath.ToString();

            //文件夹名称
            string DirectoryName = "音频文件";

            //音频文件夹路径
            string DirectoryPath = path + DirectoryName;

            //判断音频文件夹是否存在
            if (Directory.Exists(DirectoryPath) == false)
            {
                Directory.CreateDirectory(path);
            }

            //wav文件路径
            string FilePath = DirectoryPath + "\\" + fileName;

            //如果已经有该文件,则直接返回文件名
            if (File.Exists(FilePath))
            {
                return fileName;
            }
            //否则生成音频文件
            else
            {
                SpeechSynthesizer synth = new SpeechSynthesizer();

                synth.Volume = 100;

                //设置文件保存位置
                synth.SetOutputToWaveFile(FilePath);

                //电脑中需要安装Huihui的语音包
                synth.SelectVoice("Microsoft Huihui Desktop");//能读中英文

                synth.Speak(speechText);

                synth.SetOutputToNull();

            }
            return fileName;
        }

        /// <summary>
        /// MD5加密,主要根据输入的文字来生成唯一的音频文件名
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public static string Md5(string value)
        {
            var result = string.Empty;
            if (string.IsNullOrEmpty(value)) return result;
            using (var md5 = MD5.Create())
            {
                result = GetMd5Hash(md5, value);
            }
            return result;
        }

        /// <summary>
        /// MD5生成
        /// </summary>
        /// <param name="md5Hash"></param>
        /// <param name="input"></param>
        /// <returns></returns>
        static string GetMd5Hash(MD5 md5Hash, string input)
        {
            byte[] data = md5Hash.ComputeHash(Encoding.UTF8.GetBytes(input));
            var sBuilder = new StringBuilder();
            foreach (byte t in data)
            {
                sBuilder.Append(t.ToString("x2"));
            }
            return sBuilder.ToString();
        }
    }
}

(5)创建一般处理程序GetAudioStreamHandler.ashx
代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Web;

namespace TextToSpeechServer
{
    /// <summary>
    /// GetAudioStreamHandler 的摘要说明
    /// </summary>
    public class GetAudioStreamHandler : HttpTaskAsyncHandler
    {
        /// <summary>
        /// 获取音频文件所在路径
        /// </summary>
        public string ServerRequestAddress = "http://" + HttpContext.Current.Request.Url.Authority + "/音频文件/{0}";

        /// <summary>
        /// 异步生成音频文件
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        public override async Task ProcessRequestAsync(HttpContext context)
        {
            await Task.Run(() =>
            {
                string speechText = context.Request.Params["SpeechText"].ToString().Trim();

                //将|!|!|转换为换行符
                speechText = speechText.Replace("|!|!|", "\n");
                string fileName = TextToSpeechController.GetSavePath(speechText);
                string requestURL = string.Format(ServerRequestAddress, fileName);
                //直接打开生成的音频文件
                context.Response.Redirect(requestURL);
            });
        }

    }
}

(6)创建前端aspx界面
创建Web窗体
前端页面代码如下:

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="TextToSpeechPage.aspx.cs" Inherits="TextToSpeechServer.TextToSpeechPage" %>

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <title>文字转语音</title>
</head>
<body background="文字转语音.png" style="background-size:100%,100%;background-repeat:no-repeat;background-attachment:fixed">
    <form id="form1" runat="server">
    <table style="width:100%">
        <tr style="height:100px">
            <th>
                <label style="font-size:50px;color:white;">文字语音转换器</label>
            </th>
        </tr>
        <tr style="height:600px">
            <th>
                <%--<textarea style="width:800px;height:500px;margin:100px,100px,100px,100px;font-size:20px"></textarea>--%>
                <asp:TextBox ID="ConvertTextBox" runat="server" Height="500px" Width="800px" Font-Size="20px" TextMode="MultiLine"></asp:TextBox>
            </th>
        </tr>
        <tr style="height:100px">
            <th>
                <%--<button style="font-size:20px;width:150px;height:50px">开始转换</button>--%>
                <asp:Button ID="ConvertButton" runat="server" OnClick="ConvertButton_Click" Text="开始转换" style="font-size:20px;width:150px;height:50px"/>
            </th>
        </tr>
    </table>
    </form>
</body>
</html>

后端处理程序代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace TextToSpeechServer
{
    public partial class TextToSpeechPage : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {

        }

        /// <summary>
        /// 获取当前部署的服务器IP地址,生成HTTP请求链接
        /// </summary>
        public string RequestURL = "http://" + HttpContext.Current.Request.Url.Authority + "//GetAudioStreamHandler.ashx?SpeechText={0}";


        /// <summary>
        /// 生成按钮点击事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void ConvertButton_Click(object sender, EventArgs e)
        {
            if (string.IsNullOrEmpty(ConvertTextBox.Text))
            {
                ConvertTextBox.Text = "请输入信息";
            }
            else
            {
                //替换换行符,纺织报错
                string CheckedURL = string.Format(RequestURL, ConvertTextBox.Text).Replace("\n", "|!|!|");
                Response.Redirect(CheckedURL);
            }
        }
    }
}

(7)测试、发布、部署到IIS

均为常规操作流程,这里不再详细介绍。

(8)注意事项

1)部署到IIS所在的服务器时,需要确保服务器上已经安装了Speech所需的环境

·安装 Microsoft Speech Platform - Server Runtime
·安装Microsoft Speech Platform - Software Development Kit (SDK)
·安装Microsoft Speech Platform - Server Runtime Languages【语言包,其中包含文本转语音功能包(TTS)和语音识别功能包(SR),这里我们主要用TTS包】

2)部署后无法访问

·使用云产品的需要在控制台配置安全组规则,允许相关端口被其他电脑访问
配置安全组规则
·在部署的IIS所在文件夹进行权限设置,可参考这里。除了IIS_IUSRS和IUSRS外,还可以设置Everyone用户。

·可能上述设置了还会报错,如下图
报错信息
这个与IIS中的应用程序池内权限有关
IIS应用程序池权限设置
在高级设置中,将“标识”从默认的ApplicationPoolIdentity改为LocalSystem即可。
更改权限
欲知详情,可点击这里
【该部分设置private key部分,打开方式是Win+R运行,输入MMC,打开Microsoft管理控制台,但是该方法笔者没试成功~~】

(9)源码

Github链接

(10)参考文章

·IIS ApplicationPoolIdentity
·利用C#开发web应用程序时,对注册表进行操作提示没有权限的解决办法
·Microsoft Speech Platform 自学笔记2 环境要求与安装过程

(11)补充U3D中下载并播放语音
U3D下载并播放语音
创建PlayAudioController脚本

using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.UI;
using System.Security.Cryptography;
using System.Text;

public class PlayAudioController : MonoBehaviour
{
    /// <summary>
    /// 转换文字输入框
    /// </summary>
    public InputField TextToAudioInputField;

    /// <summary>
    /// 音频
    /// </summary>
    public AudioSource audioSource;


    /// <summary>
    /// 请求地址
    /// </summary>
    private string RequestURL = "http://39.104.127.80:8082/GetAudioStreamHandler.ashx?SpeechText={0}";

    /// <summary>
    /// 文件名
    /// </summary>
    string FileName = "";

    /// <summary>
    /// 是否在StreamingAssets/AudioFile中存在
    /// </summary>
    bool alreadyExit = false;

    /// <summary>
    /// 将Text转化为Speech
    /// </summary>
    public void ConvertTextToSpeech()
    {
        if (string.IsNullOrEmpty(TextToAudioInputField.text))
        {
            return;
        }

        FileName = Md5(TextToAudioInputField.text).ToUpper() + ".wav";
        string FilePath = Application.streamingAssetsPath + "/AudioFile/" + FileName;

        alreadyExit = false;
        StartCoroutine(GetWavFileAndPlay(FilePath));
    }


    /// <summary>
    /// 从StreamingAssets/AudioFile文件中加载音频文件并播放
    /// </summary>
    /// <param name="FilePath"></param>
    /// <returns></returns>
    IEnumerator GetWavFileAndPlay(string FilePath)
    {
        UnityWebRequest uwr = UnityWebRequestMultimedia.GetAudioClip(FilePath, AudioType.WAV);
        yield return uwr.SendWebRequest();
        if (uwr.isDone)
        {
            if (uwr.isNetworkError || uwr.isHttpError)
            {
                alreadyExit = false;
                Debug.Log(uwr.error);
            }
            else
            {
                AudioClip audioClip = DownloadHandlerAudioClip.GetContent(uwr);
                
                audioSource.clip = audioClip;
                audioSource.Play();
                alreadyExit = true;
            }
        }

        //判断当前音频文件是否存在
        if (!alreadyExit)
        {
            string text = TextToAudioInputField.text.Replace("\n", "|!|!|");

            StartCoroutine(SaveWavFile(text));
        }

    }

    /// <summary>
    /// 当StreamingAssets/AudioFile文件夹下不存在指定Wav文件时,下载该音频文件并播放
    /// </summary>
    /// <param name="text"></param>
    /// <returns></returns>
    IEnumerator SaveWavFile(string text)
    {
        UnityWebRequest uwr = UnityWebRequestMultimedia.GetAudioClip(string.Format(RequestURL, text),AudioType.WAV);
        yield return uwr.SendWebRequest();
        if (uwr.isNetworkError || uwr.isHttpError)
        {
            Debug.Log(uwr.error);
        }
        else
        {
            //播放下载的Wav音频
            AudioClip audioClip = DownloadHandlerAudioClip.GetContent(uwr);
            audioSource.clip = audioClip;
            audioSource.Play();

            //保存下载的Wav音频文件
            byte[] data = uwr.downloadHandler.data;
            //这里的FileMode.create是创建这个文件,如果文件名存在则覆盖重新创建
            FileStream fs = new FileStream(Application.streamingAssetsPath + "/AudioFile/" + FileName, FileMode.Create);

            fs.Write(data, 0, data.Length);
            //每次读取文件后都要记得关闭文件
            fs.Close();
        }
    }


        /// <summary>
        /// MD5加密,主要根据输入的文字来生成唯一的音频文件名
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public static string Md5(string value)
        {
            var result = string.Empty;
            if (string.IsNullOrEmpty(value)) return result;
            using (var md5 = MD5.Create())
            {
                result = GetMd5Hash(md5, value);
            }
            return result;
        }

        /// <summary>
        /// MD5生成
        /// </summary>
        /// <param name="md5Hash"></param>
        /// <param name="input"></param>
        /// <returns></returns>
        static string GetMd5Hash(MD5 md5Hash, string input)
        {

            byte[] data = md5Hash.ComputeHash(Encoding.UTF8.GetBytes(input));
            var sBuilder = new StringBuilder();
            foreach (byte t in data)
            {
                sBuilder.Append(t.ToString("x2"));
            }
            return sBuilder.ToString();
        }
}

源码

猜你喜欢

转载自blog.csdn.net/beihuanlihe130/article/details/102811228
今日推荐