Skip to main content

即時語音辨識概述

即時語音辨識 API 允許您將音訊串流即時傳送到「聽有 AI」服務,並接收即時的辨識結果。這項功能特別適用於客服系統、會議記錄、即時字幕等需要低延遲回應的應用場景。

核心優勢

超低延遲

< 200ms 的回應時間,提供流暢的即時體驗

串流處理

支援連續音訊串流,無需等待完整音檔

中間結果

提供即時的中間辨識結果,提升使用者體驗

自動斷句

智能偵測語音停頓,自動分段處理

WebSocket 連線

即時語音辨識使用 WebSocket 協定進行雙向通訊:

連線端點

wss://api.skiesoft.com/asr

連線參數

參數類型必填說明
api_keystringAPI 金鑰

基本連線範例

const WebSocket = require('ws');
const fs = require('fs');

const SERVER_URL = 'wss://api.skiesoft.com/asr';
const WEBM_FILE_PATH = 'input.webm';
const API_TOKEN = 'your-api-token-here';

const ws = new WebSocket(SERVER_URL, {
    headers: { 'Authorization': `Bearer ${API_TOKEN}` }
});

ws.on('open', async () => {
    console.log('連接成功');

    const fileStream = fs.createReadStream(WEBM_FILE_PATH);

    fileStream.on('data', (data) => {
        ws.send(data);
    });

    fileStream.on('end', () => {
        ws.send(Buffer.alloc(0)); // 發送空 buffer 表示結束
        console.log('文件發送完成');
    });
});

ws.on('message', (message) => {
    const data = JSON.parse(message.toString());
    console.log('收到訊息:', data);
    if (data.type === 'ready_to_stop') {
        ws.close();
    }
});

使用 SDK 進行即時辨識

Node.js SDK

const { SkiesoftVoice } = require('@skiesoft/voice-sdk');

const client = new SkiesoftVoice({
  apiKey: process.env.SKIESOFT_API_KEY,
  projectId: process.env.SKIESOFT_PROJECT_ID
});

// 建立即時串流
const stream = client.createRealTimeStream({
  language: 'mixed',
  sampleRate: 16000,
  encoding: 'LINEAR16',
  interimResults: true,
  enableAutomaticPunctuation: true
});

// 監聽辨識結果
stream.on('data', (result) => {
  if (result.isFinal) {
    console.log('最終結果:', result.transcript);
    console.log('信心度:', result.confidence);
  } else {
    console.log('中間結果:', result.transcript);
  }
});

// 監聽錯誤
stream.on('error', (error) => {
  console.error('辨識錯誤:', error);
});

// 監聽連線狀態
stream.on('connect', () => {
  console.log('即時辨識已連線');
});

stream.on('disconnect', () => {
  console.log('即時辨識已斷線');
});

發送音訊資料

// 從麥克風獲取音訊
const mic = require('mic');

const micInstance = mic({
  rate: '16000',
  channels: '1',
  debug: false,
  exitOnSilence: 6
});

const micInputStream = micInstance.getAudioStream();

micInputStream.on('data', (data) => {
  // 發送音訊資料到即時辨識串流
  stream.write(data);
});

// 開始錄音
micInstance.start();

進階配置

完整配置選項

const stream = client.createRealTimeStream({
  // 基本設定
  language: 'mixed',           // 語言設定
  sampleRate: 16000,          // 採樣率
  encoding: 'LINEAR16',       // 編碼格式
  // 辨識設定
  interimResults: true,       // 顯示中間結果
  enableAutomaticPunctuation: true,  // 自動標點符號
  enableWordTimeOffsets: true,       // 詞彙時間軸
  enableWordConfidence: true,        // 詞彙信心度
  
  // 進階功能
  enableSpeakerDiarization: true,    // 說話者分離
  maxSpeakers: 2,                    // 最大說話者數
  enableVoiceActivityDetection: true, // 語音活動偵測
  model: 'general',
});

語音活動偵測

自動偵測語音開始和結束:
stream.on('speechStart', () => {
  console.log('偵測到語音開始');
});

stream.on('speechEnd', () => {
  console.log('語音結束');
});

stream.on('silence', (duration) => {
  console.log(`靜音持續 ${duration}ms`);
});

結果處理

結果格式

{
  "type": "result",
  "result": {
    "transcript": "你好,歡迎使用聽有 AI",
    "confidence": 0.95,
    "isFinal": true,
    "startTime": 1.2,
    "endTime": 3.8,
    "language": "zh-TW",
    "words": [
      {
        "text": "你好",
        "startTime": 1.2,
        "endTime": 1.8,
        "confidence": 0.98
      },
      {
        "text": "歡迎",
        "startTime": 2.0,
        "endTime": 2.4,
        "confidence": 0.96
      }
    ],
    "speaker": 1
  }
}

處理不同類型的結果

stream.on('data', (result) => {
  switch (result.type) {
    case 'interim':
      // 中間結果,可能會改變
      updateTranscriptPreview(result.transcript);
      break;
      
    case 'final':
      // 最終結果,不會再改變
      addFinalTranscript(result.transcript);
      break;
      
    case 'speaker_change':
      // 說話者切換
      console.log(`說話者切換至: ${result.speaker}`);
      break;
  }
});

實際應用範例

1. 即時會議記錄

class MeetingTranscriber {
  constructor() {
    this.stream = client.createRealTimeStream({
      language: 'mixed',
      enableSpeakerDiarization: true,
      maxSpeakers: 6,
      enableAutomaticPunctuation: true
    });
    
    this.transcript = [];
    this.setupEventHandlers();
  }
  
  setupEventHandlers() {
    this.stream.on('data', (result) => {
      if (result.isFinal) {
        this.transcript.push({
          speaker: result.speaker,
          text: result.transcript,
          timestamp: new Date(),
          confidence: result.confidence
        });
        
        this.updateUI();
      }
    });
  }
  
  startRecording() {
    // 開始錄音邏輯
    this.micInstance.start();
  }
  
  stopRecording() {
    this.micInstance.stop();
    this.stream.end();
  }
  
  exportTranscript() {
    return this.transcript.map(entry => 
      `[${entry.timestamp.toLocaleTimeString()}] 說話者 ${entry.speaker}: ${entry.text}`
    ).join('\n');
  }
}

3. 即時字幕系統

class LiveCaptionSystem {
  constructor(videoElement) {
    this.videoElement = videoElement;
    this.captionContainer = document.getElementById('captions');
    
    this.stream = client.createRealTimeStream({
      language: 'mixed',
      interimResults: true,
      enableAutomaticPunctuation: true
    });
    
    this.setupCaptions();
  }
  
  setupCaptions() {
    let currentCaption = '';
    
    this.stream.on('data', (result) => {
      if (result.isFinal) {
        // 顯示最終字幕
        this.addCaption(result.transcript);
        currentCaption = '';
      } else {
        // 更新暫時字幕
        currentCaption = result.transcript;
        this.updateTempCaption(currentCaption);
      }
    });
  }
  
  addCaption(text) {
    const captionElement = document.createElement('div');
    captionElement.className = 'caption-line';
    captionElement.textContent = text;
    
    this.captionContainer.appendChild(captionElement);
    
    // 自動滾動
    this.captionContainer.scrollTop = this.captionContainer.scrollHeight;
    
    // 清理舊字幕
    this.cleanupOldCaptions();
  }
  
  updateTempCaption(text) {
    let tempElement = this.captionContainer.querySelector('.temp-caption');
    if (!tempElement) {
      tempElement = document.createElement('div');
      tempElement.className = 'temp-caption';
      this.captionContainer.appendChild(tempElement);
    }
    tempElement.textContent = text;
  }
}

效能優化

音訊緩衝管理

class AudioBuffer {
  constructor(maxSize = 1024 * 1024) { // 1MB
    this.buffer = Buffer.alloc(0);
    this.maxSize = maxSize;
  }
  
  append(chunk) {
    this.buffer = Buffer.concat([this.buffer, chunk]);
    
    // 防止緩衝區過大
    if (this.buffer.length > this.maxSize) {
      this.buffer = this.buffer.slice(-this.maxSize);
    }
  }
  
  flush() {
    const data = this.buffer;
    this.buffer = Buffer.alloc(0);
    return data;
  }
}

連線重連機制

class ReliableRealTimeStream {
  constructor(config) {
    this.config = config;
    this.reconnectAttempts = 0;
    this.maxReconnectAttempts = 5;
    this.reconnectDelay = 1000;
    
    this.connect();
  }
  
  connect() {
    this.stream = client.createRealTimeStream(this.config);
    
    this.stream.on('error', (error) => {
      console.error('串流錯誤:', error);
      this.handleReconnect();
    });
    
    this.stream.on('disconnect', () => {
      console.log('連線中斷');
      this.handleReconnect();
    });
  }
  
  handleReconnect() {
    if (this.reconnectAttempts < this.maxReconnectAttempts) {
      this.reconnectAttempts++;
      
      setTimeout(() => {
        console.log(`重新連線嘗試 ${this.reconnectAttempts}`);
        this.connect();
      }, this.reconnectDelay * this.reconnectAttempts);
    } else {
      console.error('重連失敗,已達最大嘗試次數');
    }
  }
}

錯誤處理

常見錯誤類型

stream.on('error', (error) => {
  switch (error.code) {
    case 'CONNECTION_FAILED':
      console.error('連線失敗,請檢查網路狀態');
      break;
    case 'AUTHENTICATION_FAILED':
      console.error('身份驗證失敗,請檢查 API 金鑰');
      break;
    case 'QUOTA_EXCEEDED':
      console.error('配額已用完');
      break;
    case 'RATE_LIMIT_EXCEEDED':
      console.error('請求頻率過高');
      break;
    case 'AUDIO_FORMAT_ERROR':
      console.error('音訊格式錯誤');
      break;
    default:
      console.error('未知錯誤:', error.message);
  }
});

最佳實踐

1. 音訊品質

  • 使用 16kHz 採樣率以獲得最佳效果
  • 確保音訊為單聲道
  • 實作噪音抑制和回音消除

2. 網路優化

  • 實作連線重連機制
  • 監控網路延遲和丟包
  • 使用適當的緩衝區大小

3. 使用者體驗

  • 顯示連線狀態指示器
  • 提供中間結果預覽
  • 實作語音活動視覺化

4. 資源管理

  • 適時關閉不需要的串流
  • 監控記憶體使用量
  • 實作音訊資料壓縮

需要即時語音辨識技術支援?請聯絡我們:support@skiesoft.com