From 4740d0611d428c77c8475ffcf4e78acf1dbbb646 Mon Sep 17 00:00:00 2001 From: Ravi Theja Date: Mon, 9 Dec 2024 21:28:48 +0530 Subject: [PATCH] Add get charts function (#542) * Add get charts function * code refactoring * solve linting * Add cookbook --- examples/demo_get_charts.ipynb | 252 ++++++ examples/demo_json_tour.ipynb | 59 +- examples/demo_starter_multimodal.ipynb | 754 ++++++++---------- .../demo_starter_parse_selected_pages.ipynb | 27 +- llama_parse/base.py | 88 +- 5 files changed, 700 insertions(+), 480 deletions(-) create mode 100644 examples/demo_get_charts.ipynb diff --git a/examples/demo_get_charts.ipynb b/examples/demo_get_charts.ipynb new file mode 100644 index 0000000..d3e3c4f --- /dev/null +++ b/examples/demo_get_charts.ipynb @@ -0,0 +1,252 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "d27f1082-cd10-405e-9570-6f0e934bba8b", + "metadata": {}, + "source": [ + "# Download Charts\n", + "\n", + "\"Open\n", + "\n", + "This notebook demonstrates how to download charts from a document using the JSON mode in LlamaParse.\n", + "\n", + "JSON mode provides a wealth of data and metadata for each page of your document, including details about charts and images." + ] + }, + { + "cell_type": "markdown", + "id": "a004db48-8d3f-421c-915a-477692f71b90", + "metadata": {}, + "source": [ + "### Setup\n", + "\n", + "Let's bring in our imports and set up our API keys." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bc6a7a4b-b568-4db5-bcba-62f5c517ff3a", + "metadata": {}, + "outputs": [], + "source": [ + "!pip install llama-index-core\n", + "!pip install llama-parse" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0879301c-ff91-4431-941a-6c0ef7cd8fe2", + "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\"] = \"llx-..\"" + ] + }, + { + "cell_type": "markdown", + "id": "b411d2ee-3e6b-45b0-b532-4a8e3abcdea0", + "metadata": {}, + "source": [ + "### Download Data\n", + "\n", + "Let's use [`AGENTLESS :\n", + "Demystifying LLM-based Software Engineering Agents`](https://arxiv.org/pdf/2407.01489) paper and download the charts present in the paper." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c39d408f-e885-4940-85c7-b09ca3bc7cb7", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "--2024-12-09 20:36:45-- https://arxiv.org/pdf/2407.01489\n", + "Resolving arxiv.org (arxiv.org)... 151.101.131.42, 151.101.67.42, 151.101.3.42, ...\n", + "Connecting to arxiv.org (arxiv.org)|151.101.131.42|:443... connected.\n", + "HTTP request sent, awaiting response... 200 OK\n", + "Length: 1384716 (1.3M) [application/pdf]\n", + "Saving to: ‘agentless.pdf’\n", + "\n", + "agentless.pdf 100%[===================>] 1.32M 2.12MB/s in 0.6s \n", + "\n", + "2024-12-09 20:36:45 (2.12 MB/s) - ‘agentless.pdf’ saved [1384716/1384716]\n", + "\n" + ] + } + ], + "source": [ + "!wget 'https://arxiv.org/pdf/2407.01489' -O \"agentless.pdf\"" + ] + }, + { + "cell_type": "markdown", + "id": "c2f42af8-afb3-4b3b-82d3-6b332fb38aa4", + "metadata": {}, + "source": [ + "### Using LlamaParse in JSON Mode for PDF Reading to get charts.\n", + "\n", + "Let's parse our document! \n", + "\n", + "We need to enable `extract_charts` parameter to get the charts present in the document." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9c9cd670-8229-4ad6-99a9-845bd82b7ec1", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Started parsing the file under job_id 62360aa4-19b2-463b-ace5-da43bdd3e781\n" + ] + } + ], + "source": [ + "from llama_parse import LlamaParse\n", + "\n", + "parser = LlamaParse(extract_charts=True, invalid_cache=True)\n", + "json_objs = parser.get_json_result(\"./agentless.pdf\")" + ] + }, + { + "cell_type": "markdown", + "id": "43969be5", + "metadata": {}, + "source": [ + "### Download Charts\n", + "\n", + "We will use `get_charts` function to download the charts present in the document to `charts` folder." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a7b5a8b1", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "> Charts for page 1: []\n", + "> Charts for page 2: []\n", + "> Charts for page 3: []\n", + "> Charts for page 4: []\n", + "> Charts for page 5: [{'name': 'chart_p5_0.png', 'x': 108, 'y': 80.8, 'height': 203.95, 'width': 434.93}]\n", + "> Charts for page 6: []\n", + "> Charts for page 7: [{'name': 'chart_p7_0.png', 'x': 325.8, 'y': 387.22, 'height': 100.88, 'width': 178.3}]\n", + "> Charts for page 8: []\n", + "> Charts for page 9: []\n", + "> Charts for page 10: [{'name': 'chart_p10_0.png', 'x': 111.38, 'y': 347.69, 'height': 294.72, 'width': 389.24}]\n", + "> Charts for page 11: [{'name': 'chart_p11_0.png', 'x': 286.2, 'y': 223.57, 'height': 121, 'width': 217.81}]\n", + "> Charts for page 12: [{'name': 'chart_p12_0.png', 'x': 293.04, 'y': 332.08, 'height': 55.06, 'width': 204.12}, {'name': 'chart_p12_1.png', 'x': 293.04, 'y': 433.77, 'height': 63.66, 'width': 204.12}]\n", + "> Charts for page 13: [{'name': 'chart_p13_0.png', 'x': 304.65, 'y': 234.09, 'height': 72.04, 'width': 180.91}]\n", + "> Charts for page 14: [{'name': 'chart_p14_0.png', 'x': 345.6, 'y': 90.26, 'height': 118.8, 'width': 158.4}, {'name': 'chart_p14_1.png', 'x': 329.63, 'y': 399.89, 'height': 45.14, 'width': 170.55}, {'name': 'chart_p14_2.png', 'x': 345.6, 'y': 564.91, 'height': 314.85, 'width': 158.4}]\n", + "> Charts for page 15: [{'name': 'chart_p15_0.png', 'x': 109.47, 'y': 216.8, 'height': 108.9, 'width': 393.06}]\n", + "> Charts for page 16: []\n", + "> Charts for page 17: [{'name': 'chart_p17_0.png', 'x': 133.08, 'y': 103.1, 'height': 299.8, 'width': 345.83}, {'name': 'chart_p17_1.png', 'x': 113.43, 'y': 419.08, 'height': 108.62, 'width': 385.15}]\n", + "> Charts for page 18: [{'name': 'chart_p18_0.png', 'x': 158.95, 'y': 187.38, 'height': 170.7, 'width': 294.1}]\n", + "> Charts for page 19: []\n", + "> Charts for page 20: []\n", + "> Charts for page 21: []\n", + "> Charts for page 22: []\n", + "> Charts for page 23: []\n", + "> Charts for page 24: []\n", + "> Charts for page 25: []\n" + ] + } + ], + "source": [ + "_ = parser.get_charts(json_objs, download_path=\"charts\")" + ] + }, + { + "cell_type": "markdown", + "id": "3d66eaf9", + "metadata": {}, + "source": [ + "### Let's plot a randomly selected chart" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d200787b", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "import glob\n", + "import random\n", + "from PIL import Image\n", + "import matplotlib.pyplot as plt\n", + "\n", + "# Use glob to list all PNG files in the folder\n", + "image_files = glob.glob(\"charts/*.png\")\n", + "\n", + "# Randomly select an image file\n", + "random_image = random.choice(image_files)\n", + "\n", + "# Open and plot the image\n", + "img = Image.open(random_image)\n", + "plt.imshow(img)\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "id": "fb6fc84e", + "metadata": {}, + "source": [ + "Note: You can use `get_images` to download the images present in the document." + ] + } + ], + "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" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/examples/demo_json_tour.ipynb b/examples/demo_json_tour.ipynb index 5dc205e..7178532 100644 --- a/examples/demo_json_tour.ipynb +++ b/examples/demo_json_tour.ipynb @@ -37,7 +37,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": null, "id": "0879301c-ff91-4431-941a-6c0ef7cd8fe2", "metadata": {}, "outputs": [], @@ -65,7 +65,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": null, "id": "c39d408f-e885-4940-85c7-b09ca3bc7cb7", "metadata": {}, "outputs": [ @@ -112,7 +112,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": null, "id": "9c9cd670-8229-4ad6-99a9-845bd82b7ec1", "metadata": {}, "outputs": [ @@ -141,7 +141,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": null, "id": "c588c578", "metadata": {}, "outputs": [ @@ -169,7 +169,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": null, "id": "f8845fac", "metadata": {}, "outputs": [ @@ -206,7 +206,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": null, "id": "6eca0253", "metadata": {}, "outputs": [ @@ -234,7 +234,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": null, "id": "c0354ba7", "metadata": {}, "outputs": [ @@ -287,7 +287,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": null, "id": "d236a255", "metadata": {}, "outputs": [ @@ -318,7 +318,7 @@ } ], "source": [ - "print(pages[0]['text'])" + "print(pages[0][\"text\"])" ] }, { @@ -339,7 +339,7 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": null, "id": "63d2df6f", "metadata": {}, "outputs": [ @@ -375,7 +375,7 @@ } ], "source": [ - "print(pages[0]['md'])" + "print(pages[0][\"md\"])" ] }, { @@ -429,7 +429,7 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": null, "id": "0975cbc4", "metadata": {}, "outputs": [ @@ -450,8 +450,8 @@ } ], "source": [ - "image_data = pages[0]['images'][0].copy()\n", - "del image_data['ocr']\n", + "image_data = pages[0][\"images\"][0].copy()\n", + "del image_data[\"ocr\"]\n", "print(json.dumps(image_data, indent=2))" ] }, @@ -465,7 +465,7 @@ }, { "cell_type": "code", - "execution_count": 18, + "execution_count": null, "id": "908e1cfd", "metadata": {}, "outputs": [ @@ -482,12 +482,12 @@ "source": [ "# Make a copy of json_objs with only the first page to avoid downloading all the images\n", "first_page_json = json_objs.copy()\n", - "first_page_json[0]['pages'] = [first_page_json[0]['pages'][0]] # Keep only first page\n", + "first_page_json[0][\"pages\"] = [first_page_json[0][\"pages\"][0]] # Keep only first page\n", "\n", "# get the SDK to download all the images to a local directory for us\n", "images = parser.get_images(first_page_json, download_path=\"./json_tour_screenshots\")\n", "\n", - "print(images[0]['path'])" + "print(images[0][\"path\"])" ] }, { @@ -508,7 +508,7 @@ }, { "cell_type": "code", - "execution_count": 22, + "execution_count": null, "id": "b8daf90d", "metadata": {}, "outputs": [ @@ -618,7 +618,7 @@ } ], "source": [ - "print(json.dumps(pages[0]['images'][0]['ocr'],indent=2))" + "print(json.dumps(pages[0][\"images\"][0][\"ocr\"], indent=2))" ] }, { @@ -641,7 +641,7 @@ }, { "cell_type": "code", - "execution_count": 30, + "execution_count": null, "id": "c10b9d7d", "metadata": {}, "outputs": [ @@ -782,7 +782,7 @@ } ], "source": [ - "print(json.dumps(pages[0]['items'],indent=2))" + "print(json.dumps(pages[0][\"items\"], indent=2))" ] }, { @@ -807,7 +807,7 @@ }, { "cell_type": "code", - "execution_count": 32, + "execution_count": null, "id": "7d6404a5", "metadata": {}, "outputs": [ @@ -857,7 +857,7 @@ } ], "source": [ - "print(json.dumps(pages[34]['items'][2],indent=2))" + "print(json.dumps(pages[34][\"items\"][2], indent=2))" ] }, { @@ -872,7 +872,7 @@ }, { "cell_type": "code", - "execution_count": 33, + "execution_count": null, "id": "fb0da11a", "metadata": {}, "outputs": [ @@ -909,7 +909,7 @@ }, { "cell_type": "code", - "execution_count": 34, + "execution_count": null, "id": "e7e393e6", "metadata": {}, "outputs": [ @@ -945,7 +945,7 @@ }, { "cell_type": "code", - "execution_count": 36, + "execution_count": null, "id": "29bf7e3c", "metadata": {}, "outputs": [ @@ -967,8 +967,8 @@ } ], "source": [ - "link_page = link_parsed[0]['pages'][0]\n", - "print(json.dumps(link_page['links'],indent=2))" + "link_page = link_parsed[0][\"pages\"][0]\n", + "print(json.dumps(link_page[\"links\"], indent=2))" ] }, { @@ -995,8 +995,7 @@ "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.11.9" + "pygments_lexer": "ipython3" } }, "nbformat": 4, diff --git a/examples/demo_starter_multimodal.ipynb b/examples/demo_starter_multimodal.ipynb index 3ae3c06..4ae95c1 100644 --- a/examples/demo_starter_multimodal.ipynb +++ b/examples/demo_starter_multimodal.ipynb @@ -1,415 +1,357 @@ { - "cells": [ - { - "cell_type": "markdown", - "id": "97c79c38-38a3-40f3-ba2e-250649347d63", - "metadata": { - "id": "97c79c38-38a3-40f3-ba2e-250649347d63" - }, - "source": [ - "\"Open" - ] - }, - { - "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\"] = \"\"" - ] - }, - { - "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)" - ] - }, + "cells": [ + { + "cell_type": "markdown", + "id": "97c79c38-38a3-40f3-ba2e-250649347d63", + "metadata": {}, + "source": [ + "\"Open" + ] + }, + { + "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": {}, + "source": [ + "### Installation" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "H_Vqcylb50vm", + "metadata": {}, + "outputs": [], + "source": [ + "!pip install llama-parse" + ] + }, + { + "cell_type": "markdown", + "id": "15e60ecf-519c-41fc-911b-765adaf8bad4", + "metadata": {}, + "source": [ + "### Setup\n", + "\n", + "Here we setup `LLAMA_CLOUD_API_KEY` for using `LlamaParse`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "91a9e532-1454-40e0-bbf0-fd442c350121", + "metadata": {}, + "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\"] = \"\"" + ] + }, + { + "cell_type": "markdown", + "id": "LGwBNPNotZRQ", + "metadata": {}, + "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": null, + "id": "IjtKDQRLrylI", + "metadata": {}, + "outputs": [ { - "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." - ] - }, + "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": {}, + "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": null, + "id": "dc921729-3446-42ca-8e1b-a6fd26195ed9", + "metadata": {}, + "outputs": [], + "source": [ + "from llama_index.core.schema import TextNode\n", + "from typing import List\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" + ] + }, + { + "cell_type": "markdown", + "id": "1b5d6da6", + "metadata": {}, + "source": [ + "### With anthropic-sonnet-3.5" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f2e9d9cf-8189-4fcb-b34f-cde6cc0b59c8", + "metadata": {}, + "outputs": [ { - "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\"))" - ] - }, + "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": {}, + "source": [ + "### With GPT-4o\n", + "\n", + "For comparison, we will also parse the document using GPT-4o." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6fc3f258-50ae-4988-b904-c105463a498f", + "metadata": {}, + "outputs": [ { - "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-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 GPT-4o\n", - "print(docs_gpt4o[0].get_content(metadata_mode=\"all\"))" - ] - }, + "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": {}, + "source": [ + "### View Results\n", + "\n", + "Let's visualize the results along with the original document page." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "778698aa-da7e-4081-b3b5-0372f228536f", + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "execution_count": null, - "id": "1c75bb85", - "metadata": {}, - "outputs": [], - "source": [] + "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" + ] } - ], - "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" + ], + "source": [ + "# using Sonnet-3.5\n", + "print(docs[0].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: 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-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 GPT-4o\n", + "print(docs_gpt4o[0].get_content(metadata_mode=\"all\"))" + ] + } + ], + "metadata": { + "colab": { + "provenance": [] + }, + "kernelspec": { + "display_name": "llamacloud", + "language": "python", + "name": "llamacloud" }, - "nbformat": 4, - "nbformat_minor": 5 + "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 } diff --git a/examples/demo_starter_parse_selected_pages.ipynb b/examples/demo_starter_parse_selected_pages.ipynb index 7e9ffbd..e4be503 100644 --- a/examples/demo_starter_parse_selected_pages.ipynb +++ b/examples/demo_starter_parse_selected_pages.ipynb @@ -43,7 +43,7 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -69,7 +69,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": null, "metadata": {}, "outputs": [ { @@ -105,7 +105,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": null, "metadata": {}, "outputs": [ { @@ -119,17 +119,14 @@ "source": [ "from llama_parse import LlamaParse\n", "\n", - "parser = LlamaParse(\n", - " target_pages=\"0,1,2\",\n", - " result_type=\"markdown\"\n", - ")\n", + "parser = LlamaParse(target_pages=\"0,1,2\", result_type=\"markdown\")\n", "\n", - "documents = parser.load_data('./uber_2021.pdf')" + "documents = parser.load_data(\"./uber_2021.pdf\")" ] }, { "cell_type": "code", - "execution_count": 4, + "execution_count": null, "metadata": {}, "outputs": [ { @@ -140,7 +137,7 @@ " 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 Registrant’s Common Equity, Related Stockholder Matters and Issuer Purchases of Equity Securities|47|\\n|Item 6. [Reserved]|48|\\n|Item 7. Management’s 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, + "execution_count": null, "metadata": {}, "output_type": "execute_result" } @@ -148,13 +145,6 @@ "source": [ "documents" ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] } ], "metadata": { @@ -172,8 +162,7 @@ "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.12.4" + "pygments_lexer": "ipython3" } }, "nbformat": 4, diff --git a/llama_parse/base.py b/llama_parse/base.py index 02a183a..f7411ff 100644 --- a/llama_parse/base.py +++ b/llama_parse/base.py @@ -787,54 +787,82 @@ def get_json_result( else: raise e - async def aget_images( - self, json_result: List[dict], download_path: str + async def aget_assets( + self, json_result: List[dict], download_path: str, asset_key: str ) -> List[dict]: - """Download images from the parsed result.""" + """Download assets (images or charts) from the parsed result.""" headers = {"Authorization": f"Bearer {self.api_key}"} - # make the download path + # Make the download path if not os.path.exists(download_path): os.makedirs(download_path) try: - images = [] + assets = [] for result in json_result: job_id = result["job_id"] for page in result["pages"]: if self.verbose: - print(f"> Image for page {page['page']}: {page['images']}") - for image in page["images"]: - image_name = image["name"] + print( + f"> {asset_key.capitalize()} for page {page['page']}: {page[asset_key]}" + ) + for asset in page[asset_key]: + asset_name = asset["name"] - # get the full path - image_path = os.path.join( - download_path, f"{job_id}-{image_name}" + # Get the full path + asset_path = os.path.join( + download_path, f"{job_id}-{asset_name}" ) - # get a valid image path - if not image_path.endswith(".png"): - if not image_path.endswith(".jpg"): - image_path += ".png" + # Get a valid asset path + if not asset_path.endswith(".png"): + if not asset_path.endswith(".jpg"): + asset_path += ".png" - image["path"] = image_path - image["job_id"] = job_id + asset["path"] = asset_path + asset["job_id"] = job_id - image["original_file_path"] = result.get("file_path", None) + asset["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}" + asset["page_number"] = page["page"] + with open(asset_path, "wb") as f: + asset_url = f"{self.base_url}/api/parsing/job/{job_id}/result/image/{asset_name}" async with self.client_context() as client: res = await client.get( - image_url, headers=headers, timeout=self.max_timeout + asset_url, headers=headers, timeout=self.max_timeout ) res.raise_for_status() f.write(res.content) - images.append(image) - return images + assets.append(asset) + return assets + except Exception as e: + print(f"Error while downloading {asset_key} from the parsed result:", e) + if self.ignore_errors: + return [] + else: + raise e + + async def aget_images( + self, json_result: List[dict], download_path: str + ) -> List[dict]: + """Download images from the parsed result.""" + try: + return await self.aget_assets(json_result, download_path, "images") except Exception as e: - print("Error while downloading images from the parsed result:", e) + print("Error while downloading images:", e) + if self.ignore_errors: + return [] + else: + raise e + + async def aget_charts( + self, json_result: List[dict], download_path: str + ) -> List[dict]: + """Download charts from the parsed result.""" + try: + return await self.aget_assets(json_result, download_path, "charts") + except Exception as e: + print("Error while downloading charts:", e) if self.ignore_errors: return [] else: @@ -850,6 +878,16 @@ def get_images(self, json_result: List[dict], download_path: str) -> List[dict]: else: raise e + def get_charts(self, json_result: List[dict], download_path: str) -> List[dict]: + """Download charts from the parsed result.""" + try: + return asyncio_run(self.aget_charts(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]: