• Công Nghệ
  • Toplist
  • Blog

VTCC - Blog Công Nghệ Mới Nhất

Nhận Dạng Tiếng Nói ⚡ API STT – Speech To Text

31/07/2022 by Viettel Cyberspace Center

5 Best Speech-to-Text APIs | Nordic APIs |

Restful API

REST api được dùng để nhận dạng 1 file hoàn chỉnh & nhận về kết quả nhận dạng cuối cùng.

Hiện tại API hỗ trợ 3 định dạng file audio: wav, mp3, PCM (phải gửi kèm thông tin audio trong request), sử dụng giao thức http POST với các thông tin như sau:

  • API URL: https://viettelgroup.ai/voice/api/asr/v1/rest/decode_file
  • Các tùy chọn cho request được chỉ định trong HEADER như sau:'token': (string) token dùng để xác thực người dùng. Bỏ trống nếu bạn muốn request nặc danh.
  • Các tùy chọn cho request được chỉ định trong url parameter như sau:'model': (string) mã mô hình nhận dạng.Với định dạng PCM, client phải cung cấp đủ các thông tin về audio trong header như sau:
    'sample_rate': (float) sample rate (tần số lấy mẫu) của file audio.
    'format': (string) format của audio ví dụ S16LE là *signed 16 bit little endian* (tham khảo PCM format: https://trac.ffmpeg.org/wiki/audio%20types)
    'num_of_channels': (integer) số channel của audio.
  • Request: multipart upload file với thông tin:'name'='file', 'filename'=$FILE_PATH

CURL

curl  --request POST --cacert $CERT_FILE  -H "token: $YOUR_TOKEN"  -F "file=@$PATH_TO_FILE"  https://viettelgroup.ai/voice/api/asr/v1/rest/decode_file

Trong đó:

- CERT_FILE: đường dẫn đến file chứng chỉ của https://viettelgroup.ai (Nếu CURL của bạn đã cập nhật chứng chỉ này thì có thể bỏ qua).

- PATH_TO_FILE: đường dẫn đến file cần nhận dạng.

Nếu muốn nhận dạng file PCM, bạn phải cung cấp thêm các thông tin cần thiết vào Header như sau:

`-H "sample_rate:$SAMPLE_RATE" -H "format:$FORMAT" -H "num_of_channels:$CHANNELS"`

Trong đó:

- SAMPLE_RATE: sample rate (tần số lấy mẫu) của file audio.
- FORMAT: format của audio ví dụ S16LE là *signed 16 bit little endian* (tham khảo https://trac.ffmpeg.org/wiki/audio%20types)
- CHANNELS: số channel của audio

PYTHON

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Import the json library
import requests

url = "https://viettelgroup.ai/voice/api/asr/v1/rest/decode_file"
headers = {
    'token': 'anonymous',
    #'sample_rate': 16000,
    #'format':'S16LE',
    #'num_of_channels':1,
    #'asr_model': 'model code'
}
s = requests.Session()
files = {'file': open($AUDIO_PATH,'rb')}
response = requests.post(url,files=files, headers=headers, verify=$CERT_PATH)

print(response.text)

Trong đó:

  • AUDIO_PATH: đường dẫn file audio muốn nhận dạng
  • CERT_PATH: đường dẫn tới file chứng chỉ của viettelgroup.ai : cert file
Khám Phá Thêm:   Xử Lý Ngôn Ngữ Tự Nhiên ⚡ API NLP

WebSocket API

API WebSocket hỗ trợ nhận dạng online. Do không có thông tin về audio nên bạn cần cung cấp thông tin này tới API thông qua uri query string:

content-type=audio/x-raw,+layout=(string)interleaved,+rate=(int)16000,+format=(string)S16LE,+channels=(int)1

Trong đó:

Field Mô tả
content-type trường lưu trữ thông tin của audio, các tham số dưới đây được lưu trong trường này
rate sample rate của audio
format định dạng PCM của audio. Tham khảo: PCM format
channel số kênh của audio

Để sử dụng API với account của riêng mình, bạn cần thêm thông tin token của mình thông qua trường ‘token’ trong uri query string: token=$YOUR_TOKEN

Để nhận dạng sử dụng API WebSocket, bạn cần:


  1. Tạo kết nối WebSocket tới API với các thông tin cần thiết đã nêu ở trên.
  2. Gửi data là mảng byte của luồng audio cần nhận dạng với tần suất 4 lần/giây, mỗi lần gửi với số byte = (byte rate của audio)/4. Ví dụ Audio có rate =16000, format S16LE (16bit <=> 2 byte/sample) có byte rate = 16000*2 = 32000 => Mỗi cần lần gửi lên 8000 byte.
  3. Khi kết thúc audio, client nên gửi lên byte của string ‘EOS’ encode UTF-8 để server biết & kết thúc nhận dạng. Hoặc server nhận dạng sẽ tự kết thúc nhận dạng sau một khoảng thời gian ngắn sau khi giọng nói cuối cùng được gửi lên.
  4. Đóng kết nối tới API. Kết thúc.

!!! notice “Lưu ý” Do một số client chưa được cập nhật chứng chỉ của https://viettelgroup.ai, để có thể sử dụng được kết nối bảo mật.

Khám Phá Thêm:   Nhận Dạng Ký Tự Quang Học ⚡ API OCR – Optical Character Recognition

PYTHON

Có thể sử dụng file chứng chỉ trực tiếp trong code, xem toàn bộ code tại đây: Speech to text WebSocket

JAVA

Bạn cần import chứng chỉ vào truststore thông qua công cụ keytool đi kèm với Java

$JAVA_HOME/bin/keytool -import -file $VTCC_CERT -alias wwwvtccai -keystore $JAVA_HOME/jre/lib/security/cacerts

Trong đó:

    - JAVA_HOME: thư mục JDK trên máy client.
    - VTCC_CERT: Đường dẫn đến file chứng chỉ của https://viettelgroup.ai
    - $JAVA_HOME/jre/lib/security/cacerts: Vị trí file lưu trữ truststore mặc định của Java

Nếu yêu cầu mật khẩu, vui lòng nhập vào: ‘changeit‘

Do chứng chỉ sẽ được import vào TrustStore mặc định của JAVA nên bạn chỉ cần import 1 lần duy nhất.

Xem ví dụ đầy đủ tại đây: VTCC Asr WebSocketSample

Sample code:


    #!/usr/bin/env python3
# -*- coding: utf-8 -*-
import logging
import os.path
import sys
import time
from pathlib import Path
from threading import Thread

import websocket

if sys.version_info[0] < 3:
    raise Exception("Must be using Python 3.xx")
root = logging.getLogger()
root.setLevel(logging.DEBUG)

handler = logging.StreamHandler(sys.stdout)
handler.setLevel(logging.DEBUG)
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
handler.setFormatter(formatter)
root.addHandler(handler)

dirname = os.path.dirname(__file__)
audio_path = os.path.join(Path(dirname).parent, 'test_audio.wav')
cert_path = os.path.join(Path(dirname).parent.parent, 'vtcc-cert/wwwvtccai.crt')

def rate_limited(max_per_second):
    min_interval = 1.0 / float(max_per_second)

    def decorate(func):
        last_time_called = [0.0]

        def rate_limited_function(*args, **kargs):
            elapsed = time.clock() - last_time_called[0]
            left_to_wait = min_interval - elapsed
            if left_to_wait > 0:
                time.sleep(left_to_wait)
            ret = func(*args, **kargs)
            last_time_called[0] = time.clock()
            return ret

        return rate_limited_function

    return decorate

@rate_limited(4)
def send_data(ws, data):
    ws.send(data)

def on_message(ws, message):
    print(message)

def on_error(ws, error):
    logging.warn(error)

def on_close(ws):
    logging.info("### closed ###")
    ws.close()

class AsrWebSocket:
    def __init__(self, sample_rate=16000, audio_format='S16LE', channels=1, token='anonymous',
                 url='wss://viettelgroup.ai/voice/api/asr/v1/ws/decode_online'):
        self.sample_rate = sample_rate
        self.format = audio_format
        self.channels = channels
        self.token = token
        self.url = url
        self.audio_stream = None
        self.ws = None
        self.sslopt = {
            'ca_certs': cert_path
        }

    def generate_url_query(self):
        query_url = self.url + '?content-type=audio/x-raw,+layout=(string)interleaved,+rate=(int)' + str(
            self.sample_rate)
        query_url += ',+format=(string)' + self.format + ',+channels=(int)' + str(self.channels) + '&token=' + self.token
        return query_url

    def on_open(self):
        def run():
            for block in iter(lambda: self.audio_stream.read(self.sample_rate // 4), b''):
                send_data(self.ws, block)
            self.ws.send('EOS')

        logging.info('Upload thread terminated')
        my_thread = Thread(target=run)
        my_thread.start()

    def recognize(self, audio_steam):
        self.audio_stream = audio_steam
        self.ws = websocket.WebSocketApp(self.generate_url_query(),
                                         on_message=on_message,
                                         on_error=on_error,
                                         on_close=on_close,
                                         on_open=self.on_open)
        self.ws.run_forever(sslopt=self.sslopt)

ws_asr = AsrWebSocket()
ws_asr.recognize(open(audio_path, 'rb'))
package speech.asr.ws;

import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketFrame;
import speech.asr.utils.PCMFormat;

import java.io.BufferedInputStream;
import java.nio.file.Files;
import java.nio.file.Paths;

public class AsrWebSocketSample {

    public static void main(String[] args) throws Exception {
        IResponseHandler<WebSocketFrame> handler = new IResponseHandler<WebSocketFrame>() {
            @Override
            public void onMessage(WebSocketFrame frame) {
                if (frame instanceof TextWebSocketFrame) {
                    TextWebSocketFrame textFrame = (TextWebSocketFrame) frame;
                    System.out.println(textFrame.text());
                } else
                    System.out.println(frame);
            }

            @Override
            public void onFailure(Throwable cause) {
                cause.printStackTrace();
            }

            @Override
            public void onComplete() {
                System.err.println("completed");
            }
        };
        try (
                BufferedInputStream bi = new BufferedInputStream(Files.newInputStream(Paths.get("src/main/resources/test_audio.wav")))
        ) {
            AsrWebSocketClient client = AsrWebSocketClient.newBuilder()
                    .setSampleRate(16000)
                    .setAudioFormat(PCMFormat.S16LE)
                    .setChannels(1)
                    .setHandler(handler)
                    .build();
            client.recognize(bi);
        }
    }
}

Filed Under: Tài Liệu Kỹ Thuật

Copyright © 2025 · VTCC - Cổng Thông Tin Công Nghệ Mới Nhất https://shbet.vision/