package com.huawei.sis.demo.cn_demo;

import com.huawei.sis.bean.AuthInfo;
import com.huawei.sis.bean.SisConfig;
import com.huawei.sis.bean.SisConstant;
import com.huawei.sis.bean.request.RasrRequest;
import com.huawei.sis.bean.response.RasrResponse;
import com.huawei.sis.bean.response.StateResponse;
import com.huawei.sis.client.RasrClient;
import com.huawei.sis.bean.RasrListener;
import com.huawei.sis.util.JsonUtils;

/**
 * 实时语音识别demo
 *
 * Copyright 2021 Huawei Technologies Co.,Ltd.
 */
public class RasrDemo {
  private static final int DEFAULT_HEAD_SILENCE_TIME = 1000;
  private static final int DEFAULT_TAIL_SILENCE_TIME = 500;
  private static final int DEFAULT_CONTINUE_SECONDS = 30;

  // 认证用的ak和sk硬编码到代码中或者明文存储都有很大的安全风险，建议在配置文件或者环境变量中密文存放，使用时解密，确保安全；
  // 本示例以ak和sk保存在环境变量中来实现身份验证为例，运行本示例前请先在本地环境中设置环境变量HUAWEICLOUD_SDK_AK和HUAWEICLOUD_SDK_SK。
  private String ak = System.getenv("HUAWEICLOUD_SDK_AK");
  private String sk = System.getenv("HUAWEICLOUD_SDK_SK");
  private String region = "";    // 区域，如cn-north-1、cn-north-4
  private String projectId = ""; // 项目id，在我的凭证查看。参考https://support.huaweicloud.com/api-sis/sis_03_0008.html

  private String path = "";                     // 本地音频路径，如D:/test.wav, sdk也支持byte数组传送。
  private String audioFormat = "";             // 音频格式，如pcm16k16bit，详见api文档或sdk文档
  private String property = "";       // 属性字符串，language_sampleRate_domain，如chinese_16k_general, 详见api文档

  /**
   * 实时语音识别参数设置，所有参数设置均为可选，均有默认值。用户根据需求设置参数。
   *
   * @param request request请求，包含各种参数
   */
  private void setParameters(RasrRequest request) {

    // 1. 设置是否添加标点符号，yes 或 no， 默认"no"
    request.setAddPunc("yes");
    // 2. 设置头部的最大静音时间，[0,60000], 默认10000ms
    request.setVadHead(DEFAULT_HEAD_SILENCE_TIME);
    // 3. 设置尾部最大静音时间，[0, 3000], 默认500ms，
    request.setVadTail(DEFAULT_TAIL_SILENCE_TIME);
    // 4. 设置最长持续时间，仅在continue-stream，sentence-stream模式下起作用，[1, 60], 默认30s
    request.setMaxSeconds(DEFAULT_CONTINUE_SECONDS);
    // 5. 设置是否显示中间结果，yes或no，默认“no”
    request.setIntermediateResult("no");
    // 6. 设置热词表id, 若没有则设置，否则会报错。
    // request.setVocabularyId("");
    // 7. 设置是否将音频中数字转写为阿拉伯数字，yes or no，默认yes
    request.setDigitNorm("no");
    // 8. 设置是否需要word_info，yes or no, 默认no
    request.setNeedWordInfo("no");
    // 9. 设置是否需要文本顺滑，yes or no，默认no
    request.setNeedSmooth("no");
  }

  /**
   * 定义config，所有参数可选，设置超时时间等。
   *
   * @return SisConfig
   */
  private SisConfig getConfig() {
    SisConfig config = new SisConfig();
    // 设置连接超时，默认10000ms
    config.setConnectionTimeout(SisConstant.DEFAULT_CONNECTION_TIMEOUT);
    // 设置读取超时，默认10000ms
    config.setReadTimeout(SisConstant.DEFAULT_READ_TIMEOUT);
    // 设置代理, 一定要确保代理可用才启动此设置。 代理初始化也可用不加密的代理，new ProxyHostInfo(host, port);
    // ProxyHostInfo proxy = new ProxyHostInfo(host, port, username, password);
    // config.setProxy(proxy);
    return config;
  }


  /**
   * 获取监听器，监听器的监听函数。
   *
   * @return RasrListener，用于监听实时语音识别的开始、识别结果、结束以及失败响应
   */
  private RasrListener getRasrListener() {
    RasrListener rasrListener = new RasrListener() {
      @Override
      /**
       * 连接成功回调
       */
      public void onTranscriptionConnect() {
        System.out.println("websocket connected");
      }

      @Override
      /**
       * 断开连接回调
       */
      public void onTranscriptionClose() {
        System.out.println("websocket closed");
      }

      @Override
      /**
       * 响应结果回调
       */
      public void onTranscriptionResponse(RasrResponse response) {
        printResponse(response);
      }

      @Override
      /**
       * 识别开始回调
       */
      public void onTranscriptionBegin(StateResponse response) {
        printResponse(response);
      }

      @Override
      /**
       * 识别结束回调
       */
      public void onSTranscriptionEnd(StateResponse response) {
        printResponse(response);
      }

      @Override
      /**
       * 识别出错回调
       */
      public void onTranscriptionFail(StateResponse response) {
        printResponse(response);
      }
    };
    return rasrListener;
  }


  private void printResponse(Object response) {
    try {
      System.out.println(JsonUtils.obj2Str(response, true));
    } catch (Exception e) {
      e.printStackTrace();
    }
  }

  /**
   * 实时语音识别SDK的工作流程
   */
  private void process() {
    try {
      // 1. 实现监听器接口RasrListener，用户自定义收到响应的处理逻辑。
      RasrListener rasrListener = getRasrListener();

      // 2. 初始化RasrClient
      AuthInfo authInfo = new AuthInfo(ak, sk, region, projectId);
      RasrClient rasrClient = new RasrClient(authInfo, rasrListener, getConfig());

      // 3. 配置参数
      // audioFormat为支持格式、property为属性字符串，具体填写请详细参考api文档
      RasrRequest request = new RasrRequest(audioFormat, property);
      setParameters(request);

      // 4 选择连接模式，目前实时语音识别提供三种接口，流式一句话、实时语音识别连续模式、实时语音识别单句模式
      // 选择1 流式一句话连接
      // rasrClient.shortStreamConnect(request);

      // 选择2，实时语音识别单句模式
      // rasrClient.sentenceStreamConnect(request);

      // 选择3，实时语音识别连续模式
      rasrClient.continueStreamConnect(request);

      // 5. 发送开始请求、发送音频、发送end请求
      // 发送开始请求，即将开始请求连带配置发送至服务端
      rasrClient.sendStart();

      // 发送数据，在实时语音连续模式下可多次发送。识别结果可以通过监听器获取
      // 也可以自己控制发送速率.byteLen为每次发送大小，sleepTime为每次发送后睡眠时间(ms)，一些非持续获取音频场景不需要睡眠，可设置为0.
      rasrClient.sendAudio(path, 3200, 50, property);  // 推荐使用此方法发送实时音频数据,sleeptime单位为ms
      // 其他发送实时音频数据的方法  rasrClient.sendAudio(path);  rasrClient.sendAudio(path, byteLen, sleepTime);

      // 可直接发送byte流,即byte数组
      // byte[] data = IOUtils.getFileData(path);
      // rasrClient.sendByte(data);
      // rasrClient.sendByte(data, byteLen, sleepTime);

      // 发送结尾请求
      rasrClient.sendEnd();

      // 6. 关闭客户端。发送完毕后，此步一定要实施，否则服务端因为20s没有接受任何消息而报异常。
      rasrClient.close();

    } catch (Exception e) {
      e.printStackTrace();
    }

  }

  public static void main(String[] args) {
    RasrDemo rasrDemo = new RasrDemo();
    rasrDemo.process();
  }
}
