Проблемы WebSocket с IBM Watson

Это так неприятно. Я хочу создать простое приложение для преобразования речи в текст, но у меня проблемы с подключением. Я могу получить токен, но что-то не так, вот экраны: ошибка рукопожатия, https://i.stack.imgur.com/uJt0E.png. Сначала я попытался подписаться на этого парня с YouTube, но его код не работал. Затем я попытался подписаться на документы, watson-speech npm и ibm-watson npm, но теперь я застрял.

Я получаю токен, но дальше не могу, я использую server.js и App.js для достижения этой цели, и вот код:

server.js

'use strict';

const express = require('express');
const app = express();
const vcapServices = require('vcap_services');
const cors = require('cors');

const { IamTokenManager } = require('ibm-watson/auth');

if (process.env.VCAP_SERVICES) {

  // enable rate-limiting
  const RateLimit = require('express-rate-limit');
  app.enable('trust proxy'); // required to work properly behind Bluemix's reverse proxy

  const limiter = new RateLimit({
    windowMs: 30000, // 0.5 minute
    max: 100 // limit each IP to 100 requests per windowMs
  });

  //  apply to /api/*
  app.use('/api/', limiter);
  const secure = require('express-secure-only');
  app.use(secure());
}

// app.use(express.static(__dirname + '/static'));
app.use(cors())

const sttAuthenticator = new IamTokenManager(
  {
     apikey: 'knkk_???_XjW7C9p4DUxlk6p1B9-rez8gJykyh-rYm'
  }
);

// speech to text token endpoint
app.use('/api/speech-to-text/token', function(req, res) {
  return sttAuthenticator
    .requestToken()
    .then(({ result }) => {
      res.json({ accessToken: result.access_token, url: 'https://stream.watsonplatform.net/speech-to-text/knkk_???_XjW7C9p4DUxlk6p1B9-rez8gJykyh-rYm' });
    })
    .catch(console.error);
});

const port = process.env.PORT || process.env.VCAP_APP_PORT || 3002;
app.listen(port, function() {
  console.log('Example IBM Watson Speech JS SDK client app & token server live at http://localhost:%s/', port);
});

// Chrome requires https to access the user's microphone unless it's a localhost url so
// this sets up a basic server on port 3001 using an included self-signed certificate
// note: this is not suitable for production use
// however bluemix automatically adds https support at https://<myapp>.mybluemix.net

if (!process.env.VCAP_SERVICES) {
  const fs = require('fs');
  const https = require('https');
  const HTTPS_PORT = 3001;

  const options = {
    key: fs.readFileSync(__dirname + '/keys/localhost.pem'),
    cert: fs.readFileSync(__dirname + '/keys/localhost.cert')
  };
  https.createServer(options, app).listen(HTTPS_PORT, function() {
    console.log('Secure server live at https://localhost:%s/', HTTPS_PORT);
  });
}

App.js

import React, { Component } from 'react';
import './App.css';

import recognizeMic from 'watson-speech/speech-to-text/recognize-microphone';
import WatsonSpeech from 'watson-speech/dist/watson-speech';

class App extends Component {

  constructor() {
    super()
    this.state = {

    }
  }

  onListenClick() {
    fetch('http://localhost:3002/api/speech-to-text/token')
      .then(function(response) {
          return response.text();
      }).then((token) => {
        console.log('token is', token)
        var stream = recognizeMic({
            token: token,
            objectMode: true, // send objects instead of text
            extractResults: true, // convert {results: [{alternatives:[...]}], result_index: 0} to {alternatives: [...], index: 0}
            format: false // optional - performs basic formatting on the results such as capitals an periods
        });
        stream.on('data', (data) => {
          this.setState({
            text: data.alternatives[0].transcript
          })
        });
        stream.on('error', function(err) {
            console.log(err);
        });
        document.querySelector('#stop').onclick = stream.stop.bind(stream);
      }).catch(function(error) {
          console.log(error);
      });
  }
  render() {
    return (
      <div className="App">
        <button onClick={this.onListenClick.bind(this)}>Start</button>
        <div style={{fontSize: '40px'}}>{this.state.text}</div>

      </div>
    );
  }
}

export default App;

и я получаю ошибку рукопожатия, когда меняю переменную потока на это:

var stream = WatsonSpeech.SpeechToText.recognizeMicrophone(Object.assign(token, {
          objectMode: true, // send objects instead of text
          format: false // optional - performs basic formatting on the results such as capitals an periods
      })

После перехода на IamAuthenticator и использования справки по API я все еще не могу использовать его в терминале. Тем временем я попробовал преобразовать речь Google в текст, и он работает: слева Google, справа ibm.

Вы видите ошибки в моем коде?

'use strict';

// Node-Record-lpcm16
const recorder = require('node-record-lpcm16');

const SpeechToTextV1 = require('ibm-watson/speech-to-text/v1');
const { IamAuthenticator } = require('ibm-watson/auth');

const speechToText = new SpeechToTextV1({
  authenticator: new IamAuthenticator({
    apikey: 'knkk_O4nfg_XjW7C9p4DUxlk6p1B9-rez8gJykyh-rYm',
  }),
  url: 'https://api.eu-gb.speech-to-text.watson.cloud.ibm.com/instances/c7572958-6b9c-4215-943f-7ff935bb0037',
});

const params = {
  objectMode: true,
  contentType: 'audio/flac',
  model: 'en-US_BroadbandModel',
  keywords: ['turn on', 'turn off', 'on', 'off'],
  keywordsThreshold: 0.5,
  maxAlternatives: 3,
  headers: 'chunked'
};

// Create the stream.
const recognizeStream = speechToText.recognizeUsingWebSocket(params);

// Listen for events.
recognizeStream.on('data', function(event) { onEvent('Data:', event); });
recognizeStream.on('error', function(event) { onEvent('Error:', event); });
recognizeStream.on('close', function(event) { onEvent('Close:', event); });

// Display events on the console.
function onEvent(name, event) {
    console.log(name, JSON.stringify(event, null, 2));
};

// Start recording and send the microphone input to the Speech API
recorder
.record({
    sampleRateHertz: 16000,
    threshold: 0, //silence threshold
    recordProgram: 'rec', // Try also "arecord" or "sox"
    silence: '5.0', //seconds of silence before ending
})
.stream()
.on('error', console.error)
.pipe(recognizeStream);

person humble_button    schedule 27.01.2020    source источник


Ответы (2)


Поддержка параметра токена была удалена в версии 5. Используйте IamAuthenticator.

Взгляните на MIGRATION doc и Справочник по API пример

person Allen Dean    schedule 28.01.2020
comment
Спасибо, я реализовал изменение, но все же что-то не так, так как я не получаю результатов в консоли, я отредактировал свой пост с новым кодом, который очень похож на тот, который я успешно использовал с Google API, может вы посмотрите на это? - person humble_button; 29.01.2020
comment
Извините, что изменение не устранило общую проблему. Более конкретных решений вашей проблемы, к сожалению, предложить не могу. Кстати, если это настоящий ключ API, который вы опубликовали, вы должны удалить его и создать другой набор учетных данных. - person Allen Dean; 30.01.2020

Ваш код по большей части выглядит нормально, поэтому вы должны быть очень близки к тому, чтобы заставить его работать.

Ваш первый опубликованный пример выглядит так, как будто он должен работать с одним исключением - вам нужно использовать параметр accessToken, а не параметр token:

var stream = recognizeMic({
        accessToken: token,
        objectMode: true, // send objects instead of text
        extractResults: true, // convert {results: [{alternatives:[...]}], result_index: 0} to {alternatives: [...], index: 0}
        format: false // optional - performs basic formatting on the results such as capitals an periods
    });

Вы можете использовать Token Manager как есть (хотя в конечном итоге он будет устаревшим в пользу Authenticators).

Что касается вашего последнего примера, кода на стороне сервера, все выглядит хорошо. Вы можете столкнуться с проблемами в том, что код остановки никогда не отправляется на сервер, чтобы инициировать отправку ответа. Попробуйте передать ему параметр interimResults: true. Если вы получаете данные, как ожидалось, то это ваша проблема. Чтобы исправить это, добавьте в код обработчик завершения, как показано в этот пример.

person dpopp07    schedule 30.01.2020