Gummy一句话识别、翻译Java SDK

本文介绍Gummy一句话识别和翻译Java SDK的参数和接口细节。

用户指南:关于模型介绍和选型建议请参见实时语音识别实时语音翻译

在线体验模型体验

说明

一句话识别/翻译能够直接对一分钟内的音频流(无论是从外部设备如麦克风获取的音频流,还是从本地文件读取的音频流)进行识别或翻译,并实时输出结果。在识别或翻译一句话后将停止识别或翻译任务。

  • 音频时长不能超过一分钟,否则将报错断连。

  • 一句话的结束,通过静音时长来判断,当语音后面出现的静音时长超过预设的静音时长(默认为700ms,可通过请求参数maxEndSilence设置),系统会认为当前的一句话已结束。如果语音时长超过了一分钟,则认为这一分钟内的语音是一句话。

前提条件

模型列表

模型名

模型简介

gummy-chat-v1

Gummy一句话识别、翻译模型,在识别、翻译出一句话后会结束任务。默认进行标点符号预测和逆文本正则化(INT,Inverse Text Normalization)。支持定制热词

快速开始

TranslationRecognizerChat提供了一句话识别/翻译的关键接口,支持流式调用模式。

流式调用

通过实现回调接口的方式流式输出实时识别结果。

image
  1. 启动流式语音识别/翻译

    实例化TranslationRecognizerChat,调用call方法绑定请求参数回调接口(ResultCallback)并启动流式语音识别/翻译。

  2. 流式传输

    循环调用TranslationRecognizerChatsendAudioFrame方法,将从本地文件或设备(如麦克风)读取的二进制音频流分段发送至服务端。

    在发送音频数据的过程中,服务端会通过回调接口(ResultCallback)onEvent方法,将识别结果实时返回给客户端。

    建议每次发送的音频时长约为100毫秒,数据大小保持在1KB16KB之间。

    当识别到一句话后,sendAudioFrame方法返回false,音频数据无法再继续上传。此时请终止循环。

  3. 结束处理

    调用TranslationRecognizerChatstop方法结束语音识别/翻译。

    该方法会阻塞当前线程,直到回调接口(ResultCallback)onComplete或者onError回调触发后才会释放线程阻塞。

点击查看完整示例

识别传入麦克风的语音

package org.alibaba.bailian.example.examples;

import com.alibaba.dashscope.audio.asr.translation.TranslationRecognizerChat;
import com.alibaba.dashscope.audio.asr.translation.TranslationRecognizerParam;
import com.alibaba.dashscope.audio.asr.translation.results.TranscriptionResult;
import com.alibaba.dashscope.audio.asr.translation.results.TranslationRecognizerResult;
import com.alibaba.dashscope.common.ResultCallback;
import com.alibaba.dashscope.exception.NoApiKeyException;

import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.TargetDataLine;
import java.nio.ByteBuffer;

public class Main {

    public static void main(String[] args) throws NoApiKeyException, InterruptedException, LineUnavailableException {

        // 创建Recognizer
        TranslationRecognizerChat translator = new TranslationRecognizerChat();
        // 初始化请求参数
        TranslationRecognizerParam param =
                TranslationRecognizerParam.builder()
                        // 若没有将API Key配置到环境变量中,需将your-api-key替换为自己的API Key
                        // .apiKey("your-api-key")
                        .model("gummy-chat-v1") // 设置模型名
                        .format("pcm") // 设置待识别音频格式,支持的音频格式:pcm、pcm编码的wav、mp3、ogg封装的opus、ogg封装的speex、aac、amr
                        .sampleRate(16000) // 设置待识别音频采样率(单位Hz)。仅支持16000Hz采样率。
                        .transcriptionEnabled(true) // 设置是否开启实时识别
                        .translationEnabled(true) // 设置是否开启实时翻译
                        .translationLanguages(new String[] {"en"}) // 设置翻译目标语言
                        .build();

        try {

            translator.call(param, new ResultCallback<TranslationRecognizerResult>() {
                @Override
                public void onEvent(TranslationRecognizerResult result) {
                    if (result.getTranscriptionResult() == null) {
                        return;
                    }
                    try {
                        System.out.println("RequestId: " + result.getRequestId());
                        // 打印最终结果
                        if (result.getTranscriptionResult() != null) {
                            System.out.println("Transcription Result:");
                            if (result.isSentenceEnd()) {
                                System.out.println("\tFix:" + result.getTranscriptionResult().getText());
                            } else {
                                TranscriptionResult transcriptionResult = result.getTranscriptionResult();
                                System.out.println("\tTemp Result:" + transcriptionResult.getText());
                                if (result.getTranscriptionResult().isVadPreEnd()) {
                                    System.out.printf("VadPreEnd: start:%d, end:%d, time:%d\n", transcriptionResult.getPreEndStartTime(), transcriptionResult.getPreEndEndTime(), transcriptionResult.getPreEndTimemillis());
                                }
                            }
                        }
                        if (result.getTranslationResult() != null) {
                            System.out.println("English Translation Result:");
                            if (result.isSentenceEnd()) {
                                System.out.println("\tFix:" + result.getTranslationResult().getTranslation("en").getText());
                            } else {
                                System.out.println("\tTemp Result:" + result.getTranslationResult().getTranslation("en").getText());
                            }
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }

                }

                @Override
                public void onComplete() {
                    System.out.println("Translation complete");
                }

                @Override
                public void onError(Exception e) {

                }
            });

            // 创建音频格式
            AudioFormat audioFormat = new AudioFormat(16000, 16, 1, true, false);
            // 根据格式匹配默认录音设备
            TargetDataLine targetDataLine =
                    AudioSystem.getTargetDataLine(audioFormat);
            targetDataLine.open(audioFormat);
            // 开始录音
            targetDataLine.start();
            System.out.println("请您通过麦克风讲话体验一句话语音识别和翻译功能");
            ByteBuffer buffer = ByteBuffer.allocate(1024);
            long start = System.currentTimeMillis();
            // 录音5s并进行实时识别
            while (System.currentTimeMillis() - start < 50000) {
                int read = targetDataLine.read(buffer.array(), 0, buffer.capacity());
                if (read > 0) {
                    buffer.limit(read);
                    // 将录音音频数据发送给流式识别服务
                    if (!translator.sendAudioFrame(buffer)) {
                        System.out.println("sentence end, stop sending");
                        break;
                    }
                    buffer = ByteBuffer.allocate(1024);
                    // 录音速率有限,防止cpu占用过高,休眠一小会儿
                    Thread.sleep(20);
                }
            }
            translator.stop();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 任务结束关闭 websocket 连接
            translator.getDuplexApi().close(1000, "bye");
        }
        System.exit(0);
    }
}

识别本地语音文件

示例中用到的音频为:hello_world.wav

import com.alibaba.dashscope.audio.asr.translation.TranslationRecognizerChat;
import com.alibaba.dashscope.audio.asr.translation.TranslationRecognizerParam;
import com.alibaba.dashscope.audio.asr.translation.results.TranslationRecognizerResult;
import com.alibaba.dashscope.common.ResultCallback;
import com.alibaba.dashscope.exception.NoApiKeyException;

import java.io.FileInputStream;
import java.nio.ByteBuffer;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

class RealtimeTranslateChatTask implements Runnable {
    private Path filepath;
    private TranslationRecognizerChat translator = null;

    public RealtimeTranslateChatTask(Path filepath) {
        this.filepath = filepath;
    }

    @Override
    public void run() {
        for (int i=0; i<1; i++) {
            // 初始化请求参数
            TranslationRecognizerParam param =
                    TranslationRecognizerParam.builder()
                            // 若没有将API Key配置到环境变量中,需将your-api-key替换为自己的API Key
                            // .apiKey("your-api-key")
                            .model("gummy-chat-v1") // 设置模型名
                            .format("wav") // 设置待识别音频格式,支持的音频格式:pcm、pcm编码的wav、mp3、ogg封装的opus、ogg封装的speex、aac、amr
                            .sampleRate(16000) // 设置待识别音频采样率(单位Hz)。只支持16000Hz的采样率。
                            .transcriptionEnabled(true) // 设置是否开启实时识别
                            .translationEnabled(true) // 设置是否开启实时翻译
                            .translationLanguages(new String[] {"en"}) // 设置翻译目标语言
                            .build();
            if (translator == null) {
                // 初始化流式识别服务
                translator = new TranslationRecognizerChat();
            }

            String threadName = Thread.currentThread().getName();

            // 初始化回调接口
            ResultCallback<TranslationRecognizerResult> callback =
                    new ResultCallback<TranslationRecognizerResult>() {
                        @Override
                        public void onEvent(TranslationRecognizerResult result) {
                            System.out.println("RequestId: " + result.getRequestId());
                            // 打印最终结果
                            if (result.getTranscriptionResult() != null) {
                                System.out.println("Transcription Result:"+result);
                                if (result.isSentenceEnd()) {
                                    System.out.println("\tFix:" + result.getTranscriptionResult().getText());
                                } else {
                                    System.out.println("\tTemp Result:" + result.getTranscriptionResult().getText());
                                }
                            }
                            if (result.getTranslationResult() != null) {
                                System.out.println("English Translation Result:");
                                if (result.isSentenceEnd()) {
                                    System.out.println("\tFix:" + result.getTranslationResult().getTranslation("en").getText());
                                } else {
                                    System.out.println("\tTemp Result:" + result.getTranslationResult().getTranslation("en").getText());
                                }
                            }
                        }

                        @Override
                        public void onComplete() {
                            System.out.println("[" + threadName + "] Translation complete");
                        }

                        @Override
                        public void onError(Exception e) {
                            e.printStackTrace();
                            System.out.println("[" + threadName + "] TranslationCallback error: " + e.getMessage());
                        }
                    };
            try {
                // 启动流式语音识别/翻译,绑定请求参数和回调接口
                translator.call(param, callback);
                // 替换成您自己的文件路径
                System.out.println("[" + threadName + "] Input file_path is: " + this.filepath);
                // Read file and send audio by chunks
                try (FileInputStream fis = new FileInputStream(this.filepath.toFile())) {
                    // chunk size set to 1 seconds for 16KHz sample rate
                    byte[] buffer = new byte[3200];
                    int bytesRead;
                    // Loop to read chunks of the file
                    while ((bytesRead = fis.read(buffer)) != -1) {
                        ByteBuffer byteBuffer;
                        // Handle the last chunk which might be smaller than the buffer size
                        System.out.println("[" + threadName + "] bytesRead: " + bytesRead);
                        if (bytesRead < buffer.length) {
                            byteBuffer = ByteBuffer.wrap(buffer, 0, bytesRead);
                        } else {
                            byteBuffer = ByteBuffer.wrap(buffer);
                        }
                        // Send the ByteBuffer to the translation instance
                        if (!translator.sendAudioFrame(byteBuffer)) {
                            System.out.println("sentence end, stop sending");
                            break;
                        }
                        buffer = new byte[3200];
                        Thread.sleep(100);
                    }
                    fis.close();
                    System.out.println(LocalDateTime.now());
                } catch (Exception e) {
                    e.printStackTrace();
                }

                // 通知结束
                translator.stop();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                // 任务结束关闭 websocket 连接
                if (translator != null) {
                    translator.getDuplexApi().close(1000, "bye");
                }
            }
        }
    }

}


public class Main {
    public static void main(String[] args)
            throws NoApiKeyException, InterruptedException {
        String currentDir = System.getProperty("user.dir");
        // Please replace the path with your audio source
        Path[] filePaths = {
                Paths.get(currentDir, "hello_world.wav"),
//                Paths.get(currentDir, "hello_world_male_16k_16bit_mono.wav"),
        };
        // Use ThreadPool to run recognition tasks
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        for (Path filepath:filePaths) {
            executorService.submit(new RealtimeTranslateChatTask(filepath));
        }
        executorService.shutdown();
        // wait for all tasks to complete
        executorService.awaitTermination(1, TimeUnit.MINUTES);
//        System.exit(0);
    }
}

请求参数

通过TranslationRecognizerParam的链式方法配置模型、采样率、音频格式等参数。配置完成的参数对象传入TranslationRecognizerChatcall方法中使用。

点击查看示例

TranslationRecognizerParam param =
        TranslationRecognizerParam.builder()
                .model("gummy-chat-v1")
                .format("pcm")
                .sampleRate(16000)
                .transcriptionEnabled(true)
                .translationEnabled(true)
                .translationLanguages(new String[] {"en"})
                .build();

参数

类型

默认值

是否必须

说明

model

String

-

设置一句话识别/翻译的模型。如需了解当前支持的模型,请参见模型列表

sampleRate

Integer

-

设置待识别音频采样率(单位Hz)。只支持16000Hz。

format

String

-

设置待识别音频格式。

支持的音频格式:pcm、wav、mp3、opus、speex、aac、amr。

重要

opus/speex:必须使用Ogg封装;

wav:必须为PCM编码;

amr:仅支持AMR-NB类型。

vocabularyId

String

-

设置热词ID,若未设置则不生效。

在本次语音识别中,将应用与该热词ID对应的热词信息。具体使用方法请参见定制热词

sourceLanguage

String

auto

设置源(待识别/翻译语言)语言代码。如果无法提前确定语种,可不设置,默认为auto

目前支持的语言代码:

  • zh: 中文

  • en: 英文

  • ja: 日语

  • yue: 粤语

  • ko: 韩语

  • de: 德语

  • fr: 法语

  • ru: 俄语

  • it: 意大利语

  • es: 西班牙语

transcriptionEnabled

boolean

true

设置是否启用识别功能。

模型支持单独开启识别或翻译功能,也可同时启用两种功能,但至少需要开启其中一种能力。

translationEnabled

boolean

false

设置是否启用翻译功能。要正常输出翻译结果,需配置translationLanguages参数。

模型支持单独开启识别或翻译功能,也可同时启用两种功能,但至少需要开启其中一种能力。

translationLanguages

String[]

-

设置翻译目标语言代码。目标语言的代码与sourceLanguage参数一致。

目前支持的翻译包括:

中->英,中->日,中->韩,

英->中,英->日,英->韩,

(日、韩、粤、德、法、俄、意、西)->(中、英)。

重要

目前暂不支持同时翻译为多种语言,请仅设置一个目标语言以完成翻译。

maxEndSilence

Integer

700

设置最大结束静音时长,单位为毫秒(ms),取值范围为200ms6000ms。

若语音结束后静音时长超过该预设值,系统将判定当前语句已结束。

apiKey

String

-

设置用户API Key。

关键接口

TranslationRecognizerChat

TranslationRecognizerChat通过“import com.alibaba.dashscope.audio.asr.translation.TranslationRecognizerChat;”方式引入,提供一句话识别/翻译的关键接口。

接口/方法

参数

返回值

描述

public void call(TranslationRecognizerParam param, final ResultCallback<TranslationRecognizerResult> callback)

启动一句话识别/翻译。

详细的调用流程和参考示例请参见流式调用

public boolean sendAudioFrame(ByteBuffer audioFrame)

audioFrame:二进制音频流,为ByteBuffer类型

推送音频,每次推送的音频流不宜过大或过小,建议每包音频时长为100ms左右,大小在1KB~16KB之间。

当已经识别到一句话后,调用sendAudioFrame会返回false,并且音频不会被继续上传。请停止发送并且结束调用。

识别结果在回调接口(ResultCallback)onEvent方法中获取。

详细的调用流程和参考示例请参见流式调用

public void stop()

结束一句话识别/翻译。

该方法会阻塞当前线程,直到回调接口(ResultCallback)onComplete或者onError被调用后,才会解除对当前线程的阻塞。

详细的调用流程和参考示例请参见流式调用

boolean getDuplexApi().close(int code, String reason)

code: WebSocket关闭码(Close Code)

reason:关闭原因

这两个参数可参考The WebSocket Protocol文档进行配置

true

在任务结束后,无论是否出现异常都需要关闭WebSocket连接,避免造成连接泄漏。

回调接口(ResultCallback

ResultCallback通过“import com.alibaba.dashscope.common.ResultCallback;”方式引入。

点击查看示例

ResultCallback<TranslationRecognizerResult> callback = new ResultCallback<TranslationRecognizerResult>() {
    @Override
    public void onEvent(TranslationRecognizerResult result) {
        System.out.println("RequestId为:" + result.getRequestId());
        // 在此实现处理语音识别结果的逻辑
    }

    @Override
    public void onComplete() {
        System.out.println("任务完成");
    }

    @Override
    public void onError(Exception e) {
        System.out.println("任务失败:" + e.getMessage());
    }
};

接口/方法

参数

返回值

描述

public void onEvent(TranslationRecognizerResult result)

result实时结果(TranslationRecognizerResult)

当服务有回复时会被回调。

public void onComplete()

任务完成后该接口被回调。

public void onError(Exception e)

e:异常信息

发生异常时该接口被回调。

响应结果

实时结果(TranslationRecognizerResult

封装了实时识别结果TranscriptionResult和实时翻译结果TranslationResult

由于不同语言的词汇差异,识别和翻译的中间结果可能不会同时返回,因此在某些情况下,返回的结果中可能仅包含识别或翻译的部分。识别与翻译的进度会在 isSentenceEndtrue 时同步完成。

接口/方法

参数

返回值

描述

public TranscriptionResult getTranscriptionResult()

实时识别结果

获取TranscriptionResult实例。TranscriptionResult封装了一次实时识别的结果。

TranscriptionResult关键接口参见实时识别结果(TranscriptionResult)

public TranslationResult getTranslationResult()

实时翻译结果

获取TranslationResult实例。TranslationResult封装了一次实时翻译的结果。

TranslationResult关键接口参见实时翻译结果(TranslationResult)

实时识别结果(TranscriptionResult

TranscriptionResult代表一次实时识别的结果,包含了时间戳和文本信息等。

接口/方法

参数

返回值

描述

public Long getSentenceId()

句子ID

返回句子ID。

public Long getBeginTime()

句子开始时间,单位为ms

返回句子开始时间。

public Long getEndTime()

句子结束时间,单位为ms

返回句子结束时间。

public String getText()

识别文本

返回识别文本。

public List<Word> getWords()

字时间戳信息:Word集合

返回字时间戳信息。

Word关键接口参见字时间戳信息(Word)

public boolean isSentenceEnd()

  • true:当前文本构成完整句子,识别结果为最终结果

  • false:当前文本未构成完整句子,识别结果可能会更新

当前文本是否构成完整的句子。

实时翻译结果(TranslationResult

TranslationResult代表一次实时翻译的结果,包含请求参数transcriptionTargetLanguages指定的所有语种的翻译结果。

接口/方法

参数

返回值

描述

public List<String> getLanguageList()

翻译结果中的所有语种列表

返回翻译结果中的所有语种列表。

public Translation getTranslation(String language)

language:语种,要和请求参数translationLanguages相匹配

Translation实例,某语种对应的翻译结果

返回该对应语种的翻译结果。

Translation关键接口参见某语种对应的翻译结果(Translation)

public boolean isSentenceEnd()

  • true:当前文本构成完整句子,翻译结果为最终结果

  • false:当前文本未构成完整句子,翻译结果可能会更新

当前文本是否构成完整的句子。

某语种对应的翻译结果(Translation

Translation代表实时翻译结果中一种语言的结果,包含了时间戳和文本信息等。

接口/方法

参数

返回值

描述

public Long getSentenceId()

句子ID

返回句子ID。

public String getLanguage()

翻译语种

返回翻译语种。

public Long getBeginTime()

句子开始时间,单位为ms

返回句子开始时间。

public Long getEndTime()

句子结束时间,单位为ms

返回句子结束时间。

public String getText()

识别文本

返回识别文本。

public List<Word> getWords()

字时间戳信息:Word集合

返回字时间戳信息。

Word关键接口参见字时间戳信息(Word)

public boolean isSentenceEnd()

  • true:当前文本构成完整句子,翻译结果为最终结果

  • false:当前文本未构成完整句子,翻译结果可能会更新

当前文本是否构成完整的句子。

字时间戳信息(Word

接口/方法

参数

返回值

描述

public long getBeginTime()

字开始时间,单位为ms

返回字开始时间。

public long getEndTime()

字结束时间,单位为ms

返回字结束时间。

public String getText()

返回识别的字。

错误码

如遇报错问题,请参见错误信息进行排查。

若问题仍未解决,请加入开发者群反馈遇到的问题,并提供Request ID,以便进一步排查问题。

更多示例

更多示例,请参见GitHub

常见问题

故障排查

如遇代码报错问题,请根据错误信息进行排查。

Q:为什么没有输出翻译结果?

  1. 请求参数配置要正确。

    1. 需将参数translationEnabled设置为true

    2. 需通过参数translationLanguages指定翻译目标语言。注意,该参数类型为数组而非字符串。

  2. 获取实时翻译结果(TranslationResult)时,方法getTranslation的入参要和翻译目标语言(即参数translationLanguages的值)相匹配。

    比如translationLanguages["en"],却getTranslation("zh")就无法获取翻译结果。

更多问题

请参见GitHub QA