Compare commits

...

55 Commits

Author SHA1 Message Date
Pierre-Loic Doulcet 963bd2dd2f Add support for html_remove_navigation_elements. 2024-12-06 11:03:16 +01:00
Ravi Theja cdbddef86d Add demo videos notebooks (#529) 2024-12-05 08:38:34 -08:00
Pierre-Loic Doulcet 3690109abf Add more parameters (#525)
* add after revert

* 3.8 so numpy work

* change defaults

* change requested

* change requested
2024-12-04 15:39:00 +01:00
Pierre-Loic Doulcet 2e322b4fc8 Revert "Add more paramerters"
This reverts commit 735e5f3ddc.
2024-12-04 10:20:07 +01:00
Pierre-Loic Doulcet 735e5f3ddc Add more paramerters 2024-12-04 10:17:08 +01:00
Logan e4cb4c75e5 add test for downloading images (#506) 2024-11-21 13:08:29 -06:00
Jerry Liu 1693deff72 dynamic section retrieval nb (#484) 2024-11-13 13:29:30 +01:00
Jerry Liu 3270f1228d multimodal report generation image (#461)
* cr

* cr
2024-11-13 13:28:07 +01:00
Pierre-Loic Doulcet eeabf48d29 add input url and http_proxy (#475) 2024-11-12 12:56:58 -06:00
Pierre-Loic Doulcet 89348aa8e5 add xlsx support (#472) 2024-11-01 10:09:17 -06:00
Thiago Salvatore 3ab2ce27b5 Add PurePosixPath to list of allowed file-paths (#464) 2024-10-25 10:45:47 -06:00
Sacha Bron 265261862f Add continuous_mode (#460) 2024-10-22 19:45:46 +02:00
Sacha Bron 66cf052b8c Update issue templates (#457)
* Update issue templates

* Update issue templates
2024-10-21 19:51:46 +02:00
Jerry Liu 2ca2d81e58 fix RFP example (#455) 2024-10-21 09:13:24 -07:00
Sacha Bron 951ba4dfd8 Release is_formatting_instruction parameter (#446)
* Release is_formatting_instruction parameter

* Add annotate links
2024-10-17 12:29:05 +02:00
Adam Reichert 386d210e8b CLI Testing Tool for Parsing Results to Standard Output (#363) 2024-10-16 12:40:00 -06:00
Sacha Bron 9321602845 Add missing parameters (#441) 2024-10-15 10:57:32 -06:00
Jerry Liu 26c06353f0 Add RFP Response generation workflow (#438) 2024-10-14 08:45:04 -07:00
Jerry Liu 62cf12d6eb add multimodal RAG pipeline with contextual retrieval (#429) 2024-10-06 15:25:57 -07:00
Logan 253ee61463 improve error handling for jobs (#426) 2024-10-02 18:57:46 -06:00
Sourabh Desai 2ccd2a9397 Update README.md to convey need to specify extra_info["file_name"] (#417) 2024-09-29 17:07:12 -07:00
Jerry Liu c139e8e3e6 fix excel notebook (#416) 2024-09-24 17:11:33 -07:00
Ravi Theja 6e6e96c422 Update excel rag with o1 notebook (#415) 2024-09-24 07:42:00 -07:00
Jerry Liu b677e5226d nit: move o1 excel notebook (#414) 2024-09-23 10:51:51 -07:00
Ravi Theja df723584b6 Compare Excel RAG with o1 models (#409) 2024-09-23 10:42:47 -07:00
Sacha Bron efe06ffff0 Bump to v0.5.6 2024-09-19 14:33:30 +02:00
Pierre-Loic Doulcet 6ba052d58f add premium mode support (#406) 2024-09-18 11:48:45 +02:00
Sacha Bron 8cf52058b5 Remove JSON from valid result types (#400) 2024-09-18 11:48:22 +02:00
Jerry Liu 1bae09126c fix multimodal RAG over slide deck (#402) 2024-09-17 13:08:10 +08:00
Pierre-Loic Doulcet bbbae9de9d do not attach a filepath when a stram of bytes is passed (#394) 2024-09-10 11:53:53 -06:00
Thiago Salvatore 7cb6d06316 Enable support for custom filesystem (#117) 2024-09-10 10:39:46 -06:00
Jerry Liu bca5492829 update README (#386) 2024-09-09 17:31:58 -06:00
Sourabh Desai f6a4d8681f bump to 0.5.3 (#388) 2024-09-09 11:06:58 -06:00
Sourabh Desai fd3836ec95 allow custom httpx client (#384)
* allow custom httpx client

* split into aget_images + unit test

* typo
2024-09-07 10:51:18 -07:00
Ravi Theja f304c2dc08 Add timeout to the image request using httpx (#378) 2024-09-04 11:46:30 -06:00
Simon Suo f13a1a2fc3 Support take_screenshot (#372)
* wip

* wip]

* wip
2024-08-28 22:24:14 -07:00
Pierre-Loic Doulcet df1453e30c Update README.md 2024-08-28 09:28:49 +08:00
Pierre-Loic Doulcet bac204f800 Update README.md 2024-08-28 09:28:31 +08:00
Pierre-Loic Doulcet dbf24a7daa Update README.md 2024-08-28 09:26:00 +08:00
Logan Markewich 6a29b1ac96 update to use v0.11.0 of core 2024-08-22 20:48:33 -06:00
Jerry Liu 6c700d9e0f add report generation agent (#349) 2024-08-16 09:27:23 -07:00
Jerry Liu ab69e87c2a add report generation example (#340) 2024-08-10 00:30:28 -07:00
Jerry Liu d1f97531dc small edits (#342)
cr
2024-08-09 14:22:11 -07:00
Jonathan Liu 17ebbca6ea Adds more use case notebooks to multimodal parsing (#330)
* add auto insurance example

* adds additional claims to insurance example

* add -o flag to unzip

* add example for legal docs

* adds product manual use case

* revert gitignore

* Adds explanation to insurance and legal rag
2024-08-08 17:37:25 -07:00
Jerry Liu 08ddaaaa2f add gpt-4o-mini example (#316) 2024-07-25 17:11:02 -07:00
Sacha Bron 7515fe5f3e Update issue templates 2024-07-19 15:10:41 +02:00
Sacha Bron cd49dae7ed Update issue templates 2024-07-17 23:40:14 +02:00
Sacha Bron 2977f56061 Exclude Github generated files from pre-commit 2024-07-17 23:38:08 +02:00
Adam Reichert 8938286862 Modify _get_sub_docs to use Custom Separator (#254)
Move _get_sub_docs to private function
2024-07-17 10:04:03 -07:00
Pierre-Loic Doulcet 7b90d03f28 Pierre/fix page separator (#297)
* change page_separator logic add page_prefix and page_suffix

* up

* lint

* bump version
2024-07-17 19:03:21 +02:00
Sacha Bron 9dfe4d6d79 Update issue templates 2024-07-17 17:28:38 +02:00
Sacha Bron 3a781a453e Update issue templates 2024-07-17 16:32:20 +02:00
Sacha Bron e23487b1d8 Update issue templates 2024-07-17 16:25:00 +02:00
Sacha Bron ccee75721b Update issue templates 2024-07-17 16:23:26 +02:00
Sacha Bron 0a4147116c Update issue templates 2024-07-17 16:21:20 +02:00
41 changed files with 12391 additions and 1841 deletions
+31
View File
@@ -0,0 +1,31 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: bug
assignees: ''
---
**Describe the bug**
Write a concise description of what the bug is.
**Files**
If possible, please provide the PDF file causing the issue.
**Job ID**
If you have it, please provide the ID of the job you ran.
You can find it here: https://cloud.llamaindex.ai/parse in the "History" tab.
**Client:**
Please remove untested options:
- Python Library
- API
- Frontend (cloud.llamaindex.ai)
- Typescript Library
- Notebook
**Additional context**
Add any additional context about the problem here.
What options did you use? Premium mode, multimodal, fast mode, parsing instructions, etc.
Screenshots, code snippets, etc.
+10
View File
@@ -0,0 +1,10 @@
---
name: Custom issue
about: Not a bug nor a feature request
title: ''
labels: ''
assignees: ''
---
+10
View File
@@ -0,0 +1,10 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: enhancement
assignees: ''
---
+1
View File
@@ -2,3 +2,4 @@
__pycache__/
*.pyc
.DS_Store
.idea
+2
View File
@@ -84,3 +84,5 @@ repos:
hooks:
- id: toml-sort-fix
exclude: ".*poetry.lock"
exclude: .github/ISSUE_TEMPLATE
+47 -8
View File
@@ -1,16 +1,29 @@
# LlamaParse
LlamaParse is an API created by LlamaIndex to efficiently parse and represent files for efficient retrieval and context augmentation using LlamaIndex frameworks.
[![PyPI - Downloads](https://img.shields.io/pypi/dm/llama-parse)](https://pypi.org/project/llama-parse/)
[![GitHub contributors](https://img.shields.io/github/contributors/run-llama/llama_parse)](https://github.com/run-llama/llama_parse/graphs/contributors)
[![Discord](https://img.shields.io/discord/1059199217496772688)](https://discord.gg/dGcwcsnxhU)
LlamaParse is a **GenAI-native document parser** that can parse complex document data for any downstream LLM use case (RAG, agents).
It is really good at the following:
-**Broad file type support**: Parsing a variety of unstructured file types (.pdf, .pptx, .docx, .xlsx, .html) with text, tables, visual elements, weird layouts, and more.
-**Table recognition**: Parsing embedded tables accurately into text and semi-structured representations.
-**Multimodal parsing and chunking**: Extracting visual elements (images/diagrams) into structured formats and return image chunks using the latest multimodal models.
-**Custom parsing**: Input custom prompt instructions to customize the output the way you want it.
LlamaParse directly integrates with [LlamaIndex](https://github.com/run-llama/llama_index).
Free plan is up to 1000 pages a day. Paid plan is free 7k pages per week + 0.3c per additional page.
The free plan is up to 1000 pages a day. Paid plan is free 7k pages per week + 0.3c per additional page by default. There is a sandbox available to test the API [**https://cloud.llamaindex.ai/parse ↗**](https://cloud.llamaindex.ai/parse).
Read below for some quickstart information, or see the [full documentation](https://docs.cloud.llamaindex.ai/).
If you're a company interested in enterprise RAG solutions, and/or high volume/on-prem usage of LlamaParse, come [talk to us](https://www.llamaindex.ai/contact).
## Getting Started
First, login and get an api-key from [**https://cloud.llamaindex.ai ↗**](https://cloud.llamaindex.ai).
First, login and get an api-key from [**https://cloud.llamaindex.ai/api-key ↗**](https://cloud.llamaindex.ai/api-key).
Then, make sure you have the latest LlamaIndex version installed.
@@ -25,7 +38,22 @@ Lastly, install the package:
`pip install llama-parse`
Now you can run the following to parse your first PDF file:
Now you can parse your first PDF file using the command line interface. Use the command `llama-parse [file_paths]`. See the help text with `llama-parse --help`.
```bash
export LLAMA_CLOUD_API_KEY='llx-...'
# output as text
llama-parse my_file.pdf --result-type text --output-file output.txt
# output as markdown
llama-parse my_file.pdf --result-type markdown --output-file output.md
# output as raw json
llama-parse my_file.pdf --output-raw-json --output-file output.json
```
You can also create simple scripts:
```python
import nest_asyncio
@@ -74,13 +102,18 @@ parser = LlamaParse(
language="en", # Optionally you can define a language, default=en
)
with open("./my_file1.pdf", "rb") as f:
documents = parser.load_data(f)
file_name = "my_file1.pdf"
extra_info = {"file_name": file_name}
with open(f"./{file_name}", "rb") as f:
# must provide extra_info with file_name key with passing file object
documents = parser.load_data(f, extra_info=extra_info)
# you can also pass file bytes directly
with open("./my_file1.pdf", "rb") as f:
with open(f"./{file_name}", "rb") as f:
file_bytes = f.read()
documents = parser.load_data(file_bytes)
# must provide extra_info with file_name key with passing file bytes
documents = parser.load_data(file_bytes, extra_info=extra_info)
```
## Using with `SimpleDirectoryReader`
@@ -124,3 +157,9 @@ Several end-to-end indexing examples can be found in the examples folder
## Terms of Service
See the [Terms of Service Here](./TOS.pdf).
## Get in Touch (LlamaCloud)
LlamaParse is part of LlamaCloud, our e2e enterprise RAG platform that provides out-of-the-box, production-ready connectors, indexing, and retrieval over your complex data sources. We offer SaaS and VPC options.
LlamaCloud is currently available via waitlist (join by [creating an account](https://cloud.llamaindex.ai/)). If you're interested in state-of-the-art quality and in centralizing your RAG efforts, come [get in touch with us](https://www.llamaindex.ai/contact).
File diff suppressed because it is too large Load Diff
Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 MiB

Binary file not shown.
+1 -1
View File
@@ -342,7 +342,7 @@
],
"metadata": {
"kernelspec": {
"display_name": "llama-parse-aNC435Vv-py3.10",
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
+415
View File
@@ -0,0 +1,415 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "97c79c38-38a3-40f3-ba2e-250649347d63",
"metadata": {
"id": "97c79c38-38a3-40f3-ba2e-250649347d63"
},
"source": [
"<a href=\"https://colab.research.google.com/github/run-llama/llama_parse/blob/main/examples/demo_starter_multimodal.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>"
]
},
{
"cell_type": "markdown",
"id": "4e081457",
"metadata": {},
"source": [
"# Multimodal Parsing using LlamaParse\n",
"\n",
"This cookbook shows you how to use LlamaParse to parse any document with the multimodal capabilities of Multi-Modal LLMs from Anthropic/ OpenAI.\n",
"\n",
"LlamaParse allows you to plug in external, multimodal model vendors for parsing - we handle the error correction, validation, and scalability/reliability for you.\n"
]
},
{
"cell_type": "markdown",
"id": "qOdqBxCS51Ow",
"metadata": {
"id": "qOdqBxCS51Ow"
},
"source": [
"### Installation"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "H_Vqcylb50vm",
"metadata": {
"id": "H_Vqcylb50vm"
},
"outputs": [],
"source": [
"!pip install llama-parse"
]
},
{
"cell_type": "markdown",
"id": "15e60ecf-519c-41fc-911b-765adaf8bad4",
"metadata": {
"id": "15e60ecf-519c-41fc-911b-765adaf8bad4"
},
"source": [
"### Setup\n",
"\n",
"Here we setup `LLAMA_CLOUD_API_KEY` for using `LlamaParse`."
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "91a9e532-1454-40e0-bbf0-fd442c350121",
"metadata": {
"id": "91a9e532-1454-40e0-bbf0-fd442c350121"
},
"outputs": [],
"source": [
"import nest_asyncio\n",
"\n",
"nest_asyncio.apply()\n",
"\n",
"import os\n",
"\n",
"# API access to llama-cloud\n",
"os.environ[\"LLAMA_CLOUD_API_KEY\"] = \"<YOUR LLAMACLOUD API KEY>\""
]
},
{
"cell_type": "markdown",
"id": "LGwBNPNotZRQ",
"metadata": {
"id": "LGwBNPNotZRQ"
},
"source": [
"## Download Data\n",
"\n",
"For this demonstration, we will use OpenAI's recent paper `Evaluation of OpenAI o1: Opportunities and Challenges of AGI`."
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "IjtKDQRLrylI",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "IjtKDQRLrylI",
"outputId": "31df0fac-51f2-4697-f78b-0b7c0b8cd145"
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"--2024-12-05 18:54:24-- https://arxiv.org/pdf/2409.18486\n",
"Resolving arxiv.org (arxiv.org)... 151.101.67.42, 151.101.131.42, 151.101.3.42, ...\n",
"Connecting to arxiv.org (arxiv.org)|151.101.67.42|:443... connected.\n",
"HTTP request sent, awaiting response... 200 OK\n",
"Length: 13986265 (13M) [application/pdf]\n",
"Saving to: o1.pdf\n",
"\n",
"o1.pdf 100%[===================>] 13.34M 11.8MB/s in 1.1s \n",
"\n",
"2024-12-05 18:54:26 (11.8 MB/s) - o1.pdf saved [13986265/13986265]\n",
"\n"
]
}
],
"source": [
"!wget \"https://arxiv.org/pdf/2409.18486\" -O \"o1.pdf\""
]
},
{
"cell_type": "markdown",
"id": "4e29a9d7-5bd9-4fb8-8ec1-4c128a748662",
"metadata": {
"id": "4e29a9d7-5bd9-4fb8-8ec1-4c128a748662"
},
"source": [
"## Initialize LlamaParse\n",
"\n",
"Initialize LlamaParse in multimodal mode, and specify the vendor.\n",
"\n",
"**NOTE**: optionally you can specify the Anthropic/ OpenAI API key. If you choose to do so LlamaParse will only charge you 1 credit (0.3c) per page. \n",
"\n",
"\n",
"Using your own API key may incur additional costs from your model provider and could result in failed pages or documents if you do not have sufficient usage limits."
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "dc921729-3446-42ca-8e1b-a6fd26195ed9",
"metadata": {
"id": "dc921729-3446-42ca-8e1b-a6fd26195ed9"
},
"outputs": [],
"source": [
"from llama_index.core.schema import TextNode\n",
"from typing import List\n",
"\n",
"def get_text_nodes(json_list: List[dict]):\n",
" text_nodes = []\n",
" for idx, page in enumerate(json_list):\n",
" text_node = TextNode(text=page[\"md\"], metadata={\"page\": page[\"page\"]})\n",
" text_nodes.append(text_node)\n",
" return text_nodes"
]
},
{
"cell_type": "markdown",
"id": "1b5d6da6",
"metadata": {},
"source": [
"### With anthropic-sonnet-3.5"
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "f2e9d9cf-8189-4fcb-b34f-cde6cc0b59c8",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "f2e9d9cf-8189-4fcb-b34f-cde6cc0b59c8",
"outputId": "a337cbdd-60db-4a73-b66b-2bd6159e81f2"
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Started parsing the file under job_id dd9d5e0f-160e-486a-89a2-6005e5a1c2ac\n"
]
}
],
"source": [
"from llama_parse import LlamaParse\n",
"\n",
"parser = LlamaParse(\n",
" result_type=\"markdown\",\n",
" use_vendor_multimodal_model=True,\n",
" vendor_multimodal_model_name=\"anthropic-sonnet-3.5\",\n",
" target_pages=\"24\"\n",
" # invalidate_cache=True\n",
")\n",
"json_objs = parser.get_json_result(\"o1.pdf\")\n",
"json_list = json_objs[0][\"pages\"]\n",
"docs = get_text_nodes(json_list)"
]
},
{
"cell_type": "markdown",
"id": "4f3c51b0-7878-48d7-9bc3-02b516500128",
"metadata": {
"id": "4f3c51b0-7878-48d7-9bc3-02b516500128"
},
"source": [
"### With GPT-4o\n",
"\n",
"For comparison, we will also parse the document using GPT-4o."
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "6fc3f258-50ae-4988-b904-c105463a498f",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "6fc3f258-50ae-4988-b904-c105463a498f",
"outputId": "89c525c4-2b93-4909-9657-55646e034637"
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Started parsing the file under job_id 6a4dea44-4f90-406b-b290-9e98620b1232\n"
]
}
],
"source": [
"from llama_parse import LlamaParse\n",
"\n",
"parser_gpt4o = LlamaParse(\n",
" result_type=\"markdown\",\n",
" use_vendor_multimodal_model=True,\n",
" vendor_multimodal_model=\"openai-gpt4o\",\n",
" target_pages=\"24\",\n",
" # invalidate_cache=True\n",
")\n",
"json_objs_gpt4o = parser_gpt4o.get_json_result(\"o1.pdf\")\n",
"json_list_gpt4o = json_objs_gpt4o[0][\"pages\"]\n",
"docs_gpt4o = get_text_nodes(json_list_gpt4o)"
]
},
{
"cell_type": "markdown",
"id": "44c20f7a-2901-4dd0-b635-a4b33c5664c1",
"metadata": {
"id": "44c20f7a-2901-4dd0-b635-a4b33c5664c1"
},
"source": [
"### View Results\n",
"\n",
"Let's visualize the results along with the original document page."
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "778698aa-da7e-4081-b3b5-0372f228536f",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "778698aa-da7e-4081-b3b5-0372f228536f",
"outputId": "bb89e323-7041-4fc3-d835-95e373189d02"
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"page: 25\n",
"\n",
"| Participant_ID | clinical Description Reference |\n",
"|-----------------|----------------------------------|\n",
"| Attribute | Value | Basic Personal Information: Subject 098_S_0896 is a 72.0-year-old Female who has completed 15 years of education. The ethnicity is Not Hisp/Latino and race is White. Marital status is Married. Initially diagnosed as AD, as of the date 2007-10-24, the final diagnosis was Dementia. |\n",
"| Age | 72.0 |\n",
"| Sex | Female |\n",
"| Education | 15 |\n",
"| Race | White | Biomarker Measurements: The subject's genetic profile includes an ApoE4 status of 0.0... |\n",
"| DX_bl | AD |\n",
"| DX | Dementia |\n",
"| ... | ... | Cognitive and Neurofunctional Assessments: The Mini-Mental State Examination score stands at 29.0. The Clinical Dementia Rating, sum of boxes, is 1.0. ADAS 11 and 13 scores are 4.67 and 4.67 respectively, with a score of 1.0 in delayed word recall... |\n",
"| APOE4 | 1.0 |\n",
"| TAU | 212.5 |\n",
"| ... | ... |\n",
"| MMSE | 29.0 | Volumetric Data: Under MRI conditions at a field strength of 1.5 Tesla MRI Tesla, using Cross Sectional FreeSurfer (FreeSurfer Version 4.3), the imaging data recorded includes ventricles volume at 54422.0, hippocampus volume at 6677.0, whole brain volume at 1147980.0, entorhinal cortex volume at 2782.0, fusiform gyrus volume at 19432.0, and middle temporal area volume at 24951.0. The intracranial volume measured is 1799580.0.... |\n",
"| CDRSB | 0.0 |\n",
"| ... | ... |\n",
"| FLDSTRENG | 1.5 Tesla MRI |\n",
"| Ventricles | 84599 |\n",
"| Hippocampus | 5319 |\n",
"| ... | ... |\n",
"\n",
"Figure 2: An example of a patient table and its corresponding clinical description.\n",
"\n",
"skills. Mathematics, as a highly structured and logic-driven discipline, provides an ideal testing ground for evaluating this reasoning ability. To investigate o1-preview's performance, we designed a series of tests covering various difficulty levels. We begin with high school-level math competition problems in this section, followed by college-level mathematics problems in the next section, allowing us to observe the model's logical reasoning across varying levels of complexity.\n",
"\n",
"In this section, we selected two primary areas of mathematics: algebra and counting and probability in this section. We chose these two topics because of their heavy reliance on problem-solving skills and their frequent use in assessing logical and abstract thinking [46]. The dataset used in testing is from the MATH dataset [46]. The problems in the dataset cover a wide range of subjects, including Prealgebra, Intermediate Algebra, Algebra, Geometry, Counting and Probability, Number Theory, and Precalculus. Each problem is categorized based on difficulty, ranked from level 1 to 5, according to the Art of Problem Solving (AoPS). The dataset mainly comprises problems from various high school math competitions, including the American Mathematics Competitions (AMC) 10 and 12, as well as the American Invitational Mathematics Examination (AIME), and other similar contests. Each problem comes with detailed reference solutions, allowing for a comprehensive comparison of o1-preview's solutions.\n",
"\n",
"In addition to evaluating the final answers produced by o1-preview, our analysis delves into the step-by-step reasoning process of the o1-preview's solutions. By comparing o1-preview's solutions with the dataset's solutions, we assess its ability to engage in logical reasoning, handle abstract problem-solving tasks, and apply structured approaches to reach correct answers. This deeper analysis offers insights into o1-preview's overall reasoning capabilities, using mathematics as a reliable indicator for logical and structured thought processes.\n"
]
}
],
"source": [
"# using Sonnet-3.5\n",
"print(docs[0].get_content(metadata_mode=\"all\"))"
]
},
{
"cell_type": "code",
"execution_count": 8,
"id": "1511a30f-3efc-4142-9668-7dc056a24d0c",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "1511a30f-3efc-4142-9668-7dc056a24d0c",
"outputId": "2e5e8e20-2b41-4183-f21f-dff503a03089"
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"page: 25\n",
"\n",
"\n",
"| Participant_ID | clinical Description Reference |\n",
"|----------------|--------------------------------|\n",
"| **Attribute** | **Value** |\n",
"| Age | 72.0 |\n",
"| Sex | Female |\n",
"| Education | 15 |\n",
"| Race | White |\n",
"| DX_bl | AD |\n",
"| DX | Dementia |\n",
"| ... | ... |\n",
"| APOE4 | 1.0 |\n",
"| TAU | 212.5 |\n",
"| ... | ... |\n",
"| MMSE | 29.0 |\n",
"| CDRSB | 0.0 |\n",
"| ... | ... |\n",
"| FLDSTRENG | 1.5 Tesla MRI |\n",
"| Ventricles | 84599 |\n",
"| Hippocampus | 5319 |\n",
"| ... | ... |\n",
"\n",
"**Basic Personal Information:** Subject 098_S_0896 is a 72.0-year-old Female who has completed 15 years of education. The ethnicity is Not Hisp/Latino and race is White. Marital status is Married. Initially diagnosed as AD, as of the date 2007-10-24, the final diagnosis was Dementia.\n",
"\n",
"**Biomarker Measurements:** The subject's genetic profile includes an ApoE4 status of 0.0...\n",
"\n",
"**Cognitive and Neurofunctional Assessments:** The Mini-Mental State Examination score stands at 29.0. The Clinical Dementia Rating, sum of boxes, is 1.0. ADAS 11 and 13 scores are 4.67 and 4.67 respectively, with a score of 1.0 in delayed word recall...\n",
"\n",
"**Volumetric Data:** Under MRI conditions at a field strength of 1.5 Tesla MRI Tesla, using Cross-Sectional FreeSurfer (FreeSurfer Version 4.3), the imaging data recorded includes ventricles volume at 84422.0, hippocampus volume at 6677.0, whole brain volume at 1147980.0, entorhinal cortex volume at 27820.0, fusiform gyrus volume at 19432.0, and middle temporal area volume at 24951.0. The intracranial volume measured is 1799580.0...\n",
"\n",
"Figure 2: An example of a patient table and its corresponding clinical description.\n",
"\n",
"----\n",
"\n",
"Skills. Mathematics, as a highly structured and logic-driven discipline, provides an ideal testing ground for evaluating this reasoning ability. To investigate o1-previews performance, we designed a series of tests covering various difficulty levels. We begin with high school-level math competition problems in this section, followed by college-level mathematics problems in the next section, allowing us to observe the models logical reasoning across varying levels of complexity.\n",
"\n",
"In this section, we selected two primary areas of mathematics: algebra and counting and probability in this section. We chose these two topics because of their heavy reliance on problem-solving skills and their frequent use in assessing logical and abstract thinking [46]. The dataset used in testing is from the MATH dataset [46]. The problems in the dataset cover a wide range of subjects, including Prealgebra, Intermediate Algebra, Algebra, Geometry, Counting and Probability, Number Theory, and Precalculus. Each problem is categorized based on difficulty, ranked from level 1 to 5, according to the Art of Problem Solving (AoPS). The dataset mainly comprises problems from various high school math competitions, including the American Mathematics Competitions (AMC) 10 and 12, as well as the American Invitational Mathematics Examination (AIME), and other similar contests. Each problem comes with detailed reference solutions, allowing for a comprehensive comparison of o1-previews solutions.\n",
"\n",
"In addition to evaluating the final answers produced by o1-preview, our analysis delves into the step-by-step reasoning process of the o1-previews solutions. By comparing o1-previews solutions with the datasets solutions, we assess its ability to engage in logical reasoning, handle abstract problem-solving tasks, and apply structured approaches to reach correct answers. This deeper analysis offers insights into o1-previews overall reasoning capabilities, using mathematics as a reliable indicator for logical and structured thought processes.\n"
]
}
],
"source": [
"# using GPT-4o\n",
"print(docs_gpt4o[0].get_content(metadata_mode=\"all\"))"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "1c75bb85",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"colab": {
"provenance": []
},
"kernelspec": {
"display_name": "llamacloud",
"language": "python",
"name": "llamacloud"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.4"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
@@ -0,0 +1,181 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<a href=\"https://colab.research.google.com/github/run-llama/llama_parse/blob/main/examples/demo_starter_parse_selected_pages.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Parse Selected Pages \n",
"\n",
"In this notebook we will demonstrate how to parse selected pages in a document using LlamaParse."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Installation\n",
"\n",
"Here we install `llama-parse` used for parsing the document"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"!pip install llama-parse"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Set API Key"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"# llama-parse is async-first, running the async code in a notebook requires the use of nest_asyncio\n",
"import nest_asyncio\n",
"\n",
"nest_asyncio.apply()\n",
"\n",
"import os\n",
"\n",
"# API access to llama-cloud\n",
"os.environ[\"LLAMA_CLOUD_API_KEY\"] = \"<YOUR LLAMACLOUD API KEY>\""
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Download Data\n",
"\n",
"Here we download Uber 2021 10K SEC filings data for the demonstration."
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"--2024-12-05 11:40:59-- https://raw.githubusercontent.com/run-llama/llama_index/main/docs/docs/examples/data/10k/uber_2021.pdf\n",
"Resolving raw.githubusercontent.com (raw.githubusercontent.com)... 2606:50c0:8000::154, 2606:50c0:8002::154, 2606:50c0:8003::154, ...\n",
"Connecting to raw.githubusercontent.com (raw.githubusercontent.com)|2606:50c0:8000::154|:443... connected.\n",
"HTTP request sent, awaiting response... 200 OK\n",
"Length: 1880483 (1.8M) [application/octet-stream]\n",
"Saving to: ./uber_2021.pdf\n",
"\n",
"./uber_2021.pdf 100%[===================>] 1.79M --.-KB/s in 0.1s \n",
"\n",
"2024-12-05 11:40:59 (14.2 MB/s) - ./uber_2021.pdf saved [1880483/1880483]\n",
"\n"
]
}
],
"source": [
"!wget 'https://raw.githubusercontent.com/run-llama/llama_index/main/docs/docs/examples/data/10k/uber_2021.pdf' -O './uber_2021.pdf'"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Parse the PDF file in selected pages\n",
"\n",
"Here we will parse the PDF file in selected pages and get the text in `markdown` format."
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Started parsing the file under job_id ad1087c1-b085-4dc7-9aa8-d13cdd440f2b\n"
]
}
],
"source": [
"from llama_parse import LlamaParse\n",
"\n",
"parser = LlamaParse(\n",
" target_pages=\"0,1,2\",\n",
" result_type=\"markdown\"\n",
")\n",
"\n",
"documents = parser.load_data('./uber_2021.pdf')"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[Document(id_='d0b34f4a-27ef-48e2-a92a-386e5e265f4c', embedding=None, metadata={}, excluded_embed_metadata_keys=[], excluded_llm_metadata_keys=[], relationships={}, metadata_template='{key}: {value}', metadata_separator='\\n', text='# UNITED STATES SECURITIES AND EXCHANGE COMMISSION\\n\\n# Washington, D.C. 20549\\n\\n# FORM 10-K\\n\\n(Mark One)\\n\\n☒ ANNUAL REPORT PURSUANT TO SECTION 13 OR 15(d) OF THE SECURITIES EXCHANGE ACT OF 1934\\n\\nFor the fiscal year ended December 31, 2021\\n\\nOR\\n\\n☐ TRANSITION REPORT PURSUANT TO SECTION 13 OR 15(d) OF THE SECURITIES EXCHANGE ACT OF 1934\\n\\nFor the transition period from _____ to _____\\n\\nCommission File Number: 001-38902\\n\\n# UBER TECHNOLOGIES, INC.\\n\\n(Exact name of registrant as specified in its charter)\\n\\nDelaware\\n\\n45-2647441\\n\\n(State or other jurisdiction of incorporation or organization) (I.R.S. Employer Identification No.)\\n\\n1515 3rd Street\\n\\nSan Francisco, California 94158\\n\\n(Address of principal executive offices, including zip code)\\n\\n(415) 612-8582\\n\\n(Registrants telephone number, including area code)\\n\\n# Securities registered pursuant to Section 12(b) of the Act:\\n\\n|Title of each class|Trading Symbol(s)|Name of each exchange on which registered|\\n|---|---|---|\\n|Common Stock, par value $0.00001 per share|UBER|New York Stock Exchange|\\n\\nSecurities registered pursuant to Section 12(g) of the Act: None\\n\\nIndicate by check mark whether the registrant is a well-known seasoned issuer, as defined in Rule 405 of the Securities Act. Yes ☒ No ☐\\n\\nIndicate by check mark whether the registrant is not required to file reports pursuant to Section 13 or Section 15(d) of the Act. Yes ☐ No ☒\\n\\nIndicate by check mark whether the registrant (1) has filed all reports required to be filed by Section 13 or 15(d) of the Securities Exchange Act of 1934 during the preceding 12 months (or for such shorter period that the registrant was required to file such reports), and (2) has been subject to such filing requirements for the past 90 days. Yes ☒ No ☐\\n\\nIndicate by check mark whether the registrant has submitted electronically every Interactive Data File required to be submitted pursuant to Rule 405 of Regulation S-T (§232.405 of this chapter) during the preceding 12 months (or for such shorter period that the registrant was required to submit such files). Yes ☒ No ☐\\n\\nIndicate by check mark whether the registrant is a large accelerated filer, an accelerated filer, a non-accelerated filer, a smaller reporting company, or an emerging growth company. See the definitions of “large accelerated filer,” “accelerated filer,” “smaller reporting company,” and “emerging growth company” in Rule 12b-2 of the Exchange Act.', mimetype='text/plain', start_char_idx=None, end_char_idx=None, metadata_seperator='\\n', text_template='{metadata_str}\\n\\n{content}'),\n",
" Document(id_='253b1141-a260-466e-b164-b39df67ef799', embedding=None, metadata={}, excluded_embed_metadata_keys=[], excluded_llm_metadata_keys=[], relationships={}, metadata_template='{key}: {value}', metadata_separator='\\n', text=\"# Large accelerated filer\\n\\n☒\\n\\n# Accelerated filer\\n\\n☐\\n\\n# Non-accelerated filer\\n\\n☐\\n\\n# Smaller reporting company\\n\\n☐\\n\\n# Emerging growth company\\n\\n☐\\n\\nIf an emerging growth company, indicate by check mark if the registrant has elected not to use the extended transition period for complying with any new or revised financial accounting standards provided pursuant to Section 13(a) of the Exchange Act.\\n\\n☐\\n\\nIndicate by check mark whether the registrant has filed a report on and attestation to its managements assessment of the effectiveness of its internal control over financial reporting under Section 404(b) of the Sarbanes-Oxley Act (15 U.S.C. 7262(b)) by the registered public accounting firm that prepared or issued\\n\\n☒\\n\\nIndicate by check mark whether the registrant is a shell company (as defined in Rule 12b-2 of the Exchange Act). Yes\\n\\n☐\\n\\nNo\\n\\n☒\\n\\nThe aggregate market value of the voting and non-voting common equity held by non-affiliates of the registrant as of June 30, 2021, the last business day of the registrant's most recently completed second fiscal quarter, was approximately $90.5 billion based upon the closing price reported for such date on the New York Stock Exchange.\\n\\nThe number of shares of the registrant's common stock outstanding as of February 22, 2022 was 1,954,464,088.\\n\\n# DOCUMENTS INCORPORATED BY REFERENCE\\n\\nPortions of the registrants Definitive Proxy Statement relating to the Annual Meeting of Stockholders are incorporated by reference into Part III of this Annual Report on Form 10-K where indicated. Such Definitive Proxy Statement will be filed with the Securities and Exchange Commission within 120 days after the end of the registrants fiscal year ended December 31, 2021.\", mimetype='text/plain', start_char_idx=None, end_char_idx=None, metadata_seperator='\\n', text_template='{metadata_str}\\n\\n{content}'),\n",
" Document(id_='ad988239-3ab5-498d-85ba-a29241db24d4', embedding=None, metadata={}, excluded_embed_metadata_keys=[], excluded_llm_metadata_keys=[], relationships={}, metadata_template='{key}: {value}', metadata_separator='\\n', text='# UBER TECHNOLOGIES, INC.\\n\\n# TABLE OF CONTENTS\\n\\n|Special Note Regarding Forward-Looking Statements|2|\\n|---|---|\\n|PART I|PART I|\\n|Item 1. Business|4|\\n|Item 1A. Risk Factors|11|\\n|Item 1B. Unresolved Staff Comments|46|\\n|Item 2. Properties|46|\\n|Item 3. Legal Proceedings|46|\\n|Item 4. Mine Safety Disclosures|47|\\n|PART II|PART II|\\n|Item 5. Market for Registrants Common Equity, Related Stockholder Matters and Issuer Purchases of Equity Securities|47|\\n|Item 6. [Reserved]|48|\\n|Item 7. Managements Discussion and Analysis of Financial Condition and Results of Operations|48|\\n|Item 7A. Quantitative and Qualitative Disclosures About Market Risk|69|\\n|Item 8. Financial Statements and Supplementary Data|70|\\n|Item 9. Changes in and Disagreements with Accountants on Accounting and Financial Disclosure|146|\\n|Item 9A. Controls and Procedures|147|\\n|Item 9B. Other Information|147|\\n|Item 9C. Disclosure Regarding Foreign Jurisdictions that Prevent Inspections|147|\\n|PART III|PART III|\\n|Item 10. Directors, Executive Officers and Corporate Governance|147|\\n|Item 11. Executive Compensation|147|\\n|Item 12. Security Ownership of Certain Beneficial Owners and Management and Related Stockholder Matters|148|\\n|Item 13. Certain Relationships and Related Transactions, and Director Independence|148|\\n|Item 14. Principal Accounting Fees and Services|148|\\n|PART IV|PART IV|\\n|Item 15. Exhibits, Financial Statement Schedules|148|\\n|Item 16. Form 10-K Summary|148|\\n|Exhibit Index|149|\\n|Signatures|152|', mimetype='text/plain', start_char_idx=None, end_char_idx=None, metadata_seperator='\\n', text_template='{metadata_str}\\n\\n{content}')]"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"documents"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "llamacloud",
"language": "python",
"name": "llamacloud"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.4"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
+1515
View File
File diff suppressed because one or more lines are too long
Binary file not shown.

After

Width:  |  Height:  |  Size: 195 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 363 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 343 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 185 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 254 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 650 KiB

+560
View File
@@ -0,0 +1,560 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "97c79c38-38a3-40f3-ba2e-250649347d63",
"metadata": {},
"source": [
"# Multimodal Parsing using GPT4o-mini\n",
"\n",
"<a href=\"https://colab.research.google.com/github/run-llama/llama_parse/blob/main/examples/multimodal/gpt4o_mini.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>\n",
"\n",
"This cookbook shows you how to use LlamaParse to parse any document with the multimodal capabilities of GPT4o-mini.\n",
"\n",
"LlamaParse allows you to plug in external, multimodal model vendors for parsing - we handle the error correction, validation, and scalability/reliability for you.\n"
]
},
{
"cell_type": "markdown",
"id": "15e60ecf-519c-41fc-911b-765adaf8bad4",
"metadata": {},
"source": [
"## Setup\n",
"\n",
"Download the data - the blog post from Meta on Llama3.1, in PDF form."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "91a9e532-1454-40e0-bbf0-fd442c350121",
"metadata": {},
"outputs": [],
"source": [
"import nest_asyncio\n",
"\n",
"nest_asyncio.apply()"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "0d9fb0aa-74cd-476f-8161-efd9e04248bf",
"metadata": {},
"outputs": [],
"source": [
"!wget \"https://www.dropbox.com/scl/fi/8iu23epvv3473im5rq19g/llama3.1_blog.pdf?rlkey=5u417tbdox4aip33fdubvni56&st=dzozd11e&dl=1\" -O \"data/llama3.1_blog.pdf\""
]
},
{
"cell_type": "markdown",
"id": "c70d420d-1778-4b0d-81e2-db09276e90cf",
"metadata": {},
"source": [
"![llama_blog_img](llama3.1-p5.png)"
]
},
{
"cell_type": "markdown",
"id": "4e29a9d7-5bd9-4fb8-8ec1-4c128a748662",
"metadata": {},
"source": [
"## Initialize LlamaParse\n",
"\n",
"Initialize LlamaParse in multimodal mode, and specify the vendor.\n",
"\n",
"**NOTE**: optionally you can specify the OpenAI API key. If you do so you will be charged our base LlamaParse price of 0.3c per page. If you don't then you will be charged 1.5c per page, as we will make the calls to gpt4o-mini for you and give you price predictability."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "dc921729-3446-42ca-8e1b-a6fd26195ed9",
"metadata": {},
"outputs": [],
"source": [
"from llama_index.core.schema import TextNode\n",
"from typing import List\n",
"import json\n",
"\n",
"\n",
"def get_text_nodes(json_list: List[dict]):\n",
" text_nodes = []\n",
" for idx, page in enumerate(json_list):\n",
" text_node = TextNode(text=page[\"md\"], metadata={\"page\": page[\"page\"]})\n",
" text_nodes.append(text_node)\n",
" return text_nodes\n",
"\n",
"\n",
"def save_jsonl(data_list, filename):\n",
" \"\"\"Save a list of dictionaries as JSON Lines.\"\"\"\n",
" with open(filename, \"w\") as file:\n",
" for item in data_list:\n",
" json.dump(item, file)\n",
" file.write(\"\\n\")\n",
"\n",
"\n",
"def load_jsonl(filename):\n",
" \"\"\"Load a list of dictionaries from JSON Lines.\"\"\"\n",
" data_list = []\n",
" with open(filename, \"r\") as file:\n",
" for line in file:\n",
" data_list.append(json.loads(line))\n",
" return data_list"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "f2e9d9cf-8189-4fcb-b34f-cde6cc0b59c8",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Started parsing the file under job_id bf3e7341-bb11-42d4-a5f7-bb5260ad792c\n"
]
}
],
"source": [
"from llama_parse import LlamaParse\n",
"\n",
"parser = LlamaParse(\n",
" result_type=\"markdown\",\n",
" use_vendor_multimodal_model=True,\n",
" vendor_multimodal_model_name=\"openai-gpt-4o-mini\",\n",
" invalidate_cache=True,\n",
")\n",
"json_objs = parser.get_json_result(\"./data/llama3.1_blog.pdf\")\n",
"json_list = json_objs[0][\"pages\"]\n",
"docs = get_text_nodes(json_list)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "96a81df0-1026-4e30-a930-f677dc31e344",
"metadata": {},
"outputs": [],
"source": [
"# Optional: Save\n",
"save_jsonl([d.dict() for d in docs], \"docs.jsonl\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "ee2e6920-8893-4b39-ae12-94d13c651406",
"metadata": {},
"outputs": [],
"source": [
"# Optional: Load\n",
"from llama_index.core import Document\n",
"\n",
"docs_dicts = load_jsonl(\"docs.jsonl\")\n",
"docs = [Document.parse_obj(d) for d in docs_dicts]"
]
},
{
"cell_type": "markdown",
"id": "4f3c51b0-7878-48d7-9bc3-02b516500128",
"metadata": {},
"source": [
"### Setup GPT-4o baseline\n",
"\n",
"For comparison, we will also parse the document using GPT-4o (3c per page)."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "6fc3f258-50ae-4988-b904-c105463a498f",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Started parsing the file under job_id 391ff280-08e5-4143-85f2-90ada287e26c\n"
]
}
],
"source": [
"from llama_parse import LlamaParse\n",
"\n",
"parser_gpt4o = LlamaParse(\n",
" result_type=\"markdown\",\n",
" use_vendor_multimodal_model=True,\n",
" vendor_multimodal_model=\"openai-gpt4o\",\n",
" # invalidate_cache=True\n",
")\n",
"json_objs_gpt4o = parser_gpt4o.get_json_result(\"./data/llama3.1_blog.pdf\")\n",
"# json_objs_gpt4o = parser.get_json_result(\"./data/llama2-p33.pdf\")\n",
"json_list_gpt4o = json_objs_gpt4o[0][\"pages\"]\n",
"docs_gpt4o = get_text_nodes(json_list_gpt4o)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "6a47f04e-12e1-4c80-a71d-ef7721f96401",
"metadata": {},
"outputs": [],
"source": [
"# Optional: Save\n",
"save_jsonl([d.dict() for d in docs_gpt4o], \"docs_gpt4o.jsonl\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "c38b5ca3-fa87-434b-b477-bf6a4962eb3d",
"metadata": {},
"outputs": [],
"source": [
"# Optional: Load\n",
"from llama_index.core import Document\n",
"\n",
"docs_gpt4o_dicts = load_jsonl(\"docs_gpt4o.jsonl\")\n",
"docs_gpt4o = [Document.parse_obj(d) for d in docs_gpt4o_dicts]"
]
},
{
"cell_type": "markdown",
"id": "44c20f7a-2901-4dd0-b635-a4b33c5664c1",
"metadata": {},
"source": [
"## View Results\n",
"\n",
"Let's visualize the results between GPT-4o-mini and GPT-4o along with the original document page.\n",
"\n",
"We see that \n",
"\n",
"**NOTE**: If you're using llama2-p33, just use `docs[0]`"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "778698aa-da7e-4081-b3b5-0372f228536f",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"page: 5\n",
"\n",
"# Llama 3.1 Model Evaluation\n",
"\n",
"## Category Benchmark\n",
"\n",
"| Benchmark | Gemma 2 9B IT | Mistral 7B Instruct | Llama 3.1 70B | Mistral 8x228B Instruct | GPT 3.5 Turbo |\n",
"|-------------------------------|----------------|----------------------|----------------|-------------------------|----------------|\n",
"| General | | | | | |\n",
"| MMLU (0-shot, CoT) | 73.0 | 72.3 | 86.0 | 79.9 | 69.8 |\n",
"| MMLU PRO (5-shot, CoT) | 48.3 | 36.9 | 66.4 | 56.3 | 49.2 |\n",
"| IFEval | 80.4 | 73.6 | 87.5 | 72.7 | 69.9 |\n",
"| Code | | | | | |\n",
"| HumanEval (0-shot) | 72.6 | 54.3 | 80.5 | 75.6 | 68.0 |\n",
"| MBPP EvalPlus (Human) (0-shot, CoT) | 72.8 | 71.7 | 86.0 | 78.6 | 82.0 |\n",
"| Math | | | | | |\n",
"| GSM8K | 84.5 | 76.7 | 95.1 | 88.2 | 81.6 |\n",
"| MATH (0-shot, CoT) | 51.9 | 44.3 | 70.8 | 54.1 | 43.1 |\n",
"| Reasoning | | | | | |\n",
"| ARC Challenge | 83.4 | 87.6 | 74.2 | 87.7 | 83.7 |\n",
"| GPA (0-shot) | 32.8 | 24.8 | 46.7 | 33.3 | 35.8 |\n",
"| Tool use | | | | | |\n",
"| BFCL | 76.1 | 64.0 | 94.8 | 81.4 | 78.0 |\n",
"| Noxus | 38.5 | 30.0 | 24.7 | 48.5 | 37.5 |\n",
"| Long context | | | | | |\n",
"| ZeroSCROLLS/QualiTY | 81.0 | - | 90.5 | - | - |\n",
"| InfiniteBench/En.MC | 65.1 | - | 78.2 | - | - |\n",
"| NHI/Multi-needle | 98.8 | - | 97.5 | - | - |\n",
"| Multilingual | | | | | |\n",
"| MGSM (0-shot) | 68.9 | 53.2 | 86.9 | 71.1 | 51.4 |\n",
"\n",
"## Llama 3.1 405B Human Evaluation\n",
"\n",
"| Comparison | Win Rate | Tie Rate | Loss Rate |\n",
"|----------------------------------------------|----------|----------|-----------|\n",
"| Llama 3.1 405B vs GPT-4-0125-Preview | 23.3% | 52.2% | 24.5% |\n",
"| Llama 3.1 405B vs GPT-4o | 19.1% | 51.7% | 29.2% |\n",
"| Llama 3.1 405B vs Claude 3.5 Sonnet | 24.9% | 50.8% | 24.2% |\n"
]
}
],
"source": [
"# using GPT4o-mini\n",
"print(docs[4].get_content(metadata_mode=\"all\"))"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "1511a30f-3efc-4142-9668-7dc056a24d0c",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"page: 5\n",
"\n",
"# Introducing Llama 3.1: Our most capable models to date\n",
"\n",
"## Meta\n",
"\n",
"| Category | Benchmark | Llama 3.1 8B | Gemma 2 9B IT | Mistral 7B Instruct | Llama 3.1 70B | Mixtral 8x22B Instruct | GPT 3.5 Turbo |\n",
"|----------|-----------|--------------|---------------|---------------------|---------------|-----------------------|---------------|\n",
"| General | MMLU (0-shot, CoT) | 73.0 | 72.3 (0-shot, non-CoT) | 60.5 | 86.0 | 79.9 | 69.8 |\n",
"| | MMLU PRO (5-shot, CoT) | 48.3 | 71.7 | 36.9 | 66.4 | 56.3 | 49.2 |\n",
"| | ITEval | 80.4 | 73.6 | 57.6 | 87.5 | 72.7 | 69.9 |\n",
"| Code | HumanEval (0-shot) | 72.6 | 54.3 | 40.2 | 80.5 | 75.6 | 68.0 |\n",
"| | MBPP EvalPlus (5-shot) (0-shot) | 72.8 | 71.7 | 49.5 | 86.0 | 78.6 | 82.0 |\n",
"| Math | GSM8K | 84.5 | 76.7 | 53.2 | 95.1 | 88.2 | 81.6 |\n",
"| | MATH (0-shot, CoT) | 51.9 | 44.3 | 13.0 | 68.0 | 54.1 | 43.1 |\n",
"| Reasoning | ARC Challenge (0-shot) | 83.4 | 87.6 | 74.2 | 94.8 | 88.7 | 83.7 |\n",
"| | GOPA (0-shot) | 32.8 | 40.8 | 28.0 | 46.7 | - | - |\n",
"| Tool use | BFCL | 76.1 | 60.3 | 60.4 | 94.8 | - | 85.9 |\n",
"| | Noxus | 38.5 | 30.0 | 24.7 | 56.7 | 48.5 | 37.2 |\n",
"| Long context | ZeroSCROLLS/QuaLITY | 81.0 | - | - | 90.5 | - | - |\n",
"| | InfiniteBench/En.MC | 65.1 | - | - | 78.2 | - | - |\n",
"| | NIH/Multi-needle | 98.8 | - | - | 97.5 | - | - |\n",
"| Multilingual | Multilingual MGSM (0-shot) | 68.9 | 53.2 | 29.9 | 86.9 | 71.1 | 51.4 |\n",
"\n",
"## Llama 3.1 405B Human Evaluation\n",
"\n",
"| Model Comparison | Win | Tie | Loss |\n",
"|------------------|-----|-----|------|\n",
"| Llama 3.1 405B vs GPT-4-0125-Preview | 23.3% | 52.2% | 24.5% |\n",
"| Llama 3.1 405B vs GPT-4o | 19.1% | 51.7% | 29.2% |\n",
"| Llama 3.1 405B vs Claude 3.5 Sonnet | 24.9% | 50.8% | 24.2% |\n",
"\n",
"https://ai.meta.com/blog/meta-llama-3-1/\n"
]
}
],
"source": [
"# using GPT-4o\n",
"print(docs_gpt4o[4].get_content(metadata_mode=\"all\"))"
]
},
{
"cell_type": "markdown",
"id": "705f7729-fa0f-4ca0-8562-c42afeaa8532",
"metadata": {},
"source": [
"## Setup RAG Pipeline\n",
"\n",
"Let's setup a RAG pipeline over this data.\n",
"\n",
"(we also use gpt4o-mini for the actual text synthesis step)."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "5a53ee5d-cc63-421b-8896-588c83edfcf0",
"metadata": {},
"outputs": [],
"source": [
"from llama_index.core import Settings\n",
"from llama_index.llms.openai import OpenAI\n",
"from llama_index.embeddings.openai import OpenAIEmbedding\n",
"\n",
"Settings.llm = OpenAI(model=\"gpt-4o-mini\")\n",
"Settings.embed_model = OpenAIEmbedding(model=\"text-embedding-3-large\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "60972d7a-7948-4ad7-89df-57004acee917",
"metadata": {},
"outputs": [],
"source": [
"# from llama_index.core import SummaryIndex\n",
"from llama_index.core import VectorStoreIndex\n",
"from llama_index.llms.openai import OpenAI\n",
"\n",
"index = VectorStoreIndex(docs)\n",
"query_engine = index.as_query_engine(similarity_top_k=5)\n",
"\n",
"index_gpt4o = VectorStoreIndex(docs_gpt4o)\n",
"query_engine_gpt4o = index_gpt4o.as_query_engine(similarity_top_k=5)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "e7df7bcb-1df4-4a01-88fc-2d596b1cc74d",
"metadata": {},
"outputs": [],
"source": [
"query = \"How does Llama3.1 compare against gpt-4o and Claude 3.5 Sonnet in human evals?\"\n",
"\n",
"response = query_engine.query(query)\n",
"response_gpt4o = query_engine_gpt4o.query(query)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "b7070a31-3bb8-4134-8338-20bc2fd6f3d6",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"In human evaluations, Llama 3.1 405B has a win rate of 19.1% against GPT-4o and 24.9% against Claude 3.5 Sonnet. The tie rates for Llama 3.1 405B are 51.7% against GPT-4o and 50.8% against Claude 3.5 Sonnet, while the loss rates are 29.2% against GPT-4o and 24.2% against Claude 3.5 Sonnet. This indicates that Llama 3.1 performs competitively in comparison to both models, with a notable number of ties.\n"
]
}
],
"source": [
"print(response)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "7bee8167-f021-4c87-8d28-9f40a4f7b69d",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"# Llama 3.1 Model Evaluation\n",
"\n",
"## Category Benchmark\n",
"\n",
"| Benchmark | Gemma 2 9B IT | Mistral 7B Instruct | Llama 3.1 70B | Mistral 8x228B Instruct | GPT 3.5 Turbo |\n",
"|-------------------------------|----------------|----------------------|----------------|-------------------------|----------------|\n",
"| General | | | | | |\n",
"| MMLU (0-shot, CoT) | 73.0 | 72.3 | 86.0 | 79.9 | 69.8 |\n",
"| MMLU PRO (5-shot, CoT) | 48.3 | 36.9 | 66.4 | 56.3 | 49.2 |\n",
"| IFEval | 80.4 | 73.6 | 87.5 | 72.7 | 69.9 |\n",
"| Code | | | | | |\n",
"| HumanEval (0-shot) | 72.6 | 54.3 | 80.5 | 75.6 | 68.0 |\n",
"| MBPP EvalPlus (Human) (0-shot, CoT) | 72.8 | 71.7 | 86.0 | 78.6 | 82.0 |\n",
"| Math | | | | | |\n",
"| GSM8K | 84.5 | 76.7 | 95.1 | 88.2 | 81.6 |\n",
"| MATH (0-shot, CoT) | 51.9 | 44.3 | 70.8 | 54.1 | 43.1 |\n",
"| Reasoning | | | | | |\n",
"| ARC Challenge | 83.4 | 87.6 | 74.2 | 87.7 | 83.7 |\n",
"| GPA (0-shot) | 32.8 | 24.8 | 46.7 | 33.3 | 35.8 |\n",
"| Tool use | | | | | |\n",
"| BFCL | 76.1 | 64.0 | 94.8 | 81.4 | 78.0 |\n",
"| Noxus | 38.5 | 30.0 | 24.7 | 48.5 | 37.5 |\n",
"| Long context | | | | | |\n",
"| ZeroSCROLLS/QualiTY | 81.0 | - | 90.5 | - | - |\n",
"| InfiniteBench/En.MC | 65.1 | - | 78.2 | - | - |\n",
"| NHI/Multi-needle | 98.8 | - | 97.5 | - | - |\n",
"| Multilingual | | | | | |\n",
"| MGSM (0-shot) | 68.9 | 53.2 | 86.9 | 71.1 | 51.4 |\n",
"\n",
"## Llama 3.1 405B Human Evaluation\n",
"\n",
"| Comparison | Win Rate | Tie Rate | Loss Rate |\n",
"|----------------------------------------------|----------|----------|-----------|\n",
"| Llama 3.1 405B vs GPT-4-0125-Preview | 23.3% | 52.2% | 24.5% |\n",
"| Llama 3.1 405B vs GPT-4o | 19.1% | 51.7% | 29.2% |\n",
"| Llama 3.1 405B vs Claude 3.5 Sonnet | 24.9% | 50.8% | 24.2% |\n"
]
}
],
"source": [
"print(response.source_nodes[1].get_content())"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "5f9fef7f-510b-46a5-8716-f5616f542035",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"In human evaluations, Llama 3.1 405B shows competitive performance against GPT-4o and Claude 3.5 Sonnet. Specifically, when compared to GPT-4o, Llama 3.1 won 19.1% of the time, tied 51.7%, and lost 29.2%. Against Claude 3.5 Sonnet, it won 24.9% of the time, tied 50.8%, and lost 24.2%. This indicates that Llama 3.1 performs comparably in real-world scenarios against these leading models.\n"
]
}
],
"source": [
"print(response_gpt4o)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "d40f9dd4-2dd4-4fa5-b636-1f901dc1601b",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"# Introducing Llama 3.1: Our most capable models to date\n",
"\n",
"## Meta\n",
"\n",
"| Category | Benchmark | Llama 3.1 8B | Gemma 2 9B IT | Mistral 7B Instruct | Llama 3.1 70B | Mixtral 8x22B Instruct | GPT 3.5 Turbo |\n",
"|----------|-----------|--------------|---------------|---------------------|---------------|-----------------------|---------------|\n",
"| General | MMLU (0-shot, CoT) | 73.0 | 72.3 (0-shot, non-CoT) | 60.5 | 86.0 | 79.9 | 69.8 |\n",
"| | MMLU PRO (5-shot, CoT) | 48.3 | 71.7 | 36.9 | 66.4 | 56.3 | 49.2 |\n",
"| | ITEval | 80.4 | 73.6 | 57.6 | 87.5 | 72.7 | 69.9 |\n",
"| Code | HumanEval (0-shot) | 72.6 | 54.3 | 40.2 | 80.5 | 75.6 | 68.0 |\n",
"| | MBPP EvalPlus (5-shot) (0-shot) | 72.8 | 71.7 | 49.5 | 86.0 | 78.6 | 82.0 |\n",
"| Math | GSM8K | 84.5 | 76.7 | 53.2 | 95.1 | 88.2 | 81.6 |\n",
"| | MATH (0-shot, CoT) | 51.9 | 44.3 | 13.0 | 68.0 | 54.1 | 43.1 |\n",
"| Reasoning | ARC Challenge (0-shot) | 83.4 | 87.6 | 74.2 | 94.8 | 88.7 | 83.7 |\n",
"| | GOPA (0-shot) | 32.8 | 40.8 | 28.0 | 46.7 | - | - |\n",
"| Tool use | BFCL | 76.1 | 60.3 | 60.4 | 94.8 | - | 85.9 |\n",
"| | Noxus | 38.5 | 30.0 | 24.7 | 56.7 | 48.5 | 37.2 |\n",
"| Long context | ZeroSCROLLS/QuaLITY | 81.0 | - | - | 90.5 | - | - |\n",
"| | InfiniteBench/En.MC | 65.1 | - | - | 78.2 | - | - |\n",
"| | NIH/Multi-needle | 98.8 | - | - | 97.5 | - | - |\n",
"| Multilingual | Multilingual MGSM (0-shot) | 68.9 | 53.2 | 29.9 | 86.9 | 71.1 | 51.4 |\n",
"\n",
"## Llama 3.1 405B Human Evaluation\n",
"\n",
"| Model Comparison | Win | Tie | Loss |\n",
"|------------------|-----|-----|------|\n",
"| Llama 3.1 405B vs GPT-4-0125-Preview | 23.3% | 52.2% | 24.5% |\n",
"| Llama 3.1 405B vs GPT-4o | 19.1% | 51.7% | 29.2% |\n",
"| Llama 3.1 405B vs Claude 3.5 Sonnet | 24.9% | 50.8% | 24.2% |\n",
"\n",
"https://ai.meta.com/blog/meta-llama-3-1/\n"
]
}
],
"source": [
"print(response_gpt4o.source_nodes[1].get_content())"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "llama_parse",
"language": "python",
"name": "llama_parse"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
+443
View File
@@ -0,0 +1,443 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Building a Multimodal RAG Pipeline over an Auto Insurance Claim\n",
"\n",
"<a href=\"https://colab.research.google.com/github/run-llama/llama_parse/blob/main/examples/multimodal/insurance_rag.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"This cookbook shows how to use LlamaParse and OpenAI's multimodal GPT-4o model to parse auto insurance claim documents that contain complex tabular data. In this example, we will use an auto insurance claim template form, which contains complex tabular inputs regarding information about the location of the accident, accident description, information about vehicles of both parties, and injury information. The template is shown below.\n",
"\n",
"![Auto Insurance Template](https://github.com/user-attachments/assets/aadbaa5b-16d2-490f-be35-f8ee06571633)\n",
"\n",
"This example demonstrates how LlamaParse can be used on insurance documents, which often contains complex tabular data. We parse these tabluar PDF files into markdown-formatted tables, which can be indexed and queried over with a `VectorStoreIndex`. This can help insurance companies accelerate the process of gathering information about car accidents from insurance claim documents."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Install and Setup\n",
"\n",
"Install LlamaIndex, download the data, and apply `nest_asyncio`."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"%pip install llama-index"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"!wget https://github.com/user-attachments/files/16536240/claims.zip -O claims.zip\n",
"!unzip -o claims.zip\n",
"!rm claims.zip"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import nest_asyncio\n",
"\n",
"nest_asyncio.apply()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Set up your OpenAI and LlamaCloud keys."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import os\n",
"\n",
"os.environ[\"OPENAI_API_KEY\"] = \"<Your OpenAI API Key>\"\n",
"os.environ[\"LLAMA_CLOUD_API_KEY\"] = \"<Your Llamacloud API Key>\""
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Code Implementation"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Set up LlamaParse. We want to parse the PDF files into markdown, translating the tabular data into markdown tables. To ensure accuracy, we will use the GPT-4o multimodal model to parse the PDFs."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from llama_parse import LlamaParse\n",
"\n",
"parser = LlamaParse(\n",
" result_type=\"markdown\",\n",
" parsing_instruction=\"This is an auto insurance claim document.\",\n",
" use_vendor_multimodal_model=True,\n",
" vendor_multimodal_model_name=\"openai-gpt4o\",\n",
" show_progress=True,\n",
")\n",
"\n",
"CLAIMS_DIR = \"claims\"\n",
"\n",
"\n",
"def get_claims_files(claims_dir=CLAIMS_DIR) -> list[str]:\n",
" files = []\n",
" for f in os.listdir(claims_dir):\n",
" fname = os.path.join(claims_dir, f)\n",
" if os.path.isfile(fname):\n",
" files.append(fname)\n",
" return files\n",
"\n",
"\n",
"files = get_claims_files() # get all files from the claims/ directory\n",
"md_json_objs = parser.get_json_result(\n",
" files\n",
") # extract markdown data for insurance claim document\n",
"parser.get_images(\n",
" md_json_objs, download_path=\"data_images\"\n",
") # extract images from PDFs and save them to ./data_images/"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# extract list of pages for insurance claim doc\n",
"md_json_list = []\n",
"for obj in md_json_objs:\n",
" md_json_list.extend(obj[\"pages\"])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Create helper functions to create a list of `TextNode`s from the markdown tables to feed into the `VectorStoreIndex`."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import re\n",
"from pathlib import Path\n",
"import typing as t\n",
"from llama_index.core.schema import TextNode, ImageNode\n",
"\n",
"\n",
"def get_page_number(file_name):\n",
" \"\"\"Gets page number of images using regex on file names\"\"\"\n",
" match = re.search(r\"-page-(\\d+)\\.jpg$\", str(file_name))\n",
" if match:\n",
" return int(match.group(1))\n",
" return 0\n",
"\n",
"\n",
"def _get_sorted_image_files(image_dir):\n",
" \"\"\"Get image files sorted by page.\"\"\"\n",
" raw_files = [f for f in list(Path(image_dir).iterdir()) if f.is_file()]\n",
" sorted_files = sorted(raw_files, key=get_page_number)\n",
" return sorted_files\n",
"\n",
"\n",
"def get_text_nodes(json_dicts, image_dir) -> t.List[TextNode]:\n",
" \"\"\"Creates nodes from json + images\"\"\"\n",
"\n",
" nodes = []\n",
"\n",
" docs = [doc[\"md\"] for doc in json_dicts] # extract text\n",
" image_files = _get_sorted_image_files(image_dir) # extract images\n",
"\n",
" for idx, doc in enumerate(docs):\n",
" # adds both a text node and the corresponding image node (jpg of the page) for each page\n",
" node = TextNode(\n",
" text=doc,\n",
" metadata={\"image_path\": str(image_files[idx]), \"page_num\": idx + 1},\n",
" )\n",
" image_node = ImageNode(\n",
" image_path=str(image_files[idx]),\n",
" metadata={\"page_num\": idx + 1, \"text_node_id\": node.id_},\n",
" )\n",
" nodes.extend([node, image_node])\n",
"\n",
" return nodes\n",
"\n",
"\n",
"text_nodes = get_text_nodes(md_json_list, \"data_images\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Index the documents."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from llama_index.core import (\n",
" VectorStoreIndex,\n",
" StorageContext,\n",
" load_index_from_storage,\n",
" Settings,\n",
")\n",
"from llama_index.embeddings.openai import OpenAIEmbedding\n",
"from llama_index.llms.openai import OpenAI\n",
"\n",
"embed_model = OpenAIEmbedding(model=\"text-embedding-3-large\")\n",
"llm = OpenAI(\"gpt-4o\")\n",
"\n",
"Settings.llm = llm\n",
"Settings.embed_model = embed_model\n",
"\n",
"if not os.path.exists(\"storage_insurance\"):\n",
" index = VectorStoreIndex(text_nodes, embed_model=embed_model)\n",
" index.storage_context.persist(persist_dir=\"./storage_insurance\")\n",
"else:\n",
" ctx = StorageContext.from_defaults(persist_dir=\"./storage_insurance\")\n",
" index = load_index_from_storage(ctx)\n",
"\n",
"query_engine = index.as_query_engine()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Example queries are shown below."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [
{
"data": {
"text/markdown": [
"Michael Johnson filed the insurance claim for the accident that happened on Sunset Blvd."
],
"text/plain": [
"<IPython.core.display.Markdown object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"from IPython.display import display, Markdown\n",
"\n",
"response = query_engine.query(\n",
" \"Who filed the insurance claim for the accident that happened on Sunset Blvd?\"\n",
")\n",
"display(Markdown(str(response)))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [
{
"data": {
"text/markdown": [
"Ms. Patel's accident occurred on March 10, 2023, at approximately 9:15 AM in the Boise Towne Square Mall parking lot. She was heading west at a parking space and, after checking her mirrors and blind spots, did not see any approaching vehicles. However, Michael Chen, the driver of another vehicle, was driving too fast through the parking lot and failed to stop in time, resulting in a collision with Ms. Patel's vehicle. This caused significant damage to the rear bumper and trunk of her car."
],
"text/plain": [
"<IPython.core.display.Markdown object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"response = query_engine.query(\"How did Ms. Patel's accident happen?\")\n",
"display(Markdown(str(response)))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [
{
"data": {
"text/markdown": [
"Mr. Johnson's red sedan, a 2020 Honda Accord, was damaged on the front passenger side, including a dented fender and a broken headlight. The estimated repair cost is $3,500."
],
"text/plain": [
"<IPython.core.display.Markdown object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"response = query_engine.query(\"How was Mr. Johnson's red sedan damaged?\")\n",
"display(Markdown(str(response)))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [
{
"data": {
"text/markdown": [
"Mr. Doe's Honda Accord sustained damage to the front bumper, hood, fenders, head/tail lights, windshield, and doors."
],
"text/plain": [
"<IPython.core.display.Markdown object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"response = query_engine.query(\"How was Mr. Doe's Honda Accord damaged?\")\n",
"display(Markdown(str(response)))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [
{
"data": {
"text/markdown": [
"The witness for Ms. Patel's accident is Sophia Rodriguez. She can be contacted at 5554567890."
],
"text/plain": [
"<IPython.core.display.Markdown object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"response = query_engine.query(\n",
" \"Who are some witnesses for the Ms. Patel's accident and how can we contact them?\"\n",
")\n",
"display(Markdown(str(response)))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [
{
"data": {
"text/markdown": [
"Yes, Ms. Johnson sustained injuries. She experienced minor injuries, including a bruised knee and some whiplash."
],
"text/plain": [
"<IPython.core.display.Markdown object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"response = query_engine.query(\n",
" \"Did Ms. Johnson sustain any injuries? If so, what were those injuries?\"\n",
")\n",
"display(Markdown(str(response)))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [
{
"data": {
"text/markdown": [
"Mark Johnson is liable for the damages from the accident on Lombard Street. He was driving a delivery van that collided with the rear of Emily Rodriguez's vehicle. In rear-end collisions, the driver who hits the vehicle in front is typically at fault because they are expected to maintain a safe distance and be able to stop in time to avoid a collision."
],
"text/plain": [
"<IPython.core.display.Markdown object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"chat_engine = index.as_chat_engine()\n",
"response = chat_engine.chat(\n",
" \"Given the accident that happened on Lombard Street, name a party that is liable for the damages and explain why.\"\n",
")\n",
"display(Markdown(str(response)))"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "llama-parse-5ZmnAQ0r-py3.11",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
+371
View File
@@ -0,0 +1,371 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Building a RAG Pipeline over Legal Documents\n",
"\n",
"<a href=\"https://colab.research.google.com/github/run-llama/llama_parse/blob/main/examples/multimodal/legal_rag.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>\n",
"\n",
"This example shows how LlamaParse and LlamaIndex can be used to parse various types of legal documents, which may contain complex tabular data. The advantage of this is being able to quickly retrieve a specific answer to a legal question with comprehensive context — knowledge of precedents, statutes, and cases presented in the given documents. A user can quickly find the answer to or find out more details about a specific legal question without having to read through the often long documents by using LLMs.\n",
"\n",
"In this example, we will be using legal documents from the archive of the Library of Congress ([link to dataset](https://www.loc.gov/item/2020445568/)). These documents vary by format, with some containing pure text and others containing headings, sections, and large tables. This shows how LlamaParse can parse a wide variety of documents and still retrieve accurate results.\n",
"\n",
"The documents in this example include:\n",
"- [APA Program Report](https://www.irs.gov/pub/irs-apa/a_2003-19.pdf)\n",
"- [2004 Report on the CRA performance of Barre Savings Bank in Barre, MA](https://github.com/user-attachments/files/16536412/barre_savings_bank_evaluation.pdf)\n",
"- [2016 Energy Supply/Demand Forecast](https://github.com/user-attachments/files/16536415/energy_supply_demand.pdf)\n",
"- [Transcript of Senate Committee Hearing about Foreign Markets](https://github.com/user-attachments/files/16536422/foreign_markets.pdf)\n",
"- [A Motion To Stay for an Indiana Court Case](https://github.com/user-attachments/files/16536427/motion_to_stay.pdf)\n",
"- [Article About an OC Representative's Bill to Introduce Offshore Drilling to CA](https://github.com/user-attachments/files/16536437/oc_bill_offshore_drilling.pdf)\n",
"- [Charter of the Subcommittee on Ocean Science and Technology](https://github.com/user-attachments/files/16536445/ost_subcommittee_charter.pdf)\n",
"- [US Immigration Case](https://github.com/user-attachments/files/16536446/us_immigration_case.pdf)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Setup and Installation"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Install LlamaIndex, download the data, and apply `nest_asyncio`."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"%pip install llama-index llama-parse"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"!wget https://github.com/user-attachments/files/16447759/data.zip -O data.zip\n",
"!unzip -o data.zip\n",
"!rm data.zip"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import nest_asyncio\n",
"\n",
"nest_asyncio.apply()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Set up your OpenAI and LlamaCloud keys."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import os\n",
"\n",
"os.environ[\"OPENAI_API_KEY\"] = \"<Your OpenAI API Key>\"\n",
"os.environ[\"LLAMA_CLOUD_API_KEY\"] = \"<Your LlamaCloud API Key>\""
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Code Implementation\n",
"\n",
"Set up LlamaParse. We want to parse the PDF files into markdown, translating the tabular data into markdown tables. To ensure accuracy, we will use the GPT-4o multimodal model to parse the PDFs."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from llama_parse import LlamaParse\n",
"\n",
"parser = LlamaParse(\n",
" result_type=\"markdown\",\n",
" parsing_instruction=\"Provided are a series of US legal documents.\",\n",
" use_vendor_multimodal_model=True,\n",
" vendor_multimodal_model_name=\"openai-gpt4o\",\n",
" show_progress=True,\n",
")\n",
"\n",
"DATA_DIR = \"data\"\n",
"\n",
"\n",
"def get_data_files(data_dir=DATA_DIR) -> list[str]:\n",
" files = []\n",
" for f in os.listdir(data_dir):\n",
" fname = os.path.join(data_dir, f)\n",
" if os.path.isfile(fname):\n",
" files.append(fname)\n",
" return files\n",
"\n",
"\n",
"files = get_data_files()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Load data from parser into documents containing parsed Markdown text from the legal document PDFs."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"Parsing files: 100%|██████████| 8/8 [01:25<00:00, 10.67s/it]\n"
]
}
],
"source": [
"documents = parser.load_data(\n",
" files,\n",
" extra_info={\"name\": \"US legal documents provided by the Library of Congress.\"},\n",
")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Setup LlamaIndex. Set the default LLM to GPT-4o (a multi-modal model), and create an index from the documents, and persist these documents to disk. If these documents have already been persisted, then load index from the persisted docs."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from llama_index.core import (\n",
" VectorStoreIndex,\n",
" StorageContext,\n",
" load_index_from_storage,\n",
" Settings,\n",
")\n",
"from llama_index.embeddings.openai import OpenAIEmbedding\n",
"from llama_index.llms.openai import OpenAI\n",
"\n",
"embed_model = OpenAIEmbedding(model=\"text-embedding-3-large\")\n",
"llm = OpenAI(\"gpt-4o\")\n",
"\n",
"Settings.llm = llm\n",
"Settings.embed_model = embed_model\n",
"\n",
"if not os.path.exists(\"storage_legal\"):\n",
" index = VectorStoreIndex(documents, embed_model=embed_model)\n",
" index.storage_context.persist(persist_dir=\"./storage_legal\")\n",
"else:\n",
" ctx = StorageContext.from_defaults(persist_dir=\"./storage_legal\")\n",
" index = load_index_from_storage(ctx)\n",
"\n",
"query_engine = index.as_query_engine()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Example Queries"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [
{
"data": {
"text/markdown": [
"The majority of Barre Savings Bank's loans went to residential real estate, specifically 1-4 family mortgages, which accounted for 78.7 percent of the total loans."
],
"text/plain": [
"<IPython.core.display.Markdown object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"from IPython.display import display, Markdown\n",
"\n",
"response = query_engine.query(\n",
" \"Where did the majority of Barre Savings Bank's loans go?\"\n",
")\n",
"display(Markdown(str(response)))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [
{
"data": {
"text/markdown": [
"Mr. Kubarych believes foreign markets are important because they are attractive to foreign investors for the same reasons they are attractive to Americans. The economic data is strong, and the high tech boom has created a positive perception that overshadows longer-term vulnerabilities. Additionally, foreign investors have high expectations for the U.S. to maintain a firm monetary policy in response to inflation and to act as a superpower rather than pursuing narrow nationalist economic policies."
],
"text/plain": [
"<IPython.core.display.Markdown object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"response = query_engine.query(\n",
" \"Why does Mr. Kubarych believe foreign markets are so important?\"\n",
")\n",
"display(Markdown(str(response)))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [
{
"data": {
"text/markdown": [
"House Speaker Nancy Pelosi and the Democratic majority are against the proposal of offshore drilling in California. Pelosi stated that offshore drilling is \"off the table,\" and Democrats have been consistently unwilling to bend environmental rules. They argue that oil companies are not using the 68 million acres of federal lands already leased to them, either because it takes a long time or they lack the necessary equipment."
],
"text/plain": [
"<IPython.core.display.Markdown object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"response = query_engine.query(\n",
" \"Who is against the proposal of offshore drilling in CA and why?\"\n",
")\n",
"display(Markdown(str(response)))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [
{
"data": {
"text/markdown": [
"The purpose of the Ocean Science and Technology Subcommittee (SOST) is to advise and assist the Committee on Environment, Natural Resources, and Sustainability on national issues of ocean science and technology. The SOST aims to contribute to the goals for Federal ocean science and technology by developing coordinated interagency strategies. It also retains the functions of the previously-chartered Joint Subcommittee on Ocean Science and Technology and serves as the Ocean Science and Technology Interagency Policy Committee for the National Ocean Council."
],
"text/plain": [
"<IPython.core.display.Markdown object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"response = query_engine.query(\n",
" \"What is the purpose of the Ocean Science and Technology Subcommittee?\"\n",
")\n",
"display(Markdown(str(response)))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [
{
"data": {
"text/markdown": [
"The immigration appeal is dismissed because the petitioner is not a U.S. citizen, and therefore, is not eligible to file a Petition for Alien Fiancé(e) (Form I-129F) on behalf of the beneficiary. The relevant law provides nonimmigrant classification only to aliens who are the fiancé(e)s of U.S. citizens."
],
"text/plain": [
"<IPython.core.display.Markdown object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"response = query_engine.query(\"Why is the immigration appeal dismissed?\")\n",
"display(Markdown(str(response)))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [
{
"data": {
"text/markdown": [
"An advance pricing agreement (APA) is a binding contract between a taxpayer and the IRS that establishes an approved transfer pricing method (TPM) for specific transactions. This agreement aims to prevent disputes over transfer pricing by ensuring that the taxpayer's tax returns for the covered years are consistent with the agreed TPM. APAs can be unilateral, involving only the taxpayer and the IRS, or bilateral/multilateral, involving agreements with one or more foreign tax authorities to avoid double taxation."
],
"text/plain": [
"<IPython.core.display.Markdown object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"response = query_engine.query(\"What is an advance pricing agreement?\")\n",
"display(Markdown(str(response)))"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "llama-parse-5ZmnAQ0r-py3.11",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 170 KiB

File diff suppressed because it is too large Load Diff
Binary file not shown.

After

Width:  |  Height:  |  Size: 580 KiB

@@ -165,7 +165,18 @@
"execution_count": null,
"id": "ef82a985-4088-4bb7-9a21-0318e1b9207d",
"metadata": {},
"outputs": [],
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Parsing text...\n",
"Started parsing the file under job_id 62f157a9-9ef9-4e5b-95ac-67093fa25800\n",
"..........Parsing PDF file...\n",
"Started parsing the file under job_id 1ddd5654-062b-4e19-b488-d66efc9c509d\n"
]
}
],
"source": [
"print(f\"Parsing text...\")\n",
"docs_text = parser_text.load_data(\"data/conocophillips.pdf\")\n",
@@ -174,42 +185,36 @@
"md_json_list = md_json_objs[0][\"pages\"]"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "7506b603-c01f-45de-b354-4a0728dde03c",
"metadata": {},
"outputs": [],
"source": [
"print(docs_text[0].get_content())"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "5318fb7b-fe6a-4a8a-b82e-4ed7b4512c37",
"metadata": {},
"outputs": [],
"source": [
"print(md_json_list[10][\"md\"])"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "7a46a73e-c6e2-4b0b-bd10-31b0d3e4b70f",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"dict_keys(['page', 'text', 'md', 'images', 'items'])\n"
"# Commitment to Disciplined Reinvestment Rate\n",
"\n",
"| Period | Description | Reinvestment Rate | WTI Average |\n",
"|--------------|--------------------------------------|-------------------|-------------|\n",
"| 2012-2016 | Industry Growth Focus | >100% | ~$75/BBL |\n",
"| 2017-2022 | ConocoPhillips Strategy Reset | <60% | ~$63/BBL |\n",
"| 2023E | | | at $80/BBL |\n",
"| 2024-2028 | Disciplined Reinvestment Rate | ~50% | at $60/BBL |\n",
"| 2029-2032 | | ~6% CFO CAGR | at $60/BBL |\n",
"\n",
"- **Historic Reinvestment Rate**: Gray bars\n",
"- **Reinvestment Rate at $60/BBL WTI**: Blue bars\n",
"- **Reinvestment Rate at $80/BBL WTI**: Dashed blue lines\n",
"\n",
"Reinvestment rate and cash from operations (CFO) are non-GAAP measures. Definitions and reconciliations are included in the Appendix.\n"
]
}
],
"source": [
"print(md_json_list[1].keys())"
"print(md_json_list[10][\"md\"])"
]
},
{
@@ -299,7 +304,7 @@
" image_files = _get_sorted_image_files(image_dir) if image_dir is not None else None\n",
" md_texts = [d[\"md\"] for d in json_dicts] if json_dicts is not None else None\n",
"\n",
" doc_chunks = docs[0].text.split(\"---\")\n",
" doc_chunks = [c for d in docs for c in d.text.split(\"---\")]\n",
" for idx, doc_chunk in enumerate(doc_chunks):\n",
" chunk_metadata = {\"page_num\": idx + 1}\n",
" if image_files is not None:\n",
@@ -339,25 +344,23 @@
"output_type": "stream",
"text": [
"page_num: 11\n",
"image_path: data_images/d9137e19-3974-4b5d-998f-dac0cf29dd9d-page-10.jpg\n",
"image_path: data_images/1ddd5654-062b-4e19-b488-d66efc9c509d-page_39.jpg\n",
"parsed_text_markdown: # Commitment to Disciplined Reinvestment Rate\n",
"\n",
"| Year | Reinvestment Rate | WTI Average Price | Reinvestment Rate at $60/BBL WTI | Reinvestment Rate at $80/BBL WTI |\n",
"|------------|-------------------|-------------------|----------------------------------|----------------------------------|\n",
"| 2012-2016 | >100% | ~$75/BBL | | |\n",
"| 2017-2022 | <60% | ~$63/BBL | | |\n",
"| 2023E | | | | at $80/BBL WTI |\n",
"| 2024-2028 | | | at $60/BBL WTI | at $80/BBL WTI |\n",
"| 2029-2032 | | | at $60/BBL WTI | at $80/BBL WTI |\n",
"| Period | Description | Reinvestment Rate | WTI Average |\n",
"|--------------|--------------------------------------|-------------------|-------------|\n",
"| 2012-2016 | Industry Growth Focus | >100% | ~$75/BBL |\n",
"| 2017-2022 | ConocoPhillips Strategy Reset | <60% | ~$63/BBL |\n",
"| 2023E | | | at $80/BBL |\n",
"| 2024-2028 | Disciplined Reinvestment Rate | ~50% | at $60/BBL |\n",
"| 2029-2032 | | ~6% CFO CAGR | at $60/BBL |\n",
"\n",
"**Disciplined Reinvestment Rate is the Foundation for Superior Returns on and of Capital, while Driving Durable CFO Growth**\n",
"- **Historic Reinvestment Rate**: Gray bars\n",
"- **Reinvestment Rate at $60/BBL WTI**: Blue bars\n",
"- **Reinvestment Rate at $80/BBL WTI**: Dashed blue lines\n",
"\n",
"- ~50% 10-Year Reinvestment Rate\n",
"- ~6% CFO CAGR 2024-2032 at $60/BBL WTI Mid-Cycle Planning Price\n",
"\n",
"**Note:** Reinvestment rate and cash from operations (CFO) are non-GAAP measures. Definitions and reconciliations are included in the Appendix.\n",
"parsed_text: \n",
"Commitment to Disciplined Reinvestment Rate\n",
"Reinvestment rate and cash from operations (CFO) are non-GAAP measures. Definitions and reconciliations are included in the Appendix.\n",
"parsed_text: Commitment to Disciplined Reinvestment Rate\n",
" Industry ConocoPhillips\n",
" Strategy Reset Disciplined Reinvestment Rate is the Foundation for Superior\n",
" Growth Focus Returns on and of Capital, while Driving Durable CFO Growth\n",
@@ -374,7 +377,7 @@
" 0%\n",
" 2012-2016 2017-2022 2023E 2024-2028 2029-2032\n",
" Historic Reinvestment Rate Reinvestment Rate at $60/BBL WTI Reinvestment Rate at $80/BBL WTI\n",
" Reinvestment rate andcashfrom operations (CFO) are non-GAAP measures: Definitions and reconciliations are included in the Appendix ConocoPhillips\n"
" Reinvestment rate and cash from operations (CFO) are non-GAAP measures: Definitions and reconciliations are included in the Appendix ConocoPhillips\n"
]
}
],
@@ -397,7 +400,17 @@
"execution_count": null,
"id": "6ea53c31-0e38-421c-8d9b-0e3adaa1677e",
"metadata": {},
"outputs": [],
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"/Users/jerryliu/Programming/gpt_index/.venv/lib/python3.10/site-packages/tiktoken/core.py:50: RuntimeWarning: coroutine 'LlamaParse.aload_data' was never awaited\n",
" self._core_bpe = _tiktoken.CoreBPE(mergeable_ranks, special_tokens, pat_str)\n",
"RuntimeWarning: Enable tracemalloc to get the object allocation traceback\n"
]
}
],
"source": [
"import os\n",
"from llama_index.core import (\n",
@@ -588,7 +601,7 @@
" Under $40/BBL Cost of Supply 10-Year Plan Cumulative Production (BBOE)\n",
" S50 S32/BBL Lower 48 Alaska\n",
" Average Cost of Supply\n",
" 3$40 GKA GWA\n",
" 3 $40 GKA GWA\n",
" GPA WNS\n",
" $30 EMENA\n",
" 3 Norway\n",
@@ -599,7 +612,7 @@
" APLNG Montney\n",
" S0\n",
" 10 15 20 Bakken\n",
" Resource (BBOE) Eagle Ford Other MalaysiaChina Surmont\n",
" Resource (BBOE) Eagle Ford Other Malaysia ChinaSurmont\n",
" Lower 48 Canada Alaska EMENA Asia Pacific\n",
"Costs assumemid-cycle price environment of S60/BBL WTI:\n",
" ConocoPhillips\n"
@@ -687,70 +700,126 @@
{
"cell_type": "code",
"execution_count": null,
"id": "1cdce5d8-6bb3-4cd3-929d-1cec249d9052",
"id": "d78e53cf-35cb-4ef8-b03e-1b47ba15ae64",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Added user message to memory: How does the Conoco Phillips capex/EUR in the delaware basin compare against other competitors?\n",
"Added user message to memory: Tell me about the diverse geographies where Conoco Phillips has a production base\n",
"=== Calling Function ===\n",
"Calling function: vector_tool with args: {\"input\": \"Conoco Phillips capex/EUR in the Delaware Basin\"}\n",
"Calling function: vector_tool with args: {\"input\": \"Conoco Phillips production base geographies\"}\n",
"=== Function Output ===\n",
"The ConocoPhillips capex/EUR in the Delaware Basin is $10/BOE.\n",
"ConocoPhillips' production base geographies include:\n",
"\n",
"I obtained this information from the image provided. The image clearly shows a bar chart under the section \"Delaware Basin Well Capex/EUR ($/BOE)\" where ConocoPhillips is listed with a capex/EUR of $10/BOE. This information is consistent with the parsed markdown text, which also lists ConocoPhillips' capex/EUR as $10/BOE in the Delaware Basin. There are no discrepancies between the image and the parsed markdown text in this case.\n",
"=== Calling Function ===\n",
"Calling function: vector_tool with args: {\"input\": \"competitors capex/EUR in the Delaware Basin\"}\n",
"=== Function Output ===\n",
"The competitors' Capex/EUR in the Delaware Basin can be found in the image on the slide titled \"Delaware: Vast Inventory with Proven Track Record of Performance.\" The relevant information is presented in a bar chart under the section \"Delaware Basin Well Capex/EUR ($/BOE)\".\n",
"1. **Lower 48** (Permian, Eagle Ford, Bakken, Other)\n",
"2. **Alaska** (GKA, GWA, GPA, WNS)\n",
"3. **EMENA** (Norway, Libya, Qatar)\n",
"4. **Asia Pacific** (APLNG, Malaysia, China)\n",
"5. **Canada** (Montney, Surmont)\n",
"\n",
"Here are the details:\n",
"\n",
"- ConocoPhillips: $10/BOE\n",
"- Competitor 1: $15/BOE\n",
"- Competitor 2: $20/BOE\n",
"- Competitor 3: $25/BOE\n",
"- Competitor 4: $30/BOE\n",
"- Competitor 5: $35/BOE\n",
"- Competitor 6: $40/BOE\n",
"- Competitor 7: $45/BOE\n",
"\n",
"This information was obtained directly from the image, which provides a clear visual representation of the Capex/EUR values for ConocoPhillips and its competitors in the Delaware Basin. The parsed markdown text also confirms these values, ensuring consistency between the image and the text.\n",
"This information was derived from the image on page 14, which provides a detailed breakdown of the diverse production base and the regions involved. The parsed markdown and raw text also support this information, but the image provides the clearest and most comprehensive view. There are no discrepancies between the image and the parsed text in this case.\n",
"=== LLM Response ===\n",
"The capital expenditure per estimated ultimate recovery (capex/EUR) for ConocoPhillips in the Delaware Basin is $10 per barrel of oil equivalent (BOE). When compared to its competitors, ConocoPhillips has a significantly lower capex/EUR. Here are the capex/EUR values for ConocoPhillips and its competitors:\n",
"ConocoPhillips has a diverse production base spread across various geographies, including:\n",
"\n",
"- **ConocoPhillips**: $10/BOE\n",
"- **Competitor 1**: $15/BOE\n",
"- **Competitor 2**: $20/BOE\n",
"- **Competitor 3**: $25/BOE\n",
"- **Competitor 4**: $30/BOE\n",
"- **Competitor 5**: $35/BOE\n",
"- **Competitor 6**: $40/BOE\n",
"- **Competitor 7**: $45/BOE\n",
"1. **Lower 48**:\n",
" - Permian Basin\n",
" - Eagle Ford\n",
" - Bakken\n",
" - Other regions within the continental United States\n",
"\n",
"This data indicates that ConocoPhillips has a more cost-efficient operation in the Delaware Basin compared to its competitors.\n",
"The capital expenditure per estimated ultimate recovery (capex/EUR) for ConocoPhillips in the Delaware Basin is $10 per barrel of oil equivalent (BOE). When compared to its competitors, ConocoPhillips has a significantly lower capex/EUR. Here are the capex/EUR values for ConocoPhillips and its competitors:\n",
"2. **Alaska**:\n",
" - Greater Kuparuk Area (GKA)\n",
" - Greater Prudhoe Area (GPA)\n",
" - Greater Willow Area (GWA)\n",
" - Western North Slope (WNS)\n",
"\n",
"- **ConocoPhillips**: $10/BOE\n",
"- **Competitor 1**: $15/BOE\n",
"- **Competitor 2**: $20/BOE\n",
"- **Competitor 3**: $25/BOE\n",
"- **Competitor 4**: $30/BOE\n",
"- **Competitor 5**: $35/BOE\n",
"- **Competitor 6**: $40/BOE\n",
"- **Competitor 7**: $45/BOE\n",
"3. **EMENA (Europe, Middle East, and North Africa)**:\n",
" - Norway\n",
" - Libya\n",
" - Qatar\n",
"\n",
"This data indicates that ConocoPhillips has a more cost-efficient operation in the Delaware Basin compared to its competitors.\n"
"4. **Asia Pacific**:\n",
" - Australia Pacific LNG (APLNG)\n",
" - Malaysia\n",
" - China\n",
"\n",
"5. **Canada**:\n",
" - Montney\n",
" - Surmont\n",
"\n",
"These regions highlight the global reach and diverse geographical footprint of ConocoPhillips' production operations.\n",
"Added user message to memory: Tell me about the diverse geographies where Conoco Phillips has a production base\n",
"=== Calling Function ===\n",
"Calling function: vector_tool with args: {\"input\": \"diverse geographies where Conoco Phillips has a production base\"}\n",
"=== Function Output ===\n",
"ConocoPhillips has a diverse production base that includes the Lower 48 (Permian, Bakken, Eagle Ford), Alaska, Canada (Montney, Surmont), EMENA (Norway, Libya), Asia Pacific (Malaysia, China, APLNG), and Qatar.\n",
"=== LLM Response ===\n",
"ConocoPhillips has a diverse production base spanning several key geographies:\n",
"\n",
"1. **Lower 48 (United States)**: This includes major production areas such as the Permian Basin, Bakken Formation, and Eagle Ford Shale.\n",
"2. **Alaska**: Significant operations in the North Slope region.\n",
"3. **Canada**: Operations in the Montney Formation and the Surmont oil sands project.\n",
"4. **EMENA (Europe, Middle East, and North Africa)**: Notable operations in Norway and Libya.\n",
"5. **Asia Pacific**: Includes operations in Malaysia, China, and the Australia Pacific LNG (APLNG) project.\n",
"6. **Qatar**: Involvement in the country's energy sector.\n",
"\n",
"These regions highlight the company's extensive and varied geographical footprint in the energy production industry.\n"
]
}
],
"source": [
"# response = agent.query(\"Tell me about the different regions and subregions where Conoco Phillips has a production base.\")\n",
"response = agent.query(\n",
" \"How does the Conoco Phillips capex/EUR in the delaware basin compare against other competitors?\"\n",
"query = (\n",
" \"Tell me about the diverse geographies where Conoco Phillips has a production base\"\n",
")\n",
"response = agent.query(query)\n",
"base_response = base_agent.query(query)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "355d2aa4-c26f-480e-b512-4446acbd9227",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"ConocoPhillips has a diverse production base spread across various geographies, including:\n",
"\n",
"1. **Lower 48**:\n",
" - Permian Basin\n",
" - Eagle Ford\n",
" - Bakken\n",
" - Other regions within the continental United States\n",
"\n",
"2. **Alaska**:\n",
" - Greater Kuparuk Area (GKA)\n",
" - Greater Prudhoe Area (GPA)\n",
" - Greater Willow Area (GWA)\n",
" - Western North Slope (WNS)\n",
"\n",
"3. **EMENA (Europe, Middle East, and North Africa)**:\n",
" - Norway\n",
" - Libya\n",
" - Qatar\n",
"\n",
"4. **Asia Pacific**:\n",
" - Australia Pacific LNG (APLNG)\n",
" - Malaysia\n",
" - China\n",
"\n",
"5. **Canada**:\n",
" - Montney\n",
" - Surmont\n",
"\n",
"These regions highlight the global reach and diverse geographical footprint of ConocoPhillips' production operations.\n"
]
}
],
"source": [
"print(str(response))"
]
},
@@ -764,85 +833,82 @@
"name": "stdout",
"output_type": "stream",
"text": [
"page_num: 38\n",
"image_path: data_images/d9137e19-3974-4b5d-998f-dac0cf29dd9d-page-37.jpg\n",
"parsed_text_markdown: # Delaware: Vast Inventory with Proven Track Record of Performance\n",
"page_num: 14\n",
"image_path: data_images/1ddd5654-062b-4e19-b488-d66efc9c509d-page_12.jpg\n",
"parsed_text_markdown: # Our Differentiated Portfolio: Deep, Durable and Diverse\n",
"\n",
"## Prolific Acreage Spanning Over ~659,000 Net Acres¹\n",
"## ~20 BBOE of Resource\n",
"Under $40/BBL Cost of Supply\n",
"\n",
"![Map of Delaware Basin](image)\n",
"### ~ $32/BBL\n",
"Average Cost of Supply\n",
"\n",
"### Total 10-Year Operated Permian Inventory\n",
"### WTI Cost of Supply ($/BBL)\n",
"\n",
"- Delaware Basin: 65%\n",
"- Midland Basin: 35%\n",
"| Cost ($/BBL) | Resource (BBOE) |\n",
"|--------------|-----------------|\n",
"| $0 | 0 |\n",
"| $10 | |\n",
"| $20 | |\n",
"| $30 | |\n",
"| $40 | |\n",
"| $50 | |\n",
"\n",
"### High Single-Digit Production Growth\n",
"- **Legend:**\n",
" - Lower 48\n",
" - Canada\n",
" - Alaska\n",
" - EMENA\n",
" - Asia Pacific\n",
"\n",
"## 12-Month Cumulative Production³ (BOE/FT)\n",
"*Costs assume a mid-cycle price environment of $60/BBL WTI.*\n",
"\n",
"| Months | 2019 | 2020 | 2021 | 2022 |\n",
"|--------|------|------|------|------|\n",
"| 1 | 0 | 0 | 0 | 0 |\n",
"| 2 | 5 | 6 | 7 | 8 |\n",
"| 3 | 10 | 12 | 14 | 16 |\n",
"| 4 | 15 | 18 | 21 | 24 |\n",
"| 5 | 20 | 24 | 28 | 32 |\n",
"| 6 | 25 | 30 | 35 | 40 |\n",
"| 7 | 30 | 36 | 42 | 48 |\n",
"| 8 | 35 | 42 | 49 | 56 |\n",
"| 9 | 40 | 48 | 56 | 64 |\n",
"| 10 | 45 | 54 | 63 | 72 |\n",
"| 11 | 50 | 60 | 70 | 80 |\n",
"| 12 | 55 | 66 | 77 | 88 |\n",
"## Diverse Production Base\n",
"10-Year Plan Cumulative Production (BBOE)\n",
"\n",
"~30% Improved Performance from 2019 to 2022\n",
"\n",
"## Delaware Basin Well Capex/EUR⁴ ($/BOE)\n",
"\n",
"| Company | Capex/EUR |\n",
"|------------------|-----------|\n",
"| ConocoPhillips | 10 |\n",
"| Competitor 1 | 15 |\n",
"| Competitor 2 | 20 |\n",
"| Competitor 3 | 25 |\n",
"| Competitor 4 | 30 |\n",
"| Competitor 5 | 35 |\n",
"| Competitor 6 | 40 |\n",
"| Competitor 7 | 45 |\n",
"\n",
"---\n",
"\n",
"¹ Unconventional acres. \n",
"² Source: Enverus and ConocoPhillips (March 2023). \n",
"³ Source: Enverus (March 2023) based on wells online year. \n",
"⁴ Source: Enverus (March 2023). Average single well capex/EUR. Top eight public operators based on wells online in years 2021-2022, greater than 50% oil weight. COP based on COP well design. Competitors include: CVX, DVN, EOG, MTDR, OXY, PR and XOM.\n",
"parsed_text: \n",
"Delaware: Vast Inventory with Proven Track Record of Performance\n",
" New Prolific Acreage Spanning Over 12-Month Cumulative Production? (BOE/FT)\n",
" Mexico 659,000 Net Acres' 40\n",
" Texas 3828\n",
" 30 2019\n",
" 20 30%\n",
" 10 Improved Performancefrom 2019 to 2022\n",
" Total\n",
" Permian Inventory\n",
" 10-Year Operated\n",
" 2 10 11 12\n",
" Months\n",
" Delaware Basin Well Capex/EUR4 (S/BOE)\n",
" 65% 25\n",
" Delaware Basin 20\n",
" Midland Basin 15\n",
" Low HighCost of Supplyz 10 ConocoPhillips\n",
" High Single-Digit Production Growth\n",
" \"Unconventional acres. 2Source: Enverus and ConocoPhillips (March 2023). 3SourceEnverus (March 2023) based on wells online year: \"Source; Enverus (March 2023). Average single well capex/EUR Top eight public operators based on\n",
"wells online in years 2021-2022, greater than 50% oil weight; COP based on COP well design: Competitors include; CVX DVN, EOG; MTDR, OXY, PR and XOM: ConocoPhillips\n"
"| Region | Sub-region |\n",
"|--------------|-----------------|\n",
"| Lower 48 | Permian |\n",
"| | Eagle Ford |\n",
"| | Bakken |\n",
"| | Other |\n",
"| Alaska | GKA |\n",
"| | GWA |\n",
"| | GPA |\n",
"| | WNS |\n",
"| EMENA | Norway |\n",
"| | Libya |\n",
"| | Qatar |\n",
"| Asia Pacific | APLNG |\n",
"| | Malaysia |\n",
"| | China |\n",
"| Canada | Montney |\n",
"| | Surmont |\n",
"parsed_text: Our Differentiated Portfolio: Deep; Durable and Diverse\n",
" 20 BBOE of Resource Diverse Production Base\n",
" Under $40/BBL Cost of Supply 10-Year Plan Cumulative Production (BBOE)\n",
" S50 S32/BBL Lower 48 Alaska\n",
" Average Cost of Supply\n",
" 3 $40 GKA GWA\n",
" GPA WNS\n",
" $30 EMENA\n",
" 3 Norway\n",
" 8 $20\n",
" E Qatar Libya\n",
" Asia Pacific Canada\n",
" $10 Permian\n",
" APLNG Montney\n",
" S0\n",
" 10 15 20 Bakken\n",
" Resource (BBOE) Eagle Ford Other Malaysia ChinaSurmont\n",
" Lower 48 Canada Alaska EMENA Asia Pacific\n",
"Costs assumemid-cycle price environment of S60/BBL WTI:\n",
" ConocoPhillips\n"
]
}
],
"source": [
"print(response.source_nodes[0].get_content(metadata_mode=\"all\"))"
"print(response.source_nodes[7].get_content(metadata_mode=\"all\"))"
]
},
{
@@ -855,26 +921,20 @@
"name": "stdout",
"output_type": "stream",
"text": [
"Added user message to memory: How does the Conoco Phillips capex/EUR in the delaware basin compare against other competitors?\n",
"=== Calling Function ===\n",
"Calling function: vector_tool with args: {\"input\": \"Conoco Phillips capex/EUR in the Delaware Basin\"}\n",
"=== Function Output ===\n",
"ConocoPhillips' capex/EUR in the Delaware Basin is approximately $20/BOE.\n",
"=== Calling Function ===\n",
"Calling function: vector_tool with args: {\"input\": \"competitors capex/EUR in the Delaware Basin\"}\n",
"=== Function Output ===\n",
"The average single well capex/EUR for competitors in the Delaware Basin is between $10 and $25 per BOE.\n",
"=== LLM Response ===\n",
"ConocoPhillips' capex/EUR in the Delaware Basin is approximately $20 per BOE. In comparison, the average capex/EUR for competitors in the Delaware Basin ranges between $10 and $25 per BOE. This places ConocoPhillips' capex/EUR towards the higher end of the competitive range.\n",
"ConocoPhillips' capex/EUR in the Delaware Basin is approximately $20 per BOE. In comparison, the average capex/EUR for competitors in the Delaware Basin ranges between $10 and $25 per BOE. This places ConocoPhillips' capex/EUR towards the higher end of the competitive range.\n"
"ConocoPhillips has a diverse production base spanning several key geographies:\n",
"\n",
"1. **Lower 48 (United States)**: This includes major production areas such as the Permian Basin, Bakken Formation, and Eagle Ford Shale.\n",
"2. **Alaska**: Significant operations in the North Slope region.\n",
"3. **Canada**: Operations in the Montney Formation and the Surmont oil sands project.\n",
"4. **EMENA (Europe, Middle East, and North Africa)**: Notable operations in Norway and Libya.\n",
"5. **Asia Pacific**: Includes operations in Malaysia, China, and the Australia Pacific LNG (APLNG) project.\n",
"6. **Qatar**: Involvement in the country's energy sector.\n",
"\n",
"These regions highlight the company's extensive and varied geographical footprint in the energy production industry.\n"
]
}
],
"source": [
"# base_response = base_agent.query(\"Tell me about the different regions and subregions where Conoco Phillips has a production base.\")\n",
"base_response = base_agent.query(\n",
" \"How does the Conoco Phillips capex/EUR in the delaware basin compare against other competitors?\"\n",
")\n",
"print(str(base_response))"
]
},
@@ -888,30 +948,31 @@
"name": "stdout",
"output_type": "stream",
"text": [
"Deep, Durable and Diverse Portfolio with Significant Growth Runway\n",
" 1,2002022 Lower 48 Unconventional Production' (MBOED S50 ~S32/BBL\n",
" 000 ConocoPhillips Cost of SupplyAverage\n",
" 00 S40\n",
" 500 3\n",
" 400 1 S30\n",
" 200\n",
" 5\n",
" 15,000ConocoPhillipsNet Remaining Well Inventory? 1 S20\n",
" 12,000 S10\n",
" 000\n",
" 0o0 SO\n",
" 3,000 10\n",
" Resource (BBOE)\n",
" Delaware Basin Midland Basin Eagle Ford Bakken Other\n",
" Largest Lower 48 Unconventional Producer; Growing into the Next Decade\n",
" onshore operated inventory that achieves 15% IRR at $SO/BBL WTI, Competitors include CVX, DVN, EOG, FANG, MRO, OXY, PXD,and XOM:\n",
" Source: Wood Mackenzie Lower 48 Unconventional Plays 2022 ProductionCompetitors include CVX, DVN; EOG, FANG, MRO, OXY, PXD and XOM; greaterthan50% liquids weight: ?Source: Wood Mackenzie (March 2023), Lower 48\n",
" ConocoPhillips\n"
"Our Differentiated Portfolio: Deep; Durable and Diverse\n",
" 20 BBOE of Resource Diverse Production Base\n",
" Under $40/BBL Cost of Supply 10-Year Plan Cumulative Production (BBOE)\n",
" S50 S32/BBL Lower 48 Alaska\n",
" Average Cost of Supply\n",
" 3 $40 GKA GWA\n",
" GPA WNS\n",
" $30 EMENA\n",
" 3 Norway\n",
" 8 $20\n",
" E Qatar Libya\n",
" Asia Pacific Canada\n",
" $10 Permian\n",
" APLNG Montney\n",
" S0\n",
" 10 15 20 Bakken\n",
" Resource (BBOE) Eagle Ford Other Malaysia ChinaSurmont\n",
" Lower 48 Canada Alaska EMENA Asia Pacific\n",
"Costs assumemid-cycle price environment of S60/BBL WTI:\n",
" ConocoPhillips\n"
]
}
],
"source": [
"print(base_response.source_nodes[0].get_content(metadata_mode=\"llm\"))"
"print(base_response.source_nodes[1].get_content(metadata_mode=\"all\"))"
]
}
],
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

@@ -0,0 +1,834 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Building a RAG Pipeline over IKEA Product Instruction Manuals\n",
"\n",
"<a href=\"https://colab.research.google.com/github/run-llama/llama_parse/blob/main/examples/multimodal/product_manual_rag.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"This cookbook shows how to use LlamaParse and OpenAI's multimodal models to query over IKEA instruction manual PDFs, which mainly contain images and diagrams to show how one can assemble the product.\n",
"\n",
"LlamaParse and multimodal LLMs can interpret these diagrams and translate them into textual instructions. With textual assistance, confusing visual instructions within the IKEA product manuals can be made easier to understand and interpret. Additionally, textual instructions can be helpful for those who are visually impaired."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Install and Setup\n",
"\n",
"Install LlamaIndex, download the data, and apply `nest_asyncio`."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"%pip install llama-index llama-parse llama-index-multi-modal-llms-openai git+https://github.com/openai/CLIP.git"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"!wget https://github.com/user-attachments/files/16461058/data.zip -O data.zip\n",
"!unzip -o data.zip\n",
"!rm data.zip"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import nest_asyncio\n",
"\n",
"nest_asyncio.apply()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Set up your OpenAI and LlamaCloud keys."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import os\n",
"\n",
"os.environ[\"OPENAI_API_KEY\"] = \"<Your OpenAI API Key>\"\n",
"os.environ[\"LLAMA_CLOUD_API_KEY\"] = \"<Your LlamaCloud API Key>\""
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Code Implementation"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Set up LlamaParse. We will parse the PDF files into markdown and use the GPT-4o multimodal model to parse the PDFs."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Load data from the parser."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from llama_parse import LlamaParse\n",
"\n",
"parser = LlamaParse(\n",
" result_type=\"markdown\",\n",
" parsing_instruction=\"You are given IKEA assembly instruction manuals\",\n",
" use_vendor_multimodal_model=True,\n",
" vendor_multimodal_model_name=\"openai-gpt4o\",\n",
" show_progress=True,\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"DATA_DIR = \"data\"\n",
"\n",
"\n",
"def get_data_files(data_dir=DATA_DIR) -> list[str]:\n",
" files = []\n",
" for f in os.listdir(data_dir):\n",
" fname = os.path.join(data_dir, f)\n",
" if os.path.isfile(fname):\n",
" files.append(fname)\n",
" return files\n",
"\n",
"\n",
"files = get_data_files()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Load data into docs, and save images from PDFs into `data_images` directory."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"md_json_objs = parser.get_json_result(files)\n",
"md_json_list = md_json_objs[0][\"pages\"]\n",
"image_dicts = parser.get_images(md_json_objs, download_path=\"data_images\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Create helper functions to create a list of `TextNode`s from the markdown tables to feed into the `VectorStoreIndex`."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import re\n",
"from pathlib import Path\n",
"import typing as t\n",
"from llama_index.core.schema import TextNode\n",
"\n",
"\n",
"def get_page_number(file_name):\n",
" \"\"\"Gets page number of images using regex on file names\"\"\"\n",
" match = re.search(r\"-page-(\\d+)\\.jpg$\", str(file_name))\n",
" if match:\n",
" return int(match.group(1))\n",
" return 0\n",
"\n",
"\n",
"def _get_sorted_image_files(image_dir):\n",
" \"\"\"Get image files sorted by page.\"\"\"\n",
" raw_files = [f for f in list(Path(image_dir).iterdir()) if f.is_file()]\n",
" sorted_files = sorted(raw_files, key=get_page_number)\n",
" return sorted_files\n",
"\n",
"\n",
"def get_text_nodes(json_dicts, image_dir) -> t.List[TextNode]:\n",
" \"\"\"Creates nodes from json + images\"\"\"\n",
"\n",
" nodes = []\n",
"\n",
" docs = [doc[\"md\"] for doc in json_dicts] # extract text\n",
" image_files = _get_sorted_image_files(image_dir) # extract images\n",
"\n",
" for idx, doc in enumerate(docs):\n",
" # adds both a text node and the corresponding image node (jpg of the page) for each page\n",
" node = TextNode(\n",
" text=doc,\n",
" metadata={\"image_path\": str(image_files[idx]), \"page_num\": idx + 1},\n",
" )\n",
" nodes.append(node)\n",
"\n",
" return nodes\n",
"\n",
"\n",
"text_nodes = get_text_nodes(md_json_list, \"data_images\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Index the documents."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from llama_index.core import (\n",
" VectorStoreIndex,\n",
" StorageContext,\n",
" load_index_from_storage,\n",
" Settings,\n",
")\n",
"from llama_index.embeddings.openai import OpenAIEmbedding\n",
"from llama_index.llms.openai import OpenAI\n",
"\n",
"embed_model = OpenAIEmbedding(model=\"text-embedding-3-large\")\n",
"llm = OpenAI(\"gpt-4o\")\n",
"\n",
"Settings.llm = llm\n",
"Settings.embed_model = embed_model\n",
"\n",
"if not os.path.exists(\"storage_ikea\"):\n",
" index = VectorStoreIndex(text_nodes, embed_model=embed_model)\n",
" index.storage_context.persist(persist_dir=\"./storage_ikea\")\n",
"else:\n",
" ctx = StorageContext.from_defaults(persist_dir=\"./storage_ikea\")\n",
" index = load_index_from_storage(ctx)\n",
"\n",
"retriever = index.as_retriever()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Create a custom query engine that uses GPT-4o's multimodal model."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from llama_index.core.query_engine import CustomQueryEngine\n",
"from llama_index.core.retrievers import BaseRetriever\n",
"from llama_index.multi_modal_llms.openai import OpenAIMultiModal\n",
"from llama_index.core.schema import NodeWithScore, MetadataMode\n",
"from llama_index.core.base.response.schema import Response\n",
"from llama_index.core.prompts import PromptTemplate\n",
"from llama_index.core.schema import ImageNode\n",
"\n",
"QA_PROMPT_TMPL = \"\"\"\\\n",
"Below we give parsed text from slides in two different formats, as well as the image.\n",
"\n",
"We parse the text in both 'markdown' mode as well as 'raw text' mode. Markdown mode attempts \\\n",
"to convert relevant diagrams into tables, whereas raw text tries to maintain the rough spatial \\\n",
"layout of the text.\n",
"\n",
"Use the image information first and foremost. ONLY use the text/markdown information \n",
"if you can't understand the image.\n",
"\n",
"---------------------\n",
"{context_str}\n",
"---------------------\n",
"Given the context information and not prior knowledge, answer the query. Explain whether you got the answer\n",
"from the parsed markdown or raw text or image, and if there's discrepancies, and your reasoning for the final answer.\n",
"\n",
"Query: {query_str}\n",
"Answer: \"\"\"\n",
"\n",
"QA_PROMPT = PromptTemplate(QA_PROMPT_TMPL)\n",
"\n",
"gpt_4o_mm = OpenAIMultiModal(model=\"gpt-4o\", max_new_tokens=4096)\n",
"\n",
"\n",
"class MultimodalQueryEngine(CustomQueryEngine):\n",
" qa_prompt: PromptTemplate\n",
" retriever: BaseRetriever\n",
" multi_modal_llm: OpenAIMultiModal\n",
"\n",
" def __init__(\n",
" self,\n",
" qa_prompt: PromptTemplate,\n",
" retriever: BaseRetriever,\n",
" multi_modal_llm: OpenAIMultiModal,\n",
" ):\n",
" super().__init__(\n",
" qa_prompt=qa_prompt, retriever=retriever, multi_modal_llm=multi_modal_llm\n",
" )\n",
"\n",
" def custom_query(self, query_str: str):\n",
" # retrieve most relevant nodes\n",
" nodes = self.retriever.retrieve(query_str)\n",
"\n",
" # create image nodes from the image associated with those nodes\n",
" image_nodes = [\n",
" NodeWithScore(node=ImageNode(image_path=n.node.metadata[\"image_path\"]))\n",
" for n in nodes\n",
" ]\n",
"\n",
" # create context string from parsed markdown text\n",
" ctx_str = \"\\n\\n\".join(\n",
" [r.node.get_content(metadata_mode=MetadataMode.LLM) for r in nodes]\n",
" )\n",
" # prompt for the LLM\n",
" fmt_prompt = self.qa_prompt.format(context_str=ctx_str, query_str=query_str)\n",
"\n",
" # use the multimodal LLM to interpret images and generate a response to the prompt\n",
" llm_repsonse = self.multi_modal_llm.complete(\n",
" prompt=fmt_prompt,\n",
" image_documents=[image_node.node for image_node in image_nodes],\n",
" )\n",
" return Response(\n",
" response=str(llm_repsonse),\n",
" source_nodes=nodes,\n",
" metadata={\"text_nodes\": text_nodes, \"image_nodes\": image_nodes},\n",
" )"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Create a query engine instance."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"query_engine = MultimodalQueryEngine(\n",
" qa_prompt=QA_PROMPT,\n",
" retriever=index.as_retriever(similarity_top_k=9),\n",
" multi_modal_llm=gpt_4o_mm,\n",
")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n",
"## Example Queries"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [
{
"data": {
"text/markdown": [
"The query asks about the parts included in the Uppspel, but the provided images and parsed text do not contain any information about the Uppspel. Instead, they contain information about other IKEA products such as SMÅGÖRA, FREDDE, and TUFFING.\n",
"\n",
"Therefore, based on the provided images and parsed text, I cannot determine the parts included in the Uppspel. The answer cannot be derived from the given information."
],
"text/plain": [
"<IPython.core.display.Markdown object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"from IPython.display import display, Markdown\n",
"\n",
"response = query_engine.query(\"What parts are included in the Uppspel?\")\n",
"display(Markdown(str(response)))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [
{
"data": {
"text/markdown": [
"The Tuffing is a bunk bed frame with a minimalist design, featuring a metal frame and safety rails on the top bunk. The image provided shows the Tuffing bunk bed with a ladder for access to the top bunk and a simple, sturdy construction.\n",
"\n",
"I got the answer from the image provided. The image clearly shows the design and structure of the Tuffing bunk bed. There were no discrepancies between the parsed markdown or raw text and the image. The image was the primary source for understanding what the Tuffing looks like."
],
"text/plain": [
"<IPython.core.display.Markdown object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"response = query_engine.query(\"What does the Tuffing look like?\")\n",
"display(Markdown(str(response)))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [
{
"data": {
"text/markdown": [
"The query asks for step 4 of assembling the Nordli. Based on the provided information, step 4 is described in the parsed text as follows:\n",
"\n",
"**Step 4:**\n",
"- Insert the provided tool into the hole as shown.\n",
"- Ensure the structure is properly aligned and secure.\n",
"- Push down firmly to lock the structure in place.\n",
"\n",
"This information was derived from the parsed text, as the image provided does not contain step-by-step instructions for the Nordli assembly. There are no discrepancies between the parsed markdown and raw text for this step."
],
"text/plain": [
"<IPython.core.display.Markdown object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"response = query_engine.query(\"What is step 4 of assembling the Nordli?\")\n",
"display(Markdown(str(response)))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [
{
"data": {
"text/markdown": [
"If you're confused with reading the manual, you should contact IKEA customer service for assistance. This information is derived from the image on page 2, which shows a person with a question mark next to an IKEA box and another person making a phone call to IKEA. This visual cue indicates that contacting IKEA customer service is the recommended action if you need help."
],
"text/plain": [
"<IPython.core.display.Markdown object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"response = query_engine.query(\n",
" \"What should I do if I'm confused with reading the manual?\"\n",
")\n",
"display(Markdown(str(response)))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"You can also create an agent around the query engine and chat with the agent."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from llama_index.core.agent import FunctionCallingAgentWorker\n",
"from llama_index.core.tools import QueryEngineTool\n",
"\n",
"query_engine_tool = QueryEngineTool.from_defaults(\n",
" query_engine=query_engine,\n",
" name=\"query_engine_tool\",\n",
" description=\"Useful for retrieving specific context from the data. Do NOT select if question asks for a summary of the data.\",\n",
")\n",
"agent = FunctionCallingAgentWorker.from_tools(\n",
" [query_engine_tool], llm=llm, verbose=True\n",
").as_agent()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Added user message to memory: Give a step-by-step instruction guide on how to assemble the Smagora\n",
"=== Calling Function ===\n",
"Calling function: query_engine_tool with args: {\"input\": \"step-by-step instruction guide on how to assemble the Smagora\"}\n",
"=== Function Output ===\n",
"The step-by-step instruction guide on how to assemble the Smågåra crib is provided in the images. The images show detailed visual instructions for each step of the assembly process, including the tools required, the parts involved, and the specific actions to be taken.\n",
"\n",
"Here is a summary of the steps based on the images:\n",
"\n",
"1. **Tools Required**:\n",
" - Flathead screwdriver\n",
" - Phillips screwdriver\n",
" - Hammer\n",
"\n",
"2. **Preparation**:\n",
" - Do not assemble alone; assemble with a partner.\n",
" - Do not assemble on a hard surface; use a soft surface to avoid damage.\n",
" - If you have questions or need assistance, contact IKEA customer service.\n",
"\n",
"3. **Step 1**:\n",
" - Insert 12 screws into the designated holes on the frame.\n",
"\n",
"4. **Step 2**:\n",
" - Align the side panels with the headboard and footboard.\n",
" - Use 4 connectors and secure them with bolts and washers.\n",
" - Tighten using the provided tool.\n",
" - Carefully flip the structure as shown.\n",
"\n",
"5. **Step 3**:\n",
" - Use the provided Allen key to tighten the screws into the designated holes.\n",
" - Ensure the screws are properly aligned and tightened.\n",
" - Repeat this process for all four screws.\n",
" - Make sure the screws are flush with the surface.\n",
"\n",
"6. **Step 4**:\n",
" - Insert the provided tool into the hole as shown.\n",
" - Ensure the structure is properly aligned and secure.\n",
" - Push down firmly to lock the structure in place.\n",
"\n",
"7. **Step 5**:\n",
" - Insert 4 dowels into the designated holes on the board.\n",
"\n",
"8. **Step 6**:\n",
" - Align the board with the dowels and insert it into the corresponding slots on the frame.\n",
"\n",
"9. **Step 7**:\n",
" - Insert the top panel into the side panels.\n",
" - Use 4 screws to secure the top panel.\n",
" - Ensure the screws are properly aligned and tightened using the provided tool.\n",
"\n",
"10. **Step 8**:\n",
" - Carefully flip the assembled structure upright.\n",
" - Use 2 screws to secure the bottom panel.\n",
" - Tighten the screws with the provided tool.\n",
"\n",
"These steps are derived from the images provided, which offer a clear and detailed visual guide for assembling the Smågåra crib.\n",
"=== LLM Response ===\n",
"Here is a step-by-step instruction guide on how to assemble the Smågåra crib:\n",
"\n",
"### Tools Required:\n",
"- Flathead screwdriver\n",
"- Phillips screwdriver\n",
"- Hammer\n",
"- Allen key (provided in the package)\n",
"\n",
"### Preparation:\n",
"- **Safety First**: Assemble with a partner to ensure safety and ease.\n",
"- **Surface**: Assemble on a soft surface to avoid damaging the parts.\n",
"- **Assistance**: If you have questions or need help, contact IKEA customer service.\n",
"\n",
"### Step-by-Step Assembly:\n",
"\n",
"#### Step 1: Insert Screws into the Frame\n",
"1. Insert 12 screws into the designated holes on the frame.\n",
"2. Ensure the screws are properly aligned.\n",
"\n",
"#### Step 2: Align and Secure Side Panels\n",
"1. Align the side panels with the headboard and footboard.\n",
"2. Use 4 connectors and secure them with bolts and washers.\n",
"3. Tighten the bolts using the provided tool.\n",
"4. Carefully flip the structure as shown in the instructions.\n",
"\n",
"#### Step 3: Tighten Screws\n",
"1. Use the provided Allen key to tighten the screws into the designated holes.\n",
"2. Ensure the screws are properly aligned and tightened.\n",
"3. Repeat this process for all four screws.\n",
"4. Make sure the screws are flush with the surface.\n",
"\n",
"#### Step 4: Lock the Structure\n",
"1. Insert the provided tool into the hole as shown.\n",
"2. Ensure the structure is properly aligned and secure.\n",
"3. Push down firmly to lock the structure in place.\n",
"\n",
"#### Step 5: Insert Dowels\n",
"1. Insert 4 dowels into the designated holes on the board.\n",
"\n",
"#### Step 6: Align and Insert the Board\n",
"1. Align the board with the dowels.\n",
"2. Insert the board into the corresponding slots on the frame.\n",
"\n",
"#### Step 7: Secure the Top Panel\n",
"1. Insert the top panel into the side panels.\n",
"2. Use 4 screws to secure the top panel.\n",
"3. Ensure the screws are properly aligned and tightened using the provided tool.\n",
"\n",
"#### Step 8: Secure the Bottom Panel\n",
"1. Carefully flip the assembled structure upright.\n",
"2. Use 2 screws to secure the bottom panel.\n",
"3. Tighten the screws with the provided tool.\n",
"\n",
"By following these steps, you should be able to assemble the Smågåra crib successfully. If you encounter any issues, refer to the visual instructions provided in the package or contact IKEA customer service for assistance.\n"
]
},
{
"data": {
"text/markdown": [
"Here is a step-by-step instruction guide on how to assemble the Smågåra crib:\n",
"\n",
"### Tools Required:\n",
"- Flathead screwdriver\n",
"- Phillips screwdriver\n",
"- Hammer\n",
"- Allen key (provided in the package)\n",
"\n",
"### Preparation:\n",
"- **Safety First**: Assemble with a partner to ensure safety and ease.\n",
"- **Surface**: Assemble on a soft surface to avoid damaging the parts.\n",
"- **Assistance**: If you have questions or need help, contact IKEA customer service.\n",
"\n",
"### Step-by-Step Assembly:\n",
"\n",
"#### Step 1: Insert Screws into the Frame\n",
"1. Insert 12 screws into the designated holes on the frame.\n",
"2. Ensure the screws are properly aligned.\n",
"\n",
"#### Step 2: Align and Secure Side Panels\n",
"1. Align the side panels with the headboard and footboard.\n",
"2. Use 4 connectors and secure them with bolts and washers.\n",
"3. Tighten the bolts using the provided tool.\n",
"4. Carefully flip the structure as shown in the instructions.\n",
"\n",
"#### Step 3: Tighten Screws\n",
"1. Use the provided Allen key to tighten the screws into the designated holes.\n",
"2. Ensure the screws are properly aligned and tightened.\n",
"3. Repeat this process for all four screws.\n",
"4. Make sure the screws are flush with the surface.\n",
"\n",
"#### Step 4: Lock the Structure\n",
"1. Insert the provided tool into the hole as shown.\n",
"2. Ensure the structure is properly aligned and secure.\n",
"3. Push down firmly to lock the structure in place.\n",
"\n",
"#### Step 5: Insert Dowels\n",
"1. Insert 4 dowels into the designated holes on the board.\n",
"\n",
"#### Step 6: Align and Insert the Board\n",
"1. Align the board with the dowels.\n",
"2. Insert the board into the corresponding slots on the frame.\n",
"\n",
"#### Step 7: Secure the Top Panel\n",
"1. Insert the top panel into the side panels.\n",
"2. Use 4 screws to secure the top panel.\n",
"3. Ensure the screws are properly aligned and tightened using the provided tool.\n",
"\n",
"#### Step 8: Secure the Bottom Panel\n",
"1. Carefully flip the assembled structure upright.\n",
"2. Use 2 screws to secure the bottom panel.\n",
"3. Tighten the screws with the provided tool.\n",
"\n",
"By following these steps, you should be able to assemble the Smågåra crib successfully. If you encounter any issues, refer to the visual instructions provided in the package or contact IKEA customer service for assistance."
],
"text/plain": [
"<IPython.core.display.Markdown object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"response = agent.chat(\n",
" \"Give a step-by-step instruction guide on how to assemble the Smagora\"\n",
")\n",
"display(Markdown(str(response)))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Added user message to memory: How do I assemble the Fredde?\n",
"=== Calling Function ===\n",
"Calling function: query_engine_tool with args: {\"input\": \"step-by-step instruction guide on how to assemble the Fredde\"}\n",
"=== Function Output ===\n",
"The query asks for a step-by-step instruction guide on how to assemble the Fredde. However, based on the provided images and parsed text, there is no specific mention or visual representation of the Fredde assembly instructions. The images and text provided are related to other IKEA products such as Tuffing and Smågöra, but not Fredde.\n",
"\n",
"Therefore, I cannot provide the step-by-step instructions for assembling the Fredde from the given information. If you have the specific instructions for Fredde, please provide them, and I can assist you further.\n",
"=== LLM Response ===\n",
"It appears that the specific step-by-step instructions for assembling the Fredde desk are not available in the provided data. However, I can offer a general guide based on typical assembly procedures for IKEA furniture. For the most accurate and detailed instructions, please refer to the assembly manual that comes with the product.\n",
"\n",
"### General Assembly Guide for Fredde Desk:\n",
"\n",
"#### Tools Required:\n",
"- Phillips screwdriver\n",
"- Flathead screwdriver\n",
"- Allen key (usually provided in the package)\n",
"- Hammer (if needed for dowels)\n",
"\n",
"### Step-by-Step Assembly:\n",
"\n",
"#### Step 1: Unpack and Organize\n",
"1. **Unpack** all the parts and hardware.\n",
"2. **Organize** the parts by type and size to make the assembly process easier.\n",
"\n",
"#### Step 2: Assemble the Main Frame\n",
"1. **Connect the Side Panels**: Attach the side panels to the back panel using screws and dowels as indicated in the manual.\n",
"2. **Secure the Bottom Panel**: Attach the bottom panel to the side panels.\n",
"\n",
"#### Step 3: Attach the Shelves\n",
"1. **Install the Lower Shelves**: Insert the lower shelves into the designated slots and secure them with screws.\n",
"2. **Install the Upper Shelves**: Repeat the process for the upper shelves.\n",
"\n",
"#### Step 4: Attach the Desktop\n",
"1. **Align the Desktop**: Place the desktop on top of the frame, ensuring it is properly aligned.\n",
"2. **Secure the Desktop**: Use screws to secure the desktop to the frame.\n",
"\n",
"#### Step 5: Install Additional Features\n",
"1. **Attach Monitor Shelf**: If the Fredde desk includes a monitor shelf, attach it to the back panel using screws.\n",
"2. **Install Side Extensions**: Attach any side extensions or additional shelves as per the instructions.\n",
"\n",
"#### Step 6: Final Adjustments\n",
"1. **Check Stability**: Ensure all screws are tightened and the desk is stable.\n",
"2. **Adjust Height**: If the desk has adjustable height features, set it to the desired height.\n",
"\n",
"#### Step 7: Clean Up\n",
"1. **Remove Packaging**: Dispose of any packaging materials.\n",
"2. **Organize Tools**: Put away your tools and clean the workspace.\n",
"\n",
"For the most accurate and detailed instructions, please refer to the assembly manual that comes with the Fredde desk. If you encounter any issues, IKEA customer service can provide additional support.\n"
]
},
{
"data": {
"text/markdown": [
"It appears that the specific step-by-step instructions for assembling the Fredde desk are not available in the provided data. However, I can offer a general guide based on typical assembly procedures for IKEA furniture. For the most accurate and detailed instructions, please refer to the assembly manual that comes with the product.\n",
"\n",
"### General Assembly Guide for Fredde Desk:\n",
"\n",
"#### Tools Required:\n",
"- Phillips screwdriver\n",
"- Flathead screwdriver\n",
"- Allen key (usually provided in the package)\n",
"- Hammer (if needed for dowels)\n",
"\n",
"### Step-by-Step Assembly:\n",
"\n",
"#### Step 1: Unpack and Organize\n",
"1. **Unpack** all the parts and hardware.\n",
"2. **Organize** the parts by type and size to make the assembly process easier.\n",
"\n",
"#### Step 2: Assemble the Main Frame\n",
"1. **Connect the Side Panels**: Attach the side panels to the back panel using screws and dowels as indicated in the manual.\n",
"2. **Secure the Bottom Panel**: Attach the bottom panel to the side panels.\n",
"\n",
"#### Step 3: Attach the Shelves\n",
"1. **Install the Lower Shelves**: Insert the lower shelves into the designated slots and secure them with screws.\n",
"2. **Install the Upper Shelves**: Repeat the process for the upper shelves.\n",
"\n",
"#### Step 4: Attach the Desktop\n",
"1. **Align the Desktop**: Place the desktop on top of the frame, ensuring it is properly aligned.\n",
"2. **Secure the Desktop**: Use screws to secure the desktop to the frame.\n",
"\n",
"#### Step 5: Install Additional Features\n",
"1. **Attach Monitor Shelf**: If the Fredde desk includes a monitor shelf, attach it to the back panel using screws.\n",
"2. **Install Side Extensions**: Attach any side extensions or additional shelves as per the instructions.\n",
"\n",
"#### Step 6: Final Adjustments\n",
"1. **Check Stability**: Ensure all screws are tightened and the desk is stable.\n",
"2. **Adjust Height**: If the desk has adjustable height features, set it to the desired height.\n",
"\n",
"#### Step 7: Clean Up\n",
"1. **Remove Packaging**: Dispose of any packaging materials.\n",
"2. **Organize Tools**: Put away your tools and clean the workspace.\n",
"\n",
"For the most accurate and detailed instructions, please refer to the assembly manual that comes with the Fredde desk. If you encounter any issues, IKEA customer service can provide additional support."
],
"text/plain": [
"<IPython.core.display.Markdown object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"response = agent.chat(\"How do I assemble the Fredde?\")\n",
"display(Markdown(str(response)))"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "llama-parse-5ZmnAQ0r-py3.11",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
File diff suppressed because it is too large Load Diff
Binary file not shown.

After

Width:  |  Height:  |  Size: 986 KiB

@@ -46,7 +46,7 @@
"metadata": {},
"outputs": [],
"source": [
"os.environ[\"LLAMA_CLOUD_API_KEY\"] = \"<LLAMA_CLOUD_API_KEY>"
"os.environ[\"LLAMA_CLOUD_API_KEY\"] = \"<LLAMA_CLOUD_API_KEY>\""
]
},
{
+566 -116
View File
@@ -1,22 +1,26 @@
import os
import asyncio
from urllib.parse import urlparse
import httpx
import mimetypes
import time
from pathlib import Path
from typing import List, Optional, Union
from pathlib import Path, PurePath, PurePosixPath
from typing import AsyncGenerator, Any, Dict, List, Optional, Union
from contextlib import asynccontextmanager
from io import BufferedIOBase
from llama_index.core.async_utils import run_jobs
from llama_index.core.bridge.pydantic import Field, validator
from fsspec import AbstractFileSystem
from llama_index.core.async_utils import asyncio_run, run_jobs
from llama_index.core.bridge.pydantic import Field, field_validator
from llama_index.core.constants import DEFAULT_BASE_URL
from llama_index.core.readers.base import BasePydanticReader
from llama_index.core.readers.file.base import get_default_fs
from llama_index.core.schema import Document
from llama_parse.utils import (
nest_asyncio_err,
nest_asyncio_msg,
ResultType,
Language,
SUPPORTED_FILE_TYPES,
)
from copy import deepcopy
@@ -25,32 +29,36 @@ from copy import deepcopy
# if passing as bytes or a buffer, must provide the file_name in extra_info
FileInput = Union[str, bytes, BufferedIOBase]
def _get_sub_docs(docs: List[Document]) -> List[Document]:
"""Split docs into pages, by separator."""
sub_docs = []
for doc in docs:
doc_chunks = doc.text.split("\n---\n")
for doc_chunk in doc_chunks:
sub_doc = Document(
text=doc_chunk,
metadata=deepcopy(doc.metadata),
)
sub_docs.append(sub_doc)
return sub_docs
_DEFAULT_SEPARATOR = "\n---\n"
class LlamaParse(BasePydanticReader):
"""A smart-parser for files."""
api_key: str = Field(default="", description="The API key for the LlamaParse API.")
# Library / access specific configurations
api_key: str = Field(
default="",
description="The API key for the LlamaParse API.",
validate_default=True,
)
base_url: str = Field(
default=DEFAULT_BASE_URL,
description="The base URL of the Llama Parsing API.",
)
result_type: ResultType = Field(
default=ResultType.TXT, description="The result type for the parser."
check_interval: int = Field(
default=1,
description="The interval in seconds to check if the parsing is done.",
)
custom_client: Optional[httpx.AsyncClient] = Field(
default=None, description="A custom HTTPX client to use for sending requests."
)
ignore_errors: bool = Field(
default=True,
description="Whether or not to ignore and skip errors raised during parsing.",
)
max_timeout: int = Field(
default=2000,
description="The maximum timeout in seconds to wait for the parsing to finish.",
)
num_workers: int = Field(
default=4,
@@ -58,51 +66,210 @@ class LlamaParse(BasePydanticReader):
lt=10,
description="The number of workers to use sending API requests for parsing.",
)
check_interval: int = Field(
default=1,
description="The interval in seconds to check if the parsing is done.",
)
max_timeout: int = Field(
default=2000,
description="The maximum timeout in seconds to wait for the parsing to finish.",
)
verbose: bool = Field(
default=True, description="Whether to print the progress of the parsing."
result_type: ResultType = Field(
default=ResultType.TXT, description="The result type for the parser."
)
show_progress: bool = Field(
default=True, description="Show progress when parsing multiple files."
)
language: Language = Field(
default=Language.ENGLISH, description="The language of the text to parse."
split_by_page: bool = Field(
default=True,
description="Whether to split by page using the page separator",
)
parsing_instruction: Optional[str] = Field(
default="", description="The parsing instruction for the parser."
verbose: bool = Field(
default=True, description="Whether to print the progress of the parsing."
)
skip_diagonal_text: Optional[bool] = Field(
# Parsing specific configurations (Alphabetical order)
annotate_links: Optional[bool] = Field(
default=False,
description="If set to true, the parser will ignore diagonal text (when the text rotation in degrees modulo 90 is not 0).",
description="Annotate links found in the document to extract their URL.",
)
invalidate_cache: Optional[bool] = Field(
auto_mode: Optional[bool] = Field(
default=False,
description="If set to true, the cache will be ignored and the document re-processes. All document are kept in cache for 48hours after the job was completed to avoid processing the same document twice.",
description="If set to true, the parser will automatically select the best mode to extract text from documents based on the rules provide. Will use the 'accurate' default mode by default and will upgrade page that match the rule to Premium mode.",
)
auto_mode_trigger_on_image_in_page: Optional[bool] = Field(
default=False,
description="If auto_mode is set to true, the parser will upgrade the page that contain an image to Premium mode.",
)
auto_mode_trigger_on_table_in_page: Optional[bool] = Field(
default=False,
description="If auto_mode is set to true, the parser will upgrade the page that contain a table to Premium mode.",
)
auto_mode_trigger_on_text_in_page: Optional[str] = Field(
default=None,
description="If auto_mode is set to true, the parser will upgrade the page that contain the text to Premium mode.",
)
auto_mode_trigger_on_regexp_in_page: Optional[str] = Field(
default=None,
description="If auto_mode is set to true, the parser will upgrade the page that match the regexp to Premium mode.",
)
azure_openai_api_version: Optional[str] = Field(
default=None, description="Azure Openai API Version"
)
azure_openai_deployment_name: Optional[str] = Field(
default=None, description="Azure Openai Deployment Name"
)
azure_openai_endpoint: Optional[str] = Field(
default=None, description="Azure Openai Endpoint"
)
azure_openai_key: Optional[str] = Field(
default=None, description="Azure Openai Key"
)
bbox_bottom: Optional[float] = Field(
default=None,
description="The bottom margin of the bounding box to use to extract text from documents expressed as a float between 0 and 1 representing the percentage of the page height.",
)
bbox_left: Optional[float] = Field(
default=None,
description="The left margin of the bounding box to use to extract text from documents expressed as a float between 0 and 1 representing the percentage of the page width.",
)
bbox_right: Optional[float] = Field(
default=None,
description="The right margin of the bounding box to use to extract text from documents expressed as a float between 0 and 1 representing the percentage of the page width.",
)
bbox_top: Optional[float] = Field(
default=None,
description="The top margin of the bounding box to use to extract text from documents expressed as a float between 0 and 1 representing the percentage of the page height.",
)
continuous_mode: Optional[bool] = Field(
default=False,
description="Parse documents continuously, leading to better results on documents where tables span across two pages.",
)
disable_ocr: Optional[bool] = Field(
default=False,
description="Disable the OCR on the document. LlamaParse will only extract the copyable text from the document.",
)
disable_image_extraction: Optional[bool] = Field(
default=False,
description="If set to true, the parser will not extract images from the document. Make the parser faster.",
)
do_not_cache: Optional[bool] = Field(
default=False,
description="If set to true, the document will not be cached. This mean that you will be re-charged it you reprocess them as they will not be cached.",
)
fast_mode: Optional[bool] = Field(
default=False,
description="Note: Non compatible with gpt-4o. If set to true, the parser will use a faster mode to extract text from documents. This mode will skip OCR of images, and table/heading reconstruction.",
)
do_not_unroll_columns: Optional[bool] = Field(
default=False,
description="If set to true, the parser will keep column in the text according to document layout. Reduce reconstruction accuracy, and LLM's/embedings performances in most case.",
)
extract_charts: Optional[bool] = Field(
default=False,
description="If set to true, the parser will extract/tag charts from the document.",
)
fast_mode: Optional[bool] = Field(
default=False,
description="Note: Non compatible with gpt-4o. If set to true, the parser will use a faster mode to extract text from documents. This mode will skip OCR of images, and table/heading reconstruction.",
)
guess_xlsx_sheet_names: Optional[bool] = Field(
default=False,
description="Whether to guess the sheet names of the xlsx file.",
)
html_make_all_elements_visible: Optional[bool] = Field(
default=False,
description="If set to true, when parsing HTML the parser will consider all elements display not element as display block.",
)
html_remove_fixed_elements: Optional[bool] = Field(
default=False,
description="If set to true, when parsing HTML the parser will remove fixed elements. Useful to hide cookie banners.",
)
html_remove_navigation_elements: Optional[bool] = Field(
default=False,
description="If set to true, when parsing HTML the parser will remove navigation elements. Useful to hide menus, header, footer.",
)
http_proxy: Optional[str] = Field(
default=None,
description="(optional) If set with input_url will use the specified http proxy to download the file.",
)
invalidate_cache: Optional[bool] = Field(
default=False,
description="If set to true, the cache will be ignored and the document re-processes. All document are kept in cache for 48hours after the job was completed to avoid processing the same document twice.",
)
is_formatting_instruction: Optional[bool] = Field(
default=False,
description="Allow the parsing instruction to also format the output. Disable to have a cleaner markdown output.",
)
language: Optional[str] = Field(
default="en", description="The language of the text to parse."
)
max_pages: Optional[int] = Field(
default=None,
description="The maximum number of pages to extract text from documents. If set to 0 or not set, all pages will be that should be extracted will be extracted (can work in combination with targetPages).",
)
output_pdf_of_document: Optional[bool] = Field(
default=False,
description="If set to true, the parser will also output a PDF of the document. (except for spreadsheets)",
)
output_s3_path_prefix: Optional[str] = Field(
default=None,
description="An S3 path prefix to store the output of the parsing job. If set, the parser will upload the output to S3. The bucket need to be accessible from the LlamaIndex organization.",
)
page_prefix: Optional[str] = Field(
default=None,
description="A templated prefix to add to the beginning of each page. If it contain `{page_number}`, it will be replaced by the page number.",
)
page_separator: Optional[str] = Field(
default=None,
description="The page separator to use to split the text. Default is None, which means the parser will use the default separator '\\n---\\n'.",
description="A templated page separator to use to split the text. If it contain `{page_number}`,it will be replaced by the next page number. If not set will the default separator '\\n---\\n' will be used.",
)
gpt4o_mode: bool = Field(
page_suffix: Optional[str] = Field(
default=None,
description="A templated suffix to add to the beginning of each page. If it contain `{page_number}`, it will be replaced by the page number.",
)
parsing_instruction: Optional[str] = Field(
default="", description="The parsing instruction for the parser."
)
premium_mode: Optional[bool] = Field(
default=False,
description="Use our best parser mode if set to True.",
)
skip_diagonal_text: Optional[bool] = Field(
default=False,
description="If set to true, the parser will ignore diagonal text (when the text rotation in degrees modulo 90 is not 0).",
)
structured_output: Optional[bool] = Field(
default=False,
description="If set to true, the parser will output structured data based on the provided JSON Schema.",
)
structured_output_json_schema: Optional[str] = Field(
default=None,
description="A JSON Schema to use to structure the output of the parsing job. If set, the parser will output structured data based on the provided JSON Schema.",
)
structured_output_json_schema_name: Optional[str] = Field(
default=None,
description="The named JSON Schema to use to structure the output of the parsing job. For convenience / testing, LlamaParse provides a few named JSON Schema that can be used directly. Use 'imFeelingLucky' to let llamaParse dream the schema.",
)
take_screenshot: Optional[bool] = Field(
default=False,
description="Whether to take screenshot of each page of the document.",
)
target_pages: Optional[str] = Field(
default=None,
description="The target pages to extract text from documents. Describe as a comma separated list of page numbers. The first page of the document is page 0",
)
use_vendor_multimodal_model: Optional[bool] = Field(
default=False,
description="Whether to use the vendor multimodal API.",
)
vendor_multimodal_api_key: Optional[str] = Field(
default=None,
description="The API key for the multimodal API.",
)
vendor_multimodal_model_name: Optional[str] = Field(
default=None,
description="The model name for the vendor multimodal API.",
)
webhook_url: Optional[str] = Field(
default=None,
description="A URL that needs to be called at the end of the parsing job.",
)
# Deprecated
bounding_box: Optional[str] = Field(
default=None,
description="The bounding box to use to extract text from documents describe as a string containing the bounding box margins",
)
gpt4o_mode: Optional[bool] = Field(
default=False,
description="Whether to use gpt-4o extract text from documents.",
)
@@ -110,36 +277,9 @@ class LlamaParse(BasePydanticReader):
default=None,
description="The API key for the GPT-4o API. Lowers the cost of parsing.",
)
bounding_box: Optional[str] = Field(
default=None,
description="The bounding box to use to extract text from documents describe as a string containing the bounding box margins",
)
target_pages: Optional[str] = Field(
default=None,
description="The target pages to extract text from documents. Describe as a comma separated list of page numbers. The first page of the document is page 0",
)
ignore_errors: bool = Field(
default=True,
description="Whether or not to ignore and skip errors raised during parsing.",
)
split_by_page: bool = Field(
default=True,
description="Whether to split by page (NOTE: using a predefined separator `\n---\n`)",
)
vendor_multimodal_api_key: Optional[str] = Field(
default=None,
description="The API key for the multimodal API.",
)
use_vendor_multimodal_model: bool = Field(
default=False,
description="Whether to use the vendor multimodal API.",
)
vendor_multimodal_model_name: Optional[str] = Field(
default=None,
description="The model name for the vendor multimodal API.",
)
@validator("api_key", pre=True, always=True)
@field_validator("api_key", mode="before", check_fields=True)
@classmethod
def validate_api_key(cls, v: str) -> str:
"""Validate the API key."""
if not v:
@@ -152,20 +292,67 @@ class LlamaParse(BasePydanticReader):
return v
@validator("base_url", pre=True, always=True)
@field_validator("base_url", mode="before", check_fields=True)
@classmethod
def validate_base_url(cls, v: str) -> str:
"""Validate the base URL."""
url = os.getenv("LLAMA_CLOUD_BASE_URL", None)
return url or v or DEFAULT_BASE_URL
@asynccontextmanager
async def client_context(self) -> AsyncGenerator[httpx.AsyncClient, None]:
"""Create a context for the HTTPX client."""
if self.custom_client is not None:
yield self.custom_client
else:
async with httpx.AsyncClient(timeout=self.max_timeout) as client:
yield client
def _is_input_url(self, file_path: FileInput) -> bool:
"""Check if the input is a valid URL.
This method checks for:
- Proper URL scheme (http/https)
- Valid URL structure
- Network location (domain)
"""
if not isinstance(file_path, str):
return False
try:
result = urlparse(file_path)
return all(
[
result.scheme in ("http", "https"),
result.netloc, # Has domain
result.scheme, # Has scheme
]
)
except Exception:
return False
def _is_s3_url(self, file_path: FileInput) -> bool:
"""Check if the input is a valid URL.
This method checks for:
- Proper S3 scheme (s3://)
"""
if isinstance(file_path, str):
return file_path.startswith("s3://")
return False
# upload a document and get back a job_id
async def _create_job(
self, file_input: FileInput, extra_info: Optional[dict] = None
self,
file_input: FileInput,
extra_info: Optional[dict] = None,
fs: Optional[AbstractFileSystem] = None,
) -> str:
headers = {"Authorization": f"Bearer {self.api_key}"}
url = f"{self.base_url}/api/parsing/upload"
files = None
file_handle = None
input_url = file_input if self._is_input_url(file_input) else None
input_s3_path = file_input if self._is_s3_url(file_input) else None
if isinstance(file_input, (bytes, BufferedIOBase)):
if not extra_info or "file_name" not in extra_info:
@@ -175,7 +362,11 @@ class LlamaParse(BasePydanticReader):
file_name = extra_info["file_name"]
mime_type = mimetypes.guess_type(file_name)[0]
files = {"file": (file_name, file_input, mime_type)}
elif isinstance(file_input, (str, Path)):
elif input_url is not None:
files = None
elif input_s3_path is not None:
files = None
elif isinstance(file_input, (str, Path, PurePosixPath, PurePath)):
file_path = str(file_input)
file_ext = os.path.splitext(file_path)[1].lower()
if file_ext not in SUPPORTED_FILE_TYPES:
@@ -185,36 +376,199 @@ class LlamaParse(BasePydanticReader):
)
mime_type = mimetypes.guess_type(file_path)[0]
# Open the file here for the duration of the async context
file_handle = open(file_path, "rb")
# load data, set the mime type
fs = fs or get_default_fs()
file_handle = fs.open(file_input, "rb")
files = {"file": (os.path.basename(file_path), file_handle, mime_type)}
else:
raise ValueError(
"file_input must be either a file path string, file bytes, or buffer object"
)
data: Dict[str, Any] = {}
data["from_python_package"] = True
if self.annotate_links:
data["annotate_links"] = self.annotate_links
if self.auto_mode:
data["auto_mode"] = self.auto_mode
if self.auto_mode_trigger_on_image_in_page:
data[
"auto_mode_trigger_on_image_in_page"
] = self.auto_mode_trigger_on_image_in_page
if self.auto_mode_trigger_on_table_in_page:
data[
"auto_mode_trigger_on_table_in_page"
] = self.auto_mode_trigger_on_table_in_page
if self.auto_mode_trigger_on_text_in_page is not None:
data[
"auto_mode_trigger_on_text_in_page"
] = self.auto_mode_trigger_on_text_in_page
if self.auto_mode_trigger_on_regexp_in_page is not None:
data[
"auto_mode_trigger_on_regexp_in_page"
] = self.auto_mode_trigger_on_regexp_in_page
if self.azure_openai_api_version is not None:
data["azure_openai_api_version"] = self.azure_openai_api_version
if self.azure_openai_deployment_name is not None:
data["azure_openai_deployment_name"] = self.azure_openai_deployment_name
if self.azure_openai_endpoint is not None:
data["azure_openai_endpoint"] = self.azure_openai_endpoint
if self.azure_openai_key is not None:
data["azure_openai_key"] = self.azure_openai_key
if self.bbox_bottom is not None:
data["bbox_bottom"] = self.bbox_bottom
if self.bbox_left is not None:
data["bbox_left"] = self.bbox_left
if self.bbox_right is not None:
data["bbox_right"] = self.bbox_right
if self.bbox_top is not None:
data["bbox_top"] = self.bbox_top
if self.continuous_mode:
data["continuous_mode"] = self.continuous_mode
if self.disable_ocr:
data["disable_ocr"] = self.disable_ocr
if self.disable_image_extraction:
data["disable_image_extraction"] = self.disable_image_extraction
if self.do_not_cache:
data["do_not_cache"] = self.do_not_cache
if self.do_not_unroll_columns:
data["do_not_unroll_columns"] = self.do_not_unroll_columns
if self.extract_charts:
data["extract_charts"] = self.extract_charts
if self.fast_mode:
data["fast_mode"] = self.fast_mode
if self.guess_xlsx_sheet_names:
data["guess_xlsx_sheet_names"] = self.guess_xlsx_sheet_names
if self.html_make_all_elements_visible:
data["html_make_all_elements_visible"] = self.html_make_all_elements_visible
if self.html_remove_fixed_elements:
data["html_remove_fixed_elements"] = self.html_remove_fixed_elements
if self.html_remove_navigation_elements:
data[
"html_remove_navigation_elements"
] = self.html_remove_navigation_elements
if self.http_proxy is not None:
data["http_proxy"] = self.http_proxy
if input_url is not None:
files = None
data["input_url"] = str(input_url)
if input_s3_path is not None:
files = None
data["input_s3_path"] = str(input_s3_path)
if self.invalidate_cache:
data["invalidate_cache"] = self.invalidate_cache
if self.is_formatting_instruction:
data["is_formatting_instruction"] = self.is_formatting_instruction
if self.language:
data["language"] = self.language
if self.max_pages is not None:
data["max_pages"] = self.max_pages
if self.output_pdf_of_document:
data["output_pdf_of_document"] = self.output_pdf_of_document
if self.output_s3_path_prefix is not None:
data["output_s3_path_prefix"] = self.output_s3_path_prefix
if self.page_prefix is not None:
data["page_prefix"] = self.page_prefix
# only send page separator to server if it is not None
# as if a null, "" string is sent the server will then ignore the page separator instead of using the default
if self.page_separator is not None:
data["page_separator"] = self.page_separator
if self.page_suffix is not None:
data["page_suffix"] = self.page_suffix
if self.parsing_instruction is not None:
data["parsing_instruction"] = self.parsing_instruction
if self.premium_mode:
data["premium_mode"] = self.premium_mode
if self.skip_diagonal_text:
data["skip_diagonal_text"] = self.skip_diagonal_text
if self.structured_output:
data["structured_output"] = self.structured_output
if self.structured_output_json_schema is not None:
data["structured_output_json_schema"] = self.structured_output_json_schema
if self.structured_output_json_schema_name is not None:
data[
"structured_output_json_schema_name"
] = self.structured_output_json_schema_name
if self.take_screenshot:
data["take_screenshot"] = self.take_screenshot
if self.target_pages is not None:
data["target_pages"] = self.target_pages
if self.use_vendor_multimodal_model:
data["use_vendor_multimodal_model"] = self.use_vendor_multimodal_model
if self.vendor_multimodal_api_key is not None:
data["vendor_multimodal_api_key"] = self.vendor_multimodal_api_key
if self.vendor_multimodal_model_name is not None:
data["vendor_multimodal_model_name"] = self.vendor_multimodal_model_name
if self.webhook_url is not None:
data["webhook_url"] = self.webhook_url
# Deprecated
if self.bounding_box is not None:
data["bounding_box"] = self.bounding_box
if self.gpt4o_mode:
data["gpt4o_mode"] = self.gpt4o_mode
if self.gpt4o_api_key is not None:
data["gpt4o_api_key"] = self.gpt4o_api_key
try:
async with httpx.AsyncClient(timeout=self.max_timeout) as client:
async with self.client_context() as client:
response = await client.post(
url,
files=files,
headers=headers,
data={
"language": self.language.value,
"parsing_instruction": self.parsing_instruction,
"invalidate_cache": self.invalidate_cache,
"skip_diagonal_text": self.skip_diagonal_text,
"do_not_cache": self.do_not_cache,
"fast_mode": self.fast_mode,
"do_not_unroll_columns": self.do_not_unroll_columns,
"page_separator": self.page_separator,
"gpt4o_mode": self.gpt4o_mode,
"gpt4o_api_key": self.gpt4o_api_key,
"bounding_box": self.bounding_box,
"target_pages": self.target_pages,
"vendor_multimodal_api_key": self.vendor_multimodal_api_key,
"use_vendor_multimodal_model": self.use_vendor_multimodal_model,
"vendor_multimodal_model_name": self.vendor_multimodal_model_name,
},
data=data,
)
if not response.is_success:
raise Exception(f"Failed to parse the file: {response.text}")
@@ -226,7 +580,7 @@ class LlamaParse(BasePydanticReader):
async def _get_job_result(
self, job_id: str, result_type: str, verbose: bool = False
) -> dict:
) -> Dict[str, Any]:
result_url = f"{self.base_url}/api/parsing/job/{job_id}/result/{result_type}"
status_url = f"{self.base_url}/api/parsing/job/{job_id}"
headers = {"Authorization": f"Bearer {self.api_key}"}
@@ -235,7 +589,7 @@ class LlamaParse(BasePydanticReader):
tries = 0
while True:
await asyncio.sleep(self.check_interval)
async with httpx.AsyncClient(timeout=self.max_timeout) as client:
async with self.client_context() as client:
tries += 1
result = await client.get(status_url, headers=headers)
@@ -252,7 +606,8 @@ class LlamaParse(BasePydanticReader):
continue
# Allowed values "PENDING", "SUCCESS", "ERROR", "CANCELED"
status = result.json()["status"]
result_json = result.json()
status = result_json["status"]
if status == "SUCCESS":
parsed_result = await client.get(result_url, headers=headers)
return parsed_result.json()
@@ -264,22 +619,25 @@ class LlamaParse(BasePydanticReader):
print(".", end="", flush=True)
await asyncio.sleep(self.check_interval)
continue
else:
raise Exception(
f"Failed to parse the file: {job_id}, status: {status}"
error_code = result_json.get("error_code", "No error code found")
error_message = result_json.get(
"error_message", "No error message found"
)
exception_str = f"Job ID: {job_id} failed with status: {status}, Error code: {error_code}, Error message: {error_message}"
raise Exception(exception_str)
async def _aload_data(
self,
file_path: FileInput,
extra_info: Optional[dict] = None,
fs: Optional[AbstractFileSystem] = None,
verbose: bool = False,
) -> List[Document]:
"""Load data from the input path."""
try:
job_id = await self._create_job(file_path, extra_info=extra_info)
job_id = await self._create_job(file_path, extra_info=extra_info, fs=fs)
if verbose:
print("Started parsing the file under job_id %s" % job_id)
@@ -294,7 +652,7 @@ class LlamaParse(BasePydanticReader):
)
]
if self.split_by_page:
return _get_sub_docs(docs)
return self._get_sub_docs(docs)
else:
return docs
@@ -310,17 +668,19 @@ class LlamaParse(BasePydanticReader):
self,
file_path: Union[List[FileInput], FileInput],
extra_info: Optional[dict] = None,
fs: Optional[AbstractFileSystem] = None,
) -> List[Document]:
"""Load data from the input path."""
if isinstance(file_path, (str, Path, bytes, BufferedIOBase)):
if isinstance(file_path, (str, PurePosixPath, Path, bytes, BufferedIOBase)):
return await self._aload_data(
file_path, extra_info=extra_info, verbose=self.verbose
file_path, extra_info=extra_info, fs=fs, verbose=self.verbose
)
elif isinstance(file_path, list):
jobs = [
self._aload_data(
f,
extra_info=extra_info,
fs=fs,
verbose=self.verbose and not self.show_progress,
)
for f in file_path
@@ -349,10 +709,11 @@ class LlamaParse(BasePydanticReader):
self,
file_path: Union[List[FileInput], FileInput],
extra_info: Optional[dict] = None,
fs: Optional[AbstractFileSystem] = None,
) -> List[Document]:
"""Load data from the input path."""
try:
return asyncio.run(self.aload_data(file_path, extra_info))
return asyncio_run(self.aload_data(file_path, extra_info, fs=fs))
except RuntimeError as e:
if nest_asyncio_err in str(e):
raise RuntimeError(nest_asyncio_msg)
@@ -367,12 +728,13 @@ class LlamaParse(BasePydanticReader):
job_id = await self._create_job(file_path, extra_info=extra_info)
if self.verbose:
print("Started parsing the file under job_id %s" % job_id)
result = await self._get_job_result(job_id, "json")
result["job_id"] = job_id
result["file_path"] = file_path
return [result]
if not isinstance(file_path, (bytes, BufferedIOBase)):
result["file_path"] = str(file_path)
return [result]
except Exception as e:
file_repr = file_path if isinstance(file_path, str) else "<bytes/buffer>"
print(f"Error while parsing the file '{file_repr}':", e)
@@ -418,14 +780,16 @@ class LlamaParse(BasePydanticReader):
) -> List[dict]:
"""Parse the input path."""
try:
return asyncio.run(self.aget_json(file_path, extra_info))
return asyncio_run(self.aget_json(file_path, extra_info))
except RuntimeError as e:
if nest_asyncio_err in str(e):
raise RuntimeError(nest_asyncio_msg)
else:
raise e
def get_images(self, json_result: List[dict], download_path: str) -> List[dict]:
async def aget_images(
self, json_result: List[dict], download_path: str
) -> List[dict]:
"""Download images from the parsed result."""
headers = {"Authorization": f"Bearer {self.api_key}"}
@@ -455,11 +819,18 @@ class LlamaParse(BasePydanticReader):
image["path"] = image_path
image["job_id"] = job_id
image["original_pdf_path"] = result["file_path"]
image["original_file_path"] = result.get("file_path", None)
image["page_number"] = page["page"]
with open(image_path, "wb") as f:
image_url = f"{self.base_url}/api/parsing/job/{job_id}/result/image/{image_name}"
f.write(httpx.get(image_url, headers=headers).content)
async with self.client_context() as client:
res = await client.get(
image_url, headers=headers, timeout=self.max_timeout
)
res.raise_for_status()
f.write(res.content)
images.append(image)
return images
except Exception as e:
@@ -468,3 +839,82 @@ class LlamaParse(BasePydanticReader):
return []
else:
raise e
def get_images(self, json_result: List[dict], download_path: str) -> List[dict]:
"""Download images from the parsed result."""
try:
return asyncio_run(self.aget_images(json_result, download_path))
except RuntimeError as e:
if nest_asyncio_err in str(e):
raise RuntimeError(nest_asyncio_msg)
else:
raise e
async def aget_xlsx(
self, json_result: List[dict], download_path: str
) -> List[dict]:
"""Download images from the parsed result."""
headers = {"Authorization": f"Bearer {self.api_key}"}
# make the download path
if not os.path.exists(download_path):
os.makedirs(download_path)
try:
xlsx_list = []
for result in json_result:
job_id = result["job_id"]
if self.verbose:
print("> XLSX")
xlsx_path = os.path.join(download_path, f"{job_id}.xlsx")
xlsx = {}
xlsx["path"] = xlsx_path
xlsx["job_id"] = job_id
xlsx["original_file_path"] = result.get("file_path", None)
with open(xlsx_path, "wb") as f:
xlsx_url = (
f"{self.base_url}/api/parsing/job/{job_id}/result/raw/xlsx"
)
async with self.client_context() as client:
res = await client.get(
xlsx_url, headers=headers, timeout=self.max_timeout
)
res.raise_for_status()
f.write(res.content)
xlsx_list.append(xlsx)
return xlsx_list
except Exception as e:
print("Error while downloading xlsx:", e)
if self.ignore_errors:
return []
else:
raise e
def get_xlsx(self, json_result: List[dict], download_path: str) -> List[dict]:
"""Download xlsx from the parsed result."""
try:
return asyncio_run(self.aget_xlsx(json_result, download_path))
except RuntimeError as e:
if nest_asyncio_err in str(e):
raise RuntimeError(nest_asyncio_msg)
else:
raise e
def _get_sub_docs(self, docs: List[Document]) -> List[Document]:
"""Split docs into pages, by separator."""
sub_docs = []
separator = self.page_separator or _DEFAULT_SEPARATOR
for doc in docs:
doc_chunks = doc.text.split(separator)
for doc_chunk in doc_chunks:
sub_doc = Document(
text=doc_chunk,
metadata=deepcopy(doc.metadata),
)
sub_docs.append(sub_doc)
return sub_docs
View File
+92
View File
@@ -0,0 +1,92 @@
import click
import json
from enum import Enum
from pathlib import Path
from pydantic.fields import FieldInfo
from typing import Any, Callable, List
from llama_parse.base import LlamaParse
def pydantic_field_to_click_option(name: str, field: FieldInfo) -> click.Option:
"""Convert a Pydantic field to a Click option."""
kwargs = {
"default": field.default if field.default else None,
"help": field.description,
}
if isinstance(kwargs["default"], Enum):
kwargs["default"] = kwargs["default"].value
if field.annotation is bool:
kwargs["is_flag"] = True
if field.default and field.default is True:
name = f"no-{name}"
return click.option(f'--{name.replace("_", "-")}', **kwargs)
def add_options(options: List[click.Option]) -> Callable:
def _add_options(func: Callable) -> Callable:
for option in reversed(options):
func = option(func)
return func
return _add_options
@click.command()
@click.argument("file_paths", nargs=-1, type=click.Path(exists=True, path_type=Path))
@click.option(
"--output-file", type=click.Path(path_type=Path), help="Path to save the output"
)
@click.option("--output-raw-json", is_flag=True, help="Output the raw JSON result")
@add_options(
[
pydantic_field_to_click_option(name, field)
for name, field in LlamaParse.model_fields.items()
if name not in ["custom_client"]
]
)
def parse(**kwargs: Any) -> None:
"""Parse files using LlamaParse and output the results."""
file_paths = kwargs.pop("file_paths")
output_file = kwargs.pop("output_file")
output_raw_json = kwargs.pop("output_raw_json")
# Remove None values to use LlamaParse defaults
kwargs = {k: v for k, v in kwargs.items() if v is not None}
# Remove no- prefix for boolean flags
kwargs = {k.replace("no_", ""): v for k, v in kwargs.items()}
parser = LlamaParse(**kwargs)
if output_raw_json:
results = parser.get_json_result(list(file_paths))
if output_file:
with output_file.open("w") as f:
json.dump(results, f)
click.echo(f"Results saved to {output_file}")
else:
click.echo(results)
else:
results = parser.load_data(list(file_paths))
if output_file:
with output_file.open("w") as f:
for i, doc in enumerate(results):
f.write(f"File: {doc.metadata.get('file_path', 'Unknown')}\n") # type: ignore
f.write(doc.text) # type: ignore
if i < len(results) - 1:
f.write("\n\n---\n\n")
click.echo(f"Results saved to {output_file}")
else:
for i, doc in enumerate(results):
click.echo(f"File: {doc.metadata.get('file_path', 'Unknown')}") # type: ignore
click.echo(doc.text) # type: ignore
if i < len(results) - 1:
click.echo("\n---\n")
if __name__ == "__main__":
parse()
+1
View File
@@ -11,6 +11,7 @@ class ResultType(str, Enum):
TXT = "text"
MD = "markdown"
JSON = "json"
STRUCTURED = "structured"
class Language(str, Enum):
Generated
+1665 -1519
View File
File diff suppressed because it is too large Load Diff
+9 -3
View File
@@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api"
[tool.poetry]
name = "llama-parse"
version = "0.4.8"
version = "0.5.17"
description = "Parse files into RAG-Optimized formats."
authors = ["Logan Markewich <logan@llamaindex.ai>"]
license = "MIT"
@@ -12,9 +12,15 @@ readme = "README.md"
packages = [{include = "llama_parse"}]
[tool.poetry.dependencies]
python = ">=3.8.1,<4.0"
llama-index-core = ">=0.10.29"
python = ">=3.9,<4.0"
llama-index-core = ">=0.11.0"
pydantic = "!=2.10"
click = "^8.1.7"
[tool.poetry.group.dev.dependencies]
pytest = "^8.0.0"
pytest-asyncio = "*"
ipykernel = "^6.29.0"
[tool.poetry.scripts]
llama-parse = "llama_parse.cli.main:parse"
Binary file not shown.

After

Width:  |  Height:  |  Size: 347 KiB

+105 -3
View File
@@ -1,5 +1,9 @@
import os
import pytest
import shutil
from fsspec.implementations.local import LocalFileSystem
from httpx import AsyncClient
from llama_parse import LlamaParse
@@ -73,13 +77,29 @@ def test_simple_page_markdown_buffer(markdown_parser: LlamaParse) -> None:
os.environ.get("LLAMA_CLOUD_API_KEY", "") == "",
reason="LLAMA_CLOUD_API_KEY not set",
)
def test_simple_page_progress_workers() -> None:
@pytest.mark.asyncio
async def test_simple_page_with_custom_fs() -> None:
parser = LlamaParse(result_type="markdown")
fs = LocalFileSystem()
filepath = os.path.join(
os.path.dirname(__file__), "test_files/attention_is_all_you_need.pdf"
)
result = await parser.aload_data(filepath, fs=fs)
assert len(result) == 1
@pytest.mark.skipif(
os.environ.get("LLAMA_CLOUD_API_KEY", "") == "",
reason="LLAMA_CLOUD_API_KEY not set",
)
@pytest.mark.asyncio
async def test_simple_page_progress_workers() -> None:
parser = LlamaParse(result_type="markdown", show_progress=True, verbose=True)
filepath = os.path.join(
os.path.dirname(__file__), "test_files/attention_is_all_you_need.pdf"
)
result = parser.load_data([filepath, filepath])
result = await parser.aload_data([filepath, filepath])
assert len(result) == 2
assert len(result[0].text) > 0
@@ -90,6 +110,88 @@ def test_simple_page_progress_workers() -> None:
filepath = os.path.join(
os.path.dirname(__file__), "test_files/attention_is_all_you_need.pdf"
)
result = parser.load_data([filepath, filepath])
result = await parser.aload_data([filepath, filepath])
assert len(result) == 2
assert len(result[0].text) > 0
@pytest.mark.skipif(
os.environ.get("LLAMA_CLOUD_API_KEY", "") == "",
reason="LLAMA_CLOUD_API_KEY not set",
)
@pytest.mark.asyncio
async def test_custom_client() -> None:
custom_client = AsyncClient(verify=False, timeout=10)
parser = LlamaParse(result_type="markdown", custom_client=custom_client)
filepath = os.path.join(
os.path.dirname(__file__), "test_files/attention_is_all_you_need.pdf"
)
result = await parser.aload_data(filepath)
assert len(result) == 1
assert len(result[0].text) > 0
@pytest.mark.skipif(
os.environ.get("LLAMA_CLOUD_API_KEY", "") == "",
reason="LLAMA_CLOUD_API_KEY not set",
)
@pytest.mark.asyncio
async def test_input_url() -> None:
parser = LlamaParse(result_type="markdown")
# links to a resume example
input_url = "https://cdn-blog.novoresume.com/articles/google-docs-resume-templates/basic-google-docs-resume.png"
result = await parser.aload_data(input_url)
assert len(result) == 1
assert "your name" in result[0].text.lower()
@pytest.mark.skipif(
os.environ.get("LLAMA_CLOUD_API_KEY", "") == "",
reason="LLAMA_CLOUD_API_KEY not set",
)
@pytest.mark.asyncio
async def test_input_url_with_website_input() -> None:
parser = LlamaParse(result_type="markdown")
input_url = "https://www.google.com"
result = await parser.aload_data(input_url)
assert len(result) == 1
assert "google" in result[0].text.lower()
@pytest.mark.skipif(
os.environ.get("LLAMA_CLOUD_API_KEY", "") == "",
reason="LLAMA_CLOUD_API_KEY not set",
)
@pytest.mark.asyncio
async def test_mixing_input_types() -> None:
parser = LlamaParse(result_type="markdown")
filepath = os.path.join(
os.path.dirname(__file__), "test_files/attention_is_all_you_need.pdf"
)
input_url = "https://cdn-blog.novoresume.com/articles/google-docs-resume-templates/basic-google-docs-resume.png"
result = await parser.aload_data([filepath, input_url])
assert len(result) == 2
@pytest.mark.skipif(
os.environ.get("LLAMA_CLOUD_API_KEY", "") == "",
reason="LLAMA_CLOUD_API_KEY not set",
)
@pytest.mark.asyncio
async def test_download_images() -> None:
parser = LlamaParse(result_type="markdown", take_screenshot=True)
filepath = os.path.join(
os.path.dirname(__file__), "test_files/attention_is_all_you_need.pdf"
)
json_result = await parser.aget_json([filepath])
assert len(json_result) == 1
assert len(json_result[0]["pages"][0]["images"]) > 0
download_path = os.path.join(os.path.dirname(__file__), "test_files/images")
shutil.rmtree(download_path, ignore_errors=True)
await parser.aget_images(json_result, download_path)
assert len(os.listdir(download_path)) == len(json_result[0]["pages"][0]["images"])