
# 实时语音识别单句模式
#### 功能介绍
单句模式自动检测一句话的结束，因此适合于需要与您的系统进行交互的场景，例如外呼、控制口令等场景。
实时语音识别引擎的单句识别模式，和连续识别模式类似，也会进行语音的端点检测，如果检测到静音，将直接丢弃，检测到语音才会馈入核心进行实际的解码工作，如果检测到一段语音的结束点，就会将当前这一段的识别结果返回。和连续识别不同的是，在单句模式下，返回第一段的识别结果后，将不再继续识别后续的音频。这主要是用于和用户进行语音交互的场景下，当用户说完一句话后，往往会等待后续的交互操作，例如聆听根据识别结果播报的相关内容，因而没有必要继续识别后续的音频。
#### wss-URI
- wss-URI格式： wss /v1/{project_id}/rasr/sentence-stream
  
- 参数说明
  表1参数说明 
  | 参数名        | 是否必选 | 说明                                                                               |
  |:---|:---|:---|
  | project_id | 是    | 项目编号。获取方法，请参见[获取项目ID](https://support.huaweicloud.com/api-sis/sis_03_0008.html)。 |
     
  表2请求Header参数 
  | 参数                    | 是否必选 | 参数类型   | 描述                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
  |:---|:---|:---|:---|
  | X-Auth-Token          | 是    | String | 用户Token。 用于获取操作API的权限。获取方法请参见[认证鉴权](https://support.huaweicloud.com/api-sis/sis_03_0058.html)。响应消息头中X-Subject-Token的值即为Token。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
  | Enterprise-Project-Id | 否    | String | 企业项目ID。SIS支持通过企业项目管理（EPS）对不同用户组和用户的资源使用，进行分账。 获取方法：进入"[企业项目管理](https://console.huaweicloud.com/eps/?#/eps/manager/projects)"页面，单击企业项目名称，在企业项目详情页获取Enterprise-Project-Id（企业项目ID）。 ![](https://support.huaweicloud.com/api-sis/zh-cn_image_0000001902254261.png "点击放大") 企业项目创建步骤请参见用户指南。 说明： 账户创建企业项目后，在传参时，有以下三类场景。 - 携带正确的ID，正常使用SIS服务，账单归到企业ID对应的企业项目中。  - 携带错误的ID，正常使用SIS服务，账单的企业项目会被分类为"default"。  - 不携带ID，正常使用SIS服务，账单的企业项目会被分类为"default"。   |
     
  
- 请求示例（伪码）
  ```
  wss://{endpoint}/v1/{project_id}/rasr/sentence-stream
  Request Header:
  X-Auth-Token: MIINRwYJKoZIhvcNAQcCoIINODCCDTQCAQExDTALBglghkgBZQMEAgEwgguVBgkqhkiG...
  ```
  ![](https://support.huaweicloud.com/api-sis/public_sys-resources/note_3.0-zh-cn.png)
  "endpoint"即调用API的请求地址，不同接口不同区域的"endpoint"不同，具体请参见[终端节点](https://support.huaweicloud.com/api-sis/sis_03_0004.html)。
  
- Python3语言请求代码示例
  ```
  # -*- coding: utf-8 -*-
  # 此demo仅供测试使用，强烈建议使用sdk。需提前安装websocket_client, 执行pip install websocket_client
  import websocket
  import threading
  import time
  import json
  def rasr_demo():
      url = 'wss://{{endpoint}}/v1/{{project_id}}/rasr/sentence-stream'  # endpoint和project_id需替换
      audio_path = '音频路径'
      token = '用户对应region的token'
      header = {
          'X-Auth-Token': token
      }
      with open(audio_path, 'rb') as f:
          data = f.read()
      body = {
          'command': 'START',
          'config': {
              'audio_format': 'pcm8k16bit',
              'property': 'chinese_8k_general'
          }
      }
      def _on_message(ws, message):
          print(message)
      def _on_error(ws, error):
          print(error)
      ws = websocket.WebSocketApp(url, header, on_message=_on_message, on_error=_on_error)
      _thread = threading.Thread(target=ws.run_forever, args=(None, None, 30, 20))
      _thread.start()
      time.sleep(1)
      ws.send(json.dumps(body), opcode=websocket.ABNF.OPCODE_TEXT)
      now_index = 0
      byte_len = 4000
      while now_index < len(data):
          next_index = now_index + byte_len
          if next_index > len(data):
              next_index = len(data)
          send_array = data[now_index: next_index]
          ws.send(send_array, opcode=websocket.ABNF.OPCODE_BINARY)
          now_index += byte_len
          time.sleep(0.05)
      ws.send("{\"command\": \"END\", \"cancel\": \"false\"}", opcode=websocket.ABNF.OPCODE_TEXT)
      time.sleep(10)
      ws.close()
  if __name__ == '__main__':
      rasr_demo()
  ```
  
- Java语言请求代码示例
  ```
  import okhttp3.OkHttpClient;
  import okhttp3.Request;
  import okhttp3.Response;
  import okhttp3.WebSocket;
  import okhttp3.WebSocketListener;
  import okio.ByteString;
  import java.net.URL;
  /**
   * 此demo仅供测试使用，强烈建议使用SDK
   * 使用前需已配置okhttp、okio jar包。jar包可通过下载SDK获取。
   */
  public class RasrDemo {
    public void rasrDemo() {
      try {
        // endpoint和projectId需要替换成实际信息。
        String url = "wss://{{endpoint}}/v1/{{project_id}}/rasr/sentence-stream";
        String token = "对应region的token";
        byte[] data = null;  // 存放将要发送音频的byte数组
        OkHttpClient okHttpClient = new OkHttpClient();
        Request request = new Request.Builder().url(url).header("X-Auth-Token", token).build();
        WebSocket webSocket = okHttpClient.newWebSocket(request, new MyListener());
        webSocket.send("{\"command\": \"START\", \"config\": {\"audio_format\": \"pcm8k16bit\", \"property\": \"chinese_8k_general\"}}");
        webSocket.send(ByteString.of(data));
        webSocket.send("{  \"command\": \"END\",  \"cancel\": false}");
        Thread.sleep(10000);
        webSocket.close(1000, null);
      } catch (Exception e) {
        e.printStackTrace();
      }
    }
    class MyListener extends WebSocketListener {
      @Override
      public void onOpen(WebSocket webSocket, Response response) {
        System.out.println("connected");
      }
      @Override
      public void onClosed(WebSocket webSocket, int code, String reason) {
        System.out.println("closed");
      }
      @Override
      public void onFailure(WebSocket webSocket, Throwable t, Response response) {
        t.printStackTrace();
      }
      @Override
      public void onMessage(WebSocket webSocket, String text) {
        System.out.println(text);
      }
    }
    public static void main(String[] args) {
      RasrDemo rasrDemo = new RasrDemo();
      rasrDemo.rasrDemo();
    }
  }
  ```
  
- JavaScript（nodejs推荐使用v18.20.2 (LTS)版本）
  ```
  // 导入 Node.js 的 ws 库
  const WebSocket = require('ws');
  function sentenceStreamDemo(endpoint,audioPath, projectID, token) {
      const url = `wss://${endpoint}/v1/${projectID}/rasr/sentence-stream`;  // 替换 endpoint 和 projectID
      // 读取音频文件内容
      const fs = require('fs');
      let data = fs.readFileSync(audioPath);
      // HTTP Headers中携带Token
      const headers = {
          'X-Auth-Token': token,
          //  企业id 可选加
          // 'Enterprise-Project-Id': 企业id
      };
      // 创建WebSocket实例
      const ws = new WebSocket(url, {
          headers // 添加自定义HTTP头
      });
      ws.on('open', async () => {
          const body = {
              command: 'START',
              config: {
                  audio_format: 'pcm16k16bit',
                  property: 'chinese_16k_general'
              }
          };
          ws.send(JSON.stringify(body));
          let nowIndex = 0;
          const byteLen = 3200; // 禁止空值输入 建议范围 2000-10000
          while (nowIndex < data.length) {
              const nextIndex = nowIndex + byteLen;
              const sendArray = data.slice(nowIndex, nextIndex > data.length ? data.length : nextIndex);
              ws.send(sendArray, { binary: true });
              nowIndex += byteLen;
              await new Promise(resolve => setTimeout(resolve, 100)); // 模拟延时(单位ms)
          }
          const endCommand = JSON.stringify({ command: 'END', cancel: 'false' });
          ws.send(endCommand);
      });
      ws.on('message', (data) => {
          if (data instanceof Buffer) {
              // 将Buffer转换为UTF-8编码的字符串
              const messageString = data.toString('utf8');
              console.log('Received (converted from Buffer):', messageString);
              const type = JSON.parse(messageString).resp_type;
              if (type ==='END'|| type ==='ERROR') {
                  ws.close();
              }
          }
      });
      ws.on('error', (error) => {
          console.error('WebSocket Error:', error);
      });
  };
  sentenceStreamDemo(endpoint,audioPath, projectID, token);
  ```
  
 
