wit-ai / wit

Natural Language Interface for apps and devices
https://wit.ai/
941 stars 91 forks source link

Wit.ai Speech API weird issue: Unexpected token < in JSON at position 0 #1466

Closed solyarisoftware closed 4 years ago

solyarisoftware commented 5 years ago

Hi guys

A strange issue just crashed my application when using Wit.ai speech API request.

BTW, I use a nodejs client using request module and:

 const BASEURL = 'https://api.wit.ai/speech'
 13 const VERSION = '20170307'

This the weird error:

it seems to me that JSON response payload ... contains HTML... :/ that broken the JSON.parse(...), see below stack error and my code (line 62)

undefined:1
<!DOCTYPE html>
^

SyntaxError: Unexpected token < in JSON at position 0
    at JSON.parse (<anonymous>)
    at Request._callback (/home/giorgio/cpiabot/lib/witSpeech.js:62:30)
    at Request.self.callback (/home/giorgio/cpiabot/node_modules/request/request.js:185:22)
    at Request.emit (events.js:200:13)
    at Request.<anonymous> (/home/giorgio/cpiabot/node_modules/request/request.js:1161:10)
    at Request.emit (events.js:200:13)
    at IncomingMessage.<anonymous> (/home/giorgio/cpiabot/node_modules/request/request.js:1083:12)
    at Object.onceWrapper (events.js:288:20)
    at IncomingMessage.emit (events.js:205:15)
    at endReadableNT (_stream_readable.js:1137:12)
    at processTicksAndRejections (internal/process/task_queues.js:84:9)

 48 function witSpeech(fileName) {
 49   return new Promise((resolve, reject) => {
 50
 51     // load audio file to be uploaded
 52     options.body = fs.createReadStream(fileName)
 53
 54     const elapsedTime = new Elapsed()
 55
 56     request( url, options, (err, res, body) => {
 57
 58       if (err)
 59         reject(err)
 60
 61       else {
 62         const bodyObj = JSON.parse(body)
 63
 64         //debug
 65         console.log( fileName, bodyObj)
 66         console.info( `\nwit.ai elapsed (msec): ${elapsedTime.str()}\n` )
 67
 68         // { error: 'Timeout, please try again later', code: 'timeout' }
 69         if (bodyObj.error && bodyObj.code === 'timeout')
 70           reject('timeout')
 71         else {
 72           const text = bodyObj._text
 73           //console.info(`speech recognition   : ${text}\n`)
 74           resolve(text)
 75         }
 76       }
 77     })
 78   })
 79 }

Any idea ?

Thanks giorgio

aforaleka commented 5 years ago

Hi @solyarisoftware, I'm not familiar with the request module, can you show me the full body response? And instead of JSON.parse(body), I believe you can just do body._text to get the text.

solyarisoftware commented 5 years ago

Thanks for reply

request is a common nodejs HTTP request library: https://github.com/request/request

I can't show you the "gulty" body response because the program crashed before logging.

62         const bodyObj = JSON.parse(body)

Ok. I'll "try/catch" the issue with something like:

    try {
        const bodyObj = JSON.parse(body)   
   } 
   catch(e)  {
        console.errror(e)
    } 

But immo the problem is that the http response body was HTML instead of expected JSON like this:

{
  "_text" : "some text",
  "entities" : { },
  "msg_id" : "1UuY**********DpL"
}

looking forward your feedback/thanks again giorgio

aforaleka commented 5 years ago

Have you tried removing the JSON.parse part? JSON.parse() converts text into a JavaScript object and the response of the request is not a string.

solyarisoftware commented 5 years ago

HI @aforaleka

the issue happened again and I tracked it: see here below details.

Summary: instead of receiving a JSON payload in the HTTP response, I sometime get an HTML error page (NO-JSON?!)

    <div id="core">
      <h1 id="sorry">Sorry, something went wrong.</h1>
      <p id="promise">
        We're working on it and we'll get it fixed as soon as we can.
      </p>
      <p id="back-link">
        <a id="back" href="//www.facebook.com/">Go Back</a>
      </p>

That's immo a wit.ai server issue: even in case of error, API must return a JSON data type, instead ogf an HTML.

Looking forward your feedback Thanks giorgio

Full data:

witSpeech> SyntaxError: Unexpected token < in JSON at position 0
    at JSON.parse (<anonymous>)
    at Request._callback (/home/giorgio/cpiabot/lib/witSpeech.js:70:26)
    at Request.self.callback (/home/giorgio/cpiabot/node_modules/request/request.js:185:22)
    at Request.emit (events.js:200:13)
    at Request.<anonymous> (/home/giorgio/cpiabot/node_modules/request/request.js:1161:10)
    at Request.emit (events.js:200:13)
    at IncomingMessage.<anonymous> (/home/giorgio/cpiabot/node_modules/request/request.js:1083:12)
    at Object.onceWrapper (events.js:288:20)
    at IncomingMessage.emit (events.js:205:15)
    at endReadableNT (_stream_readable.js:1137:12)
    at processTicksAndRejections (internal/process/task_queues.js:84:9)
witSpeech> <!DOCTYPE html>
<html lang="en" id="facebook">
  <head>
    <title>Facebook | Error</title>
    <meta charset="utf-8">
    <meta http-equiv="cache-control" content="no-cache">
    <meta http-equiv="cache-control" content="no-store">
    <meta http-equiv="cache-control" content="max-age=0">
    <meta http-equiv="expires" content="-1">
    <meta http-equiv="pragma" content="no-cache">
    <meta name="robots" content="noindex,nofollow">
    <style>
      html, body {
        color: #141823;
        background-color: #e9eaed;
        font-family: Helvetica, Lucida Grande, Arial,
                     Tahoma, Verdana, sans-serif;
        margin: 0;
        padding: 0;
        text-align: center;
      }

      #header {
        height: 30px;
        padding-bottom: 10px;
        padding-top: 10px;
        text-align: center;
      }

      #icon {
        width: 30px;
      }

      h1 {
        font-size: 18px;
      }

      p {
        font-size: 13px;
      }

      #footer {
        border-top: 1px solid #ddd;
        color: #9197a3;
        font-size: 12px;
        padding: 5px 8px 6px 0;
      }
    </style>
  </head>
  <body>
    <div id="header">
      <a href="//www.facebook.com/">
        <img id="icon" src="//static.facebook.com/images/logos/facebook_2x.png" />
      </a>
    </div>
    <div id="core">
      <h1 id="sorry">Sorry, something went wrong.</h1>
      <p id="promise">
        We're working on it and we'll get it fixed as soon as we can.
      </p>
      <p id="back-link">
        <a id="back" href="//www.facebook.com/">Go Back</a>
      </p>
      <div id="footer">
        Facebook
        <span id="copyright">
          &copy; 2019
        </span>
        <span id="help-link">
          &#183;
          <a id="help" href="//www.facebook.com/help/">Help Center</a>
        </span>
      </div>
    </div>
    <script>
      document.getElementById('back').onclick = function() {
        if (history.length > 1) {
          history.back();
          return false;
        }
      };

      // Adjust the display based on the window size
      if (window.innerHeight < 80 || window.innerWidth < 80) {
        // Blank if window is too small
        document.body.style.display = 'none';
      };
      if (window.innerWidth < 200 || window.innerHeight < 150) {
        document.getElementById('back-link').style.display = 'none';
        document.getElementById('help-link').style.display = 'none';
      };
      if (window.innerWidth < 200) {
        document.getElementById('sorry').style.fontSize = '16px';
      };
      if (window.innerWidth < 150) {
        document.getElementById('promise').style.display = 'none';
      };
      if (window.innerHeight < 150) {
        document.getElementById('sorry').style.margin = '4px 0 0 0';
        document.getElementById('sorry').style.fontSize = '14px';
        document.getElementById('promise').style.display = 'none';
      };
    </script>
  </body>
</html>
aforaleka commented 5 years ago

Are you using the POST method? Please check out https://wit.ai/docs/http/20170307#post__speech_link for how to call our POST /speech API. It does return a JSON.

solyarisoftware commented 5 years ago

Hi @aforaleka Yes, I do POST request:

 12 const BASEURL = 'https://api.wit.ai/speech'                                                                                                                               
 13 const VERSION = '20170307'                                                                                                                                                
 14                                                                                                                                                                           
 15 // https://wit.ai/docs/http/20170307#context_link                                                                                                                         
 16 const context = {                                                                                                                                                         
 17   timezone: 'Europe/Rome',                                                                                                                                                
 18   locale: 'it_IT',                                                                                                                                                        
 19   coords: {                                                                                                                                                               
 20     // Genova, Italia                                                                                                                                                     
 21     lat: 44.414165,                                                                                                                                                       
 22     long: 8.942184                                                                                                                                                        
 23   }                                                                                                                                                                       
 24 }                                                                                                                                                                         
 25                                                                                                                                                                           
 26 const encodedContext = encodeURIComponent(JSON.stringify(context))                                                                                                        
 27                                                                                                                                                                           
 28 const url = `${BASEURL}?v=${VERSION}&context=${encodedContext}`                                                                                                           
 29                                                                                                                                                                           
 30 const options = {                                                                                                                                                         
 31   method: 'POST',                                                                                                                                                         
 32   //body: fs.createReadStream(fileName),                                                                                                                                  
 33   encoding: null,                                                                                                                                                         
 34   headers: {                                                                                                                                                              
 35     'Authorization': `Bearer ${WITAI_TOKEN}`,                                                                                                                             
 36     'Content-Type': 'audio/wav'                                                                                                                                           
 37   }                                                                                                                                                                       
 38 }                                                                                                                                                                         
 39        

...
...
...

     request( url, options, (err, res, body) => {                                                                                                                          
 57                                                                                                                                                                           
 58       if (err) {                                                                                                                                                          
 59         console.error('witSpeech> ' + err)                                                                                                                                
 60         reject(err)                                                                                                                                                       
 61       }                                                                                                                                                                   
 62                                                                                                                                                                           
 63       else {                                                                                                                                                              
 64         let bodyObj                                                                                                                                                       
 65                                                                                                                                                                           
 66         //                                                                                                                                                                
 67         // read JSON body                                                                                                                                                 
 68         //                                                                                                                                                                
 69         try {                                                                                                                                                             
 70           bodyObj = JSON.parse(body)                                                                                                                                      
 71         }                                                                                                                                                                 
 72         catch(jsonParseError) {                                                                                                                                           
 73           console.error('witSpeech>', jsonParseError)                                                                                                                     
 74           console.error('witSpeech>', body.toString('utf8'))                                                                                                              
 75           return reject(jsonParseError)                                                                                                                                   
 76         }                                                                                                                                                                 
 77                                                                                                                                                                           
 78         //debug                                                                                                                                                           
 79         console.info( 'witSpeech>', fileName)                                                                                                                             
 80         console.info( 'witSpeech> _text:', bodyObj._text)                                                                                                                 
 81         console.info( 'witSpeech> wit.ai elapsed:', elapsedTime.str() )                                                                                                   
 82                                                                                                                                                                           
 83         // { error: 'Timeout, please try again later', code: 'timeout' }                                                                                                  
 84         if (bodyObj.error && bodyObj.code === 'timeout') {                                                                                                                
 85           console.error('witSpeech> ' + 'timeout')                                                                                                                        
 86           reject('timeout')                                                                                                                                               
 87         }                                                                                                                                                                 
 88         else {                                                                                                                                                            
 89           const text = bodyObj._text                                                                                                                                      
 90           //console.info(`speech recognition   : ${text}\n`)                                                                                                              
 91           resolve(text)                                          

I think the problem is in wit.ai server side logic. For some reason, my client request sometime produce an error on your servers and wit.ai reply with the HTML ( :( ) page saying

     <div id="core">
       <h1 id="sorry">Sorry, something went wrong.</h1>
       <p id="promise">
         We're working on it and we'll get it fixed as soon as we can.
       </p>
       <p id="back-link">
         <a id="back" href="//www.facebook.com/">Go Back</a>
       </p>

This is IMMO a "protocol" serevr side error because in any case, the client expect a JSON payload reply, not an HTML, exactly in agreement with your API specification: https://wit.ai/docs/http/20170307#post__speech_link and https://wit.ai/docs/http/20170307#get__message_link (for JSON reply specifcations).

Dont'you agree? Thanks giorgio

jtliao commented 5 years ago

can't seem to reproduce this , our 500 errors should not involve HTML

backmeupplz commented 5 years ago

@jtliao well, you can have a look at my account (logged in through github), I just had over 600 of such errors :) it seems like the issues happen in bursts, looks like it works again

solyarisoftware commented 5 years ago

Hi @backmeupplz

you can have a look at my account (logged in through github), I just had over 600 of such errors :)

Any link?

Do you confirm the server-side issue (HTML instead of JSON data error)? Did you experience these errors sending burst requests? Is not my case because I send "sparse" ferquency messages (>= 1/sec).

thanks giorgio

solyarisoftware commented 5 years ago

Hi @jtliao, about HTML (instead of expected JSON format) response (in case on unknown server error), reading https://wit.ai/docs/http/20170307

Response format

The response format is always JSON for successful requests. A failed request would yield a plain text error. An HTTP Accept header can be set to get error responses in JSON format.

I'm trying to avoit the exception adding

'Accept': 'application/json'

in http post headeer request:

 const options = {                                                                                                                                                       
   31   method: 'POST',                                                                                                                                                       
   32   //body: fs.createReadStream(fileName),                                                                                                                                
   33   encoding: null,                                                                                                                                                       
   34   headers: {                                                                                                                                                            
   35     'Authorization': `Bearer ${WITAI_TOKEN}`,                                                                                                                           
+  36     'Accept': 'application/json',                                                                                                                                       
   37     'Content-Type': 'audio/wav'                                                                                                                                         
   38   }                                                                                                                                                                     
   39 }           

it sounds correct?

If yes, you could add in the speech api example: https://wit.ai/docs/http/20170307#post__speech_link

that lack of the specification:

Definition

  POST https://api.wit.ai/speech

Example request

  $ curl -XPOST 'https://api.wit.ai/speech?v=20170307' \
   -i -L \
   -H "Authorization: Bearer $TOKEN" \
   -H "Content-Type: audio/wav" \
   --data-binary "@sample.wav"

A part that "consequence" of the internal error, still remain the question about why the error message:

"Sorry, something went wrong."

What do you think? Thanks giorgio

solyarisoftware commented 4 years ago

hi @jtliao why the issue have been closed?