Загрузить файл Word для извлечения текста через TIKA REST - PullRequest
0 голосов
/ 19 февраля 2020

Я пытаюсь вызвать Apache -TIKA через их REST API. Я успешно смог загрузить PDF-документ и вернуть текст документа через CURL

curl -X PUT --data-binary @<filename>.pdf http://localhost:9998/tika --header "Content-type: application/pdf"

Это переведено на INDY примерно так:

function GetPDFText(const FileName: String): String;
var
  IdHTTP:  TIdHTTP;
  Params: TIdMultiPartFormDataStream;
begin
  IdHTTP := TIdTTP.Create;
  try
    Params := TIdMultiPartFormDataStream.Create;
    try
      Params.Add('file', FileName, 'application/pdf')
      Result := IdHTTP.PUT('http://localhost:9998/tika', Params);
    finally
      Params.Free;
    end;    
  finally
    IdHTTP.Free;
  end;
end;

Теперь я хочу загрузить текстовый документ (.docx) Я предположил, что все, что мне нужно сделать, это изменить тип контента, когда я добавляю свой файл в Params, но это, похоже, не дает никаких результатов, хотя я не получаю сообщение об ошибке , Мне удалось заставить следующую команду CURL работать правильно

CURL -T <myDOCXfile>.docx http://localhost:9998/tika --header "Content-type: application/vnd.openxmlformats-officedocument.wordprocessingml.document"

Как изменить мой HTTP-вызов с CURL -X PUT на CURL -T?

1 Ответ

1 голос
/ 21 февраля 2020

В вашей реализации есть как минимум две проблемы:

  1. Ваш перевод с CURL -X PUT на TIdHTTP неверен.
  2. Вы не указали Accept HTTP заголовок для извлечения извлеченного текста в указанном c формате.

Как перевести curl -X PUT в Indy?

Сначала давайте проясним, что curl -X PUT --data-binary @<filename> <url> является то же самое, что curl -T <filename> <url>, когда:

  • <url> Схема HTTP или HTTPS
  • <url> не заканчивается /

Поэтому использование одного или другого не должно иметь значения в вашем случае. См. Также документация по curl .

Во-вторых, TIdMultiPartFormDataStream предназначен для использования с глаголом POST, однако ничто не может помешать вам передать его в TIdHTTP.Put, поскольку он получен косвенно от TStream. Даже существует выделенный инвариант метода TIdHTTP.Post, который принимает TIdMultiPartFormDataStream:

Функция Post (AURL: строка; ASource: TIdMultiPartFormDataStream): строка; overload;

Чтобы загрузить файл в службу, просто используйте метод TIdHTTP.Put с TFileStream в качестве аргумента, указав правильный тип содержимого файла, загружаемого в заголовок HTTP.

И, наконец, вы пытаетесь извлечь простой текст из документа, но вы не указали тип контента, который должен возвращать сервис. Это делается через HTTP-заголовок Accept. Экземпляр по умолчанию TIdHTTP имеет свойство IdHTTP.Request.Accept, инициализированное 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8' (это может варьироваться в зависимости от версии Indy). Поэтому по умолчанию Тика вернет HTML форматированный текст. Чтобы получить простой текст, вы должны изменить его на 'text/plain; charset=utf-8'.

Исправлена ​​реализация:

uses IdGlobal, IdHTTP;

function GetDocumentText(const FileName, ContentType: string): string;
var
  IdHTTP: TIdHTTP;
  Stream: TIdReadFileExclusiveStream;
begin
  IdHTTP := TIdHTTP.Create;
  try
    IdHTTP.Request.Accept := 'text/plain; charset=utf-8';
    IdHTTP.Request.ContentType := ContentType;
    Stream := TIdReadFileExclusiveStream.Create(FileName);
    try
      Result := IdHTTP.Put('http://localhost:9998/tika', Stream);
    finally
      Stream.Free;
    end;
  finally
    IdHTTP.Free;
  end;
end;

function GetPDFText(const FileName: string): string;
const
  PDFContentType = 'application/pdf';
begin
  Result := GetDocumentText(FileName, PDFContentType);
end;

function GetDOCXText(const FileName: string): string;
const
  DOCXContentType = 'application/vnd.openxmlformats-officedocument.wordprocessingml.document';
begin
  Result := GetDocumentText(FileName, DOCXContentType);
end;

Согласно документации Tika она также поддерживает публикацию данные из нескольких частей. Если вы настаиваете на использовании этого подхода, вам следует изменить целевой ресурс на /tika/form и переключиться на метод Post в своей реализации:

function GetDocumentText(const FileName, ContentType: string): string;
var
  IdHTTP: TIdHTTP;
  FormData: TIdMultiPartFormDataStream;
begin
  IdHTTP := TIdHTTP.Create;
  try
    IdHTTP.Request.Accept := 'text/plain; charset=utf-8';
    FormData := TIdMultiPartFormDataStream.Create;
    try
      FormData.AddFile('file', FileName, ContentType); { older Indy versions: FormData.Add(...) }
      Result := IdHTTP.Post('http://localhost:9998/tika/form', FormData);
    finally
      FormData.Free;
    end;
  finally
    IdHTTP.Free;
  end;
end;

Почему исходная рассматриваемая реализация работает с файлами PDF ?

Когда вы Post многочастные данные формы с помощью TIdHTTP, Indy автоматически устанавливает тип содержимого запроса на 'multipart/form-data; boundary=...whatever...'. Это не тот случай, когда вы Put (если вы не установили его вручную перед выполнением запроса) и, следовательно, TIdHttp.Request.ContentType остается пустым. Теперь я могу только догадываться, что когда Tika видит пустой тип контента, он возвращается к какому-либо типу по умолчанию, который может быть PDF, и все равно каким-то образом может читать документ из многокомпонентного запроса.

...