Skip to main content

语音翻译服务

分类:  Azure认知服务 标签:  #Azure #人工智能 #语音服务 发布于: 2023-06-05 16:58:20

大家知道有一个职业叫翻译, 特别是同时翻译非常吃香也非常厉害,但是如果人工智能能够更快速的发展的话,那么同时翻译这个职业就会很快的消失了,我们今天来介绍一下我们Azure语音服务的另外一个功能就是语音翻译,字面意思就是可以实时的,多设备的将一种语言的语音及时转移成另外一种语音的语音,例如输入时英文语音但是输出时中文语音,而且时实时的,这就是机器的同声翻译。

本节Demo代码可以从这里下载: Demo Code

创建语音翻译项目

我们先创建一个基于控制台的项目,同时向项目添加引用包:

dotnet new console -n SpeechTranslation
cd SpeechTranslation
dotnet add package Microsoft.CognitiveServices.Speech

添加了包引用之后,我们可以使用编辑器或者IDE打开该项目,同时编辑Program.cs, 添加如下的包引用:

using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading.Tasks;
using Microsoft.CognitiveServices.Speech;
using Microsoft.CognitiveServices.Speech.Audio;
using Microsoft.CognitiveServices.Speech.Translation;

SpeechTranslationConfig 对象

我们前面的语音识别服务和语音合成服务,在开始使用SDK之前,我们都需要创建一个SpeechConfig对象,但是对于语音翻译服务来讲我们需要的配置对象是``SpeechTranslationConfig, 我们通过这个配置对象来配置SDK并进行响应的服务调用,同时需要注意的是我们任然需要创建服务的keyregion`, 因此我们先定义两个常量:

//服务的Key
private static readonly string SPEECH__SUBSCRIPTION__KEY = "";
//服务的区域
private static readonly string SPEECH__SERVICE__REGION = "";

然后我们在方法Main中定义一个配置对象,然后可以从Main方法中对定义的其他方法进行调用,并传入该方法参数。

var config = SpeechTranslationConfig.FromSubscription(SPEECH__SUBSCRIPTION__KEY, SPEECH__SERVICE__REGION);

语音翻译成文本

我们之前学习过如何通过语音转文本,但是我们这个功能是从语音,翻译成你指定的语言文本。

设置语音源的语言

我们先需要设定来源语音的语言,例如中文英语等等,设定源语音还是通过配置对象SpeechTranslationConfig对象来完成。

config.SpeechRecognitionLanguage = 'zh-CN';

设置需要翻译的结果语言

同样我们还是通过配置对象来设置目标语音,同时需要注意的是我们可以设置多个目标语言,例如可以将中文同时翻译成英语,德语,法语等等。

config.AddTargetLanguage("en-US");
config.AddTargetLanguage("de");

如果需要添加多个语言多次调用方法AddTargetLanguage就可以了。您可以定义一个列表类型List<String>, 然后使用ForEach就可以一次全部加好,例如:

var langList = new List<String> {
    "en-US",
    "de",
    "fr"
};

langList.ForEach(config.AddTargetLanguage);

这样就可以一次性添加好所有需要的语言了。

从麦克风输入并翻译

从麦克风进行输入的话,有两种形式,一种是不用指定AudioConfig, 默认就会从麦克风进行输入,并翻译, 另外一种情况是指明AudioConfig,然后使用该类的方法FromDefaultMicrophoneInput 从默认的麦克风进行输入,另外可以可以使用前一章的知识,找到多个麦克风,选择麦克风的ID,然后从对应的麦克风进行读入。

我们先来看默认的方式:

public async static Task TranslationFromMic(SpeechTranslationConfig config, string sourceLang, List<string> targetLanguage)
{

    //设置源语言
    config.SpeechRecognitionLanguage = sourceLang;
    //设置目的语言
    targetLanguage.ForEach(config.AddTargetLanguage);

    using var recognizer = new TranslationRecognizer(config);

    Console.Write($"Say something in '{sourceLang}' and ");
    Console.WriteLine($"We will translate into '{string.Join("', '", targetLanguage)}'.\n ");

    var result = await recognizer.RecognizeOnceAsync();

    if (result.Reason == ResultReason.TranslatedSpeech)
    {
        Console.WriteLine($"Recognized:\"{result.Text}\"; ");

        foreach (var (language, translation) in result.Translations)
        {
            Console.WriteLine($"Translated into '{language}': {translation} ");
        }
    }
}

从代码可以看出无需指定AudioConfig默认就会从默认的麦克风进行输入了。如果我们需要明确的指定从麦克风输入该如何处理呢?我们可以按照下面的代码进行处理:

public async static Task TranslationFromMic2(SpeechTranslationConfig config, string sourceLang, List<string> targetLanguage)
{

    //设置源语言
    config.SpeechRecognitionLanguage = sourceLang;
    //设置目的语言
    targetLanguage.ForEach(config.AddTargetLanguage);

    using var audioConfig = AudioConfig.FromDefaultMicrophoneInput();

    using var recognizer = new TranslationRecognizer(config, audioConfig);

    Console.Write($"Say something in '{sourceLang}' and ");
    Console.WriteLine($"We will translate into '{string.Join("', '", targetLanguage)}'.\n ");

    var result = await recognizer.RecognizeOnceAsync();

    if (result.Reason == ResultReason.TranslatedSpeech)
    {
        Console.WriteLine($"Recognized:\"{result.Text}\"; ");

        foreach (var (language, translation) in result.Translations)
        {
            Console.WriteLine($"Translated into '{language}': {translation} ");
        }
    }
}

从代码中可以看出我们首先需要创建一个AudioConfig的对象,然后使用该对象的方法FromDefaultMicrophoneInput返回一个Audio的配置,最后我们在创建翻译对象的时候,同时传入两个配置:

using var recognizer = new TranslationRecognizer(config, audioConfig);

这样就可以从麦克风中输入音频流了,然后回翻译成相应的文字。

从文件中读入音频流进行翻译

上述我们简要的介绍了如何从麦克风中输入,我们想从文件中进行输入,该如何处理呢?原理上很简单,我们还是需要创建一个AudioConfig的对象,然后使用该对象的方法FromWaveFileInput指定输入的文件就可以了。

public async static Task TranslationFromFile(SpeechTranslationConfig config, string sourceLang, List<string> targetLanguage)
{

    //设置源语言
    config.SpeechRecognitionLanguage = sourceLang;
    //设置目的语言
    targetLanguage.ForEach(config.AddTargetLanguage);

    using var audioConfig = AudioConfig.FromWavFileInput("1.wav");

    using var recognizer = new TranslationRecognizer(config, audioConfig);

    Console.Write($"Say something in '{sourceLang}' and ");
    Console.WriteLine($"We will translate into '{string.Join("', '", targetLanguage)}'.\n ");

    var result = await recognizer.RecognizeOnceAsync();

    if (result.Reason == ResultReason.TranslatedSpeech)
    {
        Console.WriteLine($"Recognized:\"{result.Text}\"; ");

        foreach (var (language, translation) in result.Translations)
        {
            Console.WriteLine($"Translated into '{language}': {translation} ");
        }
    }
}

支持将音频翻译成文字我们介绍完了,下面我们接着介绍如何将音频翻译成另外语言的音频。

语音翻译成其他语言的语音(Speech-to-Speech)

现在我们介绍真正的"同声翻译"了。例如将英语音频翻译成中文音频或者德文音频等等。
目前有两种方式实现这个功能:

  • 监听TranslationRecognizerSynthesizing事件。
  • 手动使用文本转语音的功能进行转换。

功能上说起来很简单,直接看代码就可以了。

监听TranslationRecognizerSynthesizing事件

代码如下:

//通过事件来翻译到语音,注意如果是通过事件来翻译的话,目的语言只能单个,不能添加多个语言。
public async static Task TranslationToSpeechByEvent(SpeechTranslationConfig config, string sourceLang, string targetLanguage, string targetVoiceName)
{

    //设置源语言
    config.SpeechRecognitionLanguage = sourceLang;
    //设置目的语言
    config.AddTargetLanguage(targetLanguage);

    //设置需要转换的语言
    config.VoiceName = targetVoiceName;



    using var recognizer = new TranslationRecognizer(config);

    Console.Write($"Say something in '{sourceLang}' and ");
    Console.WriteLine($"We will translate into '{string.Join("', '", targetLanguage)}'.\n ");


    //定义事件来对语音进行翻译
    recognizer.Synthesizing += (_, e) =>
        {
            var audio = e.Result.GetAudio();
            Console.WriteLine($"Audio synthesized: {audio.Length:#,0} byte(s) {(audio.Length == 0 ? "(Complete)" : "")}");

            if (audio.Length > 0)
            {
                File.WriteAllBytes($"translation-{targetVoiceName}.wav", audio);
            }
        };

    var result = await recognizer.RecognizeOnceAsync();

    if (result.Reason == ResultReason.TranslatedSpeech)
    {
        Console.WriteLine($"Recognized:\"{result.Text}\"; ");

        foreach (var (language, translation) in result.Translations)
        {
            Console.WriteLine($"Translated into '{language}': {translation} ");
        }
    }
}

这段代码非常好理解,主要的部分就在于如何监听事件。

注意
使用事件来进行语音翻译,不支持多语言转换,因此只能从一种语言翻译到另外一种语言,但是手动就可以实现一种语言翻译成多种语言。

手动使用文本转语音的SDK

这个部分理解是非常容易的,还是老规矩,看如下的代码:

public async static Task TranslationToSpeechByManual(SpeechTranslationConfig config, string sourceLang, List<string> targetLanguage)
{

    //设置源语言
    config.SpeechRecognitionLanguage = sourceLang;
    //设置目的语言
    targetLanguage.ForEach(config.AddTargetLanguage);

    using var recognizer = new TranslationRecognizer(config);

    Console.Write($"Say something in '{sourceLang}' and ");
    Console.WriteLine($"We will translate into '{string.Join("', '", targetLanguage)}'.\n ");

    var result = await recognizer.RecognizeOnceAsync();
    if (result.Reason == ResultReason.TranslatedSpeech)
    {
        // See: https://aka.ms/speech/sdkregion#standard-and-neural-voices
        var languageToVoiceMap = new Dictionary<string, string>
        {
            ["de"] = "de-DE-KatjaNeural",
            ["en"] = "en-US-AriaNeural",
            ["it"] = "it-IT-ElsaNeural",
            ["pt"] = "pt-BR-FranciscaNeural",
            ["zh-Hans"] = "zh-CN-XiaoxiaoNeural"
        };

        Console.WriteLine($"Recognized: \"{result.Text}\"");

        foreach (var (language, translation) in result.Translations)
        {
            Console.WriteLine($"Translated into '{language}': {translation}");

            var speechConfig =
                SpeechConfig.FromSubscription(
                    SPEECH__SUBSCRIPTION__KEY, SPEECH__SERVICE__REGION);
            speechConfig.SpeechSynthesisVoiceName = languageToVoiceMap[language];

            using var audioConfig = AudioConfig.FromWavFileOutput($"{language}-translation.wav");
            using var synthesizer = new SpeechSynthesizer(speechConfig, audioConfig);

            await synthesizer.SpeakTextAsync(translation);
        }
    }

}

好了语音翻译就简要的介绍到这里了。