Задать вопрос
@Seldom7

Как реализовать потоковое распознавание речи с помощью Yandex SpeechKit? Выходит ошибка gRPC Error: Error: 12 UNIMPLEMENTED?

Доброго времени суток!
При разработке веб-сайта мне понадобилась функция потоковой распознавания речи. Хочу использовать Yandex speechKit для распознавания русской речи.
На фронте использую реакт, для записи голоса использую react-mic.
На бэке использую node.js + express.js

Я так понял, что для потоковой распознавания речи нужны вебсокеты. Хоть я и не силен в этой технологии, но кое-как я реализовал соединение с сервером, но все же был бы признателен за более правильную реализацию отправки маленьких 0,5 секундных кусочков аудио на сервер) (но это второстепенная проблема)
вот моя реализация:
import React, { useState, useEffect } from 'react';
import { ReactMic } from 'react-mic';
import io from 'socket.io-client';

const AudioRecorder = () => {
  const [record, setRecord] = useState(false);
  const [socket, setSocket] = useState(null);
  const [transcript, setTranscript] = useState('');

  useEffect(() => {
    if (socket) {
      socket.on('recognitionResult', (data) => {
        setTranscript((prev) => `${prev} ${data.alternatives[0].text}`);
      });

      socket.on('partialResult', (data) => {
        console.log('Partial result:', data);
      });

      socket.on('recognitionError', (error) => {
        console.error(error);
      });
    }

    return () => {
      if (socket) {
        socket.off('recognitionResult');
        socket.off('partialResult');
        socket.off('recognitionError');
      }
    };
  }, [socket]);

  const startRecording = () => {
    const socketInstance = io('http://localhost:3000');
    setSocket(socketInstance);
    setRecord(true);
    setTranscript(''); // Clear transcript when starting a new recording
  };

  const stopRecording = () => {
    setRecord(false);
    if (socket) {
      console.log('Emitting endAudioStream');
      socket.emit('endAudioStream');
      socket.disconnect();
    }
  };

  const onData = (recordedChunk) => {
    if (socket) {
      socket.emit('audioStream', recordedChunk);
    }
  };

  return (
    <div>
      <ReactMic
        record={record}
        className="sound-wave"
        onStop={stopRecording}
        onData={onData}
        mimeType="audio/webm"
        strokeColor="#000000"
        backgroundColor="#FF4081"
      />
      <button onClick={startRecording} type="button">Start</button>
      <button onClick={stopRecording} type="button">Stop</button>
      <div>
        <h3>Transcript:</h3>
        <p>{transcript}</p>
      </div>
    </div>
  );
};

export default AudioRecorder;


Главная проблема на сервере:
Я почитал документацию яндекса о потоковом распознавании, но к сожалению не нашел ничего дельного, может быть что-то проглядел...
Можете пожалуйста написать скрипт на node.js + express, который бы принимал эти чанки аудио и корректно отправлял бы их на сервера яндекса для обработки, чтобы когда пользователь закончил свое аудио, мы с максимум задержкой 1-2 секунды уже имели полное текстовое содержание его речи на сервере.

Отправлять распознанный текст на фронт не надо, просто его собирать и по окончанию сделать запрос на chatGPT (с chatGPT я уже написал код)

Код сервера на данный момент, который выводит ошибку gRPC Error: Error: 12 UNIMPLEMENTED:
const express = require('express');
const http = require('http');
const socketIo = require('socket.io');
const grpc = require('@grpc/grpc-js');
const protoLoader = require('@grpc/proto-loader');
const { Transform } = require('stream');
const cors = require('cors');

const PROTO_PATH = './recognizer.proto';
const packageDefinition = protoLoader.loadSync(PROTO_PATH, {
  keepCase: true,
  longs: String,
  enums: String,
  defaults: true,
  oneofs: true
});
const recognizerProto = grpc.loadPackageDefinition(packageDefinition).yandex.cloud.ai.stt.v3;

const app = express();
const server = http.createServer(app);
const io = socketIo(server, {
  cors: {
    origin: "http://localhost:5173",
    methods: ["GET", "POST"]
  }
});

app.use(cors());

io.on('connection', (socket) => {
  console.log('New client connected');

  const client = new recognizerProto.Recognizer('stt.api.cloud.yandex.net:443', grpc.credentials.createSsl());

  const metadata = new grpc.Metadata();
  metadata.add('authorization', 'Api-Key ЗДЕСЬ МОЙ API КЛЮЧ');

  const call = client.RecognizeStreaming(metadata);
  call.on('data', (response) => {
    console.log('Response received:', response);
    if (response.event === 'partial') {
      socket.emit('partialResult', response.partial);
    } else if (response.event === 'final') {
      socket.emit('recognitionResult', response.final);
    }
  });

  call.on('error', (error) => {
    console.error('gRPC Error:', error);
    socket.emit('recognitionError', error.message);
  });

  call.on('end', () => {
    console.log('Stream ended');
  });

  // Sending initial session options
  call.write({
    session_options: {
      recognition_model: {
        model: 'general',
        audio_format: {
          container_audio: {
            container_audio_type: 'OGG_OPUS'
          }
        },
        text_normalization: {
          text_normalization: 'TEXT_NORMALIZATION_ENABLED'
        },
        language_restriction: {
          restriction_type: 'WHITELIST',
          language_code: ['ru-RU']
        },
        audio_processing_type: 'REAL_TIME'
      }
    }
  });

  const audioTransform = new Transform({
    transform(chunk, encoding, callback) {
      call.write({ chunk: { data: chunk } });
      callback();
    }
  });

  socket.on('audioStream', (chunk) => {
    audioTransform.write(Buffer.from(chunk));
  });

  socket.on('endAudioStream', () => {
    console.log('audio stream end');
    audioTransform.end();
    call.end();
  });

  socket.on('disconnect', () => {
    console.log('Client disconnected');
    audioTransform.end();
    call.end();
  });
});

const port = 3000;
server.listen(port, () => {
  console.log(`Server is running on http://localhost:${port}`);
});


P.S. сижу уже с этой задачей неделю, никак не могу решить. ChatGPT гоняет одну и ту же ошибку. Заранее спасибо за помощь!
  • Вопрос задан
  • 171 просмотр
Подписаться 1 Средний Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы