Что вызывает ошибку в веб-приложении при использовании службы преобразования документов Watson?

Я пытаюсь преобразовать некоторые файлы PDF в блоки ответов с помощью службы преобразования документов Watson. Все эти файлы заархивированы в один большой файл .zip, который загружен на мой сервер Bluemix, на котором запущено приложение Node.js. Приложение разархивирует файлы в памяти и попытается отправить каждый по очереди в сервис конвертации:

var document_conversion = watson.document_conversion(dcCredentials);

function createCollection(res, solrClient, docs)
   {
   for (var doc in docs) //docs is an array of objects describing the pdf files
      {
      console.log("Converting: %s", docs[doc].filename);

      //make a stream of this pdf file
      var rs = new Readable;    //create the stream
      rs.push(docs[doc].data);  //add pdf file (string object) to stream
      rs.push(null);        //end of stream marker

      document_conversion.convert(
         {
         file: rs,
         conversion_target: "ANSWER_UNITS"
         }, 
         function (err, response) 
            {
            if (err) 
               {
               console.log("Error converting doc: ", err);
        .
        .
        .
        etc...

Каждый раз служба конвертации возвращает ошибку 400 с описанием "Ошибка в веб-приложении".

Почесав голову в течение двух дней, пытаясь выяснить причину этого довольно бесполезного сообщения об ошибке, я в значительной степени решил, что проблема должна заключаться в том, что служба преобразования не может определить, какой тип файла отправляется, поскольку нет связанное с ним имя файла. Это, конечно, всего лишь предположение с моей стороны, но я не могу проверить эту теорию, потому что я не знаю, как предоставить эту информацию службе, не записывая каждый файл на диск и не читая его обратно.

Кто-нибудь может помочь?


person David Powell    schedule 08.01.2016    source источник
comment
Интересно... кто-то прокомментировал это, чтобы запросить дополнительную информацию, и я сделал комментарий, чтобы предоставить информацию. Потом на следующий день оба коммента исчезли. Это нормально при переполнении стека?   -  person David Powell    schedule 11.01.2016


Ответы (2)


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

Метод getLengthSync() НЕ вычисляет длину потоков, используйте параметры knownLength в качестве обходного пути.

Я нашел два способа обойти это. Рассчитайте длину самостоятельно и передайте ее как опцию:

document_conversion.convert({
  file: { value: rs, options: { knownLength: 12345 } }
  ...

Или используйте буфер:

document_conversion.convert({
  file: { value: myBuffer, options: {} }
  ...

Причина, по которой вы получили ответ 400, заключалась в том, что заголовок Content-Length вашего запроса был рассчитан неправильно: длина была слишком мала для запроса, в результате чего часть MIME запроса была усечена (и не закрыта).

Я подозреваю, что это связано с тем, что поток Readable не предоставляет длину или размер вашего контента, когда библиотека запросов вычисляет размер объекта.

Кроме того, приносим извинения за бесполезное сообщение об ошибке. Мы сделаем это лучше.

person Matt F    schedule 11.01.2016
comment
Спасибо за расследование. Однако, будучи потоком, я думаю, что сервер вычислит размер после того, как он будет полностью прочитан. Потоки обычно не имеют длины iirc. Я просмотрел объект Readable в файловом приложении, которое работает, и не смог найти ничего, что показывало бы длину данных. API показывает объект конфигурации, который необходимо передать, но показывает только один параметр — требуемую цель конверсии. Если есть другие, я не могу их найти - я надеялся, что есть один, чтобы описать входящий файл mime/type. - person David Powell; 12.01.2016
comment
Длина содержимого передается на сервер в виде заголовка HTTP-запроса; он должен быть рассчитан клиентом или опущен. Из моих продолжающихся копаний я думаю, что это проблема с библиотекой данных формы, которую использует Node.js SDK. Если вы хотите описать mime/content-type файла, это должно быть отправлено как Content-Type в части файла запроса, состоящего из нескольких частей. - person Matt F; 12.01.2016
comment
Потрясающий! Мне не удалось заставить его работать с параметром knownLength (получил то же сообщение об ошибке, что и раньше), но использование буфера помогло. Служба всегда возвращает ровно ноль единиц ответа, по крайней мере, в моем небольшом тестовом почтовом индексе. Но, по крайней мере, я двигаюсь вперед. Возможно, я неправильно создаю буфер — в этот момент PDF-файл является строкой, поэтому я использую new Buffer(pdf). Может быть, вы не можете правильно представить PDF в строке, я не знаю. Спасибо! - person David Powell; 13.01.2016

Приведенный ниже код повторяет ZIP-файл и преобразует каждый документ в ANSWER_UNITS.
Он использует node-unzip-2, а ZIP-файл documents.zip содержит эти 3 примера файлов.

var unzip  = require('node-unzip-2');
var watson = require('watson-developer-cloud');
var fs     = require('fs');

var document_conversion = watson.document_conversion({
  username: 'USERNAME',
  password: 'PASSWORD',
  version_date: '2015-12-01',
  version:  'v1'
});

function convertDocument(doc) {
  document_conversion.convert({
    file: doc,
    conversion_target: document_conversion.conversion_target.ANSWER_UNITS,
  }, function (err, response) {
    if (err) {
      console.error(doc.path,'error:',err);
    } else {
      console.log(doc.path,'OK');
      // hide the results for now
      //console.log(JSON.stringify(response, null, 2));
    }
  });
}

fs.createReadStream('documents.zip')
  .pipe(unzip.Parse())
  .on('entry', function (entry) {
    if (entry.type === "File") {
      convertDocument(entry);
    } else {
      // Prevent out of memory issues calling autodrain for non processed entries
      entry.autodrain();
    }
  });

Пример вывода:

$ node app.js
 sampleHTML.html OK
 sampleWORD.docx OK
 samplePDF.pdf OK
person German Attanasio    schedule 11.01.2016
comment
Спасибо, но это не относится к моему вопросу. Я могу без проблем передать и разархивировать zip-файл; происходит сбой при отправке разархивированных файлов (уже находящихся в памяти) в службу преобразования документов. Я бы не хотел ничего записывать в файловую систему на сервере, так как все это уже находится в памяти. - person David Powell; 12.01.2016
comment
Я ничего не пишу в файловую систему. Я читаю zip-файл, анализирую его и повторяю каждую запись. - person German Attanasio; 12.01.2016