"본 튜토리얼은 **ChatGPT**를 활용해 **PDF** 파일에 기반하여 답변할 수 있는 질의응답 챗봇 코드를 다루고 있습니다. <br>\n",
"튜토리얼을 마치고 나면 위 그림과 같은 제품을 만드는 방법을 익히실 수 있게 됩니다. <br><br>\n",
"\n",
"튜토리얼은 크게 **세 단계**로 나누어 진행됩니다.\n",
"- **PDF-to-Image**\n",
"- **Text Preprocessing**\n",
"- **Vector Search**\n",
"\n",
"\n",
"# 1. PDF-to-Text\n",
"\n",
"PDF 파일에서 언어 모델이 이해할 수 있는 플레인 텍스트를 추출하는 과정입니다. <br>\n",
"해당 과정에는 PDF를 문서 이미지로 변환하는 `PDF-to-Image`, 문서 이미지에서 텍스트를 추출하는 `Image-to-Text` 로직이 포함됩니다."
]
},
{
"cell_type": "markdown",
"id": "4c3fd898-d8d9-4044-a920-6a48ae264f5b",
"metadata": {},
"source": [
"## 1.1. PDF-to-Image\n",
"\n",
"`PDF-to-Image`는 PDF 파일을 이미지 파일의 모음으로 변환하는 단계입니다. <br>\n",
"이 작업을 수행하기 위해 많은 기술들이 존재하지만, 본 튜토리얼에서는 [`pdf2image`](https://github.com/Belval/pdf2image)를 활용합니다. <br><br>\n",
"\\* `pdf2image` 활용을 위해서는 `poppler` [설치](https://pdf2image.readthedocs.io/en/latest/installation.html)가 필요합니다."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "1e728210-712b-451d-bdc7-7e283ab4f223",
"metadata": {},
"outputs": [],
"source": [
"#!apt-get install poppler-utils\n",
"#!brew install popler\n",
"#!pip install pdf2image"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "3db689ae-7b23-40d6-b1f1-fd98a9e8a549",
"metadata": {},
"outputs": [],
"source": [
"# pdf2image 라이브러리 임포트\n",
"from pdf2image import convert_from_path\n",
"\n",
"# 로컬 내 PDF 파일 경로 변수로 지정\n",
"FILE_NAME = \"sample_data/transformer.pdf\"\n",
"\n",
"# `convert_from_path` 함수 통해 PDF 파일 읽어와 이미지 리스트로 변환\n",
"images = convert_from_path(FILE_NAME)"
]
},
{
"cell_type": "markdown",
"id": "9ce06793-4099-4427-9329-dc106e80dc99",
"metadata": {},
"source": [
"본 튜토리얼에서는 2017년 공개된 [**Attention Is All You Need**](https://arxiv.org/abs/1706.03762) 논문을 예제 문서로 활용합니다."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "668c7af7-9feb-4499-ab8d-ff6a4d5e6504",
"metadata": {},
"outputs": [],
"source": [
"len(images)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "8f46f4da-92f1-443c-8d75-cb52540469ea",
"metadata": {},
"outputs": [],
"source": [
"# 다음 단계를 위해 이미지 파일 로컬에 저장\n",
"for i, image in enumerate(images):\n",
" image.save(f\"page_{str(i)}.jpg\", \"JPEG\")"
]
},
{
"cell_type": "markdown",
"id": "9599fe85-85fe-449a-9b45-b082088d5d21",
"metadata": {},
"source": [
"## 1.2. Image-to-Text\n",
"\n",
"`Image-to-Text`는 앞서 저장한 이미지 파일에서 텍스트를 추출하는 단계입니다. <br>\n",
"본 튜토리얼에서는 [`Google OCR`](https://cloud.google.com/vision/docs/ocr)을 활용하며, 기호에 따라 다른 OCR 기술 (e.g. [HuggingFace](https://huggingface.co/), [Tesseract](https://github.com/tesseract-ocr/tesseract), ...) 을 활용하실 수도 있습니다.\n",
"Google OCR에서 내려준 결과를 곧바로 활용할 경우 위 예시와 같이 각 행의 마지막에 위치한 **띄어쓰기**, **개행** 등의 *Break* 정보가 유실된 상태의 텍스트 (e.g. `Numerous` 뒤에 불필요한 개행문자가 포함) 를 얻게 됩니다.<br>\n",
"Google도 이러한 점을 고려해 [**Break Detection**](https://cloud.google.com/dotnet/docs/reference/Google.Cloud.Vision.V1/latest/Google.Cloud.Vision.V1.TextAnnotation.Types.DetectedBreak.Types.BreakType) 기술을 제공하고 있습니다. <br>\n",
"따라서 *Break Detection* 에 의해 추론된 결과에 따라 **띄어쓰기**, **개행** 등을 올바르게 정렬하는 후처리 작업을 진행합니다."
"dirty_text = \"\"\"We show that the Transformer generalizes well to other tasks by applying it successfully to English constituency parsing both with large and limited training data.\\n1 Introduction\\nRecurrent neural networks, long short-term memory [13] and gated recurrent [7] neural networks in particular, have been firmly established as state of the art approaches in sequence modeling and\\n*Equal contribution. Listing order is random. Jakob proposed replacing RNNs with self-attention and started the effort to evaluate this idea.\"\"\""
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "0ac6e172-1a44-464c-9dfe-5c28f95f2561",
"metadata": {},
"outputs": [],
"source": [
"dirty_text"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "8d446ed6-6d7e-4acc-84ee-a69527b544af",
"metadata": {},
"outputs": [],
"source": [
"cleanse_text(dirty_text)"
]
},
{
"cell_type": "markdown",
"id": "d1cd4efa-9f2a-475a-b520-dfa0fa6e43a0",
"metadata": {},
"source": [
"## 2.2. Text Chunking\n",
"\n",
"`Text Chunking`은 하나의 벡터에 명료하고 확실한 정보를 담기 위해 텍스트를 **의미적으로 자르는 단계**입니다. <br>\n",
"대개 문단 단위로 자르는 로직, 토큰 갯수로 자르는 로직 등이 있으며 본 튜토리얼에서는 편의상 **토큰 갯수**로 자르는 로직을 구현합니다. <br>\n",
"`Text Cleansing`과 마찬가지로 목적에 따라 다른 분할 로직을 활용하시는게 바람직합니다."
]
},
{
"cell_type": "markdown",
"id": "a76baec9-b4d7-427a-bf98-16bd1edf2a5c",
"metadata": {},
"source": [
"**OpenAI**는 토큰 단위 비즈니스 로직을 지원하기 위해 문장의 토큰 갯수를 반환해주는 [`tiktoken`](https://github.com/openai/tiktoken) 라이브러리를 제공합니다. <br>\n",
" \"Your role is to answer the user's query based on the references provided.\",\n",
" \"You must base your answer solely on the references, regardless of your own knowledge, and you must include the page information in your answer.\",\n",
`Image-to-Text`는 앞서 저장한 이미지 파일에서 텍스트를 추출하는 단계입니다. <br>
본 튜토리얼에서는 [`Google OCR`](https://cloud.google.com/vision/docs/ocr)을 활용하며, 기호에 따라 다른 OCR 기술 (e.g. [HuggingFace](https://huggingface.co/), [Tesseract](https://github.com/tesseract-ocr/tesseract), ...) 을 활용하실 수도 있습니다.
Google OCR에서 내려준 결과를 곧바로 활용할 경우 위 예시와 같이 각 행의 마지막에 위치한 **띄어쓰기**, **개행** 등의 *Break* 정보가 유실된 상태의 텍스트 (e.g. `Numerous` 뒤에 불필요한 개행문자가 포함) 를 얻게 됩니다.<br>
Google도 이러한 점을 고려해 [**Break Detection**](https://cloud.google.com/dotnet/docs/reference/Google.Cloud.Vision.V1/latest/Google.Cloud.Vision.V1.TextAnnotation.Types.DetectedBreak.Types.BreakType) 기술을 제공하고 있습니다. <br>
따라서 *Break Detection* 에 의해 추론된 결과에 따라 **띄어쓰기**, **개행** 등을 올바르게 정렬하는 후처리 작업을 진행합니다.
dirty_text="""We show that the Transformer generalizes well to other tasks by applying it successfully to English constituency parsing both with large and limited training data.\n1 Introduction\nRecurrent neural networks, long short-term memory [13] and gated recurrent [7] neural networks in particular, have been firmly established as state of the art approaches in sequence modeling and\n*Equal contribution. Listing order is random. Jakob proposed replacing RNNs with self-attention and started the effort to evaluate this idea."""