65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 Azure Cognitive Services 构建通用翻译器,第三部分:文本翻译和语音转换

starIconstarIconstarIconstarIconstarIcon

5.00/5 (1投票)

2022年3月14日

CPOL

5分钟阅读

viewsIcon

4206

如何翻译文本并将其转换为语音以完成通用翻译器的构建

本系列三篇文章的前两部分构建了一个 Web 前端和 Java 后端,使用户能够 录制语音将其转录为文本

还有两个步骤来完成通用翻译器:文本翻译和将翻译后的文本转换为语音。

请遵循本教程完成 Java 后端,使用 Azure 翻译服务翻译文本,然后重用 Azure 语音服务将文本转换回语音。

必备组件

请确保已安装免费的 Java 11 JDK 以用于后端应用程序。后端应用程序还需要 Azure Functions 运行时版本 4

还需要 GStreamer 来转换 WebM 音频文件,以便 Azure API 进行处理。

该应用程序的完整源代码可在 GitHub 上找到,后端应用程序也可作为 Docker 镜像 mcasperson/translator 使用。

创建翻译服务

Azure 翻译服务执行两种语言之间的翻译。 Microsoft 文档提供了创建翻译资源说明。

创建资源后,记下密钥和区域。我们配置后端服务时将需要它们。

语言间文本翻译

TranslateService 类定义了语言间文本翻译的逻辑。

package com.matthewcasperson.azuretranslate.services;
import java.io.IOException;
import okhttp3.HttpUrl;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import org.apache.commons.text.StringEscapeUtils;
public class TranslateService {

此类公开了一个名为 translate 的单一方法,该方法将要翻译的文本、源语言和目标语言作为 string 接收。

public String translate(final String input, final String sourceLanguage,
      final String targetLanguage) throws IOException {

应用程序通过其 REST API 与 Azure 翻译服务进行交互。此代码构建了要调用的终结点。

    final HttpUrl url = new HttpUrl.Builder()
        .scheme("https")
        .host("api.cognitive.microsofttranslator.com")
        .addPathSegment("/translate")
        .addQueryParameter("api-version", "3.0")
        .addQueryParameter("from", sourceLanguage)
        .addQueryParameter("to", targetLanguage)
        .build();

然后,OkHttp 客户端发起 API 请求。

    final OkHttpClient client = new OkHttpClient();

REST API 调用在请求正文中传递一个 JSON 对象,其中包含要翻译的文本。

    final MediaType mediaType = MediaType.parse("application/json");
    final RequestBody body = RequestBody.create("[{\"Text\": \""
        + StringEscapeUtils.escapeJson(input) + "\"}]", mediaType);

两个 HTTP 标头包含翻译服务密钥和区域,均在环境变量中定义。

    final Request request = new Request.Builder().url(url).post(body) 
        .addHeader("Ocp-Apim-Subscription-Key", System.getenv("TRANSLATOR_KEY")) 
        .addHeader("Ocp-Apim-Subscription-Region", System.getenv("TRANSLATOR_REGION")) 
        .addHeader("Content-type", "application/json") 
        .build();

请求执行,并返回响应。

    final Response response = client.newCall(request).execute();
    return response.body().string();
  }
}

文本转语音

SpeechService 类定义了文本转语音的逻辑。

package com.matthewcasperson.azuretranslate.services;
import com.microsoft.cognitiveservices.speech.AudioDataStream;
import com.microsoft.cognitiveservices.speech.SpeechConfig;
import com.microsoft.cognitiveservices.speech.SpeechSynthesisOutputFormat;
import com.microsoft.cognitiveservices.speech.SpeechSynthesisResult;
import com.microsoft.cognitiveservices.speech.SpeechSynthesizer;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import org.apache.commons.io.FileUtils;
public class SpeechService {

此类公开了一个名为 translateText 的单一方法,该方法将要转换的文本和要说的语言作为 string 接收。

  public byte[] translateText(final String input, final String targetLanguage) 
         throws IOException {

Azure SDK 支持将音频保存为文件。将此音频捕获到临时文件中。

    final Path tempFile = Files.createTempFile("", ".wav");

然后,代码使用语音服务密钥和区域创建一个 SpeechConfig 对象,这两者都来自环境变量。

    try (final SpeechConfig speechConfig = SpeechConfig.fromSubscription(
        System.getenv("SPEECH_KEY"),
        System.getenv("SPEECH_REGION"))) {

接下来,代码配置目标语言。

      speechConfig.setSpeechSynthesisLanguage(targetLanguage);

然后,代码定义音频文件的格式。有几十种格式可用,对于示例应用程序来说,任何一种都可以,尽管 Opus 压缩方案 据说非常适合基于语音的 Web 应用程序。

   speechConfig.setSpeechSynthesisOutputFormat
      (SpeechSynthesisOutputFormat. Webm24Khz16Bit24KbpsMonoOpus);

SpeechSynthesizer 类现在执行语音合成。

      final SpeechSynthesizer synthesizer = new SpeechSynthesizer(speechConfig, null);

然后,应用程序将文本转换为语音。

      final SpeechSynthesisResult result = synthesizer.SpeakText(input);

应用程序将生成的音频保存到文件中并返回文件内容。

      final AudioDataStream stream = AudioDataStream.fromResult(result);
      stream.saveToWavFile(tempFile.toString());
      return Files.readAllBytes(tempFile);
    } finally {

最后,代码清理临时文件。

      FileUtils.deleteQuietly(tempFile.toFile());
    }
  }
}

公开新终结点

接下来,应用程序在 Function 类中将这两个服务公开为函数终结点。

首先,我们将服务创建为 static 变量。

    private static final SpeechService SPEECH_SERVICE = new SpeechService();
    private static final TranslateService TRANSLATE_SERVICE = new TranslateService();

然后,我们将这两个新方法添加到 Function 类中。

第一个名为 translate,它公开了一个 HTTP POST 终结点,该终结点在请求正文中接收要翻译的文本,并通过查询参数接收源语言和目标语言。该方法返回上游 Azure 翻译服务返回的 JSON 正文。

    @FunctionName("translate")
    public HttpResponseMessage translate(
        @HttpTrigger(
            name = "req",
            methods = {HttpMethod.POST},
            authLevel = AuthorizationLevel.ANONYMOUS)
        HttpRequestMessage<Optional<String>> request,
        final ExecutionContext context) {
        if (request.getBody().isEmpty()) {
            return request.createResponseBuilder(HttpStatus.BAD_REQUEST)
                .body("The text to translate file must be in the body of the post.")
                .build();
        }
        try {
            final String text = TRANSLATE_SERVICE.translate(
                request.getBody().get(),
                request.getQueryParameters().get("sourceLanguage"),
                request.getQueryParameters().get("targetLanguage"));
            return request.createResponseBuilder(HttpStatus.OK).body(text).build();
        } catch (final IOException ex) {
            return request.createResponseBuilder(HttpStatus.INTERNAL_SERVER_ERROR)
                .body("There was an error translating the text.")
                .build();
        }
    }

第二个函数名为 speak,也公开了一个 HTTP POST 终结点。此终结点在请求正文中接收要合成的文本,并通过查询参数接收要转换为语音的语言,然后将二进制音频返回到响应中。

    @FunctionName("speak")
    public HttpResponseMessage speak(
        @HttpTrigger(
            name = "req",
            methods = {HttpMethod.POST},
            authLevel = AuthorizationLevel.ANONYMOUS)
        HttpRequestMessage<Optional<String>> request,
        final ExecutionContext context) {
        if (request.getBody().isEmpty()) {
            return request.createResponseBuilder(HttpStatus.BAD_REQUEST)
                .body("The text to translate file must be in the body of the post.")
                .build();
        }
        try {
            final byte[] audio = SPEECH_SERVICE.translateText(
                request.getBody().get(),
                request.getQueryParameters().get("targetLanguage"));
            return request.createResponseBuilder(HttpStatus.OK).body(audio).build();
        } catch (final IOException ex) {
            return request.createResponseBuilder(HttpStatus.INTERNAL_SERVER_ERROR)
                .body("There was an error converting the text to speech.")
                .build();
        }
    }

定义新的应用设置

代码现在需要两个新的环境变量:TRANSLATOR_KEYTRANSLATOR_REGION。必须在 Azure Functions 应用中将这些变量定义为应用设置。

az functionapp config appsettings set --name yourappname 
--resource-group yourresourcegroup --settings "TRANSLATOR_KEY=yourtranslatorkey"

az functionapp config appsettings set --name yourappname --resource-group yourresourcegroup 
--settings "TRANSLATOR_REGION=yourtranslatorregion"

后端代码中使用的四个环境变量(TRANSLATOR_KEYTRANSLATOR_REGIONSPEECH_KEYSPEECH_REGION)定义为应用设置,如下面的截图所示。

在本地测试 API

语音服务密钥和区域必须公开为环境变量。因此,我们在 PowerShell 中运行以下命令:

$env:SPEECH_KEY="your key goes here"
$env:SPEECH_REGION="your region goes here"
$env:TRANSLATOR_KEY="your key goes here"
$env:TRANSLATOR_REGION="your region goes here"

或者,我们可以在 Bash 中运行等效命令:

export SPEECH_KEY="your key goes here"
export SPEECH_REGION="your region goes here"
export TRANSLATOR_KEY="your key goes here"
export TRANSLATOR_REGION="your region goes here"

接下来,要构建后端,我们运行:

mvn clean package

然后,要在本地运行该函数,我们运行以下命令:

mvn azure-functions:run

最后,我们启动上一篇文章中详细介绍的前端 Web 应用程序,命令为:

npm start

应用程序现在已完全可用!用户可以录制消息,将其转录,翻译,并将翻译后的文本转换为语音。

部署后端应用程序

幸运的是,上一篇文章已经完成了部署后端应用程序的所有繁重工作。现在只需重建 Docker 镜像。我们使用以下命令完成此操作:

docker build . -t dockerhubuser/translator

然后,我们将更新后的镜像推送到 DockerHub。

docker push dockerhubuser/translator

假设已在 Azure Function 上配置了 持续部署,一旦新镜像被推送,DockerHub 将触发 Azure Function 的重新部署。

至此,应用程序已上线并准备好进行翻译!

后续步骤

本教程通过实现语言间的文本翻译并提供文本转语音的功能,结束了我们的通用翻译器系列。因此,通用翻译器可以将浏览器录制的语音翻译成另一种语言,帮助旅行者、工作者等与地球上的几乎任何人进行交流。

示例应用程序演示了将高级文本和语音 AI 添加到 Java 应用程序是多么容易。尽管几年前这还是科幻小说,但开发人员现在只需几百行代码就可以将通用翻译器嵌入到他们的应用程序中。

对于那些希望更进一步,将语音和文本服务嵌入到其他应用程序中的人,请从 GitHub Fork 前端后端代码。然后,探索各种 Azure Cognitive Services,以增强应用程序的独特性。

要了解有关 Microsoft Cognitive Services Speech SDK 的更多信息并查看示例,请查看 Microsoft Cognitive Services Speech SDK 示例

© . All rights reserved.