Как прочитать исходный PDF-файл в источнике данных индексатора в пользовательском WebApiSkill после включения «Разрешить набору навыков читать данные файла»

В настройках индексатора я вижу следующее:

При наведении на него я прочитал следующее:

True означает, что исходные данные файла получены из источника данных вашего BLOB-объекта. сохраняется. Это позволяет передать исходный файл пользовательскому навыку, или навыку «Извлечение документов».

Как прочитать исходный PDF-файл в связанном источнике данных большого двоичного объекта в пользовательском WebApiSkill?

file_data_base64 = value.get('data', {}).get('file_data', '')
...

РЕДАКТИРОВАТЬ

Я включил Allow Skillset to read file data в индексаторе. Моя полная установка:

  • Входные данные WebApiSkill
inputs=[
    InputFieldMappingEntry(name = "file_data", source = "/document/file_data")
],
  • Чтение входных данных WebApiSkill
import azure.functions as func
import datetime
import json
import logging
import base64
import fitz
from io import BytesIO

app = func.FunctionApp()
logging.basicConfig(level=logging.INFO)


@app.route(route = "CustomSplitSkill", auth_level=func.AuthLevel.FUNCTION)
def CustomSplitSkill(req: func.HttpRequest) -> func.HttpResponse:
    logging.info('Python HTTP trigger function processed a request.')

    try:
        req_body = req.get_json()
        logging.info('Request body parsed successfully.')
    except ValueError:
        logging.error(f"Invalid input: {e}")
        return func.HttpResponse("Invalid input", status_code=400)

    # 'values' expected top-level key in the request body
    response_body = {"values": []}
    for value in req_body.get('values', []):
        recordId = value.get('recordId')
        file_data_base64 = value.get('data', {}).get('file_data', '').get('data', '')
        if not file_data_base64:
            logging.error("No file_data found in the request.")
            return func.HttpResponse("Invalid input: No file_data found", status_code=400)

        try:
            file_data = base64.b64decode(file_data_base64)

            try:
                pdf_document = fitz.open(stream=BytesIO(file_data), filetype='pdf')
            except fitz.FileDataError as e:
                logging.error(f"Failed to open PDF document: {e}")
                return func.HttpResponse("Failed to open PDF document", status_code=400)
            except Exception as e:
                logging.error(f"An unexpected error occurred while opening the PDF document: {e}")
                return func.HttpResponse("An unexpected error occurred", status_code=500)
            
            if pdf_document.page_count == 0:
                logging.error("No pages found in the PDF document.")
                return func.HttpResponse("Invalid PDF: No pages found", status_code=400)

            extracted_text = ""
            for page_num in range(pdf_document.page_count):
                page = pdf_document.load_page(page_num)
                extracted_text += page.get_text()

            combined_list = [{'textItems': ['text1', 'text2'], 'numberItems': [0, 1]}]  # i deleted the chunking and associated page extraction for simplicity

            response_record = {
                "recordId": recordId,
                "data": {
                    "subdata": combined_list
                }
            }
            response_body['values'].append(response_record)
        except Exception as e:
            logging.error(f"Error processing file_data: {e}")
            return func.HttpResponse("Error processing file_data", status_code=500)

    logging.info('Function executed successfully.')
    return func.HttpResponse(json.dumps(response_body), mimetype = "application/json")

Ошибка:

Message:
Could not execute skill because the Web Api request failed.

Details:
Web Api response status: 'NotFound', Web Api response details: ''

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

только эта ошибка? просмотрите журналы индексатора и подробную информацию о точной причине сбоя

JayashankarGS 14.06.2024 14:35

Извините, детали добавлены

Mike B 14.06.2024 14:48

Ваш веб-API не возвращает ответ, пожалуйста, проверьте его.

JayashankarGS 14.06.2024 15:05

Это связано с тем, как считываются данные. Это тоже часть вопроса. Я сгенерировал и закодировал PDF-файл, который является частью моей команды curl для тестирования сценария. Всё работает, pdf читается правильно. Но это не работает в конвейере

Mike B 14.06.2024 18:42

Пожалуйста, добавьте полный код вашего навыка веб-API.

JayashankarGS 14.06.2024 20:13

Код навыка обновлен.

Mike B 15.06.2024 14:33

Можете ли вы проверить журналы функции. Потому что ваша функция возвращается пустой.

JayashankarGS 17.06.2024 06:56

В функции Azure на вкладке «Вызовы» вы можете увидеть количество ошибок, где вы найдете журналы и подробную информацию.

JayashankarGS 17.06.2024 06:58

Спасибо. Последний совет по отладке оказался очень полезным. Ошибка там явно проявилась. Я слишком долго смотрел не в то место (поток журнала)...

Mike B 17.06.2024 12:09
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
9
119
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Согласно этой документации, когда вы включаете параметр allowSkillsetToReadFileData в индексаторе, вы получите данные файла по пути /document/file_data в контексте документа.

То же самое передается вашему пользовательскому набору навыков веб-API inputs.

"inputs": [
      {
        "name": "file_data",
        "source": "/document/file_data"
      }
    ]

и доступ к нему осуществляется в функции, как показано ниже.

file_data = value.get('data', {}).get('file_data', '')

Благодарю за ваш ответ. Выглядит многообещающе!

Mike B 14.06.2024 14:11

Я только что попробовал, но что-то не получается...

Mike B 14.06.2024 14:12

Рад, что вы обнаружили ошибку и исправили код.

JayashankarGS 21.06.2024 11:55

Спасибо за поддержку. Странно, что в Интернете нет примеров извлечения страниц. Для меня было несложно использовать для этого программу чтения PDF-файлов на Python, но я понятия не имею, что делают другие xD

Mike B 25.06.2024 12:45
Ответ принят как подходящий

Входные данные для вашего WebApiSkill в вашем наборе навыков должны быть установлены на:

"inputs": [
      {
        "name": "file_data",
        "source": "/document/file_data"
      }
    ]

Включите «Разрешить набору навыков читать данные файла» в индексаторе:

    indexing_parameters_configuration = IndexingParametersConfiguration(
        allow_skillset_to_read_file_data=True
    )

    # otherwise: HTTP response error: () Configuration property 'queryTimeout' is not supported for the data source of type 'azureblob'.
    indexing_parameters_configuration.query_timeout = None

    indexer = SearchIndexer(  
        name=indexer_name,  
        description = "Chunks, pages and embeddings",  
        skillset_name=skillset_name,  
        target_index_name=target_index_name,  
        data_source_name=data_source_name,
        parameters = {"configuration": indexing_parameters_configuration} 
    ) 

Входные данные file_data закодированы в формате Base64, поэтому сначала их необходимо декодировать, а затем открыть как байтовый поток с помощью программы чтения PDF по вашему выбору:

import re
import azure.functions as func
import datetime
import json
import logging
import base64
import fitz
from io import BytesIO

app = func.FunctionApp()
logging.basicConfig(level=logging.INFO)


@app.route(route = "CustomSplitSkill", auth_level=func.AuthLevel.FUNCTION)
def CustomSplitSkill(req: func.HttpRequest) -> func.HttpResponse:
    logging.info('Python HTTP trigger function processed a request.')

    try:
        req_body = req.get_json()
        logging.info('Request body parsed successfully.')
    except ValueError:
        logging.error(f"Invalid input: {e}")
        return func.HttpResponse("Invalid input", status_code=400)

    # 'values' expected top-level key in the request body
    response_body = {"values": []}
    for value in req_body.get('values', []):
        recordId = value.get('recordId')
        file_data_base64 = value.get('data', {}).get('file_data', '').get('data', '')
        if not file_data_base64:
            logging.error("No file_data found in the request.")
            return func.HttpResponse("Invalid input: No file_data found", status_code=400)

        try:
            file_data = base64.b64decode(file_data_base64)

            try:
                pdf_document = fitz.open(stream=BytesIO(file_data), filetype='pdf')
            except fitz.FileDataError as e:
                logging.error(f"Failed to open PDF document: {e}")
                return func.HttpResponse("Failed to open PDF document", status_code=400)
            except Exception as e:
                logging.error(f"An unexpected error occurred while opening the PDF document: {e}")
                return func.HttpResponse("An unexpected error occurred", status_code=500)
            
            if pdf_document.page_count == 0:
                logging.error("No pages found in the PDF document.")
                return func.HttpResponse("Invalid PDF: No pages found", status_code=400)

            combined_list = [{'textItems': ['text1', 'text2'], 'numberItems': [0, 1]}]  # I deleted the chunking and associated page extraction in order to reduce the amount of code

            response_record = {
                "recordId": recordId,
                "data": {
                    "subdata": combined_list
                }
            }
            response_body['values'].append(response_record)
        except Exception as e:
            logging.error(f"Error processing file_data: {e}")
            return func.HttpResponse("Error processing file_data", status_code=500)

    logging.info('Function executed successfully.')
    return func.HttpResponse(json.dumps(response_body), mimetype = "application/json")

Другие вопросы по теме