Compare commits

...

127 Commits

Author SHA1 Message Date
Jerry Liu fd14b5a6e5 cr 2024-11-12 23:24:49 -08:00
Jerry Liu 15cc7c4070 cr 2024-11-12 23:19:15 -08:00
Jerry Liu fc709438a7 cr 2024-11-10 19:03:15 -08:00
Jerry Liu 5801375f8c cr 2024-11-10 17:47:58 -08:00
Jerry Liu 8a45ba81ba cr 2024-11-10 16:25:37 -08:00
Jerry Liu e16644f9c1 cr 2024-11-10 16:17:48 -08:00
Jerry Liu 2e85a0c0c0 cr 2024-11-09 22:37:08 -08: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
Jerry Liu e58b40b34c nit fix multimodal (#292) 2024-07-16 09:17:36 -07:00
Jerry Liu 0db05b9b96 Add sonnet cookbook + llamaparse fixes (#289) 2024-07-16 09:16:24 -07:00
Jerry Liu a8a191ae87 nit: slide deck fix (#288) 2024-07-15 14:44:19 -07:00
Hemant Malik 4d92775aa8 llama-parse with elasticsearch vector database example notebook (#258)
* llama-parse with elasticsearch vector database example notebook

* lint

---------

Co-authored-by: Logan Markewich <logan.markewich@live.com>
2024-07-15 14:29:13 -07:00
Jerry Liu 477847111e create multi-modal RAG notebook (#284) 2024-07-15 14:29:01 -07:00
Adam Reichert efbcfb1d2e Make File Extension Check Case-Insensitive (#277)
Make File Type Check Case-Insensitive
2024-07-13 13:43:41 -07:00
Logan a9b01c761c v0.4.7 2024-07-13 10:56:24 -06:00
Pierre-Loic Doulcet dac2f7c84e New parameters (#285)
wip
2024-07-12 09:06:21 +02:00
Logan Markewich 478142e509 lock 2024-07-08 09:45:18 -06:00
Logan Markewich e76d5ba679 v0.4.6 2024-07-08 09:42:25 -06:00
Huu Le 23dc9c0f68 fix file_input type issue (#271) 2024-07-08 09:31:31 -06:00
Sourabh Desai 8b96176d8a allow for bytes or buffer as input (#259)
* allow for bytes or buffer as input

* format & readme update

* lint
2024-06-28 23:31:35 -07:00
Logan 1bbf5f4823 v0.4.5 (#251) 2024-06-26 16:38:33 -07:00
Pierre-Loic Doulcet 2f57682035 add target_pages and bounding_box parameters (#250) 2024-06-26 16:25:44 -07:00
Jerry Liu 4c05160f98 add baseline to dcf excel RAG (#234) 2024-06-12 00:19:35 -07:00
Jerry Liu 3e9ad64a7f add split by page mode (#212) 2024-06-11 13:52:33 -07:00
Jerry Liu 21fa19c73b rewrite advanced example (#231) 2024-06-11 13:52:24 -07:00
Pierre-Loic Doulcet 58257d546b Pierre/new options (#216)
* Add spreadsheet extensions

* linting

* fix tests

* Add new parameters to the parser

* add option to API call

* lint

* lint remove trailing space

---------

Co-authored-by: Logan Markewich <logan.markewich@live.com>
2024-06-07 18:17:54 -06:00
Adam Reichert 5e99d810fd Fix Typo in description of invalidate_cache argument of LlamaParse constructor (#221)
Fix Typo
2024-06-07 17:32:57 -06:00
Jerry Liu a2dc717d85 add simple excel notebook (with dcf) (#215) 2024-06-06 08:48:33 -07:00
Logan 87062e6ca8 add link to docs 2024-06-05 16:10:28 -06:00
Jerry Liu ae3a21c5ff add KG agent (#211) 2024-06-05 12:58:07 -07:00
Ravi Theja ccebb8a2fa Add Excel spreadsheet example with llamaparse (#204) 2024-05-30 09:48:33 -06:00
Pierre-Loic Doulcet 2d21d6e688 Add spreadsheet extensions (#203)
* Add spreadsheet extensions

* linting

* fix tests

---------

Co-authored-by: Logan Markewich <logan.markewich@live.com>
2024-05-29 20:11:28 -06:00
Logan 270d96b7e3 bump version, add image support (#201) 2024-05-28 15:54:54 -06:00
Ajit Mistry ea21daa96f Add example for Weaviate (#181)
add weaviate example
2024-05-28 13:40:11 -07:00
dependabot[bot] 42845f8d07 Bump requests from 2.31.0 to 2.32.2 (#198)
Bumps [requests](https://github.com/psf/requests) from 2.31.0 to 2.32.2.
- [Release notes](https://github.com/psf/requests/releases)
- [Changelog](https://github.com/psf/requests/blob/main/HISTORY.md)
- [Commits](https://github.com/psf/requests/compare/v2.31.0...v2.32.2)

---
updated-dependencies:
- dependency-name: requests
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-23 20:44:57 +02:00
dependabot[bot] 8b63ae9c46 Bump tqdm from 4.66.2 to 4.66.3 (#197)
Bumps [tqdm](https://github.com/tqdm/tqdm) from 4.66.2 to 4.66.3.
- [Release notes](https://github.com/tqdm/tqdm/releases)
- [Commits](https://github.com/tqdm/tqdm/compare/v4.66.2...v4.66.3)

---
updated-dependencies:
- dependency-name: tqdm
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-23 20:43:04 +02:00
Pierre-Loic Doulcet 173060dc50 New option skip diagonal text and invalidate cache (#178)
* New option skip diagonal text and invalidate cache
2024-05-23 20:42:38 +02:00
Pierre-Loic Doulcet d19b35cd48 allow for .jpg images (#195) 2024-05-23 20:23:09 +02:00
Jerry Liu 0c83fbd679 nit: add caltrain weekend doc (#193) 2024-05-22 00:57:18 -07:00
Jerry Liu 6ae9c1d9cb clean up gpt4o notebook (#192) 2024-05-21 08:40:50 -07:00
Jerry Liu 27523b657a fix colab badge (#186) 2024-05-17 20:49:27 -07:00
Jerry Liu 56d73c1a3f llamaparse example over caltrain schedule (#185) 2024-05-17 09:22:16 -07:00
Jerry Liu 0d2ad9faab gpt4o notebook over tesla impact docs (#180)
Co-authored-by: Logan Markewich <logan.markewich@live.com>
2024-05-16 00:07:54 -07:00
Logan 4572f00657 add new mode and params for openai (#179)
add new mode
2024-05-14 12:24:25 -06:00
Logan 9ed208131f Ensure image extensions, vbump (#159) 2024-04-24 20:39:39 -06:00
Pierre-Loic Doulcet 91b03b2ea7 add html support (#154) 2024-04-23 13:14:13 -06:00
Yi Ding 70b5dc3a63 some notebook updates (#148) 2024-04-18 21:57:10 -06:00
Anoop Sharma d6ab0aa232 Added utils files (#91) 2024-04-14 15:17:31 -06:00
Logan f679e1c76b Skip tests if CICD doesn't populate the secrets (#142) 2024-04-14 15:12:22 -06:00
Logan b91f86ba3d v0.4.1 (#141) 2024-04-14 13:09:00 -06:00
Logan 0f2302fda4 QoL Changes (#140) 2024-04-14 13:01:39 -06:00
henrycunh ff729c05af docs: update readme with link to llamacloud (#139)
Having copy paste a link is silly!
2024-04-14 11:56:47 -07:00
Gautam Kumar 76a6821fb8 Fixing paths of data in example notebook (#136) 2024-04-10 15:52:35 -06:00
Logan 97c7a38a69 vbump (#111) 2024-03-21 10:51:50 -06:00
Pierre-Loic Doulcet 5d398a8a64 Extend supported formats (#110) 2024-03-21 10:44:18 -06:00
Jerry Liu 4252f6186b fixes to insurance demo (#97) 2024-03-21 00:02:47 -07:00
Jerry Liu 22148ade9f fix advanced RAG notebook title (#98) 2024-03-21 00:02:38 -07:00
Jerry Liu b8332fe8e1 nit: add colab badge to mongodb notebook (#109) 2024-03-21 00:02:29 -07:00
Ravi Theja e40e92a133 Add mongodb llamaparse example (#107) 2024-03-20 23:37:42 -07:00
Jerry Liu ba8f345f80 Revert "cr"
This reverts commit 2ddbf1ba0d.
2024-03-19 00:21:29 -07:00
Jerry Liu 2ddbf1ba0d cr 2024-03-19 00:20:42 -07:00
Haotian Zhang 23567c8f98 Init LlamaParseJsonNodeParser example (#93) 2024-03-18 15:15:36 -04:00
Logan 8d39ae7763 add agent demo (#88)
* add agent demo

* remove mention of react agent

* agents folder
2024-03-18 16:12:56 +01:00
Jerry Liu a2edc41fc7 nit: fix grammar in insurance cookbook (#89)
cr
2024-03-18 16:11:03 +01:00
Ikko Eltociear Ashimine 591b6fc44d Update demo_parsing_instructions.ipynb (#86)
usefull -> useful
2024-03-16 18:15:30 +01:00
Pierre-Loic Doulcet f8a3d92ce0 demo insurance + parsing instructions (#84) 2024-03-16 18:14:49 +01:00
Laurie Voss a1d18d83da Adding parsing instructions demo (#82) 2024-03-15 10:07:53 +01:00
Jerry Liu 1ad881e9fc add financial powerpoint cookbook (#78)
cr
2024-03-14 13:59:35 +01:00
Jerry Liu 2de26be464 add basic ppt demo (#75) 2024-03-14 00:28:49 -07:00
Logan Markewich 36f09543b2 v0.3.9 2024-03-13 08:59:00 -06:00
Jerry Liu 393acf8557 let client support more file types (#74) 2024-03-12 23:29:16 -07:00
Logan ab27f2ab79 fix to json bug (#68) 2024-03-07 08:53:37 -06:00
Jerry Liu d13b5ea30a add json cookbook (#64) 2024-03-06 10:06:55 -08:00
Pierre-Loic Doulcet 81843b9285 Pierre/json images (#62) 2024-03-06 08:38:45 -08:00
Logan b19f85234b fix language (#60) 2024-03-05 12:27:34 -06:00
Stefano Lottini 9dee30a616 Astra DB vector store imports from newly-named package (#26)
* Astra DB vector store imports from newly-named package

* removed explicit astrapy installation (comes with the astra vector store)

* fix (new) package renaming
2024-03-03 22:08:45 -08:00
Jerry Liu 4489eb1291 add language cookbook (#48)
* cr

* cr
2024-03-03 22:06:58 -08:00
Igor Udot dde72e3800 fix(base): add file_path to exception msg (#53)
Co-authored-by: igor.udot <igor.udot@espressif.com>
2024-03-03 22:06:09 -08:00
Jerry Liu e49fca4b51 add table comparisons cookbook (#55) 2024-03-01 16:36:00 -08:00
Jerry Liu 0411b08c07 [version] bump version to 0.3.5 (#49) 2024-02-28 17:05:22 -08:00
Stefano Lottini 6c490ab781 Astra DB notebooks allow optional namespace specification (#27) 2024-02-28 15:14:33 -08:00
Pierre-Loic Doulcet 737884d297 ADD: Support for language parameter in the package (#37)
* ADD: Support for language parameter in the package

* add language enum
2024-02-28 15:14:04 -08:00
71 changed files with 24061 additions and 1760 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: ''
---
+48
View File
@@ -0,0 +1,48 @@
name: Build Package
# Build package on its own without additional pip install
on:
push:
branches:
- main
pull_request:
env:
POETRY_VERSION: "1.6.1"
jobs:
build:
runs-on: ${{ matrix.os }}
strategy:
# You can use PyPy versions in python-version.
# For example, pypy-2.7 and pypy-3.8
matrix:
os: [ubuntu-latest, windows-latest]
python-version: ["3.9"]
steps:
- uses: actions/checkout@v3
- name: Set up python ${{ matrix.python-version }}
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
- name: Install Poetry
uses: snok/install-poetry@v1
with:
version: ${{ env.POETRY_VERSION }}
- name: Install deps
shell: bash
run: poetry install
- name: Ensure lock works
shell: bash
run: poetry lock
- name: Build
shell: bash
run: poetry build
- name: Test installing built package
shell: bash
run: python -m pip install .
- name: Test import
shell: bash
working-directory: ${{ vars.RUNNER_TEMP }}
run: python -c "import llama_parse"
+81
View File
@@ -0,0 +1,81 @@
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
#
# ******** NOTE ********
# We have attempted to detect the languages in your repository. Please check
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
name: "CodeQL"
on:
push:
branches: ["main"]
pull_request:
# The branches below must be a subset of the branches above
branches: ["main"]
schedule:
- cron: "30 16 * * 4"
jobs:
analyze:
name: Analyze
# Runner size impacts CodeQL analysis time. To learn more, please see:
# - https://gh.io/recommended-hardware-resources-for-running-codeql
# - https://gh.io/supported-runners-and-hardware-resources
# - https://gh.io/using-larger-runners
# Consider using larger runners for possible analysis time improvements.
runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }}
timeout-minutes: ${{ (matrix.language == 'swift' && 120) || 360 }}
permissions:
actions: read
contents: read
security-events: write
strategy:
fail-fast: false
matrix:
language: ["python"]
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby', 'swift' ]
# Use only 'java' to analyze code written in Java, Kotlin or both
# Use only 'javascript' to analyze code written in JavaScript, TypeScript or both
# Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support
steps:
- name: Checkout repository
uses: actions/checkout@v3
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
# queries: security-extended,security-and-quality
# Autobuild attempts to build any compiled languages (C/C++, C#, Go, Java, or Swift).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v2
# ️ Command-line programs to run using the OS shell.
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
# If the Autobuild fails above, remove it and uncomment the following three lines.
# modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance.
# - run: |
# echo "Run, Build Application using script"
# ./location_of_script_within_repo/buildscript.sh
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2
with:
category: "/language:${{matrix.language}}"
+37
View File
@@ -0,0 +1,37 @@
name: Linting
on:
push:
branches:
- main
pull_request:
env:
POETRY_VERSION: "1.6.1"
jobs:
build:
runs-on: ubuntu-latest
strategy:
# You can use PyPy versions in python-version.
# For example, pypy-2.7 and pypy-3.8
matrix:
python-version: ["3.9"]
steps:
- uses: actions/checkout@v3
with:
fetch-depth: ${{ github.event_name == 'pull_request' && 2 || 0 }}
- name: Set up python ${{ matrix.python-version }}
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
- name: Install Poetry
uses: snok/install-poetry@v1
with:
version: ${{ env.POETRY_VERSION }}
- name: Install pre-commit
shell: bash
run: poetry run pip install pre-commit
- name: Run linter
shell: bash
run: poetry run make lint
+64
View File
@@ -0,0 +1,64 @@
name: Publish llama-parse to PyPI / GitHub
on:
push:
tags:
- "v*"
workflow_dispatch:
env:
POETRY_VERSION: "1.6.1"
PYTHON_VERSION: "3.9"
jobs:
build-n-publish:
name: Build and publish to PyPI
if: github.repository == 'run-llama/llama_parse'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up python ${{ env.PYTHON_VERSION }}
uses: actions/setup-python@v4
with:
python-version: ${{ env.PYTHON_VERSION }}
- name: Install Poetry
uses: snok/install-poetry@v1
with:
version: ${{ env.POETRY_VERSION }}
- name: Install deps
shell: bash
run: pip install -e .
- name: Build and publish to pypi
uses: JRubics/poetry-publish@v1.17
with:
pypi_token: ${{ secrets.LLAMA_PARSE_PYPI_TOKEN }}
ignore_dev_requirements: "yes"
- name: Create GitHub Release
id: create_release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # This token is provided by Actions, you do not need to create your own token
with:
tag_name: ${{ github.ref }}
release_name: ${{ github.ref }}
draft: false
prerelease: false
- name: Get Asset name
run: |
export PKG=$(ls dist/ | grep tar)
set -- $PKG
echo "name=$1" >> $GITHUB_ENV
- name: Upload Release Asset (sdist) to GitHub
id: upload-release-asset
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: dist/${{ env.name }}
asset_name: ${{ env.name }}
asset_content_type: application/zip
+40
View File
@@ -0,0 +1,40 @@
name: Unit Testing
on:
push:
branches:
- main
pull_request:
env:
POETRY_VERSION: "1.6.1"
LLAMA_CLOUD_API_KEY: ${{ secrets.LLAMA_CLOUD_API_KEY }}
jobs:
test:
runs-on: ubuntu-latest
strategy:
# You can use PyPy versions in python-version.
# For example, pypy-2.7 and pypy-3.8
matrix:
python-version: ["3.8", "3.10", "3.11"]
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Set up python ${{ matrix.python-version }}
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
- name: Install Poetry
uses: snok/install-poetry@v1
with:
version: ${{ env.POETRY_VERSION }}
- name: Install deps
shell: bash
run: poetry install --with dev
- name: Run testing
env:
CI: true
shell: bash
run: poetry run pytest tests
+3 -1
View File
@@ -1,3 +1,5 @@
.git
__pycache__/
*.pyc
*.pyc
.DS_Store
.idea
+88
View File
@@ -0,0 +1,88 @@
---
default_language_version:
python: python3
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.5.0
hooks:
- id: check-byte-order-marker
- id: check-merge-conflict
- id: check-symlinks
- id: check-toml
- id: check-yaml
- id: detect-private-key
- id: end-of-file-fixer
- id: mixed-line-ending
- id: trailing-whitespace
- repo: https://github.com/charliermarsh/ruff-pre-commit
rev: v0.1.5
hooks:
- id: ruff
args: [--fix, --exit-non-zero-on-fix]
exclude: ".*poetry.lock"
- repo: https://github.com/psf/black-pre-commit-mirror
rev: 23.10.1
hooks:
- id: black-jupyter
name: black-src
alias: black
exclude: ".*poetry.lock"
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.0.1
hooks:
- id: mypy
additional_dependencies:
[
"types-requests",
"types-Deprecated",
"types-redis",
"types-setuptools",
"types-PyYAML",
"types-protobuf==4.24.0.4",
]
args:
[
--disallow-untyped-defs,
--ignore-missing-imports,
--python-version=3.8,
]
- repo: https://github.com/adamchainz/blacken-docs
rev: 1.16.0
hooks:
- id: blacken-docs
name: black-docs-text
alias: black
types_or: [rst, markdown, tex]
additional_dependencies: [black==23.10.1]
# Using PEP 8's line length in docs prevents excess left/right scrolling
args: [--line-length=79]
- repo: https://github.com/pre-commit/mirrors-prettier
rev: v3.0.3
hooks:
- id: prettier
exclude: poetry.lock
- repo: https://github.com/codespell-project/codespell
rev: v2.2.6
hooks:
- id: codespell
additional_dependencies: [tomli]
exclude: ^(poetry.lock|examples)
args:
[
"--ignore-words-list",
"astroid,gallary,momento,narl,ot,rouge,nin,gere,te,inh,vor",
]
- repo: https://github.com/srstevenson/nb-clean
rev: 3.1.0
hooks:
- id: nb-clean
args: [--preserve-cell-outputs, --remove-empty-cells]
- repo: https://github.com/pappasam/toml-sort
rev: v0.23.1
hooks:
- id: toml-sort-fix
exclude: ".*poetry.lock"
exclude: .github/ISSUE_TEMPLATE
+14
View File
@@ -0,0 +1,14 @@
GIT_ROOT ?= $(shell git rev-parse --show-toplevel)
help: ## Show all Makefile targets.
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[33m%-30s\033[0m %s\n", $$1, $$2}'
format: ## Run code autoformatters (black).
pre-commit install
git ls-files | xargs pre-commit run black --files
lint: ## Run linters: pre-commit (black, ruff, codespell) and mypy
pre-commit install && git ls-files | xargs pre-commit run --show-diff-on-failure --files
test: ## Run tests via pytest
pytest tests
+85 -9
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).
Currently available in preview mode for **free**. Try it out today!
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).
**NOTE:** Currently, only PDF files are supported.
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`.
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,10 +38,26 @@ 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
nest_asyncio.apply()
from llama_parse import LlamaParse
@@ -36,8 +65,9 @@ from llama_parse import LlamaParse
parser = LlamaParse(
api_key="llx-...", # can also be set in your env as LLAMA_CLOUD_API_KEY
result_type="markdown", # "markdown" and "text" are available
num_workers=4, # if multiple files passed, split in `num_workers` API calls
verbose=True
num_workers=4, # if multiple files passed, split in `num_workers` API calls
verbose=True,
language="en", # Optionally you can define a language, default=en
)
# sync
@@ -53,12 +83,46 @@ documents = await parser.aload_data("./my_file.pdf")
documents = await parser.aload_data(["./my_file1.pdf", "./my_file2.pdf"])
```
## Using with file object
You can parse a file object directly:
```python
import nest_asyncio
nest_asyncio.apply()
from llama_parse import LlamaParse
parser = LlamaParse(
api_key="llx-...", # can also be set in your env as LLAMA_CLOUD_API_KEY
result_type="markdown", # "markdown" and "text" are available
num_workers=4, # if multiple files passed, split in `num_workers` API calls
verbose=True,
language="en", # Optionally you can define a language, default=en
)
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(f"./{file_name}", "rb") as f:
file_bytes = f.read()
# 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`
You can also integrate the parser as the default PDF loader in `SimpleDirectoryReader`:
```python
import nest_asyncio
nest_asyncio.apply()
from llama_parse import LlamaParse
@@ -67,11 +131,13 @@ from llama_index.core import SimpleDirectoryReader
parser = LlamaParse(
api_key="llx-...", # can also be set in your env as LLAMA_CLOUD_API_KEY
result_type="markdown", # "markdown" and "text" are available
verbose=True
verbose=True,
)
file_extractor = {".pdf": parser}
documents = SimpleDirectoryReader("./data", file_extractor=file_extractor).load_data()
documents = SimpleDirectoryReader(
"./data", file_extractor=file_extractor
).load_data()
```
Full documentation for `SimpleDirectoryReader` can be found on the [LlamaIndex Documentation](https://docs.llamaindex.ai/en/stable/module_guides/loading/simpledirectoryreader.html).
@@ -84,6 +150,16 @@ Several end-to-end indexing examples can be found in the examples folder
- [Advanced RAG Example](examples/demo_advanced.ipynb)
- [Raw API Usage](examples/demo_api.ipynb)
## Documentation
[https://docs.cloud.llamaindex.ai/](https://docs.cloud.llamaindex.ai/)
## 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

@@ -0,0 +1,302 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# LlamaParse Agent\n",
"\n",
"This demo walks through using an OpenAI Agent with [LlamaParse](https://cloud.llamaindex.ai)."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Setup"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"!pip install llama-parse llama-index llama-index-postprocessor-sbert-rerank"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import os\n",
"\n",
"os.environ[\"LLAMA_CLOUD_API_KEY\"] = \"llx-...\"\n",
"os.environ[\"OPENAI_API_KEY\"] = \"sk-...\""
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from llama_index.core import Settings\n",
"from llama_index.embeddings.openai import OpenAIEmbedding\n",
"from llama_index.llms.openai import OpenAI\n",
"\n",
"Settings.embed_model = OpenAIEmbedding(model=\"text-embedding-3-small\")\n",
"Settings.llm = OpenAI(model=\"gpt-3.5-turbo\", temperature=0.2)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Parsing \n",
"\n",
"For parsing, lets use a [recent paper](https://huggingface.co/papers/2403.09611) on Multi-Modal pretraining"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"!wget https://arxiv.org/pdf/2403.09611.pdf -O paper.pdf"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Below, we can tell the parser to skip content we don't want. In this case, the references section will just add noise to a RAG system."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from llama_parse import LlamaParse\n",
"\n",
"parser = LlamaParse(\n",
" result_type=\"markdown\",\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Started parsing the file under job_id 81251f39-01be-434e-99e8-1c1b83b82098\n"
]
}
],
"source": [
"documents = await parser.aload_data(\"paper.pdf\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Embeddings have been explicitly disabled. Using MockEmbedding.\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"41it [00:00, 26765.21it/s]\n",
"100%|██████████| 41/41 [00:13<00:00, 2.98it/s]\n"
]
}
],
"source": [
"import nest_asyncio\n",
"\n",
"nest_asyncio.apply()\n",
"\n",
"from llama_index.core.node_parser import (\n",
" MarkdownElementNodeParser,\n",
" SentenceSplitter,\n",
")\n",
"\n",
"# explicitly extract tables with the MarkdownElementNodeParser\n",
"node_parser = MarkdownElementNodeParser(num_workers=8)\n",
"nodes = node_parser.get_nodes_from_documents(documents)\n",
"nodes, objects = node_parser.get_nodes_and_objects(nodes)\n",
"\n",
"# Chain splitters to ensure chunk size requirements are met\n",
"nodes = SentenceSplitter(chunk_size=512, chunk_overlap=20).get_nodes_from_documents(\n",
" nodes\n",
")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Chat over the paper, lets find out what it is about!"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from llama_index.core import VectorStoreIndex, SummaryIndex\n",
"\n",
"vector_index = VectorStoreIndex(nodes=nodes)\n",
"summary_index = SummaryIndex(nodes=nodes)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from llama_index.agent.openai import OpenAIAgent\n",
"from llama_index.core.tools import QueryEngineTool, ToolMetadata\n",
"from llama_index.postprocessor.colbert_rerank import ColbertRerank\n",
"\n",
"tools = [\n",
" QueryEngineTool(\n",
" vector_index.as_query_engine(\n",
" similarity_top_k=8, node_postprocessors=[ColbertRerank(top_n=3)]\n",
" ),\n",
" metadata=ToolMetadata(\n",
" name=\"search\",\n",
" description=\"Search the document, pass the entire user message in the query\",\n",
" ),\n",
" ),\n",
" QueryEngineTool(\n",
" summary_index.as_query_engine(),\n",
" metadata=ToolMetadata(\n",
" name=\"summarize\",\n",
" description=\"Summarize the document using the user message\",\n",
" ),\n",
" ),\n",
"]\n",
"\n",
"agent = OpenAIAgent.from_tools(tools=tools, verbose=True)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Added user message to memory: What is the summary of the paper?\n",
"=== Calling Function ===\n",
"Calling function: summarize with args: {\"input\":\"summary\"}\n",
"Got output: The research focuses on developing Multimodal Large Language Models (MLLMs) by incorporating image-caption, interleaved image-text, and text-only data for pre-training. It highlights the importance of factors like the image encoder, resolution, and token count, while downplaying the design of the vision-language connector. With models scaling up to 30B parameters, the MM1 family demonstrates impressive performance in pre-training metrics and competitive outcomes on diverse multimodal benchmarks. It demonstrates abilities such as in-context learning and multi-image reasoning, aiming to provide valuable insights for creating MLLMs that benefit the research community.\n",
"========================\n",
"\n"
]
}
],
"source": [
"# note -- this will take a while with local LLMs, its sending every node in the document to the LLM\n",
"resp = agent.chat(\"What is the summary of the paper?\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"The summary of the paper highlights the development of Multimodal Large Language Models (MLLMs) by incorporating image-caption, interleaved image-text, and text-only data for pre-training. The research emphasizes factors like the image encoder, resolution, and token count, while de-emphasizing the design of the vision-language connector. The MM1 family of models, scaling up to 30B parameters, shows impressive performance in pre-training metrics and competitive outcomes on various multimodal benchmarks. These models demonstrate capabilities such as in-context learning and multi-image reasoning, aiming to provide valuable insights for creating MLLMs that benefit the research community.\n"
]
}
],
"source": [
"print(str(resp))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Added user message to memory: How do the authors evaluate their work?\n",
"=== Calling Function ===\n",
"Calling function: search with args: {\"input\":\"evaluation methods\"}\n",
"Got output: The evaluation methods involve synthesizing all benchmark results into a single meta-average number to simplify comparisons. This is achieved by normalizing the evaluation metrics with respect to a baseline configuration, standardizing the results for each task, adjusting every metric by dividing it by its respective baseline, and then averaging across all metrics.\n",
"========================\n",
"\n"
]
}
],
"source": [
"resp = agent.chat(\"How do the authors evaluate their work?\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"The authors evaluate their work by synthesizing all benchmark results into a single meta-average number to simplify comparisons. They normalize the evaluation metrics with respect to a baseline configuration, standardize the results for each task, adjust every metric by dividing it by its respective baseline, and then average across all metrics for evaluation.\n"
]
}
],
"source": [
"print(str(resp))"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "llama-parse-aNC435Vv-py3.10",
"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.
+529
View File
@@ -0,0 +1,529 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "c148b65e-e8a6-476e-86ba-bf6a73d479c7",
"metadata": {},
"source": [
"# RAG over the Caltrain Weekend Schedule \n",
"\n",
"<a href=\"https://colab.research.google.com/github/run-llama/llama_parse/blob/main/examples/caltrain/caltrain_text_mode.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>\n",
"\n",
"This example shows off LlamaParse parsing capabilities to build a functioning query pipeline over the Caltrain weekend schedule, a big timetable containing all trains northbound and southbound and their stops in various cities.\n",
"\n",
"Naive parsing solutions mess up in representing this tabular representation, leading to LLM hallucinations. In contrast, LlamaParse text-mode spatially lays out the table in a neat format, enabling more sophisticated LLMs like gpt-4-turbo to understand the spacing and reason over all the numbers.\n",
"\n",
"**NOTE**: LlamaParse markdown mode doesn't quite work yet - it's in development!"
]
},
{
"cell_type": "markdown",
"id": "ef115dbe-b834-4639-828e-e2c11aef710b",
"metadata": {},
"source": [
"## Setup\n",
"\n",
"Download the data."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "e6ae2e38-30c9-4865-aa13-47780bc3848f",
"metadata": {},
"outputs": [],
"source": [
"import nest_asyncio\n",
"\n",
"nest_asyncio.apply()"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "335ce1d0-757a-4f09-846e-21c409768871",
"metadata": {},
"outputs": [],
"source": [
"!wget \"https://www.caltrain.com/media/31602/download?inline?inline\" -O caltrain_schedule_weekend.pdf"
]
},
{
"cell_type": "markdown",
"id": "45fa9120-65bb-4772-9db7-53e7cecf9adc",
"metadata": {},
"source": [
"## Initialize LlamaParse\n",
"\n",
"Initialize LlamaParse in `text` mode which will represent complex documents incl. text, tables, and figures as nicely formatted text."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "54aa9579-84d4-49bc-ab54-5474e69c1188",
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"/Users/jerryliu/Programming/llama_parse/.venv/lib/python3.10/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n",
" from .autonotebook import tqdm as notebook_tqdm\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Started parsing the file under job_id 5f73353a-1f4b-480d-9eea-58d1d22b75f6\n"
]
}
],
"source": [
"from llama_parse import LlamaParse\n",
"\n",
"docs = LlamaParse(result_type=\"text\").load_data(\"./caltrain_schedule_weekend.pdf\")"
]
},
{
"cell_type": "markdown",
"id": "602756b2-9ea1-4519-a8e3-c773ec624205",
"metadata": {},
"source": [
"Take a look at the below text (and zoom out from the browser to really get the effect!). You'll see that the entire table is nicely laid out."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "4928281a-591a-4653-b451-b2b8112a7101",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"ZONE 2ZONE 3ZONE 4ZONE 4 ZONE 3ZONE 2ZONE 1ZONE 1\n",
" Printer-Friendly Caltrain Schedule\n",
" Northbound WEEKEND SERVICE to SAN FRANCISCO 2XX Local\n",
"\n",
"\n",
" Train No. 221 225 229 233 237 241 245 249 253 257 261 265 269 273 *277 *281\n",
" Service Types L2 L2 L2 L2 L2 L2 L2 L2 L2 L2 L2 L2 L2 L2 L2 L2\n",
" Tamien 7:12a 9:05a 10:05a 11:05a 1:05p 3:05p 5:05p 7:05p 9:05p 11:05p\n",
" San Jose Diridon 7:19a 9:12a 10:12a 11:12a 12:12p 1:12p 2:12p 3:12p 4:12p 5:12p 6:12p 7:12p 8:12p 9:12p 10:19p 11:12p\n",
" Santa Clara 7:25a 9:18a 10:18a 11:18a 12:18p 1:18p 2:18p 3:18p 4:18p 5:18p 6:18p 7:18p 8:18p 9:18p 10:25p 11:18p\n",
" Lawrence 7:31a 9:24a 10:24a 11:24a 12:24p 1:24p 2:24p 3:24p 4:24p 5:24p 6:24p 7:24p 8:24p 9:24p 10:31p 11:24p\n",
" Sunnyvale 7:35a 9:28a 10:28a 11:28a 12:28p 1:28p 2:28p 3:28p 4:28p 5:28p 6:28p 7:28p 8:28p 9:28p 10:35p 11:28p\n",
" Mountain View 7:40a 9:34a 10:34a 11:34a 12:34p 1:34p 2:34p 3:34p 4:34p 5:34p 6:34p 7:34p 8:34p 9:34p 10:40p 11:34p\n",
" San Antonio 7:43a 9:37a 10:37a 11:37a 12:37p 1:37p 2:37p 3:37p 4:37p 5:37p 6:37p 7:37p 8:37p 9:37p 10:44p 11:37p\n",
" California Ave 7:48a 9:42a 10:42a 11:42a 12:42p 1:42p 2:42p 3:42p 4:42p 5:42p 6:42p 7:42p 8:42p 9:42p 10:48p 11:42p\n",
" Palo Alto 7:52a 9:46a 10:46a 11:46a 12:46p 1:46p 2:46p 3:46p 4:46p 5:46p 6:46p 7:46p 8:46p 9:46p 10:53p 11:46p\n",
" Menlo Park 7:55a 9:50a 10:50a 11:50a 12:50p 1:50p 2:50p 3:50p 4:50p 5:50p 6:50p 7:50p 8:50p 9:50p 10:56p 11:50p\n",
" Redwood City 8:01a 9:56a 10:56a 11:56a 12:56p 1:56p 2:56p 3:56p 4:56p 5:56p 6:56p 7:56p 8:56p 9:56p 11:02p 11:56p\n",
" San Carlos 8:05a 10:01a 11:01a 12:01p 1:01p 2:01p 3:01p 4:01p 5:01p 6:01p 7:01p 8:01p 9:01p 10:01p 11:07p 12:01a\n",
" Belmont 8:09a 10:04a 11:04a 12:04p 1:04p 2:04p 3:04p 4:04p 5:04p 6:04p 7:04p 8:04p 9:04p 10:04p 11:10p 12:04a\n",
" Hillsdale 8:12a 10:08a 11:08a 12:08p 1:08p 2:08p 3:08p 4:08p 5:08p 6:08p 7:08p 8:08p 9:08p 10:08p 11:14p 12:08a\n",
" Hayward Park 8:15a 10:11a 11:11a 12:11p 1:11p 2:11p 3:11p 4:11p 5:11p 6:11p 7:11p 8:11p 9:11p 10:11p 11:17p 12:11a\n",
" San Mateo 8:19a 10:15a 11:15a 12:15p 1:15p 2:15p 3:15p 4:15p 5:15p 6:15p 7:15p 8:15p 9:15p 10:15p 11:21p 12:15a\n",
" Burlingame 8:22a 10:19a 11:19a 12:19p 1:19p 2:19p 3:19p 4:19p 5:19p 6:19p 7:19p 8:19p 9:19p 10:19p 11:25p 12:19a\n",
" Broadway 8:25a 10:22a 11:22a 12:22p 1:22p 2:22p 3:22p 4:22p 5:22p 6:22p 7:22p 8:22p 9:22p 10:22p 11:28p 12:22a\n",
" Millbrae 8:29a 10:26a 11:26a 12:26p 1:26p 2:26p 3:26p 4:26p 5:26p 6:26p 7:26p 8:26p 9:26p 10:26p 11:32p 12:26a\n",
" San Bruno 8:34a 10:30a 11:30a 12:30p 1:30p 2:30p 3:30p 4:30p 5:30p 6:30p 7:30p 8:30p 9:30p 10:30p 11:37p 12:30a\n",
" S. San Francisco 8:38a 10:34a 11:34a 12:34p 1:34p 2:34p 3:34p 4:34p 5:34p 6:34p 7:34p 8:34p 9:34p 10:34p 11:41p 12:34a\n",
" Bayshore 8:44a 10:41a 11:41a 12:41p 1:41p 2:41p 3:41p 4:41p 5:41p 6:41p 7:41p 8:41p 9:41p 10:41p 11:47p 12:41a\n",
" 22 ndStreet 8:50a 10:46a 11:46a 12:46p 1:46p 2:46p 3:46p 4:46p 5:46p 6:46p 7:46p 8:46p 9:46p 10:46p 11:53p 12:46a\n",
" San Francisco 8:56a 10:52a 11:53a 12:53p 1:52p 2:52p 3:52p 4:52p 5:52p 6:52p 7:52p 8:52p 9:52p 10:52p 11:59p 12:52a\n",
" *On SAP Center event days, Train 277 or Train 281departure from San Jose Diridon station may be delayed and will depart no later than 10:30p or 11:30p respectively.\n",
"\n",
"\n",
" Southbound WEEKEND SERVICE to SAN JOSE 2XX Local\n",
" Train No. 224 228 232 236 240 244 248 252 256 260 264 268 272 276 280 284\n",
" Service Types L2 L2 L2 L2 L2 L2 L2 L2 L2 L2 L2 L2 L2 L2 L2 L2\n",
" San Francisco 8:28a 9:58a 10:58a 11:58a 12:58p 1:58p 2:58p 3:58p 4:58p 5:58p 6:58p 7:58p 8:58p 9:58p 10:58p 12:05a\n",
" 22 ndStreet 8:33a 10:03a 11:03a 12:03p 1:03p 2:03p 3:03p 4:03p 5:03p 6:03p 7:03p 8:03p 9:03p 10:03p 11:03p 12:10a\n",
" Bayshore 8:38a 10:08a 11:08a 12:08p 1:08p 2:08p 3:08p 4:08p 5:08p 6:08p 7:08p 8:08p 9:08p 10:08p 11:08p 12:15a\n",
" S. San Francisco 8:45a 10:15a 11:15a 12:15p 1:15p 2:15p 3:15p 4:15p 5:15p 6:15p 7:15p 8:15p 9:15p 10:15p 11:15p 12:22a\n",
" San Bruno 8:49a 10:19a 11:19a 12:19p 1:19p 2:19p 3:19p 4:19p 5:19p 6:19p 7:19p 8:19p 9:19p 10:19p 11:19p 12:26a\n",
" Millbrae 8:53a 10:24a 11:24a 12:24p 1:24p 2:24p 3:24p 4:24p 5:24p 6:24p 7:24p 8:24p 9:24p 10:24p 11:24p 12:31a\n",
" Broadway 8:57a 10:27a 11:27a 12:27p 1:27p 2:27p 3:27p 4:27p 5:27p 6:27p 7:27p 8:27p 9:27p 10:27p 11:27p 12:35a\n",
" Burlingame 9:00a 10:31a 11:31a 12:31p 1:31p 2:31p 3:31p 4:31p 5:31p 6:31p 7:31p 8:31p 9:31p 10:31p 11:31p 12:38a\n",
" San Mateo 9:04a 10:34a 11:34a 12:34p 1:34p 2:34p 3:34p 4:34p 5:34p 6:34p 7:34p 8:34p 9:34p 10:34p 11:34p 12:41a\n",
" Hayward Park 9:07a 10:37a 11:37a 12:37p 1:37p 2:37p 3:37p 4:37p 5:37p 6:37p 7:37p 8:37p 9:37p 10:37p 11:37p 12:45a\n",
" Hillsdale 9:10a 10:41a 11:41a 12:41p 1:41p 2:41p 3:41p 4:41p 5:41p 6:41p 7:41p 8:41p 9:41p 10:41p 11:41p 12:48a\n",
" Belmont 9:14a 10:44a 11:44a 12:44p 1:44p 2:44p 3:44p 4:44p 5:44p 6:44p 7:44p 8:44p 9:44p 10:44p 11:44p 12:52a\n",
" San Carlos 9:17a 10:48a 11:48a 12:48p 1:48p 2:48p 3:48p 4:48p 5:48p 6:48p 7:48p 8:48p 9:48p 10:48p 11:48p 12:55a\n",
" Redwood City 9:21a 10:52a 11:52a 12:52p 1:52p 2:52p 3:52p 4:52p 5:52p 6:52p 7:52p 8:52p 9:52p 10:52p 11:52p 12:59a\n",
" Menlo Park 9:28a 10:58a 11:58a 12:58p 1:58p 2:58p 3:58p 4:58p 5:58p 6:58p 7:58p 8:58p 9:58p 10:58p 11:58p 1:05a\n",
" Palo Alto 9:32a 11:02a 12:02p 1:02p 2:02p 3:02p 4:02p 5:02p 6:02p 7:02p 8:02p 9:02p 10:02p 11:02p 12:02a 1:09a\n",
" California Avenue 9:36a 11:06a 12:06p 1:06p 2:06p 3:06p 4:06p 5:06p 6:06p 7:06p 8:06p 9:06p 10:06p 11:06p 12:06a 1:12a\n",
" San Antonio 9:41a 11:11a 12:11p 1:11p 2:11p 3:11p 4:11p 5:11p 6:11p 7:11p 8:11p 9:11p 10:11p 11:11p 12:10a 1:17a\n",
" Mountain View 9:45a 11:16a 12:16p 1:16p 2:16p 3:16p 4:16p 5:16p 6:16p 7:16p 8:16p 9:16p 10:16p 11:16p 12:15a 1:21a\n",
" Sunnyvale 9:51a 11:21a 12:21p 1:21p 2:21p 3:21p 4:21p 5:21p 6:21p 7:21p 8:21p 9:21p 10:21p 11:21p 12:20a 1:26a\n",
" Lawrence 9:55a 11:26a 12:26p 1:26p 2:26p 3:26p 4:26p 5:26p 6:26p 7:26p 8:26p 9:26p 10:26p 11:26p 12:25a 1:31a\n",
" Santa Clara 10:01a 11:32a 12:32p 1:32p 2:32p 3:32p 4:32p 5:32p 6:32p 7:32p 8:32p 9:32p 10:32p 11:32p 12:31a 1:37a\n",
" San Jose Diridon 10:10a 11:40a 12:40p 1:38p 2:40p 3:38p 4:40p 5:38p 6:40p 7:38p 8:40p 9:38p 10:40p 11:38p 12:39a 1:44a\n",
" Tamien 10:15a 11:45a 12:45p 2:45p 4:45p 6:45p 8:45p 10:45p 12:44a 1:49a\n",
" EFFECTIVE September 12, 2022 Timetable subject to change without notice.\n"
]
}
],
"source": [
"print(docs[0].get_content())"
]
},
{
"cell_type": "markdown",
"id": "8f5064d4-3e33-4f67-9b2e-46787161538f",
"metadata": {},
"source": [
"## Initialize Query Engine\n",
"\n",
"We now initialize a query engine over this data. Here we use a baseline summary index, which doesn't do vector indexing/chunking and instead dumps the entire text into the prompt.\n",
"\n",
"We see that the LLM (gpt-4-turbo) is able to provide all the stops for train no 225 northbound."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "b3e985b6-9d38-449f-9cf9-aae166824eed",
"metadata": {},
"outputs": [],
"source": [
"from llama_index.core import SummaryIndex\n",
"from llama_index.llms.openai import OpenAI\n",
"\n",
"llm = OpenAI(model=\"gpt-4o\")\n",
"index = SummaryIndex.from_documents(docs)\n",
"query_engine = index.as_query_engine(llm=llm)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "66eb0976-2cd6-4b14-9083-124baae9ed5d",
"metadata": {},
"outputs": [],
"source": [
"response = query_engine.query(\n",
" \"What are the stops (and times) for train no 237 northbound?\"\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "7dc6f275-07f4-429e-9335-f50982fe974c",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"The stops and times for train no. 237 northbound are as follows:\n",
"\n",
"- San Jose Diridon: 12:12 PM\n",
"- Santa Clara: 12:18 PM\n",
"- Lawrence: 12:24 PM\n",
"- Sunnyvale: 12:28 PM\n",
"- Mountain View: 12:34 PM\n",
"- San Antonio: 12:37 PM\n",
"- California Ave: 12:42 PM\n",
"- Palo Alto: 12:46 PM\n",
"- Menlo Park: 12:50 PM\n",
"- Redwood City: 12:56 PM\n",
"- San Carlos: 1:01 PM\n",
"- Belmont: 1:04 PM\n",
"- Hillsdale: 1:08 PM\n",
"- Hayward Park: 1:11 PM\n",
"- San Mateo: 1:15 PM\n",
"- Burlingame: 1:19 PM\n",
"- Broadway: 1:22 PM\n",
"- Millbrae: 1:26 PM\n",
"- San Bruno: 1:30 PM\n",
"- S. San Francisco: 1:34 PM\n",
"- Bayshore: 1:41 PM\n",
"- 22nd Street: 1:46 PM\n",
"- San Francisco: 1:52 PM\n"
]
}
],
"source": [
"print(str(response))"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "229c4cb0-cf94-4a9f-bc7c-590388f50c1f",
"metadata": {},
"outputs": [],
"source": [
"response = query_engine.query(\n",
" \"What are all the trains (and times) that end at Tamien going Southbound?\"\n",
")"
]
},
{
"cell_type": "markdown",
"id": "6cf9fce0-5067-48f6-a7ef-62aa9e2edc3d",
"metadata": {},
"source": [
"It gets most of the answers correct (to be fair it misses two trains)."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "51cf03ff-7728-4815-ab72-3bf54fc4a2c0",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"The trains that end at Tamien going Southbound are:\n",
"\n",
"- Train 224 at 10:15a\n",
"- Train 228 at 11:45a\n",
"- Train 240 at 2:45p\n",
"- Train 248 at 4:45p\n",
"- Train 256 at 6:45p\n",
"- Train 264 at 8:45p\n",
"- Train 272 at 10:45p\n",
"- Train 284 at 1:49a\n"
]
}
],
"source": [
"print(str(response))"
]
},
{
"cell_type": "markdown",
"id": "e51e7feb-b74f-4101-8963-933ac7ec9763",
"metadata": {},
"source": [
"## Try Baseline\n",
"\n",
"In contrast, we try a baseline approach with the default PDF reader (PyPDF) in `SimpleDirectoryReader`."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "364e5155-cc75-4302-a754-9444ae28e6b1",
"metadata": {},
"outputs": [],
"source": [
"from llama_index.core import SimpleDirectoryReader\n",
"from llama_index.core import SummaryIndex\n",
"from llama_index.llms.openai import OpenAI\n",
"\n",
"llm = OpenAI(model=\"gpt-4o\")\n",
"input_file = \"caltrain_schedule_weekend.pdf\"\n",
"reader = SimpleDirectoryReader(input_files=[input_file])\n",
"base_docs = reader.load_data()\n",
"index = SummaryIndex.from_documents(base_docs)\n",
"base_query_engine = index.as_query_engine(llm=llm)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "a4011389-2d27-4a1a-bf8d-7309da28ab15",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Southbound WEEKEND SERVICE to SAN JOSE\n",
"Train No. 224 228 232 236 240 244 248 252 256 260 264 268 272 276 280 284\n",
"Service Types L2 L2 L2 L2 L2 L2 L2 L2 L2 L2 L2 L2 L2 L2 L2 L2\n",
"San Francisco 8:28a 9:58a 10:58a 11:58a 12:58p 1:58p 2:58p 3:58p 4:58p 5:58p 6:58p 7:58p 8:58p 9:58p 10:58p 12:05a\n",
"22nd Street 8:33a 10:03a 11:03a 12:03p 1:03p 2:03p 3:03p 4:03p 5:03p 6:03p 7:03p 8:03p 9:03p 10:03p 11:03p 12:10a\n",
"Bayshore 8:38a 10:08a 11:08a 12:08p 1:08p 2:08p 3:08p 4:08p 5:08p 6:08p 7:08p 8:08p 9:08p 10:08p 11:08p 12:15a\n",
"S. San Francisco 8:45a 10:15a 11:15a 12:15p 1:15p 2:15p 3:15p 4:15p 5:15p 6:15p 7:15p 8:15p 9:15p 10:15p 11:15p 12:22a\n",
"San Bruno 8:49a 10:19a 11:19a 12:19p 1:19p 2:19p 3:19p 4:19p 5:19p 6:19p 7:19p 8:19p 9:19p 10:19p 11:19p 12:26a\n",
"Millbrae 8:53a 10:24a 11:24a 12:24p 1:24p 2:24p 3:24p 4:24p 5:24p 6:24p 7:24p 8:24p 9:24p 10:24p 11:24p 12:31a\n",
"Broadway 8:57a 10:27a 11:27a 12:27p 1:27p 2:27p 3:27p 4:27p 5:27p 6:27p 7:27p 8:27p 9:27p 10:27p 11:27p 12:35a\n",
"Burlingame 9:00a 10:31a 11:31a 12:31p 1:31p 2:31p 3:31p 4:31p 5:31p 6:31p 7:31p 8:31p 9:31p 10:31p 11:31p 12:38a\n",
"San Mateo 9:04a 10:34a 11:34a 12:34p 1:34p 2:34p 3:34p 4:34p 5:34p 6:34p 7:34p 8:34p 9:34p 10:34p 11:34p 12:41a\n",
"Hayward Park 9:07a 10:37a 11:37a 12:37p 1:37p 2:37p 3:37p 4:37p 5:37p 6:37p 7:37p 8:37p 9:37p 10:37p 11:37p 12:45a\n",
"Hillsdale 9:10a 10:41a 11:41a 12:41p 1:41p 2:41p 3:41p 4:41p 5:41p 6:41p 7:41p 8:41p 9:41p 10:41p 11:41p 12:48a\n",
"Belmont 9:14a 10:44a 11:44a 12:44p 1:44p 2:44p 3:44p 4:44p 5:44p 6:44p 7:44p 8:44p 9:44p 10:44p 11:44p 12:52a\n",
"San Carlos 9:17a 10:48a 11:48a 12:48p 1:48p 2:48p 3:48p 4:48p 5:48p 6:48p 7:48p 8:48p 9:48p 10:48p 11:48p 12:55a\n",
"Redwood City 9:21a 10:52a 11:52a 12:52p 1:52p 2:52p 3:52p 4:52p 5:52p 6:52p 7:52p 8:52p 9:52p 10:52p 11:52p 12:59a\n",
"Menlo Park 9:28a 10:58a 11:58a 12:58p 1:58p 2:58p 3:58p 4:58p 5:58p 6:58p 7:58p 8:58p 9:58p 10:58p 11:58p 1:05a\n",
"Palo Alto 9:32a 11:02a 12:02p 1:02p 2:02p 3:02p 4:02p 5:02p 6:02p 7:02p 8:02p 9:02p 10:02p 11:02p 12:02a 1:09a\n",
"California Avenue 9:36a 11:06a 12:06p 1:06p 2:06p 3:06p 4:06p 5:06p 6:06p 7:06p 8:06p 9:06p 10:06p 11:06p 12:06a 1:12a\n",
"San Antonio 9:41a 11:11a 12:11p 1:11p 2:11p 3:11p 4:11p 5:11p 6:11p 7:11p 8:11p 9:11p 10:11p 11:11p 12:10a 1:17a\n",
"Mountain View 9:45a 11:16a 12:16p 1:16p 2:16p 3:16p 4:16p 5:16p 6:16p 7:16p 8:16p 9:16p 10:16p 11:16p 12:15a 1:21a\n",
"Sunnyvale 9:51a 11:21a 12:21p 1:21p 2:21p 3:21p 4:21p 5:21p 6:21p 7:21p 8:21p 9:21p 10:21p 11:21p 12:20a 1:26a\n",
"Lawrence 9:55a 11:26a 12:26p 1:26p 2:26p 3:26p 4:26p 5:26p 6:26p 7:26p 8:26p 9:26p 10:26p 11:26p 12:25a 1:31a\n",
"Santa Clara 10:01a 11:32a 12:32p 1:32p 2:32p 3:32p 4:32p 5:32p 6:32p 7:32p 8:32p 9:32p 10:32p 11:32p 12:31a 1:37a\n",
"San Jose Diridon 10:10a 11:40a 12:40p 1:38p 2:40p 3:38p 4:40p 5:38p 6:40p 7:38p 8:40p 9:38p 10:40p 11:38p 12:39a 1:44a\n",
"Tamien 10:15a 11:45a 12:45p 2:45p 4:45p 6:45p 8:45p 10:45p 12:44a 1:49aPrinter-Friendly Caltrain Schedule\n",
"Northbound WEEKEND SERVICE to SAN FRANCISCO\n",
"Train No. 221 225 229 233 237 241 245 249 253 257 261 265 269 273 *277 *281\n",
"Service Types L2 L2 L2 L2 L2 L2 L2 L2 L2 L2 L2 L2 L2 L2 L2 L2\n",
"Tamien 7:12a 9:05a 10:05a 11:05a 1:05p 3:05p 5:05p 7:05p 9:05p 11:05p\n",
"San Jose Diridon 7:19a 9:12a 10:12a 11:12a 12:12p 1:12p 2:12p 3:12p 4:12p 5:12p 6:12p 7:12p 8:12p 9:12p 10:19p 11:12p\n",
"Santa Clara 7:25a 9:18a 10:18a 11:18a 12:18p 1:18p 2:18p 3:18p 4:18p 5:18p 6:18p 7:18p 8:18p 9:18p 10:25p 11:18p\n",
"Lawrence 7:31a 9:24a 10:24a 11:24a 12:24p 1:24p 2:24p 3:24p 4:24p 5:24p 6:24p 7:24p 8:24p 9:24p 10:31p 11:24p\n",
"Sunnyvale 7:35a 9:28a 10:28a 11:28a 12:28p 1:28p 2:28p 3:28p 4:28p 5:28p 6:28p 7:28p 8:28p 9:28p 10:35p 11:28p\n",
"Mountain View 7:40a 9:34a 10:34a 11:34a 12:34p 1:34p 2:34p 3:34p 4:34p 5:34p 6:34p 7:34p 8:34p 9:34p 10:40p 11:34p\n",
"San Antonio 7:43a 9:37a 10:37a 11:37a 12:37p 1:37p 2:37p 3:37p 4:37p 5:37p 6:37p 7:37p 8:37p 9:37p 10:44p 11:37p\n",
"California Ave 7:48a 9:42a 10:42a 11:42a 12:42p 1:42p 2:42p 3:42p 4:42p 5:42p 6:42p 7:42p 8:42p 9:42p 10:48p 11:42p\n",
"Palo Alto 7:52a 9:46a 10:46a 11:46a 12:46p 1:46p 2:46p 3:46p 4:46p 5:46p 6:46p 7:46p 8:46p 9:46p 10:53p 11:46p\n",
"Menlo Park 7:55a 9:50a 10:50a 11:50a 12:50p 1:50p 2:50p 3:50p 4:50p 5:50p 6:50p 7:50p 8:50p 9:50p 10:56p 11:50p\n",
"Redwood City 8:01a 9:56a 10:56a 11:56a 12:56p 1:56p 2:56p 3:56p 4:56p 5:56p 6:56p 7:56p 8:56p 9:56p 11:02p 11:56p\n",
"San Carlos 8:05a 10:01a 11:01a 12:01p 1:01p 2:01p 3:01p 4:01p 5:01p 6:01p 7:01p 8:01p 9:01p 10:01p 11:07p 12:01a\n",
"Belmont 8:09a 10:04a 11:04a 12:04p 1:04p 2:04p 3:04p 4:04p 5:04p 6:04p 7:04p 8:04p 9:04p 10:04p 11:10p 12:04a\n",
"Hillsdale 8:12a 10:08a 11:08a 12:08p 1:08p 2:08p 3:08p 4:08p 5:08p 6:08p 7:08p 8:08p 9:08p 10:08p 11:14p 12:08a\n",
"Hayward Park 8:15a 10:11a 11:11a 12:11p 1:11p 2:11p 3:11p 4:11p 5:11p 6:11p 7:11p 8:11p 9:11p 10:11p 11:17p 12:11a\n",
"San Mateo 8:19a 10:15a 11:15a 12:15p 1:15p 2:15p 3:15p 4:15p 5:15p 6:15p 7:15p 8:15p 9:15p 10:15p 11:21p 12:15a\n",
"Burlingame 8:22a 10:19a 11:19a 12:19p 1:19p 2:19p 3:19p 4:19p 5:19p 6:19p 7:19p 8:19p 9:19p 10:19p 11:25p 12:19a\n",
"Broadway 8:25a 10:22a 11:22a 12:22p 1:22p 2:22p 3:22p 4:22p 5:22p 6:22p 7:22p 8:22p 9:22p 10:22p 11:28p 12:22a\n",
"Millbrae 8:29a 10:26a 11:26a 12:26p 1:26p 2:26p 3:26p 4:26p 5:26p 6:26p 7:26p 8:26p 9:26p 10:26p 11:32p 12:26a\n",
"San Bruno 8:34a 10:30a 11:30a 12:30p 1:30p 2:30p 3:30p 4:30p 5:30p 6:30p 7:30p 8:30p 9:30p 10:30p 11:37p 12:30a\n",
"S. San Francisco 8:38a 10:34a 11:34a 12:34p 1:34p 2:34p 3:34p 4:34p 5:34p 6:34p 7:34p 8:34p 9:34p 10:34p 11:41p 12:34a\n",
"Bayshore 8:44a 10:41a 11:41a 12:41p 1:41p 2:41p 3:41p 4:41p 5:41p 6:41p 7:41p 8:41p 9:41p 10:41p 11:47p 12:41a\n",
"22nd Street 8:50a 10:46a 11:46a 12:46p 1:46p 2:46p 3:46p 4:46p 5:46p 6:46p 7:46p 8:46p 9:46p 10:46p 11:53p 12:46a\n",
"San Francisco 8:56a 10:52a 11:53a 12:53p 1:52p 2:52p 3:52p 4:52p 5:52p 6:52p 7:52p 8:52p 9:52p 10:52p 11:59p 12:52aZONE 2 ZONE 3 ZONE 4 ZONE 4 ZONE 3 ZONE 2 ZONE 1 ZONE 12XX Local\n",
"2XX Local\n",
"EFFECTIVE September 12, 2022 Timetable subject to change without notice. *On SAP Center event days, Train 277 or Train 281departure from San Jose Diridon station may be delayed and will depart no later than 10:30p or 11:30p respectively.\n"
]
}
],
"source": [
"print(base_docs[0].get_content())"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "42203c70-7ca7-4200-bf47-6282eefca3bf",
"metadata": {},
"outputs": [],
"source": [
"base_response = base_query_engine.query(\n",
" \"What are the stops (and times) for train no 237 northbound?\"\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "06aa47b6-0f31-4b2d-90f0-bf6c74befd38",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Train No. 237 northbound stops at the following stations and times:\n",
"\n",
"- Tamien: 1:05p\n",
"- San Jose Diridon: 1:12p\n",
"- Santa Clara: 1:18p\n",
"- Lawrence: 1:24p\n",
"- Sunnyvale: 1:28p\n",
"- Mountain View: 1:34p\n",
"- San Antonio: 1:37p\n",
"- California Ave: 1:42p\n",
"- Palo Alto: 1:46p\n",
"- Menlo Park: 1:50p\n",
"- Redwood City: 1:56p\n",
"- San Carlos: 2:01p\n",
"- Belmont: 2:04p\n",
"- Hillsdale: 2:08p\n",
"- Hayward Park: 2:11p\n",
"- San Mateo: 2:15p\n",
"- Burlingame: 2:19p\n",
"- Broadway: 2:22p\n",
"- Millbrae: 2:26p\n",
"- San Bruno: 2:30p\n",
"- S. San Francisco: 2:34p\n",
"- Bayshore: 2:41p\n",
"- 22nd Street: 2:46p\n",
"- San Francisco: 2:52p\n"
]
}
],
"source": [
"print(str(base_response))"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "4f3c1de7-3351-4cd8-991c-34a777952194",
"metadata": {},
"outputs": [],
"source": [
"base_response = base_query_engine.query(\n",
" \"What are all the trains (and times) that end at Tamien going Southbound?\"\n",
")"
]
},
{
"cell_type": "markdown",
"id": "513b1007-7508-4fb1-836c-de9353433a67",
"metadata": {},
"source": [
"Note that the trains don't line up with the times!"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "108edb92-76af-406b-a139-8b9e7c6528f2",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"The trains that end at Tamien going Southbound are:\n",
"\n",
"- Train 224 at 10:15a\n",
"- Train 228 at 11:45a\n",
"- Train 240 at 2:45p\n",
"- Train 252 at 4:45p\n",
"- Train 264 at 6:45p\n",
"- Train 276 at 8:45p\n",
"- Train 284 at 10:45p\n",
"- Train 284 at 12:44a\n"
]
}
],
"source": [
"print(str(base_response))"
]
}
],
"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
}
Binary file not shown.
File diff suppressed because one or more lines are too long
+55 -44
View File
@@ -17,14 +17,13 @@
"metadata": {},
"outputs": [],
"source": [
"!pip install llama-index\n",
"!pip install llama-index-core==0.10.6.post1\n",
"!pip install llama-index-embeddings-openai\n",
"!pip install llama-index-postprocessor-flag-embedding-reranker\n",
"!pip install git+https://github.com/FlagOpen/FlagEmbedding.git\n",
"!pip install llama-parse\n",
"!pip install llama-index-vector-stores-astra\n",
"!pip install astrapy"
"%pip install llama-index\n",
"%pip install llama-index-core==0.10.6.post1\n",
"%pip install llama-index-embeddings-openai\n",
"%pip install llama-index-postprocessor-flag-embedding-reranker\n",
"%pip install git+https://github.com/FlagOpen/FlagEmbedding.git\n",
"%pip install llama-parse\n",
"%pip install llama-index-vector-stores-astra-db"
]
},
{
@@ -33,7 +32,7 @@
"metadata": {},
"outputs": [],
"source": [
"!wget 'https://raw.githubusercontent.com/run-llama/llama_index/main/docs/examples/data/10q/uber_10q_march_2022.pdf' -O './uber_10q_march_2022.pdf'"
"!wget 'https://raw.githubusercontent.com/run-llama/llama_index/main/docs/docs/examples/data/10q/uber_10q_march_2022.pdf' -O './uber_10q_march_2022.pdf'"
]
},
{
@@ -45,15 +44,17 @@
},
{
"cell_type": "code",
"execution_count": 1,
"execution_count": null,
"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-\"\n",
"\n",
@@ -61,12 +62,13 @@
"os.environ[\"OPENAI_API_KEY\"] = \"sk-\"\n",
"\n",
"ASTRA_API_ENDPOINT = \"<enter AstraDB endpoint>\"\n",
"ASTRA_TOKEN = \"<enter your Astra DB Token>\""
"ASTRA_TOKEN = \"<enter your Astra DB Token>\"\n",
"ASTRA_NAMESPACE = None # or: \"my_keyspace\". Must exist on Astra already."
]
},
{
"cell_type": "code",
"execution_count": 2,
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
@@ -75,7 +77,7 @@
"from llama_index.core import VectorStoreIndex\n",
"from llama_index.core import Settings\n",
"\n",
"embed_model=OpenAIEmbedding(model=\"text-embedding-3-small\")\n",
"embed_model = OpenAIEmbedding(model=\"text-embedding-3-small\")\n",
"llm = OpenAI(model=\"gpt-3.5-turbo-0125\")\n",
"\n",
"Settings.llm = llm\n",
@@ -93,7 +95,7 @@
},
{
"cell_type": "code",
"execution_count": 3,
"execution_count": null,
"metadata": {},
"outputs": [
{
@@ -107,12 +109,12 @@
"source": [
"from llama_parse import LlamaParse\n",
"\n",
"documents = LlamaParse(result_type=\"markdown\").load_data('./uber_10q_march_2022.pdf')"
"documents = LlamaParse(result_type=\"markdown\").load_data(\"./uber_10q_march_2022.pdf\")"
]
},
{
"cell_type": "code",
"execution_count": 4,
"execution_count": null,
"metadata": {},
"outputs": [
{
@@ -168,7 +170,7 @@
}
],
"source": [
"print(documents[0].text[:1000] + '...')"
"print(documents[0].text[:1000] + \"...\")"
]
},
{
@@ -180,27 +182,27 @@
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {
"tags": []
},
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from llama_index.vector_stores.astra import AstraDBVectorStore\n",
"from llama_index.vector_stores.astra_db import AstraDBVectorStore\n",
"\n",
"# define two storage classes representing two collections (to compare advanced approach vs. baseline) \n",
"# define two storage classes representing two collections (to compare advanced approach vs. baseline)\n",
"\n",
"astra_db_store_advanced = AstraDBVectorStore(\n",
" token=ASTRA_TOKEN,\n",
" api_endpoint=ASTRA_API_ENDPOINT,\n",
" namespace=ASTRA_NAMESPACE,\n",
" collection_name=\"astra_v_table_llamaparse_advanced\",\n",
" embedding_dimension=1536\n",
" embedding_dimension=1536,\n",
")\n",
"astra_db_store_base = AstraDBVectorStore(\n",
" token=ASTRA_TOKEN,\n",
" api_endpoint=ASTRA_API_ENDPOINT,\n",
" namespace=ASTRA_NAMESPACE,\n",
" collection_name=\"astra_v_table_llamaparse_base\",\n",
" embedding_dimension=1536\n",
" embedding_dimension=1536,\n",
")"
]
},
@@ -217,13 +219,15 @@
},
{
"cell_type": "code",
"execution_count": 6,
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from llama_index.core.node_parser import MarkdownElementNodeParser\n",
"\n",
"node_parser = MarkdownElementNodeParser(llm=OpenAI(model=\"gpt-3.5-turbo-0125\"), num_workers=8)"
"node_parser = MarkdownElementNodeParser(\n",
" llm=OpenAI(model=\"gpt-3.5-turbo-0125\"), num_workers=8\n",
")"
]
},
{
@@ -237,7 +241,7 @@
},
{
"cell_type": "code",
"execution_count": 9,
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
@@ -246,17 +250,23 @@
},
{
"cell_type": "code",
"execution_count": 10,
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from llama_index.core import StorageContext\n",
"\n",
"storage_context_advanced = StorageContext.from_defaults(vector_store=astra_db_store_advanced)\n",
"storage_context_advanced = StorageContext.from_defaults(\n",
" vector_store=astra_db_store_advanced\n",
")\n",
"storage_context_base = StorageContext.from_defaults(vector_store=astra_db_store_base)\n",
"\n",
"recursive_index = VectorStoreIndex(nodes=base_nodes+objects, storage_context=storage_context_advanced)\n",
"raw_index = VectorStoreIndex.from_documents(documents, storage_context=storage_context_base)"
"recursive_index = VectorStoreIndex(\n",
" nodes=base_nodes + objects, storage_context=storage_context_advanced\n",
")\n",
"raw_index = VectorStoreIndex.from_documents(\n",
" documents, storage_context=storage_context_base\n",
")"
]
},
{
@@ -265,7 +275,9 @@
"metadata": {},
"outputs": [],
"source": [
"from llama_index.postprocessor.flag_embedding_reranker import FlagEmbeddingReranker\n",
"from llama_index.postprocessor.flag_embedding_reranker import (\n",
" FlagEmbeddingReranker,\n",
")\n",
"\n",
"reranker = FlagEmbeddingReranker(\n",
" top_n=5,\n",
@@ -273,12 +285,12 @@
")\n",
"\n",
"recursive_query_engine = recursive_index.as_query_engine(\n",
" similarity_top_k=15, \n",
" node_postprocessors=[reranker], \n",
" verbose=True\n",
" similarity_top_k=15, node_postprocessors=[reranker], verbose=True\n",
")\n",
"\n",
"raw_query_engine = raw_index.as_query_engine(similarity_top_k=15, node_postprocessors=[reranker])"
"raw_query_engine = raw_index.as_query_engine(\n",
" similarity_top_k=15, node_postprocessors=[reranker]\n",
")"
]
},
{
@@ -298,7 +310,7 @@
},
{
"cell_type": "code",
"execution_count": 12,
"execution_count": null,
"metadata": {},
"outputs": [
{
@@ -339,7 +351,7 @@
"\n",
"response_2 = recursive_query_engine.query(query)\n",
"print(\"\\n***********New LlamaParse+ Recursive Retriever Query Engine***********\")\n",
"print(response_2)\n"
"print(response_2)"
]
},
{
@@ -356,7 +368,7 @@
},
{
"cell_type": "code",
"execution_count": 13,
"execution_count": null,
"metadata": {},
"outputs": [
{
@@ -420,7 +432,7 @@
},
{
"cell_type": "code",
"execution_count": 14,
"execution_count": null,
"metadata": {},
"outputs": [
{
@@ -476,7 +488,7 @@
},
{
"cell_type": "code",
"execution_count": 15,
"execution_count": null,
"metadata": {},
"outputs": [
{
@@ -552,8 +564,7 @@
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.10.8"
"pygments_lexer": "ipython3"
}
},
"nbformat": 4,
File diff suppressed because one or more lines are too long
+6 -8
View File
@@ -11,7 +11,7 @@
},
{
"cell_type": "code",
"execution_count": 4,
"execution_count": null,
"metadata": {},
"outputs": [
{
@@ -38,7 +38,7 @@
},
{
"cell_type": "code",
"execution_count": 5,
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
@@ -47,7 +47,7 @@
},
{
"cell_type": "code",
"execution_count": 6,
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
@@ -88,7 +88,7 @@
},
{
"cell_type": "code",
"execution_count": 7,
"execution_count": null,
"metadata": {},
"outputs": [
{
@@ -128,10 +128,8 @@
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.11.5"
},
"orig_nbformat": 4
"pygments_lexer": "ipython3"
}
},
"nbformat": 4,
"nbformat_minor": 2
+25 -24
View File
@@ -23,12 +23,12 @@
},
{
"cell_type": "code",
"execution_count": 1,
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# First, install the required dependencies\n",
"!pip install --quiet llama-index llama-parse llama-index-vector-stores-astra llama-index-llms-openai astrapy"
"%pip install --quiet llama-index llama-parse llama-index-vector-stores-astra-db llama-index-llms-openai"
]
},
{
@@ -40,7 +40,7 @@
},
{
"cell_type": "code",
"execution_count": 2,
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
@@ -51,8 +51,11 @@
"\n",
"# Get all required API keys and parameters\n",
"llama_cloud_api_key = getpass(\"Enter your Llama Index Cloud API Key: \")\n",
"api_endpoint = input(\"Enter you Astra DB API Endpoint: \")\n",
"api_endpoint = input(\"Enter your Astra DB API Endpoint: \")\n",
"token = getpass(\"Enter your Astra DB Token: \")\n",
"namespace = (\n",
" input(\"Enter your Astra DB namespace (optional, must exist on Astra): \") or None\n",
")\n",
"openai_api_key = getpass(\"Enter your OpenAI API Key: \")\n",
"\n",
"os.environ[\"LLAMA_CLOUD_API_KEY\"] = llama_cloud_api_key\n",
@@ -61,7 +64,7 @@
},
{
"cell_type": "code",
"execution_count": 3,
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
@@ -80,7 +83,7 @@
},
{
"cell_type": "code",
"execution_count": 4,
"execution_count": null,
"metadata": {},
"outputs": [
{
@@ -93,7 +96,7 @@
],
"source": [
"# Grab a PDF from Arxiv for indexing\n",
"import requests \n",
"import requests\n",
"\n",
"# The URL of the file you want to download\n",
"url = \"https://arxiv.org/pdf/1706.03762.pdf\"\n",
@@ -115,7 +118,7 @@
},
{
"cell_type": "code",
"execution_count": 5,
"execution_count": null,
"metadata": {},
"outputs": [
{
@@ -134,7 +137,7 @@
},
{
"cell_type": "code",
"execution_count": 6,
"execution_count": null,
"metadata": {},
"outputs": [
{
@@ -143,7 +146,7 @@
"'rmer - model architecture.\\nThe Transformer follows this overall architecture using stacked self-attention and point-wise, fully\\nconnected layers for both the encoder and decoder, shown in the left and right halves of Figure 1,\\nrespectively.\\n3.1 Encoder and Decoder Stacks\\nEncoder: The encoder is composed of a stack of N = 6 identical layers. Each layer has two\\nsub-layers. The first is a multi-head self-attention mechanism, and the second is a simple, position-\\nwise fully connected feed-forward network. We employ a residual connection [11] around each of\\nthe two sub-layers, followed by layer normalization [1]. That is, the output of each sub-layer is\\nLayerNorm(x + Sublayer(x)), where Sublayer(x) is the function implemented by the sub-layer\\nitself. To facilitate these residual connections, all sub-layers in the model, as well as the embedding\\nlayers, produce outputs of dimension dmodel = 512.\\nDecoder: The decoder is also composed of a stack of N = 6 identical layers. In addition '"
]
},
"execution_count": 6,
"execution_count": null,
"metadata": {},
"output_type": "execute_result"
}
@@ -162,26 +165,25 @@
},
{
"cell_type": "code",
"execution_count": 7,
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from llama_index.vector_stores.astra import AstraDBVectorStore\n",
"from llama_index.vector_stores.astra_db import AstraDBVectorStore\n",
"\n",
"astra_db_store = AstraDBVectorStore(\n",
" token=token,\n",
" api_endpoint=api_endpoint,\n",
" namespace=namespace,\n",
" collection_name=\"astra_v_table_llamaparse\",\n",
" embedding_dimension=1536\n",
" embedding_dimension=1536,\n",
")"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {
"tags": []
},
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from llama_index.core.node_parser import SimpleNodeParser\n",
@@ -193,7 +195,7 @@
},
{
"cell_type": "code",
"execution_count": 9,
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
@@ -218,7 +220,7 @@
},
{
"cell_type": "code",
"execution_count": 10,
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
@@ -227,7 +229,7 @@
},
{
"cell_type": "code",
"execution_count": 11,
"execution_count": null,
"metadata": {},
"outputs": [
{
@@ -250,7 +252,7 @@
},
{
"cell_type": "code",
"execution_count": 12,
"execution_count": null,
"metadata": {},
"outputs": [
{
@@ -259,7 +261,7 @@
"'We used beam search as described in the previous section, but no\\ncheckpoint averaging. We present these results in Table 3.\\nIn Table 3 rows (A), we vary the number of attention heads and the attention key and value dimensions,\\nkeeping the amount of computation constant, as described in Section 3.2.2. While single-head\\nattention is 0.9 BLEU worse than the best setting, quality also drops off with too many heads.\\nIn Table 3 rows (B), we observe that reducing the attention key size dk hurts model quality. This\\nsuggests that determining compatibility is not easy and that a more sophisticated compatibility\\nfunction than dot product may be beneficial. We further observe in rows (C) and (D) that, as expected,\\nbigger models are better, and dropout is very helpful in avoiding over-fitting. In row (E) we replace our\\nsinusoidal positional encoding with learned positional embeddings [9], and observe nearly identical\\nresults to the base model.\\n6.3 English Constituency Parsing\\nTo evaluate if the Transformer can generalize to other tasks we performed experiments on English\\nconstituency parsing. This task presents specific challenges: the output is subject to strong structural\\nconstraints and is significantly longer than the input. Furthermore, RNN sequence-to-sequence\\nmodels have not been able to attain state-of-the-art results in small-data regimes [37].\\nWe trained a 4-layer transformer with dmodel = 1024 on the Wall Street Journal (WSJ) portion of the\\nPenn Treebank [25], about 40K training sentences. We also trained it in a semi-supervised setting,\\nusing the larger high-confidence and BerkleyParser corpora from with approximately 17M sentences\\n[37]. We used a vocabulary of 16K tokens for the WSJ only setting and a vocabulary of 32K tokens\\nfor the semi-supervised setting.\\nWe performed only a small number of experiments to select the dropout, both attention and residual\\n(section 5.4), learning rates and beam size on the Section 22 development set, all other parameters\\nremained unchanged from the English-to-German base translation model. During inference, we\\n 9\\n---\\nTable 4: The Transformer generalizes well to English constituency parsing (Results are on Section 23\\nof WSJ)\\n Parser Training WSJ 23 F1\\n Vinyals & Kaiser el al. (2014) [37] WSJ only, discriminative 88.3\\n Petrov et al. (2006) [29] WSJ only, discriminative 90.4\\n Zhu et al. (2013) [40] WSJ only, discriminative 90.4\\n Dyer et al. (2016) [8] WSJ only, discriminative 91.7\\n Transformer (4 layers) WSJ only, discriminative 91.3\\n Zhu et al. (2013) [40] semi-supervised 91.3\\n Huang & Harper (2009) [14] semi-supervised 91.3\\n McClosky et al. (2006) [26] semi-supervised 92.1\\n Vinyals & Kaiser el al. (2014) [37] semi-supervised 92.1\\n Transformer (4 layers) semi-supervised 92.7\\n Luong et al. (2015) [23] multi-task 93.0\\n Dyer et al. (2016) [8] generative 93.3\\nincreased the maximum output length to input length + 300. We used a beam size of 21 and α = 0.3\\nfor both WSJ only and the semi-supervised setting.\\nOur results in Table 4 show that despite the lack of task-specific tuning our model performs sur-\\nprisingly well, yielding better results than all previously reported models with the exception of the\\nRecurrent Neural Network Grammar [8].\\nIn contrast to RNN sequence-to-sequence models [37], the Transformer outperforms the Berkeley-\\nParser [29] even when training only on the WSJ training set of 40K sentences.\\n7 Conclusion\\nIn this work, we presented the Transformer, the first sequence transduction model based entirely on\\nattention, replacing the recurrent layers most commonly used in encoder-decoder architectures with\\nmulti-headed self-attention.\\nFor translation tasks, the Transformer can be trained significantly faster than architectures based\\non recurrent or convolutional layers.'"
]
},
"execution_count": 12,
"execution_count": null,
"metadata": {},
"output_type": "execute_result"
}
@@ -285,8 +287,7 @@
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.11.6"
"pygments_lexer": "ipython3"
}
},
"nbformat": 4,
+12 -20
View File
@@ -13,12 +13,12 @@
"metadata": {},
"outputs": [],
"source": [
"!pip install llama-index llama-parse"
"%pip install llama-index llama-parse"
]
},
{
"cell_type": "code",
"execution_count": 2,
"execution_count": null,
"metadata": {},
"outputs": [
{
@@ -45,7 +45,7 @@
},
{
"cell_type": "code",
"execution_count": 7,
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
@@ -55,12 +55,13 @@
"nest_asyncio.apply()\n",
"\n",
"import os\n",
"\n",
"os.environ[\"LLAMA_CLOUD_API_KEY\"] = \"llx-...\""
]
},
{
"cell_type": "code",
"execution_count": 3,
"execution_count": null,
"metadata": {},
"outputs": [
{
@@ -79,7 +80,7 @@
},
{
"cell_type": "code",
"execution_count": 4,
"execution_count": null,
"metadata": {},
"outputs": [
{
@@ -107,7 +108,7 @@
},
{
"cell_type": "code",
"execution_count": 5,
"execution_count": null,
"metadata": {},
"outputs": [
{
@@ -126,7 +127,7 @@
},
{
"cell_type": "code",
"execution_count": 6,
"execution_count": null,
"metadata": {},
"outputs": [
{
@@ -157,18 +158,11 @@
"source": [
"print(documents[0].text[20000:21000] + \"...\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "llama-parse-aNC435Vv-py3.11",
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
@@ -181,11 +175,9 @@
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.11.5"
},
"orig_nbformat": 4
"pygments_lexer": "ipython3"
}
},
"nbformat": 4,
"nbformat_minor": 2
"nbformat_minor": 4
}
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+531
View File
@@ -0,0 +1,531 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# LlamaParse - Fast checking Insurance Contract for Coverage\n",
"\n",
"<a href=\"https://colab.research.google.com/github/run-llama/llama_parse/blob/main/examples/demo_insurance.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>\n",
"\n",
"In this notebook we will look at how LlamaParse can be used to extract structured coverage information from an insurance policy."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Installation of required packages"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"%pip install llama-index llama-parse"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Download an insurance policy fron IRDAI\n",
"\n",
"The Insurance Regulatory and Development Authority of India (IRDAI) maintains a great resource: https://policyholder.gov.in/web/guest/non-life-insurance-products where all insurance policies available in India are publicly available for download! Let's download a complex health insurance policy as an example."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"!wget \"https://policyholder.gov.in/documents/37343/931203/NBHTGBP22011V012223.pdf/c392bcc1-f6a8-cadd-ab84-495b3273d2c3?version=1.0&t=1669350459879&download=true\" -O \"./policy.pdf\""
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Initializing LlamaIndex and LlamaParse"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# llama-parse is async-first, running the sync code in a notebook requires the use of nest_asyncio\n",
"import nest_asyncio\n",
"\n",
"nest_asyncio.apply()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import os\n",
"\n",
"os.environ[\"LLAMA_CLOUD_API_KEY\"] = \"llx-...\"\n",
"os.environ[\"OPENAI_API_KEY\"] = \"sk-...\""
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from llama_index.llms.openai import OpenAI\n",
"from llama_index.embeddings.openai import OpenAIEmbedding\n",
"from llama_index.core import VectorStoreIndex\n",
"from llama_index.core import Settings\n",
"\n",
"# for the purpose of this example, we will use the small model embedding and gpt3.5\n",
"embed_model = OpenAIEmbedding(model=\"text-embedding-3-small\")\n",
"llm = OpenAI(model=\"gpt-3.5-turbo-0125\")\n",
"\n",
"Settings.llm = llm"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Vanilla Approach - Parse the Policy with LlamaParse into Markdown"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Started parsing the file under job_id b8946573-c911-4e00-8921-1bad1cda3d64\n",
"......"
]
}
],
"source": [
"from llama_parse import LlamaParse\n",
"\n",
"documents = LlamaParse(result_type=\"markdown\").load_data(\"./policy.pdf\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"## Preamble\n",
"\n",
"This Travel Infinity Policy is a contract of insurance between You and Us which is subject to payment of full premium in advance and the terms, conditions and exclusions of this Policy. Expense incurred outside the policy period will NOT be covered. Unutilized Sum Insured will expire at the end of the policy year. All applicable benefits, details and limits are mentioned in your Certificate of insurance. We will cover only allopathic treatments in this policy.\n",
"\n",
"## Defined Terms\n",
"\n",
"The terms listed below in this Section and used elsewhere in the Policy in Initial Capitals shall have the meaning set out against them in this Section.\n",
"\n",
"### Standard Definitions\n",
"\n",
"|2.1|Accident or Accidental|means sudden, unforeseen and involuntary event caused by external, visible and violent means.|\n",
"|---|---|---|\n",
"|2.2|Co-payment|means a cost sharing requirement under a health insurance policy that provides that the policyholder/insured will bear a specified percentage of the admissible claims a\n"
]
}
],
"source": [
"print(documents[0].text[0:1000])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Markdown Element Node Parser\n",
"Our markdown element node parser works well for parsing the markdown output of LlamaParse into a set of table and text nodes."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from llama_index.core.node_parser import MarkdownElementNodeParser\n",
"\n",
"node_parser = MarkdownElementNodeParser(\n",
" llm=OpenAI(model=\"gpt-3.5-turbo-0125\"), num_workers=8\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"nodes = node_parser.get_nodes_from_documents(documents)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"base_nodes, objects = node_parser.get_nodes_and_objects(nodes)\n",
"\n",
"recursive_index = VectorStoreIndex(nodes=base_nodes + objects)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"query_engine = recursive_index.as_query_engine(similarity_top_k=25)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Querying the model for coverage"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"You are covered for the expenses incurred on any alternate travel booking under any mode of transport, up to the limit of the Sum Insured as mentioned in the Certificate of insurance, if the delay of the airlines was caused due to specific reasons outlined in the policy. The amount you are covered for will depend on the specific terms and conditions of your policy, including the maximum coverage limit specified in the Certificate of insurance.\n"
]
}
],
"source": [
"query_1 = \"My trip was delay and I paid 45, how much am I cover for?\"\n",
"\n",
"response_1 = query_engine.query(query_1)\n",
"print(str(response_1))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The information is split across the document which leads to retrieval issues. Let's try some parsing instructions to improve our result."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Started parsing the file under job_id ec9e77c9-6ad9-4c9b-9efb-c9f659b0d481\n",
"....."
]
}
],
"source": [
"documents_with_instruction = LlamaParse(\n",
" result_type=\"markdown\",\n",
" parsing_instruction=\"\"\"\n",
"This document is an insurance policy.\n",
"When a benefits/coverage/exlusion is describe in the document ammend to it add a text in the follwing benefits string format (where coverage could be an exclusion).\n",
"\n",
"For {nameofrisk} and in this condition {whenDoesThecoverageApply} the coverage is {coverageDescription}. \n",
" \n",
"If the document contain a benefits TABLE that describe coverage amounts, do not ouput it as a table, but instead as a list of benefits string.\n",
" \n",
"\"\"\",\n",
").load_data(\"./policy.pdf\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Let see how the 2 parsing compare (change target page to explore)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"## Inpatient treatment\n",
"\n",
"Claim Form (filled and signed by pe Insured)\n",
"Hospital Daily Cash\n",
"Release of Medical information Form (filled and signed by pe Insured)\n",
"Waiver of Deductible\n",
"Original papological and diagnostic reports, discharge summary indoor case papers (if any) and prescriptions issued by pe treating Medical practitioner or Network Provider\n",
"Optional Co-payment\n",
"Adventure Sports Cover\n",
"Home to Home Cover\n",
"Passport and Visa copy wip Entry Stamp of Country of Visit and exit Stamp from India\n",
"Extension to in-patient care\n",
"Ambulance Charge\n",
"FIR report of police (if applicable)\n",
"\n",
"## Out-patient treatment\n",
"\n",
"Cancer Screening & Mammographic Examination\n",
"Original bills and receipts for:\n",
"1. Charges paid towards Hospital accommodation, nursing facilities, and oper medical services rendered\n",
"2. Fees paid to pe Medical Practitioner and for special nursing charges\n",
"3. Charges incurred towards any and all test and / or examinations rendered in connection wip pe treatment\n",
"4. Charges incurred towards medicines or drugs purchased from a registered pharmacy oper pan pe Network provider duly supported by pe prescriptions of pe Medical Practitioner attending to pe Insured Person\n",
"5. Any oper document as required by pe Company to assist pe Claim\n",
"\n",
"## Medical evacuation\n",
"\n",
"Medical reports and transportation details issued by the evacuation agency, prescriptions and medical report by the attending Medical Practitioner furnishing the name of the Insured Person and details of treatment rendered along with the statement confirming the necessity of evacuation.\n",
"\n",
"Documentary proof for expenses incurred towards the Medical Evacuation.\n",
"\n",
"## Compassionate visit\n",
"\n",
"A certificate from the Medical Practitioner recommending the presence in the form of special assistance to be rendered by an additional member during the entire period of hospitalization. The certificate shall also specify the minimum period in which person is admitted in the hospital.\n",
"\n",
"Discharge summary of the Hospital furnishing details including the date of admission and date of discharge.\n",
"\n",
"Stamped boarding pass with invoice used for the travel by the Immediate Family Member.\n",
"\n",
"Copy passport of Immediate Family Member with entry and exit stamp.\n",
"\n",
"## Escort of Minor Child\n",
"\n",
"A certificate from the Medical Practitioner specifying the minimum period of Hospitalization.\n",
"\n",
"Discharge summary of the Hospital furnishing details including the date of admission and date of discharge.\n",
"\n",
"Stamped Boarding pass used for the return travel of the child to the Country of Residence.\n",
"\n",
"Stamped Boarding pass of the attendant from the Country of Residence to the place of hospitalization (if attendant is necessary).\n",
"\n",
"Copy of passport of the child with entry and exit stamp.\n",
"\n",
"## Upgradation to Business Class\n",
"\n",
"A certificate from the Medical Practitioner specifying the minimum period of Hospitalization.\n",
"\n",
"Discharge summary of the Hospital furnishing the details including the date of admission and date of discharge.\n",
"\n",
"Product Name: Travel infinity | Product UIN: NBHTGBP22011V012223\n",
"\n",
"\n",
"=========================================================\n",
"\n",
"\n",
"# Insurance Policy\n",
"\n",
"## Benefits:\n",
"\n",
"- For Inpatient treatment and in this condition when admitted to a hospital, the coverage is reimbursement for medical expenses incurred.\n",
"- For Hospital Daily Cash and in this condition when hospitalized, the coverage is daily cash benefit.\n",
"- For Waiver of Deductible and in this condition when a deductible is applicable, the coverage is waiver of the deductible amount.\n",
"- For Optional Co-payment and in this condition when a co-payment is required, the coverage is optional co-payment.\n",
"- For Adventure Sports Cover and in this condition when participating in adventure sports, the coverage is coverage for injuries related to adventure sports.\n",
"- For Home to Home Cover and in this condition when requiring medical evacuation, the coverage is assistance for repatriation to home country.\n",
"- For Extension to in-patient care and in this condition when extended hospital stay is necessary, the coverage is extension of coverage for in-patient care.\n",
"- For Ambulance Charge and in this condition when ambulance services are utilized, the coverage is reimbursement for ambulance charges.\n",
"- For Out-patient treatment and in this condition when receiving outpatient medical care, the coverage is reimbursement for outpatient medical expenses.\n",
"- For Cancer Screening & Mammographic Examination and in this condition when undergoing cancer screening or mammographic examination, the coverage is coverage for these preventive services.\n",
"- For New Born baby Cover and in this condition when a newborn is covered under the policy, the coverage is medical expenses coverage for the newborn.\n",
"- For Maternity and in this condition when maternity services are required, the coverage is coverage for maternity expenses.\n",
"- For Complete pre-existing disease cover and in this condition when seeking treatment for pre-existing conditions, the coverage is coverage for pre-existing conditions.\n",
"- For Medical sum insured replenishment in case of hospitalization due to accident and in this condition when hospitalized due to an accident, the coverage is replenishment of the sum insured.\n",
"- For Waiver of sublimit for insured above 60 years of age and in this condition when the insured is above 60 years of age, the coverage is waiver of sublimits.\n",
"- For Psychiatric Counseling and in this condition when seeking psychiatric counseling, the coverage is coverage for psychiatric counseling services.\n",
"- For Physiotherapy and in this condition when undergoing physiotherapy, the coverage is coverage for physiotherapy sessions.\n",
"- For Terrorism cover and in this condition when affected by terrorism, the coverage is coverage for medical expenses related to terrorism incidents.\n",
"- For Medical tele-consultation and in this condition when consulting a medical practitioner remotely, the coverage is coverage for tele-consultation services.\n",
"- For Medical evacuation and in this condition when requiring medical evacuation, the coverage is coverage for medical evacuation services.\n",
"- For Compassionate visit and in this condition when requiring a compassionate visit, the coverage is coverage for travel expenses for a family member to visit.\n",
"- For Escort of Minor Child and in this condition when escorting a minor child for medical treatment, the coverage is coverage for escort services for the child.\n",
"- For Upgradation to Business Class and in this condition when requiring upgradation to business class for medical travel, the coverage is coverage for upgradation to business class.\n"
]
}
],
"source": [
"target_page = 45\n",
"pages_vanilla = documents[0].text.split(\"\\n---\\n\")\n",
"pages_with_instructions = documents_with_instruction[0].text.split(\"\\n---\\n\")\n",
"\n",
"print(pages_vanilla[target_page])\n",
"print(\"\\n\\n=========================================================\\n\\n\")\n",
"print(pages_with_instructions[target_page])"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"node_parser_instruction = MarkdownElementNodeParser(\n",
" llm=OpenAI(model=\"gpt-3.5-turbo-0125\"), num_workers=8\n",
")\n",
"nodes_instruction = node_parser.get_nodes_from_documents(documents_with_instruction)\n",
"(\n",
" base_nodes_instruction,\n",
" objects_instruction,\n",
") = node_parser_instruction.get_nodes_and_objects(nodes_instruction)\n",
"\n",
"recursive_index_instruction = VectorStoreIndex(\n",
" nodes=base_nodes_instruction + objects_instruction\n",
")\n",
"query_engine_instruction = recursive_index_instruction.as_query_engine(\n",
" similarity_top_k=25\n",
")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Comparing Instruction-Augmented Parsing vs. Vanilla Parsing\n",
"\n",
"When we parse the document with natural language instructions to add context on insurance coverage, we are able to correctly answer a wide range of queries in our RAG pipeline. In contrast, a RAG pipeline built with the vanilla method is not able to answer these queries."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Vanilla:\n",
"You are covered for the amount you paid due to the trip delay, up to the limit specified in the certificate of insurance.\n",
"With instructions:\n",
"For Trip Delay coverage, you are covered for a fixed benefit amount as mentioned in the certificate of insurance for every block of hours of delay.\n"
]
}
],
"source": [
"query_1 = \"My trip was delayed and I paid 45, how much am I covered for?\"\n",
"\n",
"response_1 = query_engine.query(query_1)\n",
"print(\"Vanilla:\")\n",
"print(response_1)\n",
"\n",
"print(\"With instructions:\")\n",
"response_1_i = query_engine_instruction.query(query_1)\n",
"print(response_1_i)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Looking at the policy it says in list I that one expense not covered is Baby food"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Vanilla:\n",
"Baby food is not explicitly mentioned in the provided context information regarding insurance coverages and benefits.\n",
"With instructions:\n",
"Baby food is excluded from coverage according to the policy terms.\n"
]
}
],
"source": [
"query_2 = \"I just had a baby, is baby food covered?\"\n",
"\n",
"response_2 = query_engine.query(query_2)\n",
"print(\"Vanilla:\")\n",
"print(response_2)\n",
"\n",
"print(\"With instructions:\")\n",
"response_2_i = query_engine_instruction.query(query_2)\n",
"print(response_2_i)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Vanilla:\n",
"Gauze used in your operation would typically be covered under the \"Emergency In-patient Medical Treatment\" or \"Emergency In-patient Medical Treatment with OPD\" benefits of the policy.\n",
"With instructions:\n",
"Gauze is not covered for use in your operation as it falls under the category of items that are excluded from coverage in the insurance policy.\n"
]
}
],
"source": [
"query_3 = \"How is gauze used in my operation covered?\"\n",
"\n",
"response_3 = query_engine.query(query_3)\n",
"print(\"Vanilla:\")\n",
"print(response_3)\n",
"\n",
"print(\"With instructions:\")\n",
"response_3_i = query_engine_instruction.query(query_3)\n",
"print(response_3_i)"
]
}
],
"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": 4
}
+363
View File
@@ -0,0 +1,363 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "d27f1082-cd10-405e-9570-6f0e934bba8b",
"metadata": {},
"source": [
"# LlamaParse JSON Mode + Multimodal RAG\n",
"\n",
"<a href=\"https://colab.research.google.com/github/run-llama/llama_parse/blob/main/examples/demo_json.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>\n",
"\n",
"This notebook shows you how to use LlamaParse JSON mode with LlamaIndex to build a simple multimodal RAG pipeline.\n",
"\n",
"Using JSON mode gives you back a list of json dictionaries, which contains both text and images. You can then download these images and use a multimodal model to extract information and index them."
]
},
{
"cell_type": "markdown",
"id": "a004db48-8d3f-421c-915a-477692f71b90",
"metadata": {},
"source": [
"## Setup\n",
"\n",
"Define imports, env variables, global LLM/embedding models."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "bc6a7a4b-b568-4db5-bcba-62f5c517ff3a",
"metadata": {},
"outputs": [],
"source": [
"!pip install llama-index\n",
"!pip install llama-index-core\n",
"!pip install llama-index-llms-anthropic llama-index-multi-modal-llms-anthropic\n",
"!pip install llama-index-embeddings-huggingface\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-\"\n",
"\n",
"# Using Anthropic API for embeddings/LLMs\n",
"os.environ[\"ANTHROPIC_API_KEY\"] = \"sk-\""
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "391e2d95-5569-4d73-9f16-5b59d7326f8d",
"metadata": {},
"outputs": [],
"source": [
"from llama_index.llms.anthropic import Anthropic\n",
"\n",
"llm = Anthropic(model=\"claude-3-opus-20240229\", temperature=0.0)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "700f48e8-8b52-41f3-90f9-144d5fdd5c52",
"metadata": {},
"outputs": [],
"source": [
"from llama_index.core import Settings\n",
"\n",
"Settings.llm = llm\n",
"Settings.embed_model = \"local:BAAI/bge-small-en-v1.5\""
]
},
{
"cell_type": "markdown",
"id": "b411d2ee-3e6b-45b0-b532-4a8e3abcdea0",
"metadata": {},
"source": [
"## Load Data\n",
"\n",
"Let's load in the Uber 10Q report."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "c39d408f-e885-4940-85c7-b09ca3bc7cb7",
"metadata": {},
"outputs": [],
"source": [
"!wget 'https://raw.githubusercontent.com/run-llama/llama_index/main/docs/docs/examples/data/10q/uber_10q_march_2022.pdf' -O './uber_10q_march_2022.pdf'"
]
},
{
"cell_type": "markdown",
"id": "c2f42af8-afb3-4b3b-82d3-6b332fb38aa4",
"metadata": {},
"source": [
"## Using LlamaParse in JSON Mode for PDF Reading\n",
"\n",
"We show you how to run LlamaParse in JSON mode for PDF reading."
]
},
{
"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 cf5a4f51-1af8-47f7-9b3d-80a905d06b89\n"
]
}
],
"source": [
"from llama_parse import LlamaParse\n",
"\n",
"parser = LlamaParse(verbose=True)\n",
"json_objs = parser.get_json_result(\"./uber_10q_march_2022.pdf\")\n",
"json_list = json_objs[0][\"pages\"]"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "b26d21d1-05b5-4f49-b937-c13106a84015",
"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[\"text\"], metadata={\"page\": page[\"page\"]})\n",
" text_nodes.append(text_node)\n",
" return text_nodes"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "364a3276-d2db-4aee-9bc6-617ffd726d25",
"metadata": {},
"outputs": [],
"source": [
"text_nodes = get_text_nodes(json_list)"
]
},
{
"cell_type": "markdown",
"id": "2fe2e911-0393-42e8-a233-65639cdbebc4",
"metadata": {},
"source": [
"## Extract/Index images from image dicts\n",
"\n",
"Here we use a multimodal model to extract and index images from image dictionaries."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "36012145-5521-4ddb-a53e-df9ebd1ca8dd",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"mkdir: llama2_images: File exists\n"
]
}
],
"source": [
"# call get_images on parser, convert to ImageDocuments\n",
"!mkdir llama2_images\n",
"\n",
"from llama_index.core.schema import ImageDocument\n",
"from llama_index.multi_modal_llms.anthropic import AnthropicMultiModal\n",
"\n",
"\n",
"def get_image_text_nodes(json_objs: List[dict]):\n",
" \"\"\"Extract out text from images using a multimodal model.\"\"\"\n",
" anthropic_mm_llm = AnthropicMultiModal(max_tokens=300)\n",
" image_dicts = parser.get_images(json_objs, download_path=\"llama2_images\")\n",
" image_documents = []\n",
" img_text_nodes = []\n",
" for image_dict in image_dicts:\n",
" image_doc = ImageDocument(image_path=image_dict[\"path\"])\n",
" response = anthropic_mm_llm.complete(\n",
" prompt=\"Describe the images as alt text\",\n",
" image_documents=[image_doc],\n",
" )\n",
" text_node = TextNode(text=str(response), metadata={\"path\": image_dict[\"path\"]})\n",
" img_text_nodes.append(text_node)\n",
" return img_text_nodes"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "38f25045-6102-4920-9cd0-42b0ae6c872f",
"metadata": {},
"outputs": [],
"source": [
"image_text_nodes = get_image_text_nodes(json_objs)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "4683c97a-da06-408a-9fe9-7e3c0aceb77d",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"'The image shows a bar graph titled \"Monthly Active Platform Consumers (in millions)\". The graph displays data from Q2 2020 to Q1 2022 over 8 quarters. The number of monthly active platform consumers starts at 55 million in Q2 2020 and steadily increases each quarter, reaching 115 million by Q1 2022. The graph illustrates consistent quarter-over-quarter growth in this metric over the nearly 2 year time period shown.'"
]
},
"execution_count": null,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"image_text_nodes[0].get_content()"
]
},
{
"cell_type": "markdown",
"id": "3cfdf6db-381c-4e53-a0fb-e7670f75e0d5",
"metadata": {},
"source": [
"## Build Index across image and text nodes\n",
"\n",
"Here we build a vector index across both text nodes and text nodes extracted from images."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "939aec6c-064a-4319-b2dc-70cc4a304c06",
"metadata": {},
"outputs": [],
"source": [
"from llama_index.core import VectorStoreIndex\n",
"\n",
"index = VectorStoreIndex(text_nodes + image_text_nodes)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "529340d5-9319-4cdf-8ee1-bbd01ed00226",
"metadata": {},
"outputs": [],
"source": [
"query_engine = index.as_query_engine()"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "81d7ff30-5a87-44da-880d-4b1f41434d90",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"The bar graph titled \"Monthly Active Platform Consumers (in millions)\" shows the number of monthly active consumers on Uber's platform over a period of 8 quarters from Q2 2020 to Q1 2022. \n",
"\n",
"The graph indicates steady quarter-over-quarter growth in this metric, starting at 55 million monthly active platform consumers in Q2 2020 and increasing each quarter to reach 115 million by Q1 2022. This represents consistent growth in Uber's user base on their platform over the nearly 2 year period shown in the graph.\n"
]
}
],
"source": [
"# ask question over image!\n",
"response = query_engine.query(\n",
" \"What does the bar graph titled 'Monthly Active Platform Consumers' show?\"\n",
")\n",
"print(str(response))"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "c4f14ad8-6bfd-49d9-b3d5-7215cf0e4ac1",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Based on the context provided, some of the main risk factors for Uber include:\n",
"\n",
"- A significant percentage of Uber's bookings come from large metropolitan areas, which could be negatively impacted by various economic, social, weather, regulatory and other conditions, including COVID-19.\n",
"\n",
"- Uber may fail to successfully offer autonomous vehicle technologies on its platform or these technologies may not perform as expected. \n",
"\n",
"- Retaining and attracting high-quality personnel is important for Uber's business and continued attrition could adversely impact the company.\n",
"\n",
"- Security breaches, data privacy issues, cyberattacks and unauthorized access to Uber's proprietary data and systems pose risks.\n",
"\n",
"- Uber is subject to climate change risks, both physical and transitional, that could adversely impact its business if not managed properly. \n",
"\n",
"- Uber relies on third parties for open marketplaces to distribute its platform and software, and interference from these third parties could harm its business.\n",
"\n",
"- Uber will require additional capital to support its growth and this capital may not be available on reasonable terms.\n",
"\n",
"- Acquisitions and integrations carry risks if Uber is unable to successfully identify and integrate suitable businesses.\n",
"\n",
"- Extensive government regulations around payments, financial services, data privacy and other areas pose compliance risks and challenges for Uber's business model in certain jurisdictions.\n"
]
}
],
"source": [
"# ask question over text!\n",
"response = query_engine.query(\"What are the main risk factors for Uber?\")\n",
"print(str(response))"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"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": 5
}
File diff suppressed because one or more lines are too long
+444
View File
@@ -0,0 +1,444 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "28d15ea5-a3eb-4ee5-9d91-8dbd95e53129",
"metadata": {},
"source": [
"# Multi-Language Support in LlamaParse\n",
"\n",
"LlamaParse supports users to specify a `language` parameter before uploading documents, giving users better OCR capabilities over non-English PDFs, parsing images into more accurate representations.\n",
"\n",
"You can specify 80+ different languages: see this file for a full list of supported languages: https://github.com/run-llama/llama_parse/blob/main/llama_parse/base.py.\n",
"\n",
"This notebook shows a demo of this in action. "
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "15539193-2f5c-4ecf-9ca4-9aee6f888468",
"metadata": {},
"outputs": [],
"source": [
"%pip install llama-index llama-parse"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "87322210-c21c-43d6-b459-2e8a828ac576",
"metadata": {},
"outputs": [],
"source": [
"# llama-parse is async-first, running the sync 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",
"# os.environ[\"LLAMA_CLOUD_API_KEY\"] = \"llx-...\""
]
},
{
"cell_type": "markdown",
"id": "2b5cabdf-342a-42d2-8ad4-0ba7c46cdfb9",
"metadata": {},
"source": [
"## Load in a French PDF\n",
"\n",
"We load in the 2022 annual report from Agence France Tresor."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "e81e0a08-3a99-42e6-adcc-00bb4ce1c3d4",
"metadata": {},
"outputs": [],
"source": [
"!wget \"https://www.dropbox.com/scl/fi/fxg17log5ydwoflhxmgrb/treasury_report.pdf?rlkey=mdintk0o2uuzkple26vc4v6fd&dl=1\" -O treasury_report.pdf"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "ecfc578c-3c7f-4ec1-aa06-51565c28632b",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Started parsing the file under job_id 476966e1-9e04-49e7-a5dc-952b053b8b94\n",
"......"
]
}
],
"source": [
"from llama_parse import LlamaParse\n",
"\n",
"parser = LlamaParse(result_type=\"text\", language=\"fr\")\n",
"documents = parser.load_data(\"./treasury_report.pdf\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "0c37db27-3496-4a59-918b-701c9ad7706d",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
" ET GESTION DE LA DETTE DE L’ÉTAT\n",
" P.56 FOCUS OAT VERTES\n",
" P.60 CONTRÔLE DES RISQUES & POST-MARCHÉ\n",
" Chiffres de lexercice 2022 P.64 À 105\n",
" P.65 ACTIVITÉ DE LAFT\n",
" P.84 RAPPORT STATISTIQUE\n",
" FICHES TECHNIQUES GLOSSAIRES LISTE DES ABRÉVIATIONS\n",
" P.106 P.118 P.122\n",
" AGENCE FRANCE TRÉSOR - RAPPORT DACTIVITÉ 2022 3\n",
"---\n",
" Édito\n",
" 111 Avec une croissance\n",
" de +2,5 %, la France a illustré\n",
" une nouvelle fois sa résilience\n",
" économique face aux chocs.\n",
"4 AGENCE FRANCE TRÉSOR - RAPPORT DACTIVITÉ 2022\n",
"---\n",
" L’économie française en 2022 :\n",
" résilience face aux chocs géopolitiques\n",
" et économiques\n",
" sa résilience économique face aux lors du dernier trimestre de 2022.\n",
"LE DÉBUT DE chocs. Cette croissance a été permise Malgré un climat des affaires impacté\n",
"LANNÉE 2022 grâce à une forte demande intérieure par linflation, le soutien apporté\n",
" alimentée par le dynamisme de aux TPE/PME leur a permis de faire\n",
"SEMBLAIT linvestissement et, en dépit de face aux défis énergétiques tout en\n",
" linflation, dune résilience de la préservant lemploi.\n",
"ENGAGÉ DANS consommation des ménages sur une\n",
" grande partie de lannée. Afin de combattre linflation qui a\n",
"UNE DYNAMIQUE largement dépassé la cible de 2 %,\n",
" Le taux dinflation des prix à la la BCE, de concert avec les banques\n",
"EFFICACE DE consommation français est resté lun centrales des principales économies\n",
"SORTIE DE CRISE des plus bas dEurope avec +6,0 % développées, a adapté sa fonction de\n",
" en 2022, sappuyant, dune part, sur réaction en mettant fin aux politiques\n",
"PORTÉE PAR latout structurel que représente un dassouplissement monétaire quelle\n",
" mix énergétique parmi les moins menait depuis la crise financière de\n",
"UNE REPRISE exposés à la Russie et, dautre part, 2008. Ainsi, dès juillet 2022, et pour\n",
" sur les politiques proactives du la première fois en 10 ans, la BCE a\n",
"ÉCONOMIQUE gouvernement avec la mise en place augmenté ses taux directeurs. Les\n",
" du bouclier tarifaire, de la remise taux demprunts de l’État à 10 ans se\n",
"INÉDITE carburant et du chèque énergie. sont ainsi progressivement éloignés\n",
"AMORCÉE Ces dispositifs, temporaires, ont de leur territoire négatif pour\n",
" été progressivement supprimés : la atteindre 3,10 % en fin dannée.\n",
"EN 2021. remise carburant, dabord prolongée\n",
" jusqu’à mi-novembre a pris fin Cette décision sest également\n",
"Le déclenchement de la guerre en en décembre 2022, tandis que le accompagnée de la fin du\n",
"Ukraine par la Russie dès février a chèque énergie exceptionnel a pris programme dachat durgence (PEPP)\n",
"rebattu les cartes de cet équilibre, fin en mars 2023. mis en place pendant la pandémie,\n",
"provoquant des bouleversements suivi de la réduction progressive de\n",
"majeurs sur les plans géopolitiques et Le marché du travail français a par son bilan, à un rythme mensuel de 15\n",
"économiques, avec le déploiement ailleurs montré toute sa robustesse, milliards deuros par mois.\n",
"de sanctions à lencontre de la Russie la dynamique de reprise initiée en\n",
"et une forte poussée inflationniste. 2021 ainsi que leffet des réformes LAgence France Trésor a fait face à ce\n",
"Face à cette situation, les principales structurelles engagées les années contexte de grands bouleversements\n",
"banques centrales mondiales, dont précédentes permettant au taux géopolitiques, économiques et\n",
"la Banque centrale européenne demploi des Français âgés de 15 à 64 financiers en sappuyant sur ses\n",
"(BCE), ont engagé une politique de ans datteindre fin 2022 un niveau principes de régularité, de prévisibilité\n",
"normalisation monétaire rapide de 68,1 %, un record depuis 1975. et de transparence. Cette stratégie\n",
"pour lutter contre linflation. La reprise économique de début sest de nouveau révélée robuste et,\n",
"Parallèlement, le gouvernement dannée et les effets positifs du plan alliée à lengagement et à lefficacité\n",
"français a mis en place des mesures France Relance ont permis la création de ses équipes, ainsi qu’à la qualité\n",
"(à hauteur de 43,6 milliards deuros de 337 100 emplois, essentiellement de crédit de la signature de la France,\n",
"sur lannée 2022) pour protéger les dans le secteur salarié marchand. Ce lui a permis daccomplir sa mission\n",
"entreprises et les ménages. dynamisme a aussi conduit à la chute de financement de laction publique\n",
" du taux de chômage, atteignant son au bénéfice de tous.\n",
"Avec une croissance de +2,5 %, la niveau le plus bas depuis mars 2008\n",
"France a illustré une nouvelle fois avec 7,2 % de demandeurs demploi\n",
" Emmanuel Moulin\n",
" DIRECTEUR GÉNÉRAL DU TRÉSOR\n",
" ET PRÉSIDENT DE LAFT\n",
" AGENCE FRANCE TRÉSOR - RAPPORT DACTIVITÉ 2022 5\n",
"---\n",
" du directeur général Le mot\n",
" 011 En 2022, le choc dinflation\n",
" et la normalisation\n",
" de la politique monétaire\n",
" ont mis fin à une décennie\n",
" de taux historiquement bas.\n",
"6 AGENCE FRANCE TRÉSOR - RAPPORT DACTIVITÉ 2022\n",
"---\n",
" MALGRÉ UN CONTEXTE DE MARCHÉ MOUVEMENTÉ ET LES MESURES DAMPLEUR\n",
" PRISES POUR LIMITER LIMPACT DE LINFLATION SUR LES MÉNAGES ET\n",
" LES ENTREPRISES, LE PROGRAMME DE FINANCEMENT À MOYEN ET LONG TERME\n",
" EST DEMEURÉ INCHANGÉ À 260 MILLIARDS DEUROS, STABLE PAR RAPPORT\n",
" À 2021, ET LA DETTE DE COURT TERME A ÉTÉ RÉDUITE DE 7 MILLIARDS DEUROS.\n",
"En janvier 2022, la normalisation de dobligations indexées sur linflation, la dette de court terme a été réduite\n",
"la politique monétaire en zone euro sur lequel a été enregistré un de 7 milliards deuros. En effet, le\n",
"était une perspective de moyen supplément dindexation supérieur dynamisme des recettes fiscales et\n",
"terme. Quelques semaines plus tard, de 17 milliards deuros à celui de la trésorerie levée lors de la crise\n",
"linvasion de lUkraine par la Russie lannée 2021. Il sest également sanit\n"
]
}
],
"source": [
"print(documents[0].get_content()[1000:10000])"
]
},
{
"cell_type": "markdown",
"id": "be161577-7b1e-4710-b721-f549feb8e6d0",
"metadata": {},
"source": [
"## Download Chinese PDF"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "ac332ea3-cfff-4216-b292-62410a26c336",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"--2024-02-28 16:41:26-- https://www.dropbox.com/scl/fi/g5ojyzk4m44hl7neut6vc/chinese_pdf.pdf?rlkey=45reu51kjvdvic6zucr8v9sh3&dl=1\n",
"Resolving www.dropbox.com (www.dropbox.com)... 162.125.13.18\n",
"Connecting to www.dropbox.com (www.dropbox.com)|162.125.13.18|:443... connected.\n",
"HTTP request sent, awaiting response... 302 Found\n",
"Location: https://uc7a03fdb7d960dbedb23e9298ab.dl.dropboxusercontent.com/cd/0/inline/COJ69Wg2e7wH9S0ELzl4j4znoonRSQS-JJrH6mxy_vcrvY-KV7f10kMyQH6IYmtfMh_9xcDNOYnLkWkwMTYItwE1XQB5nqXbjmLJ4jLbDrMeu7-b49m796ctxevwnp7k1_U/file?dl=1# [following]\n",
"--2024-02-28 16:41:27-- https://uc7a03fdb7d960dbedb23e9298ab.dl.dropboxusercontent.com/cd/0/inline/COJ69Wg2e7wH9S0ELzl4j4znoonRSQS-JJrH6mxy_vcrvY-KV7f10kMyQH6IYmtfMh_9xcDNOYnLkWkwMTYItwE1XQB5nqXbjmLJ4jLbDrMeu7-b49m796ctxevwnp7k1_U/file?dl=1\n",
"Resolving uc7a03fdb7d960dbedb23e9298ab.dl.dropboxusercontent.com (uc7a03fdb7d960dbedb23e9298ab.dl.dropboxusercontent.com)... 162.125.13.15\n",
"Connecting to uc7a03fdb7d960dbedb23e9298ab.dl.dropboxusercontent.com (uc7a03fdb7d960dbedb23e9298ab.dl.dropboxusercontent.com)|162.125.13.15|:443... connected.\n",
"HTTP request sent, awaiting response... 302 Found\n",
"Location: /cd/0/inline2/COKEp-d6ZqzrIIaPRlanov72wwnd7GX5eNSPnsxug0A8pOpek8hO6eFxp84cY3_NMBRsAqtX-IIVPpcfYHNoV__mpu1SsOV8wV8a68DwVKaVJRJriY_KV8lEFocvLgf7c7mhrREbIJ1UBN2fx6S_qWegwVIen1z1-pw-K7icMnA3EKJNqM9DFtqx9ct0FI4vdYGsv8ckLF26WgAhs96k1cHn-VRJle4SKstdYs8EmBxiuFLXZRCL3gljwAsLu3J6WRvis9v7VJ2zNhgrcT-ZnVujlpQGoGWLLPmREKffK608Xfz1XE35DzO28e_mm4SUPRfsP2mvIUrJUtUrhobR4siqQRGojxi0S7-da4Y7fpB4Tw/file?dl=1 [following]\n",
"--2024-02-28 16:41:27-- https://uc7a03fdb7d960dbedb23e9298ab.dl.dropboxusercontent.com/cd/0/inline2/COKEp-d6ZqzrIIaPRlanov72wwnd7GX5eNSPnsxug0A8pOpek8hO6eFxp84cY3_NMBRsAqtX-IIVPpcfYHNoV__mpu1SsOV8wV8a68DwVKaVJRJriY_KV8lEFocvLgf7c7mhrREbIJ1UBN2fx6S_qWegwVIen1z1-pw-K7icMnA3EKJNqM9DFtqx9ct0FI4vdYGsv8ckLF26WgAhs96k1cHn-VRJle4SKstdYs8EmBxiuFLXZRCL3gljwAsLu3J6WRvis9v7VJ2zNhgrcT-ZnVujlpQGoGWLLPmREKffK608Xfz1XE35DzO28e_mm4SUPRfsP2mvIUrJUtUrhobR4siqQRGojxi0S7-da4Y7fpB4Tw/file?dl=1\n",
"Reusing existing connection to uc7a03fdb7d960dbedb23e9298ab.dl.dropboxusercontent.com:443.\n",
"HTTP request sent, awaiting response... 200 OK\n",
"Length: 8074860 (7.7M) [application/binary]\n",
"Saving to: chinese_pdf.pdf\n",
"\n",
"chinese_pdf.pdf 100%[===================>] 7.70M 37.9MB/s in 0.2s \n",
"\n",
"2024-02-28 16:41:28 (37.9 MB/s) - chinese_pdf.pdf saved [8074860/8074860]\n",
"\n"
]
}
],
"source": [
"!wget \"https://www.dropbox.com/scl/fi/g5ojyzk4m44hl7neut6vc/chinese_pdf.pdf?rlkey=45reu51kjvdvic6zucr8v9sh3&dl=1\" -O chinese_pdf.pdf"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "45235b17-08f0-48f1-92aa-06711225860b",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Started parsing the file under job_id 0089f0b6-29ee-4e94-a8bf-49a137666f15\n",
".........."
]
}
],
"source": [
"from llama_parse import LlamaParse\n",
"\n",
"parser = LlamaParse(result_type=\"text\", language=\"ch_sim\")\n",
"documents = parser.load_data(\"./chinese_pdf.pdf\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "f0d546cc-6549-4cf5-8b37-0896f4e8d43d",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"中国投资有限责任公司2022年度报告 5\n",
"---\n",
"企业文化与核心价值观\n",
"使命 核心价值观\n",
" 致力于实现国家外汇资金多元化投资,在可接受风险范围内 责任 合力\n",
" 实现股东权益最大化,以服务于国家经济发展和深化金融体\n",
" 制改革的需要 忠于使命、勤勉尽责 立足大局、有效协同\n",
" 是公司遵奉的核心价值取向 是实现公司可持续发展的关键\n",
" 愿景 专业 进取\n",
" 成为受人尊重的国际一流主权财富基金 坚持良好的专业精神和职业操守 求知进取、追求卓越\n",
" 是公司成功的基石 是公司成功和发展壮大的内驱力\n",
"---\n",
"01 我们将一以贯之地践行全球发展倡议,充分维护投资东道国利益,\n",
" 积极投身可持续投资,助力世界经济实现更高质量、更有韧性的发展。\n",
" 致 辞\n",
" 3 中国投资有限责任公司2022年度报告 中国投资有限责任公司2022年度报告 4\n",
"---\n",
" “行之力则知愈进,知之深则行愈达。”站在新的历史起点上,中投公司\n",
" 将继续秉承精益求精、追求卓越的专业精神,与国内外合作伙伴一起深化\n",
" 合作,共聚力量、共迎挑战、共享成果,开启打造世界一流主权财富基金\n",
" 的新篇章,为助力全球经济发展作出新贡献! #Ave彭纯\n",
" 董事长\n",
" 2022年,是中投公司成立十五周年。\n",
"董事长致辞 自2007年成立以来,中投公司坚守长期机构投资者定位,坚持国际化、市场化、专业化、负责任原则,搭\n",
" 建起符合大型国际投资机构特点的治理架构,形成了系统完备的投资管理体系,经受住了国际金融危机、世纪\n",
" 疫情等多个历史罕见的风险与挑战。如今,公司对外投资业务覆盖国际市场主要资产类别以及全球110多个国家\n",
" 和地区,培养了一支高素质专业化的投资管理人才队伍,搭建了互利共赢的投资合作“朋友圈”,长期投资收\n",
" 益超越董事会制定的考核目标,为促进国家外汇资产保值增值、服务国内国际双循环作出了积极贡献,在推动\n",
" 全球投资合作、助力世界经济增长中贡献了中投力量,书写了中国主权财富基金不平凡的创业发展史。\n",
"5 中国投资有限责任公司2022年度报告 中国投资有限责任公司2022年度报告 6\n",
"---\n",
" 2022年以来,全球地缘政治风险显著攀升,产业链供应链持续调整重构,美欧央行大幅加息,国际资本 我们守正创新,坚决践行双碳与可持续发展理念。更加包容、更加普惠、更有韧性的发展是全球\n",
"市场剧烈震荡,MSCI全球股票指数、彭博全球债券指数一度自高点下跌超过22%、13%。面对风高浪急的国 可持续发展的关键。我们积极履行负责任投资者理念,制定《关于践行双碳目标和可持续投资行动的意见》,\n",
"际环境和前所未有的巨大挑战,公司保持战略定力,发挥长期机构投资者优势,不断优化资产配置和投资策 积极开展气候变化、能源转型等主题投资。我们发布《运营碳中和行动计划》,明确时间表和路线图,全力实\n",
"略,着力提升总组合韧性,加强重点领域风险防控,年度投资收益跑赢大市;截至2022年底,过去十年对外 现节能减排目标。我们探索以绿色资源引领乡村发展的新方法,在四个定点帮扶县持续推进巩固脱贫成果与乡\n",
"投资年化净收益率按美元计算为6.43%,超出十年业绩目标26个基点;自成立以来累计年化国有资本增值率达 村振兴的有效衔接,助力民生保障与产业扶持,积极履行企业社会责任。\n",
"到12.67%,圆满完成五年战略规划主要目标任务。 面向未来,我们坚信,发展与合作是破解全球性问题的“钥匙”。中投公司将一以贯之地践行全球发展倡\n",
" 我们矢志不渝,积极打造世界一流主权财富基金。长期资本对于促进世界经济持续发展有着不 议,秉持互利共赢理念,以资本为纽带,促进国际产业交流合作,推动世界互联互通;充分维护投资东道国利\n",
"可替代的作用。我们坚持国际化、市场化、专业化、负责任原则,快速恢复常态化对外交流交往,按照互利共 益,与东道国共创价值、共享价值;积极投身可持续投资,推动被投企业履行社会责任,助力世界经济实现更\n",
"赢原则深化与国内外各类机构合作,持续为世界经济发展提供长期资本支持。我们积极创新对外投资方式,稳 高质量、更有韧性的发展。\n",
"健运行多支新型双边基金,新设相关投资合作平台,深入推进中国市场价值创造,促进被投资公司拓展市场空\n",
"间,助推国际投资与产业合作高质量发展。 经济全球化的潮流不可阻挡。我们呼吁各国携起手来,做多边主义的坚定维护者,打造更加开放有序的投\n",
" 资环境,便利资本和资源要素在全球顺畅流动。我们尊重各方的利益关切,在开放中捕捉投资机遇,以务实合\n",
" 我们直面挑战,着力加强自主投资能力建设。面对持续动荡的国际金融市场,我们锚定配置方 作应对共同挑战,并肩前进分享发展红利,推动世界经济平稳运行和持续增长。\n",
"向,强化研究驱动,有序实施组合调整、策略优化,及时调整公开市场投资布局,质量并重推进非公开市场投\n",
"资,完成另类资产投资占比50%的资产配置目标,对外投资总组合的韧性和质量不断提高。我们持续深化投资 “行之力则知愈进,知之深则行愈达。”过去的十五年,是中投人不惧挑战、接续奋斗的十五\n",
"管理体制机制改革,统一非公开市场投资决策制度流程,配强投资决策专职委员并设立支持团队,投资管理科 年。 2023年是中投人落实新一轮战略规划的开局之年。上半年,在风高浪急的国际环境下,中投公司锚定战略目\n",
"学化、专业化水平得到进一步提升。 标,统筹好发展和安全,取得了良好业绩,实现了良好开局。近期,公司部分董事更换,我们对离任董事在指导和支\n",
" 持公司完善公司治理、深化投资管理体制机制改革、应对国际市场风险挑战等方面所作的贡献表示衷心感谢,对新\n",
" 我们勇担使命,坚定走好中国特色金融发展之路。面对新征程新要求,我们坚持发挥“积极股 任董事表示热烈欢迎。站在新的历史起点上,中投公司将完整、准确、全面贯彻新发展理念,积极助力构建新发展格\n",
"东”作用,督促控参股金融企业优化产品服务、加大资源倾斜力度,全力支持稳经济稳增长。我们积极创新完 局,牢牢把握高质量发展首要任务,继续秉承精益求精、追求卓越的专业精神,与国内外合作伙伴一起深化合作,共\n",
"善“汇金模式”,推动优化国有金融资本布局,以市场化方式参与问题金融机构救助,助力金融市场稳定健康 聚力量、共迎挑战、共享成果,开启打造世界一流主权财富基金的新篇章,为助力全球经济发展作出新贡献!\n",
"发展。我们主动适应新形势新要求,围绕国有金融资本管理体系建设等重大课题深入研究,压实派出董事自主\n",
"履职责任,不断提升机构化履职能力。\n",
" 我们坚守底线,持续夯实全面风险管理体系。面对风高浪急的国际环境,我们优化风险管理委员\n",
"会设置,修订全面风险管理基本制度,增加风险类别的覆盖度,全面提升风险预见、应对、处置水平。在对外投\n",
"资方面,我们严守法律合规底线,健全地缘政治、气候变化等非传统风险防控机制,突出抓好流动性管理,对外\n",
"投资总组合风险保持在董事会规定的容忍度内。在国有金融资本受托管理方面,我们建立健全控参股金融企业风\n",
"险监测体系,全面开展多维度风险画像,推动控参股金融企业风险减存量、控增量、防变量取得积极成效。\n",
"7 中国投资有限责任公司2022年度报告 中国投资有限责任公司2022年度报告 8\n",
"---\n",
"02 中投公司的组建宗旨是实现国家外汇资金多元化投资,在可接受风\n",
" 险范围内实现股东权益最大化,以服务于国家宏观经济发展和深化\n",
" 公 司 介 绍 金融体制改革的需要。\n",
" 9 中国投资有限责任公司2022年度报告 中国投资有限责任公司2022年度报告 10\n",
"---\n",
"公司概况中国投资有限责任公司(以下简称“中投公司”)依照《中华人民共和国公司法》(以下简称“《公司 公司治理 中投公司按照《公司法》及《中国投资有限责任公司章程》(以下简称“《中投公司章程》”)中的有关规\n",
"法》”)于2007年9月成立,总部设在北京。中投公司的初始资本金为2000亿美元,由中国财政部发行1.55万 定,设立了董事会、监事会和执行委员会(以下简称“执委会”),三者之间权责明确、独立履职、有效制衡。\n",
"亿元人民币特别国债募集。截至2022年底,公司总资产达1.24万亿美元。 2022年,中投公司健全完善董事会、监事会运行机制,强化下设专门委员会的职能发挥,持续提升公司治\n",
" 中投公司的组建宗旨是实现国家外汇资金多元化投资,在可接受风险范围内实现股东权益最大化,以服务于 理效能。公司根据业务发展需要,优化调整投资管理架构,完善投资决策和投后管理制度机制,深化全面风险管\n",
"国家宏观经济发展和深化金融体制改革的需要。 理体系建设,全面提升机构化投资能力。\n",
" 中投公司开展境外投资业务与境内金融机构股权管理工作。其中,境外投资业务由下设子公司⸺中投国际\n",
"有限责任公司(以下简称“中投国际”)和中投海外直接投资有限责任公司(以下简称“中投海外”)承担,业\n",
"务范围包括公开市场股票和债券投资,对冲基金和多资产,泛行业私募股权和私募信用投资,房地产、基础设\n",
"施、资源商品、农业等领域的基金投资与直接投资,以及多双边基金管理等。 组织架构图\n",
" 中央汇金投资有限责任公司(以下简称“中央汇金”)作为中投公司的子公司,根据国务院授权,对国有重\n",
"点金融企业进行股权投资,以出资额为限代表国家依法对国有重点金融企业行使出资人权利和履行出资人义务。 董事会 监事会\n",
"中央汇金不开展商业性经营活动,不干预其控股的国有重点金融企业的日常经营活动。 提名与\n",
" 薪酬委员会\n",
" 中投国际和中投海外开展的境外业务与中央汇金开展的境内业务之间实行严格的“防火墙”政策和措施。\n",
" 战略与\n",
" 社会责任\n",
" 委员会\n",
" 风险管理 执行 国际咨询 监督 审计\n",
" 委员会 委员会 委员会 委员会 委员会\n",
" 境外投资 管理与支持 境内股权\n",
" 业务部门 部门 管理部门\n",
"11 中国投资有限责任公司2022年度报告 中国投资有限责任公司2022年度报告 12\n",
"---\n",
"董事会 沈如军\n",
" 党委委员、执行董事、副总经理\n",
" 中投公司董事会行使《公司法》和《中投公司章程》中规定的有限责任公司董事会的职权,主要包括:审核 1964年出生,管理学博士,高级会计师。历任中国工商银行计划财务部副总经理、\n",
"和批准公司的发展战略、经营方针和投资计划;确定公司需向股东报告的重大事项;制定公司年度预决算方案; 北京市分行副行长、财务会计部总经理、山东省分行行长,交通银行执行董事、副\n",
"任免公司高级管理人员;决定或授权批准设立内部管理机构等。 行长。现任本公司党委委员、执行董事、副总经理。\n",
" 董事会由执行董事、非执行董事、独立董事以及职工董事构成。 丛亮\n",
" 2022年,面对复杂严峻的国际经济形势,董事会加强对公司重大经营管理事项的指导和督促,及时听取投 非执行董事\n",
"资形势、经营管理、风险防控等汇报,认真审议经营计划、财务预算和决算、业绩考核等重要议题,深入谋划中 1971年出生,经济学博士。历任国家发展和改革委员会国民经济综合司副司长、司\n",
"投公司新一轮战略规划,明确发展目标、基本原则和重点举措,为公司下一阶段改革发展描绘新的蓝图。董事会 长,国家发展和改革委员会秘书长、新闻发言人,国家发展和改革委员会副主任,\n",
"专门委员会根据授权,重点关注关系企业长远发展的重大事项,为董事会出谋划策,推动公司高质量发展迈上新 国家粮食和物资储备局局长。现任国家发展和改革委员会副主任,并兼任本公司非\n",
"台阶。 执行董事。\n",
" 许宏才\n",
" 非执行董事\n",
"董事会成员 1963年出生,经济学学士。历任财政部预算司副司长、司长,财政部部长助理,财\n",
" 政部副部长。现任全国人大财政经济委员会副主任委员、全国人大常委会预算工作\n",
" 彭 纯 \n"
]
}
],
"source": [
"print(documents[0].get_content()[1000:10000])"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "640f0679-7f7e-4b0a-a46d-b099ae382fe2",
"metadata": {},
"outputs": [],
"source": [
"# download another copy with a different name to avoid hitting pdf cache\n",
"!wget \"https://www.dropbox.com/scl/fi/g5ojyzk4m44hl7neut6vc/chinese_pdf.pdf?rlkey=45reu51kjvdvic6zucr8v9sh3&dl=1\" -O chinese_pdf2.pdf"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "bfcacf90-ca67-4bfd-b023-be0af2cb18c5",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Started parsing the file under job_id 99538f59-24f7-4f1e-ab27-4081933fa5ee\n"
]
}
],
"source": [
"from llama_parse import LlamaParse\n",
"\n",
"base_parser = LlamaParse(result_type=\"text\", language=\"en\")\n",
"base_documents = parser.load_data(\"./chinese_pdf2.pdf\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "b264ed4e-647a-4f51-9f79-fdf82b76762a",
"metadata": {},
"outputs": [],
"source": [
"print(base_documents[0].get_content()[1000:10000])"
]
}
],
"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
}
+368
View File
@@ -0,0 +1,368 @@
{
"cells": [
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"# LlamaParse With MongoDB\n",
"\n",
"<a href=\"https://colab.research.google.com/github/run-llama/llama_parse/blob/main/examples/demo_mongodb.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>\n",
"\n",
"In this notebook, we provide a straightforward example of using LlamaParse with MongoDB Atlas VectorSearch.\n",
"\n",
"We illustrate the process of using llama-parse to parse a PDF document, then index the document with a MongoDB vector store, and subsequently perform basic queries against this store.\n",
"\n",
"This notebook is structured similarly to quick start guides, aiming to introduce users to utilizing llama-parse in conjunction with a MongoDB Atlas VectorSearch."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Installation"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"%pip install llama-index llama-parse\n",
"%pip install llama-index-vector-stores-mongodb llama-index-llms-openai"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Setup API Keys"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import os\n",
"\n",
"os.environ[\n",
" \"LLAMA_CLOUD_API_KEY\"\n",
"] = \"\" # Get it from https://cloud.llamaindex.ai/api-key\n",
"os.environ[\"OPENAI_API_KEY\"] = \"\" # Get it from https://platform.openai.com/api-keys"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# llama-parse is async-first, running the sync code in a notebook requires the use of nest_asyncio\n",
"import nest_asyncio\n",
"\n",
"nest_asyncio.apply()\n",
"\n",
"import requests\n",
"import pymongo\n",
"\n",
"from llama_index.vector_stores.mongodb import MongoDBAtlasVectorSearch\n",
"from llama_parse import LlamaParse\n",
"from llama_index.embeddings.openai import OpenAIEmbedding\n",
"from llama_index.core import VectorStoreIndex, StorageContext\n",
"from llama_index.core.node_parser import SimpleNodeParser"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Download Document\n",
"\n",
"We will use `Attention is all you need` paper."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Download complete.\n"
]
}
],
"source": [
"# The URL of the file you want to download\n",
"url = \"https://arxiv.org/pdf/1706.03762.pdf\"\n",
"# The local path where you want to save the file\n",
"file_path = \"./attention.pdf\"\n",
"\n",
"# Perform the HTTP request\n",
"response = requests.get(url)\n",
"\n",
"# Check if the request was successful\n",
"if response.status_code == 200:\n",
" # Open the file in binary write mode and save the content\n",
" with open(file_path, \"wb\") as file:\n",
" file.write(response.content)\n",
" print(\"Download complete.\")\n",
"else:\n",
" print(\"Error downloading the file.\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Parse the document using `LlamaParse`."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Started parsing the file under job_id 09a49745-9f21-4190-9de8-27e4e1a4bdf5\n"
]
}
],
"source": [
"documents = LlamaParse(result_type=\"text\").load_data(file_path)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"rmer - model architecture.\n",
"The Transformer follows this overall architecture using stacked self-attention and point-wise, fully\n",
"connected layers for both the encoder and decoder, shown in the left and right halves of Figure 1,\n",
"respectively.\n",
"3.1 Encoder and Decoder Stacks\n",
"Encoder: The encoder is composed of a stack of N = 6 identical layers. Each layer has two\n",
"sub-layers. The first is a multi-head self-attention mechanism, and the second is a simple, position-\n",
"wise fully connected feed-forward network. We employ a residual connection [11] around each of\n",
"the two sub-layers, followed by layer normalization [1]. That is, the output of each sub-layer is\n",
"LayerNorm(x + Sublayer(x)), where Sublayer(x) is the function implemented by the sub-layer\n",
"itself. To facilitate these residual connections, all sub-layers in the model, as well as the embedding\n",
"layers, produce outputs of dimension dmodel = 512.\n",
"Decoder: The decoder is also composed of a stack of N = 6 identical layers. In addition \n"
]
}
],
"source": [
"# Take a quick look at some of the parsed text from the document:\n",
"print(documents[0].get_content()[10000:11000])"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"### Create `MongoDBAtlasVectorSearch`."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"mongo_uri = os.environ[\"MONGO_URI\"]\n",
"\n",
"mongodb_client = pymongo.MongoClient(mongo_uri)\n",
"mongodb_vector_store = MongoDBAtlasVectorSearch(mongodb_client)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Create nodes."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"node_parser = SimpleNodeParser()\n",
"\n",
"nodes = node_parser.get_nodes_from_documents(documents)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Create Index and Query Engine."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"storage_context = StorageContext.from_defaults(vector_store=mongodb_vector_store)\n",
"\n",
"index = VectorStoreIndex(\n",
" nodes=nodes,\n",
" storage_context=storage_context,\n",
" embed_model=OpenAIEmbedding(),\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"query_engine = index.as_query_engine(similarity_top_k=2)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Test Query"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"***********New LlamaParse+ Basic Query Engine***********\n",
"The BLEU score on the WMT 2014 English-to-German translation task is 28.4.\n"
]
}
],
"source": [
"query = \"What is BLEU score on the WMT 2014 English-to-German translation task?\"\n",
"\n",
"response = query_engine.query(query)\n",
"print(\"\\n***********New LlamaParse+ Basic Query Engine***********\")\n",
"print(response)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"We varied the learning\n",
"rate over the course of training, according to the formula:\n",
" lrate = d0.5 (3)\n",
" model · min(step_num0.5, step_num · warmup_steps1.5)\n",
"This corresponds to increasing the learning rate linearly for the first warmup_steps training steps,\n",
"and decreasing it thereafter proportionally to the inverse square root of the step number. We used\n",
"warmup_steps = 4000.\n",
"5.4 Regularization\n",
"We employ three types of regularization during training:\n",
" 7\n",
"---\n",
"Table 2: The Transformer achieves better BLEU scores than previous state-of-the-art models on the\n",
"English-to-German and English-to-French newstest2014 tests at a fraction of the training cost.\n",
" Model BLEU Training Cost (FLOPs)\n",
" EN-DE EN-FR EN-DE EN-FR\n",
" ByteNet [18] 23.75\n",
" Deep-Att + PosUnk [39] 39.2 1.0 · 1020\n",
" GNMT + RL [38] 24.6 39.92 2.3 · 1019 1.4 · 1020\n",
" ConvS2S [9] 25.16 40.46 9.6 · 1018 1.5 · 1020\n",
" MoE [32] 26.03 40.56 2.0 · 1019 1.2 · 1020\n",
" Deep-Att + PosUnk Ensemble [39] 40.4 8.0 · 1020\n",
" GNMT + RL Ensemble [38] 26.30 41.16 1.8 · 1020 1.1 · 1021\n",
" ConvS2S Ensemble [9] 26.36 41.29 7.7 · 1019 1.2 · 1021\n",
" Transformer (base model) 27.3 38.1 3.3 · 1018\n",
" Transformer (big) 28.4 41.8 2.3 · 1019\n",
"Residual Dropout We apply dropout [33] to the output of each sub-layer, before it is added to the\n",
"sub-layer input and normalized. In addition, we apply dropout to the sums of the embeddings and the\n",
"positional encodings in both the encoder and decoder stacks. For the base model, we use a rate of\n",
"Pdrop = 0.1.\n",
"Label Smoothing During training, we employed label smoothing of value ϵls = 0.1 [36]. This\n",
"hurts perplexity, as the model learns to be more unsure, but improves accuracy and BLEU score.\n",
"6 Results\n",
"6.1 Machine Translation\n",
"On the WMT 2014 English-to-German translation task, the big transformer model (Transformer (big)\n",
"in Table 2) outperforms the best previously reported models (including ensembles) by more than 2.0\n",
"BLEU, establishing a new state-of-the-art BLEU score of 28.4. The configuration of this model is\n",
"listed in the bottom line of Table 3. Training took 3.5 days on 8 P100 GPUs. Even our base model\n",
"surpasses all previously published models and ensembles, at a fraction of the training cost of any of\n",
"the competitive models.\n",
"On the WMT 2014 English-to-French translation task, our big model achieves a BLEU score of 41.0,\n",
"outperforming all of the previously published single models, at less than 1/4 the training cost of the\n",
"previous state-of-the-art model. The Transformer (big) model trained for English-to-French used\n",
"dropout rate Pdrop = 0.1, instead of 0.3.\n",
"For the base models, we used a single model obtained by averaging the last 5 checkpoints, which\n",
"were written at 10-minute intervals. For the big models, we averaged the last 20 checkpoints. We\n",
"used beam search with a beam size of 4 and length penalty α = 0.6 [38]. These hyperparameters\n",
"were chosen after experimentation on the development set. We set the maximum output length during\n",
"inference to input length + 50, but terminate early when possible [38].\n",
"Table 2 summarizes our results and compares our translation quality and training costs to other model\n",
"architectures from the literature.\n"
]
}
],
"source": [
"# Take a look at one of the source nodes from the response\n",
"print(response.source_nodes[0].get_content())"
]
}
],
"metadata": {
"colab": {
"provenance": []
},
"kernelspec": {
"display_name": "anthropic_env",
"language": "python",
"name": "anthropic_env"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3"
},
"vscode": {
"interpreter": {
"hash": "b0fa6594d8f4cbf19f97940f81e996739fb7646882a419484c72d19e05852a7e"
}
}
},
"nbformat": 4,
"nbformat_minor": 0
}
+544
View File
@@ -0,0 +1,544 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# LlamaParse - Parsing comic books with parsing intructions\n",
"Parsing intructions allow you to instruct our parsing model the same way you would instruct an LLM!\n",
"\n",
"They can be useful to help the parser get better results on complex document layouts, to extract data in a specific format, or to transform the document in other ways.\n",
"\n",
"Using Parsing Instruction you will get better results out of LlamaParse on complicated documents, and also be able to simplify your application code."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Installation\n",
"\n",
"Parsing instructions are part of the llamaParse API. They can be accessed by directly specifying the parsing_instruction parameter in the API or by using the LlamaParse python module (which we will use for this tutorial).\n",
"\n",
"To install llama-parse, just get it from PIP:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Collecting llama-parse\n",
" Downloading llama_parse-0.3.8-py3-none-any.whl (6.7 kB)\n",
"Collecting llama-index-core>=0.10.7 (from llama-parse)\n",
" Downloading llama_index_core-0.10.19-py3-none-any.whl (15.3 MB)\n",
"\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m15.3/15.3 MB\u001b[0m \u001b[31m31.9 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
"\u001b[?25hRequirement already satisfied: PyYAML>=6.0.1 in /usr/local/lib/python3.10/dist-packages (from llama-index-core>=0.10.7->llama-parse) (6.0.1)\n",
"Requirement already satisfied: SQLAlchemy[asyncio]>=1.4.49 in /usr/local/lib/python3.10/dist-packages (from llama-index-core>=0.10.7->llama-parse) (2.0.28)\n",
"Requirement already satisfied: aiohttp<4.0.0,>=3.8.6 in /usr/local/lib/python3.10/dist-packages (from llama-index-core>=0.10.7->llama-parse) (3.9.3)\n",
"Collecting dataclasses-json (from llama-index-core>=0.10.7->llama-parse)\n",
" Downloading dataclasses_json-0.6.4-py3-none-any.whl (28 kB)\n",
"Collecting deprecated>=1.2.9.3 (from llama-index-core>=0.10.7->llama-parse)\n",
" Downloading Deprecated-1.2.14-py2.py3-none-any.whl (9.6 kB)\n",
"Collecting dirtyjson<2.0.0,>=1.0.8 (from llama-index-core>=0.10.7->llama-parse)\n",
" Downloading dirtyjson-1.0.8-py3-none-any.whl (25 kB)\n",
"Requirement already satisfied: fsspec>=2023.5.0 in /usr/local/lib/python3.10/dist-packages (from llama-index-core>=0.10.7->llama-parse) (2023.6.0)\n",
"Collecting httpx (from llama-index-core>=0.10.7->llama-parse)\n",
" Downloading httpx-0.27.0-py3-none-any.whl (75 kB)\n",
"\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m75.6/75.6 kB\u001b[0m \u001b[31m6.3 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
"\u001b[?25hCollecting llamaindex-py-client<0.2.0,>=0.1.13 (from llama-index-core>=0.10.7->llama-parse)\n",
" Downloading llamaindex_py_client-0.1.13-py3-none-any.whl (107 kB)\n",
"\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m108.0/108.0 kB\u001b[0m \u001b[31m10.0 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
"\u001b[?25hRequirement already satisfied: nest-asyncio<2.0.0,>=1.5.8 in /usr/local/lib/python3.10/dist-packages (from llama-index-core>=0.10.7->llama-parse) (1.6.0)\n",
"Requirement already satisfied: networkx>=3.0 in /usr/local/lib/python3.10/dist-packages (from llama-index-core>=0.10.7->llama-parse) (3.2.1)\n",
"Requirement already satisfied: nltk<4.0.0,>=3.8.1 in /usr/local/lib/python3.10/dist-packages (from llama-index-core>=0.10.7->llama-parse) (3.8.1)\n",
"Requirement already satisfied: numpy in /usr/local/lib/python3.10/dist-packages (from llama-index-core>=0.10.7->llama-parse) (1.25.2)\n",
"Collecting openai>=1.1.0 (from llama-index-core>=0.10.7->llama-parse)\n",
" Downloading openai-1.13.3-py3-none-any.whl (227 kB)\n",
"\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m227.4/227.4 kB\u001b[0m \u001b[31m16.3 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
"\u001b[?25hRequirement already satisfied: pandas in /usr/local/lib/python3.10/dist-packages (from llama-index-core>=0.10.7->llama-parse) (1.5.3)\n",
"Requirement already satisfied: pillow>=9.0.0 in /usr/local/lib/python3.10/dist-packages (from llama-index-core>=0.10.7->llama-parse) (9.4.0)\n",
"Requirement already satisfied: requests>=2.31.0 in /usr/local/lib/python3.10/dist-packages (from llama-index-core>=0.10.7->llama-parse) (2.31.0)\n",
"Requirement already satisfied: tenacity<9.0.0,>=8.2.0 in /usr/local/lib/python3.10/dist-packages (from llama-index-core>=0.10.7->llama-parse) (8.2.3)\n",
"Collecting tiktoken>=0.3.3 (from llama-index-core>=0.10.7->llama-parse)\n",
" Downloading tiktoken-0.6.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (1.8 MB)\n",
"\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m1.8/1.8 MB\u001b[0m \u001b[31m43.1 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
"\u001b[?25hRequirement already satisfied: tqdm<5.0.0,>=4.66.1 in /usr/local/lib/python3.10/dist-packages (from llama-index-core>=0.10.7->llama-parse) (4.66.2)\n",
"Requirement already satisfied: typing-extensions>=4.5.0 in /usr/local/lib/python3.10/dist-packages (from llama-index-core>=0.10.7->llama-parse) (4.10.0)\n",
"Collecting typing-inspect>=0.8.0 (from llama-index-core>=0.10.7->llama-parse)\n",
" Downloading typing_inspect-0.9.0-py3-none-any.whl (8.8 kB)\n",
"Requirement already satisfied: aiosignal>=1.1.2 in /usr/local/lib/python3.10/dist-packages (from aiohttp<4.0.0,>=3.8.6->llama-index-core>=0.10.7->llama-parse) (1.3.1)\n",
"Requirement already satisfied: attrs>=17.3.0 in /usr/local/lib/python3.10/dist-packages (from aiohttp<4.0.0,>=3.8.6->llama-index-core>=0.10.7->llama-parse) (23.2.0)\n",
"Requirement already satisfied: frozenlist>=1.1.1 in /usr/local/lib/python3.10/dist-packages (from aiohttp<4.0.0,>=3.8.6->llama-index-core>=0.10.7->llama-parse) (1.4.1)\n",
"Requirement already satisfied: multidict<7.0,>=4.5 in /usr/local/lib/python3.10/dist-packages (from aiohttp<4.0.0,>=3.8.6->llama-index-core>=0.10.7->llama-parse) (6.0.5)\n",
"Requirement already satisfied: yarl<2.0,>=1.0 in /usr/local/lib/python3.10/dist-packages (from aiohttp<4.0.0,>=3.8.6->llama-index-core>=0.10.7->llama-parse) (1.9.4)\n",
"Requirement already satisfied: async-timeout<5.0,>=4.0 in /usr/local/lib/python3.10/dist-packages (from aiohttp<4.0.0,>=3.8.6->llama-index-core>=0.10.7->llama-parse) (4.0.3)\n",
"Requirement already satisfied: wrapt<2,>=1.10 in /usr/local/lib/python3.10/dist-packages (from deprecated>=1.2.9.3->llama-index-core>=0.10.7->llama-parse) (1.14.1)\n",
"Requirement already satisfied: pydantic>=1.10 in /usr/local/lib/python3.10/dist-packages (from llamaindex-py-client<0.2.0,>=0.1.13->llama-index-core>=0.10.7->llama-parse) (2.6.3)\n",
"Requirement already satisfied: anyio in /usr/local/lib/python3.10/dist-packages (from httpx->llama-index-core>=0.10.7->llama-parse) (3.7.1)\n",
"Requirement already satisfied: certifi in /usr/local/lib/python3.10/dist-packages (from httpx->llama-index-core>=0.10.7->llama-parse) (2024.2.2)\n",
"Collecting httpcore==1.* (from httpx->llama-index-core>=0.10.7->llama-parse)\n",
" Downloading httpcore-1.0.4-py3-none-any.whl (77 kB)\n",
"\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m77.8/77.8 kB\u001b[0m \u001b[31m8.5 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
"\u001b[?25hRequirement already satisfied: idna in /usr/local/lib/python3.10/dist-packages (from httpx->llama-index-core>=0.10.7->llama-parse) (3.6)\n",
"Requirement already satisfied: sniffio in /usr/local/lib/python3.10/dist-packages (from httpx->llama-index-core>=0.10.7->llama-parse) (1.3.1)\n",
"Collecting h11<0.15,>=0.13 (from httpcore==1.*->httpx->llama-index-core>=0.10.7->llama-parse)\n",
" Downloading h11-0.14.0-py3-none-any.whl (58 kB)\n",
"\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m58.3/58.3 kB\u001b[0m \u001b[31m5.7 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
"\u001b[?25hRequirement already satisfied: click in /usr/local/lib/python3.10/dist-packages (from nltk<4.0.0,>=3.8.1->llama-index-core>=0.10.7->llama-parse) (8.1.7)\n",
"Requirement already satisfied: joblib in /usr/local/lib/python3.10/dist-packages (from nltk<4.0.0,>=3.8.1->llama-index-core>=0.10.7->llama-parse) (1.3.2)\n",
"Requirement already satisfied: regex>=2021.8.3 in /usr/local/lib/python3.10/dist-packages (from nltk<4.0.0,>=3.8.1->llama-index-core>=0.10.7->llama-parse) (2023.12.25)\n",
"Requirement already satisfied: distro<2,>=1.7.0 in /usr/lib/python3/dist-packages (from openai>=1.1.0->llama-index-core>=0.10.7->llama-parse) (1.7.0)\n",
"Requirement already satisfied: charset-normalizer<4,>=2 in /usr/local/lib/python3.10/dist-packages (from requests>=2.31.0->llama-index-core>=0.10.7->llama-parse) (3.3.2)\n",
"Requirement already satisfied: urllib3<3,>=1.21.1 in /usr/local/lib/python3.10/dist-packages (from requests>=2.31.0->llama-index-core>=0.10.7->llama-parse) (2.0.7)\n",
"Requirement already satisfied: greenlet!=0.4.17 in /usr/local/lib/python3.10/dist-packages (from SQLAlchemy[asyncio]>=1.4.49->llama-index-core>=0.10.7->llama-parse) (3.0.3)\n",
"Collecting mypy-extensions>=0.3.0 (from typing-inspect>=0.8.0->llama-index-core>=0.10.7->llama-parse)\n",
" Downloading mypy_extensions-1.0.0-py3-none-any.whl (4.7 kB)\n",
"Collecting marshmallow<4.0.0,>=3.18.0 (from dataclasses-json->llama-index-core>=0.10.7->llama-parse)\n",
" Downloading marshmallow-3.21.1-py3-none-any.whl (49 kB)\n",
"\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m49.4/49.4 kB\u001b[0m \u001b[31m4.5 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
"\u001b[?25hRequirement already satisfied: python-dateutil>=2.8.1 in /usr/local/lib/python3.10/dist-packages (from pandas->llama-index-core>=0.10.7->llama-parse) (2.8.2)\n",
"Requirement already satisfied: pytz>=2020.1 in /usr/local/lib/python3.10/dist-packages (from pandas->llama-index-core>=0.10.7->llama-parse) (2023.4)\n",
"Requirement already satisfied: exceptiongroup in /usr/local/lib/python3.10/dist-packages (from anyio->httpx->llama-index-core>=0.10.7->llama-parse) (1.2.0)\n",
"Requirement already satisfied: packaging>=17.0 in /usr/local/lib/python3.10/dist-packages (from marshmallow<4.0.0,>=3.18.0->dataclasses-json->llama-index-core>=0.10.7->llama-parse) (23.2)\n",
"Requirement already satisfied: annotated-types>=0.4.0 in /usr/local/lib/python3.10/dist-packages (from pydantic>=1.10->llamaindex-py-client<0.2.0,>=0.1.13->llama-index-core>=0.10.7->llama-parse) (0.6.0)\n",
"Requirement already satisfied: pydantic-core==2.16.3 in /usr/local/lib/python3.10/dist-packages (from pydantic>=1.10->llamaindex-py-client<0.2.0,>=0.1.13->llama-index-core>=0.10.7->llama-parse) (2.16.3)\n",
"Requirement already satisfied: six>=1.5 in /usr/local/lib/python3.10/dist-packages (from python-dateutil>=2.8.1->pandas->llama-index-core>=0.10.7->llama-parse) (1.16.0)\n",
"Installing collected packages: dirtyjson, mypy-extensions, marshmallow, h11, deprecated, typing-inspect, tiktoken, httpcore, httpx, dataclasses-json, openai, llamaindex-py-client, llama-index-core, llama-parse\n",
"Successfully installed dataclasses-json-0.6.4 deprecated-1.2.14 dirtyjson-1.0.8 h11-0.14.0 httpcore-1.0.4 httpx-0.27.0 llama-index-core-0.10.19 llama-parse-0.3.8 llamaindex-py-client-0.1.13 marshmallow-3.21.1 mypy-extensions-1.0.0 openai-1.13.3 tiktoken-0.6.0 typing-inspect-0.9.0\n"
]
}
],
"source": [
"%pip install llama-parse"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## API key\n",
"\n",
"The use of LlamaParse requires an API key which you can get here: https://cloud.llamaindex.ai/parse"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import os\n",
"\n",
"os.environ[\"LLAMA_CLOUD_API_KEY\"] = \"llx-...\""
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Async (Notebook only)\n",
"llama-parse is async-first, so running the code in a notebook requires the use of nest_asyncio\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import nest_asyncio\n",
"\n",
"nest_asyncio.apply()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Import the package"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from llama_parse import LlamaParse"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Using llamaparse for getting better results (on Manga!)\n",
"\n",
"Sometimes the layout of a page is unusual and you will get sub-optimal reading order results with LlamaParse. For example, when parsing manga you expect the reading order to be right to left even if the content is in English!"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Let's download an extract of a great manga \"The manga guide to calculus\", by Hiroyuki Kojima (https://www.amazon.com/Manga-Guide-Calculus-Hiroyuki-Kojima/dp/1593271948)\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"--2024-03-13 13:57:19-- https://drive.usercontent.google.com/uc?id=1tZJhcpepLRdQFJFCFX50QIqLyLgqzZsY&export=download\n",
"Resolving drive.usercontent.google.com (drive.usercontent.google.com)... 173.194.211.132, 2607:f8b0:400c:c10::84\n",
"Connecting to drive.usercontent.google.com (drive.usercontent.google.com)|173.194.211.132|:443... connected.\n",
"HTTP request sent, awaiting response... 303 See Other\n",
"Location: https://drive.usercontent.google.com/download?id=1tZJhcpepLRdQFJFCFX50QIqLyLgqzZsY&export=download [following]\n",
"--2024-03-13 13:57:19-- https://drive.usercontent.google.com/download?id=1tZJhcpepLRdQFJFCFX50QIqLyLgqzZsY&export=download\n",
"Reusing existing connection to drive.usercontent.google.com:443.\n",
"HTTP request sent, awaiting response... 200 OK\n",
"Length: 3041634 (2.9M) [application/octet-stream]\n",
"Saving to: ./manga.pdf\n",
"\n",
"./manga.pdf 100%[===================>] 2.90M --.-KB/s in 0.04s \n",
"\n",
"2024-03-13 13:57:20 (78.6 MB/s) - ./manga.pdf saved [3041634/3041634]\n",
"\n"
]
}
],
"source": [
"! wget \"https://drive.usercontent.google.com/uc?id=1tZJhcpepLRdQFJFCFX50QIqLyLgqzZsY&export=download\" -O ./manga.pdf"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Without parsing instructions\n",
"For the sake of comparison, let's first parse without any instructions."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Started parsing the file under job_id 25bf4202-78d8-4705-88cf-c616ae7c82af\n"
]
}
],
"source": [
"vanilaParsing = LlamaParse(result_type=\"markdown\").load_data(\"./manga.pdf\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"As you can see below, LlamaParse is not doing a great job here. It is interpreting the grid of comic panels as a table, and trying to fit the dialogue into a table. It's very hard to follow."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"The Asagake Times Sanda-Cho Distributor\n",
"\n",
"A newspaper distributor? do I have the wrong map?\n",
"\n",
"Youre looking Its next for the Sanda-cho door. branch office? Everybody mistakes us for the office because we are larger. What Is a Function? 3\n",
"---\n",
"## Calculating the Derivative of a Constant, Linear, or Quadratic Function\n",
"\n",
"|1.|Lets find the derivative of constant function f(x) = α. The differential coefficient of f(x) at x = a is|\n",
"|---|---|\n",
"| |lim ε→0 (f(a + ε) - f(a)) / ε = lim ε→0 (α - α) = lim ε→0 0 = 0|\n",
"| |Thus, the derivative of f(x) is f(x) = 0. This makes sense, since our function is constant—the rate of change is 0.|\n",
"\n",
"Note: The differential coefficient of f(x) at x = a is often simply called the derivative of f(x) at x = a, or just f(a).\n",
"\n",
"|2.|Lets calculate the derivative of linear function f(x) = αx + β. The derivative of f(x) at x = α is|\n",
"|---|---|\n",
"| |lim ε→0 (f(α + ε) - f(a)) = \n"
]
}
],
"source": [
"print(vanilaParsing[0].text[100:1000])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Using parsing instructions\n",
"Let's try to parse the manga with custom instructions:\n",
"\n",
"\"The provided document is a manga comic book. Most pages do NOT have a title. It does not contain tables. Try to reconstruct the dialogue spoken in a cohesive way.\"\n",
"\n",
"To do so just pass the parsing instruction as a parameter to LlamaParse:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Started parsing the file under job_id 88ab273e-b2a7-4f84-8e72-e9367cf6b114\n",
"."
]
}
],
"source": [
"parsingInstructionManga = \"\"\"The provided document is a manga comic book. Most pages do NOT have a title.\n",
"It does not contain tables.\n",
"Try to reconstruct the dialogue spoken in a cohesive way.\"\"\"\n",
"withInstructionParsing = LlamaParse(\n",
" result_type=\"markdown\", parsing_instruction=parsingInstructionManga\n",
").load_data(\"./manga.pdf\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Let's see how it compare with page 3! We encourage you to play with the target page and explore other pages. As you will see, the parsing instruction allowed LlamaParse to make sense of the document!\n",
"\n",
"<img src=\"https://drive.usercontent.google.com/download?id=1M87rXTIZE8d5v7aHmVZVW6gW3eDGq6ks&authuser=0\" />\n",
"\n",
"\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"The Asagake Times Sanda-Cho Distributor\n",
"\n",
"A newspaper distributor? do I have the wrong map?\n",
"\n",
"Youre looking Its next for the Sanda-cho door. branch office? Everybody mistakes us for the office because we are larger. What Is a Function? 3\n",
"\n",
"\n",
"------------------------------------------------------------\n",
"\n",
"\n",
"# The Asagake Times\n",
"\n",
"Sanda-Cho Distributor\n",
"\n",
"A newspaper distributor?\n",
"\n",
"Do I have the wrong map?\n",
"\n",
"You're looking for the Sanda-cho branch office?\n",
"\n",
"It's next door.\n",
"\n",
"Everybody mistakes us for the office because we are larger.\n",
"\n",
"What Is a Function? 3\n"
]
}
],
"source": [
"target_page = 1\n",
"print(vanilaParsing[0].text.split(\"\\n---\\n\")[target_page])\n",
"print(\"\\n\\n------------------------------------------------------------\\n\\n\")\n",
"print(withInstructionParsing[0].text.split(\"\\n---\\n\")[target_page])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Math - doing more with parsing instuction!\n",
"\n",
"But this manga is about math and full of equations, why not ask the parser to output them in **LaTeX**?\n",
"\n",
"<img src=\"https://drive.usercontent.google.com/download?id=1tze3xcQ7axVA-vC_iZeAj_GvYcyNuYDa&authuser=0\" />"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Started parsing the file under job_id 3a055e64-d91e-484e-b9b0-99a2e637c08d\n",
"."
]
}
],
"source": [
"parsingInstructionMangaLatex = \"\"\"The provided document is a manga comic book. Most pages do NOT have a title.\n",
"It does not contain tables.\n",
"Try to reconstruct the dialogue spoken in a cohesive way.\n",
"Output any math equation in LATEX markdown (between $$)\"\"\"\n",
"withLatex = LlamaParse(\n",
" result_type=\"markdown\", parsing_instruction=parsingInstructionMangaLatex\n",
").load_data(\"./manga.pdf\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"\n",
"[Without instruction]------------------------------------------------------------\n",
"\n",
"\n",
"## Calculating the Derivative of a Constant, Linear, or Quadratic Function\n",
"\n",
"|1.|Lets find the derivative of constant function f(x) = α. The differential coefficient of f(x) at x = a is|\n",
"|---|---|\n",
"| |lim ε→0 (f(a + ε) - f(a)) / ε = lim ε→0 (α - α) = lim ε→0 0 = 0|\n",
"| |Thus, the derivative of f(x) is f(x) = 0. This makes sense, since our function is constant—the rate of change is 0.|\n",
"\n",
"Note: The differential coefficient of f(x) at x = a is often simply called the derivative of f(x) at x = a, or just f(a).\n",
"\n",
"|2.|Lets calculate the derivative of linear function f(x) = αx + β. The derivative of f(x) at x = α is|\n",
"|---|---|\n",
"| |lim ε→0 (f(α + ε) - f(a)) = lim ε→0 (α(a + ε) + β - (αa + β)) = lim ε→0 α = α|\n",
"| |Thus, the derivative of f(x) is f(x) = α, a constant value. This result should also be intuitive—linear functions have a constant rate of change by definition.|\n",
"\n",
"|3.|Lets find the derivative of f(x) = x^2, which appeared in the story. The differential coefficient of f(x) at x = a is|\n",
"|---|---|\n",
"| |lim ε→0 ((a + ε)^2 - a^2) / ε = lim (a^2 + 2aε + ε^2 - a^2) / ε = lim (2aε + ε^2) = lim (2a + ε) = 2a|\n",
"| |Thus, the differential coefficient of f(x) at x = a is 2a, or f(a) = 2a. Therefore, the derivative of f(x) is f(x) = 2x.|\n",
"\n",
"## Summary\n",
"\n",
"- The calculation of a limit that appears in calculus is simply a formula calculating an error.\n",
"- A limit is used to obtain a derivative.\n",
"- The derivative is the slope of the tangent line at a given point.\n",
"- The derivative is nothing but the rate of change.\n",
"\n",
"## Chapter 1 Lets Differentiate a Function!\n",
"\n",
"\n",
"[With instruction to output math in LATEX!]------------------------------------------------------------\n",
"\n",
"\n",
"# Derivative of Constant, Linear, or Quadratic Function\n",
"\n",
"## Calculating the Derivative of a Constant, Linear, or Quadratic Function\n",
"\n",
"1. Lets find the derivative of constant function f(x) = α. The differential coefficient of f(x) at x = a is\n",
"\n",
"$$\n",
"\\begin{align*}\n",
"&\\lim_{{\\varepsilon \\to 0}} \\left( \\frac{f(a + \\varepsilon) - f(a)}{\\varepsilon} \\right) = \\lim_{{\\varepsilon \\to 0}} \\frac{\\alpha - \\alpha}{\\varepsilon} = \\lim_{{\\varepsilon \\to 0}} 0 = 0 \\\\\n",
"\\end{align*}\n",
"$$\n",
"Thus, the derivative of f(x) is f(x) = 0. This makes sense, since our function is constant—the rate of change is 0.\n",
"\n",
"Note: The differential coefficient of f(x) at x = a is often simply called the derivative of f(x) at x = a, or just f(a).\n",
"\n",
"2. Lets calculate the derivative of linear function f(x) = αx + β. The derivative of f(x) at x = α is\n",
"\n",
"$$\n",
"\\begin{align*}\n",
"&\\lim_{{\\varepsilon \\to 0}} \\left( \\frac{f(\\alpha + \\varepsilon) - f(a)}{\\varepsilon} \\right) = \\lim_{{\\varepsilon \\to 0}} \\frac{\\alpha(a + \\varepsilon) + \\beta - (\\alpha a + \\beta)}{\\varepsilon} = \\lim_{{\\varepsilon \\to 0}} \\alpha = \\alpha \\\\\n",
"\\end{align*}\n",
"$$\n",
"Thus, the derivative of f(x) is f(x) = α, a constant value. This result should also be intuitive—linear functions have a constant rate of change by definition.\n",
"\n",
"3. Lets find the derivative of f(x) = x2. The differential coefficient of f(x) at x = a is\n",
"\n",
"$$\n",
"\\begin{align*}\n",
"&\\lim_{{\\varepsilon \\to 0}} \\left( \\frac{f(a + \\varepsilon) - f(a)}{\\varepsilon} \\right) = \\lim_{{\\varepsilon \\to 0}} \\left( (a + \\varepsilon)^2 - a^2 \\right) = \\lim_{{\\varepsilon \\to 0}} 2a\\varepsilon + \\varepsilon = \\lim_{{\\varepsilon \\to 0}} (2a + \\varepsilon) = 2a \\\\\n",
"\\end{align*}\n",
"$$\n",
"Thus, the differential coefficient of f(x) at x = a is 2a, or f(a) = 2a. Therefore, the derivative of f(x) is f(x) = 2x.\n",
"\n",
"### Summary\n",
"\n",
"- The calculation of a limit that appears in calculus is simply a formula calculating an error.\n",
"- A limit is used to obtain a derivative.\n",
"- The derivative is the slope of the tangent line at a given point.\n",
"- The derivative is nothing but the rate of change.\n"
]
}
],
"source": [
"target_page = 2\n",
"print(\n",
" \"\\n\\n[Without instruction]------------------------------------------------------------\\n\\n\"\n",
")\n",
"print(vanilaParsing[0].text.split(\"\\n---\\n\")[target_page])\n",
"print(\n",
" \"\\n\\n[With instruction to output math in LATEX!]------------------------------------------------------------\\n\\n\"\n",
")\n",
"print(withLatex[0].text.split(\"\\n---\\n\")[target_page])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"And here is the result as rendered by https://upmath.me/ .\n",
"\n",
"\n",
"<img src=\"https://drive.usercontent.google.com/download?id=1qGo5bMGYOiIC9MnprcgEByaYjU9YII2Q&authuser=0\" />\n",
"\n",
"\n",
"Over this short notebook we saw how to use parsing instructions to increase the quality and accuracy of parsing with LLamaParse!"
]
}
],
"metadata": {
"colab": {
"provenance": []
},
"kernelspec": {
"display_name": "Python 3",
"name": "python3"
},
"language_info": {
"name": "python"
}
},
"nbformat": 4,
"nbformat_minor": 0
}
+367
View File
@@ -0,0 +1,367 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# RAG for Table Comparisons with LlamaParse + LlamaIndex\n",
"\n",
"<a href=\"https://colab.research.google.com/github/run-llama/llama_parse/blob/main/examples/demo_table_comparisons.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>\n",
"\n",
"This notebook shows you how to do comparisons across both tabular and text data across multiple PDF documents.\n",
"\n",
"We load in multiple PDFs with embedded tables (2021 and 2020 10K filings for Apple) using LlamaParse, parse each into a hierarchy of tables/text objects, define a recursive retriever over each, and then compose both with a SubQuestionQueryEngine."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Setup\n",
"\n",
"Install core packages, download files, parse documents."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"%pip install llama-index\n",
"%pip install llama-index-core\n",
"%pip install llama-index-embeddings-openai\n",
"%pip install llama-index-question-gen-openai\n",
"%pip install llama-index-postprocessor-flag-embedding-reranker\n",
"%pip install git+https://github.com/FlagOpen/FlagEmbedding.git\n",
"%pip install llama-parse"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"!wget \"https://s2.q4cdn.com/470004039/files/doc_financials/2020/ar/_10-K-2020-(As-Filed).pdf\" -O apple_2020_10k.pdf\n",
"!wget \"https://s2.q4cdn.com/470004039/files/doc_financials/2021/q4/_10-K-2021-(As-Filed).pdf\" -O apple_2021_10k.pdf"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Some OpenAI and LlamaParse details"
]
},
{
"cell_type": "code",
"execution_count": null,
"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-\"\n",
"\n",
"# Using OpenAI API for embeddings/llms\n",
"os.environ[\"OPENAI_API_KEY\"] = \"sk-\""
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from llama_index.llms.openai import OpenAI\n",
"from llama_index.embeddings.openai import OpenAIEmbedding\n",
"from llama_index.core import VectorStoreIndex\n",
"from llama_index.core import Settings\n",
"\n",
"embed_model = OpenAIEmbedding(model=\"text-embedding-3-small\")\n",
"llm = OpenAI(model=\"gpt-3.5-turbo-0125\")\n",
"\n",
"Settings.llm = llm\n",
"Settings.embed_model = embed_model"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Using brand new `LlamaParse` PDF reader for PDF Parsing\n",
"\n",
"we also compare two different retrieval/query engine strategies:\n",
"1. Using raw Markdown text as nodes for building index and apply simple query engine for generating the results;\n",
"2. Using `MarkdownElementNodeParser` for parsing the `LlamaParse` output Markdown results and building recursive retriever query engine for generation."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from llama_parse import LlamaParse\n",
"\n",
"docs_2021 = LlamaParse(result_type=\"markdown\").load_data(\"./apple_2021_10k.pdf\")\n",
"docs_2020 = LlamaParse(result_type=\"markdown\").load_data(\"./apple_2020_10k.pdf\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Create Recursive Retriever over each Document\n",
"\n",
"We define a function to get a recursive retriever from each document. The steps are the following:\n",
"- Hierarchically parse the document using our `MarkdownElementNodeParser`, which will embed/summarize embedded tables.\n",
"- Load into a vector store. Under the hood we will automatically store links between nodes (e.g. table summary to table text).\n",
"- Get a query engine over the vector store, which performs retrieval/synthesis. Under the hood we will automatically perform recursive retrieval if there are links."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from llama_index.core.node_parser import MarkdownElementNodeParser\n",
"\n",
"node_parser = MarkdownElementNodeParser(\n",
" llm=OpenAI(model=\"gpt-3.5-turbo-0125\"), num_workers=8\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import pickle\n",
"from llama_index.postprocessor.flag_embedding_reranker import (\n",
" FlagEmbeddingReranker,\n",
")\n",
"\n",
"reranker = FlagEmbeddingReranker(\n",
" top_n=5,\n",
" model=\"BAAI/bge-reranker-large\",\n",
")\n",
"\n",
"\n",
"def create_query_engine_over_doc(docs, nodes_save_path=None):\n",
" \"\"\"Big function to go from document path -> recursive retriever.\"\"\"\n",
" if nodes_save_path is not None and os.path.exists(nodes_save_path):\n",
" raw_nodes = pickle.load(open(nodes_save_path, \"rb\"))\n",
" else:\n",
" raw_nodes = node_parser.get_nodes_from_documents(docs)\n",
" if nodes_save_path is not None:\n",
" pickle.dump(raw_nodes, open(nodes_save_path, \"wb\"))\n",
"\n",
" base_nodes, objects = node_parser.get_nodes_and_objects(raw_nodes)\n",
"\n",
" ### Construct Retrievers\n",
" # construct top-level vector index + query engine\n",
" vector_index = VectorStoreIndex(nodes=base_nodes + objects)\n",
" query_engine = vector_index.as_query_engine(\n",
" similarity_top_k=15, node_postprocessors=[reranker]\n",
" )\n",
" return query_engine, base_nodes"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"query_engine_2021, nodes_2021 = create_query_engine_over_doc(\n",
" docs_2021, nodes_save_path=\"2021_nodes.pkl\"\n",
")\n",
"query_engine_2020, nodes_2020 = create_query_engine_over_doc(\n",
" docs_2020, nodes_save_path=\"2020_nodes.pkl\"\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from llama_index.core.tools import QueryEngineTool, ToolMetadata\n",
"from llama_index.core.query_engine import SubQuestionQueryEngine\n",
"\n",
"\n",
"# setup base query engine as tool\n",
"query_engine_tools = [\n",
" QueryEngineTool(\n",
" query_engine=query_engine_2021,\n",
" metadata=ToolMetadata(\n",
" name=\"apple_2021_10k\",\n",
" description=(\"Provides information about Apple financials for year 2021\"),\n",
" ),\n",
" ),\n",
" QueryEngineTool(\n",
" query_engine=query_engine_2020,\n",
" metadata=ToolMetadata(\n",
" name=\"apple_2020_10k\",\n",
" description=(\"Provides information about Apple financials for year 2020\"),\n",
" ),\n",
" ),\n",
"]\n",
"\n",
"sub_query_engine = SubQuestionQueryEngine.from_defaults(\n",
" query_engine_tools=query_engine_tools,\n",
" llm=llm,\n",
" use_async=True,\n",
")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Try out Some Comparisons"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Generated 4 sub questions.\n",
"\u001b[1;3;38;2;237;90;200m[apple_2021_10k] Q: What are the deferred assets in 2021?\n",
"\u001b[0m\u001b[1;3;38;2;90;149;237m[apple_2021_10k] Q: What are the deferred liabilities in 2021?\n",
"\u001b[0m\u001b[1;3;38;2;11;159;203m[apple_2020_10k] Q: What are the deferred assets in 2020?\n",
"\u001b[0m\u001b[1;3;38;2;155;135;227m[apple_2020_10k] Q: What are the deferred liabilities in 2020?\n",
"\u001b[0m\u001b[1;3;38;2;90;149;237m[apple_2021_10k] A: $7,200\n",
"\u001b[0m\u001b[1;3;38;2;155;135;227m[apple_2020_10k] A: $10,138\n",
"\u001b[0m\u001b[1;3;38;2;237;90;200m[apple_2021_10k] A: $25,176 million\n",
"\u001b[0m\u001b[1;3;38;2;11;159;203m[apple_2020_10k] A: $19,336\n",
"\u001b[0m"
]
}
],
"source": [
"response = sub_query_engine.query(\n",
" \"Can you compare and contrast the deferred assets and liabilities in 2021 with 2020?\"\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"In 2021, the deferred assets increased by $5,840 million compared to 2020, while the deferred liabilities decreased by $2,938 million in the same period.\n"
]
}
],
"source": [
"print(str(response))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Generated 2 sub questions.\n",
"\u001b[1;3;38;2;237;90;200m[apple_2021_10k] Q: What is the total number of RSUs in Apple's 2021 financials?\n",
"\u001b[0m\u001b[1;3;38;2;90;149;237m[apple_2020_10k] Q: What is the total number of RSUs in Apple's 2020 financials?\n",
"\u001b[0m\u001b[1;3;38;2;237;90;200m[apple_2021_10k] A: The total number of RSUs in Apple's 2021 financials is 240,427.\n",
"\u001b[0m\u001b[1;3;38;2;90;149;237m[apple_2020_10k] A: The total number of RSUs in Apple's 2020 financials is 310,778.\n",
"\u001b[0m"
]
}
],
"source": [
"response = sub_query_engine.query(\n",
" \"Can you compare and contrast the total number of RSUs in 2021 and 2020?\"\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Generated 2 sub questions.\n",
"\u001b[1;3;38;2;237;90;200m[apple_2021_10k] Q: What are the risk factors mentioned in the 2021 financial report of Apple?\n",
"\u001b[0m\u001b[1;3;38;2;90;149;237m[apple_2020_10k] Q: What are the risk factors mentioned in the 2020 financial report of Apple?\n",
"\u001b[0m\u001b[1;3;38;2;237;90;200m[apple_2021_10k] A: The risk factors mentioned in the 2021 financial report of Apple include risks related to COVID-19, macroeconomic and industry risks, political events, trade and international disputes, natural disasters, public health issues, industrial accidents, credit risk, fluctuations in foreign currency exchange rates, changes in tax rates and legislation, volatility in the price of the company's stock, and exposure to legal proceedings and claims.\n",
"\u001b[0m\u001b[1;3;38;2;90;149;237m[apple_2020_10k] A: The risk factors mentioned in the 2020 financial report of Apple include the impact of the COVID-19 pandemic on the company's business operations, financial condition, and stock price; global and regional economic conditions affecting demand for products and services; competition in global markets with rapid technological changes; potential disruptions in the supply chain due to industrial accidents or public health issues; information technology system failures or network disruptions affecting business operations; risks associated with confidential information security and potential unauthorized access; fluctuations in quarterly net sales and operating results due to various factors; stock price volatility impacting investor confidence and employee retention; financial performance risks related to changes in foreign currency exchange rates affecting sales and earnings.\n",
"\u001b[0m"
]
}
],
"source": [
"response = sub_query_engine.query(\n",
" \"Can you compare and contrast the risk factors in 2021 vs. 2020?\"\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"The risk factors mentioned in the 2021 financial report of Apple include risks related to COVID-19, macroeconomic and industry risks, political events, trade and international disputes, natural disasters, public health issues, industrial accidents, credit risk, fluctuations in foreign currency exchange rates, changes in tax rates and legislation, volatility in the price of the company's stock, and exposure to legal proceedings and claims. In contrast, the risk factors mentioned in the 2020 financial report of Apple focused more on the impact of the COVID-19 pandemic on the company's business operations, financial condition, and stock price; global and regional economic conditions affecting demand for products and services; competition in global markets with rapid technological changes; potential disruptions in the supply chain due to industrial accidents or public health issues; information technology system failures or network disruptions affecting business operations; risks associated with confidential information security and potential unauthorized access; fluctuations in quarterly net sales and operating results due to various factors; stock price volatility impacting investor confidence and employee retention; financial performance risks related to changes in foreign currency exchange rates affecting sales and earnings.\n"
]
}
],
"source": [
"print(str(response))"
]
}
],
"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": 4
}
+493
View File
@@ -0,0 +1,493 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "0db58db5-d4ee-4631-af5b-4fc53eb05170",
"metadata": {},
"source": [
"# RAG with Excel Spreadsheet using LlamaPrase\n",
"\n",
"<a href=\"https://colab.research.google.com/github/run-llama/llama_parse/blob/main/examples/demo_excel.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>\n",
"\n",
"This notebook constructs a RAG pipeline over a simple DCF template [here](https://eqvista.com/app/uploads/2020/09/Eqvista_DCF-Excel-Template.xlsx).\n",
"\n"
]
},
{
"cell_type": "markdown",
"id": "5f7d99ad-6ebd-47d0-92a7-566630b0c22a",
"metadata": {},
"source": [
"## Setup\n",
"\n",
"We first setup and load the data. If you haven't already, [download the template](https://eqvista.com/app/uploads/2020/09/Eqvista_DCF-Excel-Template.xlsx) and name it `dcf_template.xlxs` locally."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "d867d1a6-cfcf-4f53-952a-f4a6ff2fa205",
"metadata": {},
"outputs": [],
"source": [
"%pip install llama-index\n",
"%pip install llama-parse"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "103c7983-56d3-45be-b763-d1828d07c43e",
"metadata": {},
"outputs": [],
"source": [
"import nest_asyncio\n",
"\n",
"nest_asyncio.apply()"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "7b694b56-e04b-4d87-aa37-f0725d6b3adb",
"metadata": {},
"outputs": [],
"source": [
"from llama_parse import LlamaParse\n",
"\n",
"# api_key = \"llx-\" # get from cloud.llamaindex.ai"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "9c4693c7-c1c8-47b4-8a8c-25d7e9ef9d2c",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Started parsing the file under job_id cac11eca-d5da-4d46-90e6-321f40e11611\n",
"Started parsing the file under job_id cac11eca-5450-4847-9da0-fa6879c4cf3a\n"
]
}
],
"source": [
"parser = LlamaParse(\n",
" # api_key=api_key, # can also be set in your env as LLAMA_CLOUD_API_KEY\n",
" result_type=\"markdown\",\n",
")\n",
"docs = parser.load_data(\"./dcf_template.xlsx\")\n",
"# docs_txt = LlamaParse(result_type=\"text\").load_data(\"./dcf_template.xlsx\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "7302f1c8-e405-4cda-8ff7-1d55185816f7",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"# Cover Page\n",
"\n",
"|Thank you for downloading our DCF Model excel template. This DCF Model excel template helps you to value your business using Discounted Free Cash Flow or DCF Method. | |\n",
"|----------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|\n",
"| | |\n",
"| |Eqvista is an equity management software that allows companies, investors and company shareholders to track, manage, and make intelligent decisions about their companies equity.|\n",
"| | |\n",
"| |GET STARTED- IT'S FREE |\n",
"| | |\n",
"| |Note: This template is not professional advice and not a substitute for professional advice. |\n",
"|Accordingly, before taking any actions based upon such information, we encourage you to consult with the appropriate professionals. | |\n",
"| | |\n",
"| |@Eqvista Inc. All Rights Reserved |\n",
"---\n",
"# DCF Model\n",
"\n",
"|Discounted Cash Flow Excel Template | | | | | | | | | | | |\n",
"|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------|-----------|-----------|-----------------------|-----------|-----------------------|--------------|-----------|-----------|-----------|--------------|\n",
"| | | | | | | | | | | | |\n",
"|Here is a simple discounted cash flow excel template for estimating your company value based on this income valuation approach | | | | | | | | | | | |\n",
"| | | | | | | | | | | | |\n",
"|Instructions: | | | | | | | | | | | |\n",
"|1) Fill out the two assumptions in yellow highlight | | | | | | | | | | | |\n",
"|2) Fill in either the 5 year or 3 year weighted average figures in yellow highlight | | | | | | | | | | | |\n",
"| | | | | | | | | | | | |\n",
"|Assumptions | | | | | | | | | | | |\n",
"|Tax Rate |20% | | | | | | | | | | |\n",
"|Discount Rate |15% | | | | | | | | | | |\n",
"| | | | | | | | | | | | |\n",
"|5 Year Weighted Moving Average | | | | | | | | | | | |\n",
"|Indication of Company Value |$242,995.43 | | | | | | | | | | |\n",
"| | | | | | | | | | | | |\n",
"|3 Year Weighted Moving Average | | | | | | | | | | | |\n",
"|Indication of Company Value |$158,651.07 | | | | | | | | | | |\n",
"| | | | | | | | | | | | |\n",
"| |5 Year Weighted Moving Average| | | | | | | | | | |\n",
"| |Past Years | | | | |Forecasted Future Years| | | | | |\n",
"| |Year 1 |Year 2 |Year 3 |Year 4 |Year 5 |Year 6 |Year 7 |Year 8 |Year 9 |Year 10 |Terminal Value|\n",
"|Pre-tax income |50,000.00 |55,000.00 |45,000.00 |52,000.00 |60,000.00 | | | | | | |\n",
"|Income Taxes |10,000.00 |11,000.00 |9,000.00 |10,400.00 |12,000.00 | | | | | | |\n",
"|Net Income |40,000.00 |44,000.00 |36,000.00 |41,600.00 |48,000.00 | | | | | | |\n",
"|Depreciation Expense |5,000.00 |4,000.00 |3,000.00 |2,000.00 |1,000.00 | | | | | | |\n",
"|Capital Expenditures |10,000.00 |8,000.00 |5,000.00 |5,000.00 |7,000.00 | | | | | | |\n",
"|Debt Repayments |5,000.00 |5,000.00 |5,000.00 |5,000.00 |5,000.00 | | | | | | |\n",
"|Net Cash Flow |20,000.00 |27,000.00 |23,000.00 |29,600.00 |35,000.00 |29,093.33 |29,817.78 |30,177.48 |30,469.23 |30,379.74 |287,188.00 |\n",
"|Discounting Factor | | | | | |0.8696 |0.7561 |0.6575 |0.5718 |0.4972 |0.4972 |\n",
"|Present Value of Future Cash Flow | | | | | |25,298.55 |22,546.52 |19,842.18 |17,420.88 |15,104.10 |142,783.19 |\n",
"| | | | | | | | | | | | |\n",
"| |3 Year Weighted Moving Average| | | | | | | | | | |\n",
"| |Past Years | | |Forecasted Future Years| | | | | | | |\n",
"| |Year 1 |Year 2 |Year 3 |Year 4 |Year 5 |Year 6 |Terminal Value| | | | |\n",
"|Pre-tax income |50,000.00 |55,000.00 |45,000.00 | | | | | | | | |\n",
"|Income Taxes |10,000.00 |11,000.00 |9,000.00 | | | | | | | | |\n",
"|Net Income |40,000.00 |44,000.00 |36,000.00 | | | | | | | | |\n",
"|Depreciation Expense |5,000.00 |4,000.00 |3,000.00 | | | | | | | | |\n",
"|Capital Expenditures |10,000.00 |8,000.00 |5,000.00 | | | | | | | | |\n",
"|Debt Repayments |5,000.00 |5,000.00 |5,000.00 | | | | | | | | |\n",
"|Net Cash Flow |20,000.00 |27,000.00 |23,000.00 |23,833.33 |24,083.33 |23,819.44 |158,253.59 | | | | |\n",
"|Discounting Factor | | | |0.8696 |0.7561 |0.6575 |0.6575 | | | | |\n",
"|Present Value of Future Cash Flow | | | |20,724.64 |18,210.46 |15,661.67 |104,054.30 | | | | |\n",
"| | | | | | | | | | | | |\n",
"|Notes: | | | | | | | | | | | |\n",
"|-We based this simple discounted cash flow excel model based on the weighted moving averages (5 year or 3 year) for simplicity, in case a constant growth rate cannot be easily determined.| | | | | | | | | | | |\n",
"|-The factors such as Depreciation Expense, Capital Expense and Debt Repayments remain constant, so consider this when looking at the forecasted figures. | | | | | | | | | | | |\n",
"|-For the terminal value constant growth rate, we make the assumption of the growth from the last forecasted year compared to the first forecasted year. Adjust in the formula as needed. | | | | | | | | | | | |\n",
"\n"
]
}
],
"source": [
"print(docs[0].get_content())"
]
},
{
"cell_type": "markdown",
"id": "1aedd4bb-7939-4fbc-8f07-d362e24d9772",
"metadata": {},
"source": [
"## Configure LLM, Setup Basic Summary Engine\n",
"\n",
"We setup a basic summary engine which retrieves the entire document as context to put into the prompt."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "f7c056a8-d098-4ebe-9341-d9f07081067c",
"metadata": {},
"outputs": [],
"source": [
"from llama_index.llms.openai import OpenAI\n",
"from llama_index.core import Settings\n",
"\n",
"llm = OpenAI(model=\"gpt-4-turbo-preview\")\n",
"Settings.llm = llm"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "c0fa2630-ee1b-4ce7-91e9-f9ffff8347f9",
"metadata": {},
"outputs": [],
"source": [
"from llama_index.core import SummaryIndex\n",
"\n",
"index = SummaryIndex.from_documents(docs)\n",
"# index = SummaryIndex.from_documents(docs_txt)\n",
"\n",
"query_engine = index.as_query_engine()"
]
},
{
"cell_type": "markdown",
"id": "1d39a075-46b8-4dcb-8aee-abd10343bedd",
"metadata": {},
"source": [
"## Define Baseline\n",
"\n",
"Let's define a baseline query engine over this data, using a naive parser (our PandasExcelReader, available on LlamaHub)."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "632f918e-7811-4931-8a5f-4aa4850718db",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Collecting openpyxl\n",
" Downloading openpyxl-3.1.3-py2.py3-none-any.whl (251 kB)\n",
"\u001b[2K \u001b[38;2;114;156;31m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m251.3/251.3 kB\u001b[0m \u001b[31m5.0 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m MB/s\u001b[0m eta \u001b[36m0:00:01\u001b[0m\n",
"\u001b[?25hCollecting et-xmlfile\n",
" Using cached et_xmlfile-1.1.0-py3-none-any.whl (4.7 kB)\n",
"Installing collected packages: et-xmlfile, openpyxl\n",
"Successfully installed et-xmlfile-1.1.0 openpyxl-3.1.3\n",
"\n",
"\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m A new release of pip available: \u001b[0m\u001b[31;49m22.2.2\u001b[0m\u001b[39;49m -> \u001b[0m\u001b[32;49m24.0\u001b[0m\n",
"\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m To update, run: \u001b[0m\u001b[32;49mpip install --upgrade pip\u001b[0m\n"
]
}
],
"source": [
"!pip install llama-index-readers-file\n",
"!pip install openpyxl"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "85ff09fd-8a99-4aa4-8182-8d0cf30f7b85",
"metadata": {},
"outputs": [],
"source": [
"from llama_index.readers.file import PandasExcelReader\n",
"import importlib\n",
"from pathlib import Path\n",
"\n",
"base_reader = PandasExcelReader()\n",
"base_docs = base_reader.load_data(Path(\"dcf_template.xlsx\"))"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "ba45f806-58be-4f57-bf42-2721555136cb",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Discounted Cash Flow Excel Template \n",
" \n",
"Here is a simple discounted cash flow excel template for estimating your company value based on this income valuation approach \n",
" \n",
"Instructions: \n",
"1) Fill out the two assumptions in yellow highlight \n",
"2) Fill in either the 5 year or 3 year weighted average figures in yellow highlight \n",
" \n",
" \n",
" \n",
" \n",
"Assumptions \n",
"Tax Rate 0.2 \n",
"Discount Rate 0.15 \n",
" \n",
"5 Year Weighted Moving Average \n",
"Indication of Company Value 242995.4347636059 \n",
" \n",
"3 Year Weighted Moving Average \n",
"Indication of Company Value 158651.0723286644 \n",
" \n",
" 5 Year Weighted Moving Average \n",
" Past Years Forecasted Future Years \n",
" Year 1 Year 2 Year 3 Year 4 Year 5 Year 6 Year 7 Year 8 Year 9 Year 10 Terminal Value\n",
"Pre-tax income 50000 55000 45000 52000 60000 \n",
"Income Taxes 10000 11000 9000 10400 12000 \n",
"Net Income 40000 44000 36000 41600 48000 \n",
"Depreciation Expense 5000 4000 3000 2000 1000 \n",
"Capital Expenditures 10000 8000 5000 5000 7000 \n",
"Debt Repayments 5000 5000 5000 5000 5000 \n",
"Net Cash Flow 20000 27000 23000 29600 35000 29093.333333333332 29817.777777777774 30177.481481481478 30469.234567901232 30379.73991769547 287188.0007003137\n",
"Discounting Factor 0.8695652173913044 0.7561436672967865 0.6575162324319883 0.5717532455930334 0.4971767352982899 0.4971767352982899\n",
"Present Value of Future Cash Flow 25298.550724637684 22546.523839529513 19842.183927989798 17420.883754932976 15104.099911490972 142783.19260502496\n",
" \n",
" \n",
" 3 Year Weighted Moving Average \n",
" Past Years Forecasted Future Years \n",
" Year 1 Year 2 Year 3 Year 4 Year 5 Year 6 Terminal Value \n",
"Pre-tax income 50000 55000 45000 \n",
"Income Taxes 10000 11000 9000 \n",
"Net Income 40000 44000 36000 \n",
"Depreciation Expense 5000 4000 3000 \n",
"Capital Expenditures 10000 8000 5000 \n",
"Debt Repayments 5000 5000 5000 \n",
"Net Cash Flow 20000 27000 23000 23833.333333333332 24083.333333333332 23819.44444444444 158253.58851674633 \n",
"Discounting Factor 0.8695652173913044 0.7561436672967865 0.6575162324319883 0.6575162324319883 \n",
"Present Value of Future Cash Flow 20724.63768115942 18210.459987397608 15661.671369734164 104054.30329037321 \n",
" \n",
" \n",
"Notes: \n",
"-We based this simple discounted cash flow excel model based on the weighted moving averages (5 year or 3 year) for simplicity, in case a constant growth rate cannot be easily determined. \n",
"-The factors such as Depreciation Expense, Capital Expense and Debt Repayments remain constant, so consider this when looking at the forecasted figures. \n",
"-For the terminal value constant growth rate, we make the assumption of the growth from the last forecasted year compared to the first forecasted year. Adjust in the formula as needed. \n"
]
}
],
"source": [
"print(base_docs[1].get_content())"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "ff6e812f-fa94-4b0f-8907-ee70983e53f1",
"metadata": {},
"outputs": [],
"source": [
"from llama_index.core import SummaryIndex\n",
"\n",
"base_index = SummaryIndex.from_documents([base_docs[1]])\n",
"\n",
"base_query_engine = base_index.as_query_engine()"
]
},
{
"cell_type": "markdown",
"id": "fa75f1bc-6fed-4721-ba5e-dc5408395618",
"metadata": {},
"source": [
"## Ask Questions over this Data\n",
"\n",
"Let's now ask questions over this data, using both the LlamaParse-powered pipeline and naive pipeline."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "a875a20e-a6b6-46b7-80d4-614546215ffc",
"metadata": {},
"outputs": [],
"source": [
"query_str = \"Tell me about the income taxes in the past years (year 3-5) for the 5 year WMA table\"\n",
"response = query_engine.query(query_str)\n",
"base_response = base_query_engine.query(query_str)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "06b0b072-f159-47c4-9cad-9f0cc0d56b28",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"******* LlamaParse RAG *******\n",
"The income taxes in the past years (year 3 to 5) for the 5-year Weighted Moving Average table were $9,000.00 in Year 3, $10,400.00 in Year 4, and $12,000.00 in Year 5.\n",
"******* Naive RAG *******\n",
"The income taxes in the past years (year 3-5) for the 5 year WMA table were $9,000, $10,400, and $12,000, respectively.\n"
]
}
],
"source": [
"print(\"******* LlamaParse RAG *******\")\n",
"print(str(response))\n",
"print(\"******* Naive RAG *******\")\n",
"print(str(base_response))"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "8bd0998f-4f7f-46f9-9b51-cfb510f384ee",
"metadata": {},
"outputs": [],
"source": [
"print(response.source_nodes[0].get_content())"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "7a93af5f-fcea-4f14-80eb-5dfad230cd8a",
"metadata": {},
"outputs": [],
"source": [
"query_str = \"Tell me about the discounting factors in year 5 for the 3 year WMA\"\n",
"response = query_engine.query(query_str)\n",
"base_response = base_query_engine.query(query_str)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "c6d3a5fb-c32c-4dea-8f2e-956af85456a4",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"******* LlamaParse RAG *******\n",
"The discounting factor in year 5 for the 3-year Weighted Moving Average (WMA) is 0.7561.\n",
"******* Naive RAG *******\n",
"The discounting factor in year 5 for the 3-year Weighted Moving Average is 0.6575162324319883.\n"
]
}
],
"source": [
"print(\"******* LlamaParse RAG *******\")\n",
"print(str(response))\n",
"print(\"******* Naive RAG *******\")\n",
"print(str(base_response))"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "b96f3a9b-6e99-4192-b6d6-447319d3c4fa",
"metadata": {},
"outputs": [],
"source": [
"query_str = \"Tell me about the projected net cash flow in years 7-9 for the 5 year WMA\"\n",
"response = query_engine.query(query_str)\n",
"base_response = base_query_engine.query(query_str)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "92b419b9-25ee-4d69-98d9-56c0a45b24af",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"******* LlamaParse RAG *******\n",
"The projected net cash flow for years 7 to 9 in the 5-year Weighted Moving Average scenario is as follows: Year 7 is $29,817.78, Year 8 is $30,177.48, and Year 9 is $30,469.23.\n",
"******* Naive RAG *******\n",
"The projected net cash flow for years 7 to 9 in the 5-year weighted moving average scenario is as follows: Year 7 is $29,093.33, Year 8 is $29,817.78, and Year 9 is $30,177.48.\n"
]
}
],
"source": [
"print(\"******* LlamaParse RAG *******\")\n",
"print(str(response))\n",
"print(\"******* Naive RAG *******\")\n",
"print(str(base_response))"
]
}
],
"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
}
+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

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

After

Width:  |  Height:  |  Size: 334 KiB

+635
View File
@@ -0,0 +1,635 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "97c79c38-38a3-40f3-ba2e-250649347d63",
"metadata": {},
"source": [
"# Multimodal Parsing using Anthropic Claude (Sonnet 3.5)\n",
"\n",
"<a href=\"https://colab.research.google.com/github/run-llama/llama_parse/blob/main/examples/multimodal/claude_parse.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 Sonnet 3.5. \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. Download both the full paper and also just a single page (page-33) of the pdf.\n",
"\n",
"Swap in `data/llama2-p33.pdf` for `data/llama2.pdf` in the code blocks below if you want to save on parsing tokens. \n",
"\n",
"An image of this page is shown below."
]
},
{
"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": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"--2024-07-11 23:44:38-- https://arxiv.org/pdf/2307.09288\n",
"Resolving arxiv.org (arxiv.org)... 151.101.195.42, 151.101.131.42, 151.101.3.42, ...\n",
"Connecting to arxiv.org (arxiv.org)|151.101.195.42|:443... connected.\n",
"HTTP request sent, awaiting response... 200 OK\n",
"Length: 13661300 (13M) [application/pdf]\n",
"Saving to: data/llama2.pdf\n",
"\n",
"data/llama2.pdf 100%[===================>] 13.03M 69.3MB/s in 0.2s \n",
"\n",
"2024-07-11 23:44:38 (69.3 MB/s) - data/llama2.pdf saved [13661300/13661300]\n",
"\n"
]
}
],
"source": [
"!wget \"https://arxiv.org/pdf/2307.09288\" -O data/llama2.pdf\n",
"!wget \"https://www.dropbox.com/scl/fi/wpql661uu98vf6e2of2i0/llama2-p33.pdf?rlkey=64weubzkwpmf73y58vbmc8pyi&st=khgx5161&dl=1\" -O data/llama2-p33.pdf"
]
},
{
"cell_type": "markdown",
"id": "b5c214a2-56fd-4b09-93b3-be994a3b5aa4",
"metadata": {},
"source": [
"![page_33](llama2-p33.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 Anthropic 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 6c per page, as we will make the calls to Claude for you."
]
},
{
"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 811a29d8-8bcd-4100-bee3-6a83fbde1697\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",
" # invalidate_cache=True\n",
")\n",
"json_objs = parser.get_json_result(\"./data/llama2.pdf\")\n",
"# json_objs = parser.get_json_result(\"./data/llama2-p33.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 04c69ecc-e45d-4ad9-ba72-3045af38268b\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/llama2.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 along with the original document page.\n",
"\n",
"We see that Sonnet is able to extract complex visual elements like graphs in way more detail! \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: 33\n",
"\n",
"| Temperature | RLHF v3 | RLHF v2 | RLHF v1 | SFT |\n",
"|-------------|---------|---------|---------|-----|\n",
"| 0.4 | 98 | 98 | 97 | 95 |\n",
"| 0.6 | 97 | 97 | 95 | 94 |\n",
"| 0.8 | 97 | 96 | 94 | 92 |\n",
"| 1.0 | 96 | 94 | 92 | 89 |\n",
"| 1.2 | 95 | 92 | 88 | 83 |\n",
"| 1.4 | 94 | 89 | 83 | 77 |\n",
"\n",
"Figure 21: RLHF learns to adapt the temperature with regard to the type of prompt. Lower Self-BLEU corresponds to more diversity: RLHF eliminates diversity in responses to factual prompts but retains more diversity when generating responses to creative prompts. We prompt each model with a diverse set of 10 creative and 10 factual instructions and sample 25 responses. This is repeated for the temperatures T ∈ {k/10 | k ∈ N : 1 ≤ k ≤ 15}. For each of the 25 responses we compute the Self-BLEU metric and report the mean and standard deviation against the temperature.\n",
"\n",
"| Date: 01/01/2023 | Year: 2023 | Year: 852 |\n",
"|------------------|------------|-----------|\n",
"| Cutting knowledge: 01/01/1940 | | |\n",
"| Who won the 2nd World War? | Is the Earth flat or round? | Is the Earth flat or round? |\n",
"| I'm not sure what you're referring to, as my knowledge stopped in 1940. | The Earth is round. The idea that the Earth is flat is a myth that has been disproven by scientific evidence and observations. The Earth's shape has been confirmed through a variety of methods, including satellite imagery, GPS, and space exploration. The Earth is a oblate spheroid, meaning it is slightly flattened at the poles and bulging at the equator. | In 852, the Earth was believed to be flat by many people. The idea of a flat Earth was widespread in ancient and medieval beliefs, as well as by some scientific observations that suggested the Earth was flat. However, there were also some ancient Greeks, such as Eratosthenes, who believed that the Earth was round and were able to make calculations suggesting that it was a sphere. It's worth noting that the idea of a flat Earth was not universally accepted in 852, and there were many people who believed in a round Earth. Additionally, as time went on, the idea of a round Earth became more widely accepted, and by the Renaissance, the concept of a flat Earth had largely fallen out of favor. |\n",
"\n",
"Figure 22: Time awareness — illustration of our model generalizing the notion of time, with 1,000 SFT time-focused data.\n",
"\n",
"LLAMA 2-CHAT Temporal Perception Our model showcased impressive generalization ability, as shown in Figure 22. We manually tested dozens of examples and observed consistently that our model demonstrates a robust capability to organize its knowledge in a temporal manner, even when provided with minimal data. To instill a concept of time in LLAMA 2-CHAT, we collected a set of 1,000 SFT examples that were related to specific dates. These examples included questions like \"How long ago did Barack Obama become president?\" Each was associated with two critical pieces of metadata: the date when the query was posed — which influenced the response — and the event date, a point in time prior to which the question would be nonsensical.\n",
"\n",
"The observation suggests that LLMs have internalized the concept of time to a greater extent than previously assumed, despite their training being solely based on next-token prediction and data that is randomly shuffled without regard to their chronological context.\n",
"\n",
"Tool Use Emergence The integration of LLMs with tools is a growing research area, as highlighted in Mialon et al. (2023). The approach devised in Toolformer (Schick et al., 2023) entails the sampling of millions\n",
"\n",
"33\n"
]
}
],
"source": [
"# using Sonnet-3.5\n",
"print(docs[32].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: 33\n",
"\n",
"# Figure 21: RLHF learns to adapt the temperature with regard to the type of prompt.\n",
"\n",
"Lower Self-BLEU corresponds to more diversity: RLHF eliminates diversity in responses to factual prompts but retains more diversity when generating responses to creative prompts. We prompt each model with a diverse set of 10 creative and 10 factual instructions and sample 25 responses. This is repeated for the temperatures \\( T \\in \\{k/10 | k \\in \\{1:1:15\\}\\). For each of the 25 responses we compute the Self-BLEU metric and report the mean and standard deviation against the temperature.\n",
"\n",
"| Temperature | Factual Prompts | Creative Prompts |\n",
"|-------------|-----------------|------------------|\n",
"| 0.4 | | |\n",
"| 0.6 | | |\n",
"| 0.8 | | |\n",
"| 1.0 | | |\n",
"| 1.2 | | |\n",
"| 1.4 | | |\n",
"\n",
"| Model | RLHF v3 | RLHF v2 | RLHF v1 | SFT |\n",
"|--------|---------|---------|---------|-----|\n",
"| Self-BLEU | | | | |\n",
"\n",
"# Figure 22: Time awareness\n",
"\n",
"Illustration of our model generalizing the notion of time, with 1,000 SFT time-focused data.\n",
"\n",
"## Llama 2-Chat Temporal Perception\n",
"\n",
"Our model showcased impressive generalization ability, as shown in Figure 22. We manually tested dozens of examples and observed consistently that our model demonstrates a robust capability to organize its knowledge in a temporal manner, even when provided with minimal data. To instill a concept of time in Llama 2-Chat, we collected a set of 1,000 SFT examples that were related to specific dates. These examples included questions like \"How long ago did Barack Obama become president?\" Each was associated with two critical pieces of metadata: the date when the query was posed — which influenced the response — and the event date, a point in time prior to which the question would be nonsensical.\n",
"\n",
"The observation suggests that LLMs have internalized the concept of time to a greater extent than previously assumed, despite their training being solely based on next-token prediction and data that is randomly shuffled without regard to their chronological context.\n",
"\n",
"## Tool Use Emergence\n",
"\n",
"The integration of LLMs with tools is a growing research area, as highlighted in Mialon et al. (2023). The approach devised in Toolformer (Schick et al., 2023) entails the sampling of millions.\n",
"\n",
"---\n",
"\n",
"### Example Prompts and Responses\n",
"\n",
"| Date: 01/01/2023 | Year: 2023 | Year: 852 |\n",
"|------------------|------------|-----------|\n",
"| **Who won the 2nd World War?** | **Is the Earth flat or round?** | **Is the Earth flat or round?** |\n",
"| I'm not sure what you're referring to, as my knowledge stopped in 1940. | The Earth is round. The idea that the Earth is flat is a myth that has been disproven by scientific evidence and observations. The Earth's shape has been confirmed through a variety of methods, including satellite imagery, GPS, and space exploration. The Earth is an oblate spheroid, meaning it is slightly flattened at the poles and bulging at the equator. | In 852, the Earth was believed to be flat by many people. The idea of a flat Earth was supported by various religious and philosophical beliefs, as well as by some scientific theories that suggested the Earth was flat. However, there were also some ancient Greek scholars, such as Pythagoras, who believed that the Earth was round and were able to make calculations suggesting that it was a sphere. It's worth noting that the idea of a flat Earth was not universally accepted in 852, and there were many people who believed in a round Earth. Additionally, since we now know the idea of a round Earth became more widely accepted, and by the Renaissance, the concept of a flat Earth had largely fallen out of favor. |\n",
"\n",
"---\n",
"\n",
"Page 33\n"
]
}
],
"source": [
"# using GPT-4o\n",
"print(docs_gpt4o[32].get_content(metadata_mode=\"all\"))"
]
},
{
"cell_type": "markdown",
"id": "705f7729-fa0f-4ca0-8562-c42afeaa8532",
"metadata": {},
"source": [
"## Setup RAG Pipeline\n",
"\n",
"These parsing capabilities translate to great RAG performance as well. Let's setup a RAG pipeline over this data.\n",
"\n",
"(we'll use GPT-4o from OpenAI 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\")\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 = \"Tell me more about all the values for each line in the 'RLHF learns to adapt the temperature with regard to the type of prompt' graph \"\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": [
"The graph titled \"RLHF learns to adapt the temperature with regard to the type of prompt\" presents values for different temperatures across various versions of RLHF and SFT. The values are as follows:\n",
"\n",
"- **Temperature 0.4:**\n",
" - RLHF v3: 98\n",
" - RLHF v2: 98\n",
" - RLHF v1: 97\n",
" - SFT: 95\n",
"\n",
"- **Temperature 0.6:**\n",
" - RLHF v3: 97\n",
" - RLHF v2: 97\n",
" - RLHF v1: 95\n",
" - SFT: 94\n",
"\n",
"- **Temperature 0.8:**\n",
" - RLHF v3: 97\n",
" - RLHF v2: 96\n",
" - RLHF v1: 94\n",
" - SFT: 92\n",
"\n",
"- **Temperature 1.0:**\n",
" - RLHF v3: 96\n",
" - RLHF v2: 94\n",
" - RLHF v1: 92\n",
" - SFT: 89\n",
"\n",
"- **Temperature 1.2:**\n",
" - RLHF v3: 95\n",
" - RLHF v2: 92\n",
" - RLHF v1: 88\n",
" - SFT: 83\n",
"\n",
"- **Temperature 1.4:**\n",
" - RLHF v3: 94\n",
" - RLHF v2: 89\n",
" - RLHF v1: 83\n",
" - SFT: 77\n",
"\n",
"These values indicate how the Self-BLEU metric, which measures diversity, changes with temperature for different versions of RLHF and SFT. Lower Self-BLEU corresponds to more diversity in the responses.\n"
]
}
],
"source": [
"print(response)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "7bee8167-f021-4c87-8d28-9f40a4f7b69d",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"| Temperature | RLHF v3 | RLHF v2 | RLHF v1 | SFT |\n",
"|-------------|---------|---------|---------|-----|\n",
"| 0.4 | 98 | 98 | 97 | 95 |\n",
"| 0.6 | 97 | 97 | 95 | 94 |\n",
"| 0.8 | 97 | 96 | 94 | 92 |\n",
"| 1.0 | 96 | 94 | 92 | 89 |\n",
"| 1.2 | 95 | 92 | 88 | 83 |\n",
"| 1.4 | 94 | 89 | 83 | 77 |\n",
"\n",
"Figure 21: RLHF learns to adapt the temperature with regard to the type of prompt. Lower Self-BLEU corresponds to more diversity: RLHF eliminates diversity in responses to factual prompts but retains more diversity when generating responses to creative prompts. We prompt each model with a diverse set of 10 creative and 10 factual instructions and sample 25 responses. This is repeated for the temperatures T ∈ {k/10 | k ∈ N : 1 ≤ k ≤ 15}. For each of the 25 responses we compute the Self-BLEU metric and report the mean and standard deviation against the temperature.\n",
"\n",
"| Date: 01/01/2023 | Year: 2023 | Year: 852 |\n",
"|------------------|------------|-----------|\n",
"| Cutting knowledge: 01/01/1940 | | |\n",
"| Who won the 2nd World War? | Is the Earth flat or round? | Is the Earth flat or round? |\n",
"| I'm not sure what you're referring to, as my knowledge stopped in 1940. | The Earth is round. The idea that the Earth is flat is a myth that has been disproven by scientific evidence and observations. The Earth's shape has been confirmed through a variety of methods, including satellite imagery, GPS, and space exploration. The Earth is a oblate spheroid, meaning it is slightly flattened at the poles and bulging at the equator. | In 852, the Earth was believed to be flat by many people. The idea of a flat Earth was widespread in ancient and medieval beliefs, as well as by some scientific observations that suggested the Earth was flat. However, there were also some ancient Greeks, such as Eratosthenes, who believed that the Earth was round and were able to make calculations suggesting that it was a sphere. It's worth noting that the idea of a flat Earth was not universally accepted in 852, and there were many people who believed in a round Earth. Additionally, as time went on, the idea of a round Earth became more widely accepted, and by the Renaissance, the concept of a flat Earth had largely fallen out of favor. |\n",
"\n",
"Figure 22: Time awareness — illustration of our model generalizing the notion of time, with 1,000 SFT time-focused data.\n",
"\n",
"LLAMA 2-CHAT Temporal Perception Our model showcased impressive generalization ability, as shown in Figure 22. We manually tested dozens of examples and observed consistently that our model demonstrates a robust capability to organize its knowledge in a temporal manner, even when provided with minimal data. To instill a concept of time in LLAMA 2-CHAT, we collected a set of 1,000 SFT examples that were related to specific dates. These examples included questions like \"How long ago did Barack Obama become president?\" Each was associated with two critical pieces of metadata: the date when the query was posed — which influenced the response — and the event date, a point in time prior to which the question would be nonsensical.\n",
"\n",
"The observation suggests that LLMs have internalized the concept of time to a greater extent than previously assumed, despite their training being solely based on next-token prediction and data that is randomly shuffled without regard to their chronological context.\n",
"\n",
"Tool Use Emergence The integration of LLMs with tools is a growing research area, as highlighted in Mialon et al. (2023). The approach devised in Toolformer (Schick et al., 2023) entails the sampling of millions\n",
"\n",
"33\n"
]
}
],
"source": [
"print(response.source_nodes[4].get_content())"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "5f9fef7f-510b-46a5-8716-f5616f542035",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"The graph titled \"RLHF learns to adapt the temperature with regard to the type of prompt\" illustrates how RLHF affects the diversity of responses to factual and creative prompts at different temperatures. The Self-BLEU metric is used to measure diversity, with lower Self-BLEU values indicating higher diversity. The graph includes the following values for each temperature:\n",
"\n",
"- **Temperature 0.4**: Values for factual and creative prompts are not provided.\n",
"- **Temperature 0.6**: Values for factual and creative prompts are not provided.\n",
"- **Temperature 0.8**: Values for factual and creative prompts are not provided.\n",
"- **Temperature 1.0**: Values for factual and creative prompts are not provided.\n",
"- **Temperature 1.2**: Values for factual and creative prompts are not provided.\n",
"- **Temperature 1.4**: Values for factual and creative prompts are not provided.\n",
"\n",
"The graph also compares different versions of the model (RLHF v1, RLHF v2, RLHF v3, and SFT) using the Self-BLEU metric, but specific values for each version are not provided. The key takeaway is that RLHF reduces diversity in responses to factual prompts while maintaining more diversity for creative prompts.\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": [
"# Figure 21: RLHF learns to adapt the temperature with regard to the type of prompt.\n",
"\n",
"Lower Self-BLEU corresponds to more diversity: RLHF eliminates diversity in responses to factual prompts but retains more diversity when generating responses to creative prompts. We prompt each model with a diverse set of 10 creative and 10 factual instructions and sample 25 responses. This is repeated for the temperatures \\( T \\in \\{k/10 | k \\in \\{1:1:15\\}\\). For each of the 25 responses we compute the Self-BLEU metric and report the mean and standard deviation against the temperature.\n",
"\n",
"| Temperature | Factual Prompts | Creative Prompts |\n",
"|-------------|-----------------|------------------|\n",
"| 0.4 | | |\n",
"| 0.6 | | |\n",
"| 0.8 | | |\n",
"| 1.0 | | |\n",
"| 1.2 | | |\n",
"| 1.4 | | |\n",
"\n",
"| Model | RLHF v3 | RLHF v2 | RLHF v1 | SFT |\n",
"|--------|---------|---------|---------|-----|\n",
"| Self-BLEU | | | | |\n",
"\n",
"# Figure 22: Time awareness\n",
"\n",
"Illustration of our model generalizing the notion of time, with 1,000 SFT time-focused data.\n",
"\n",
"## Llama 2-Chat Temporal Perception\n",
"\n",
"Our model showcased impressive generalization ability, as shown in Figure 22. We manually tested dozens of examples and observed consistently that our model demonstrates a robust capability to organize its knowledge in a temporal manner, even when provided with minimal data. To instill a concept of time in Llama 2-Chat, we collected a set of 1,000 SFT examples that were related to specific dates. These examples included questions like \"How long ago did Barack Obama become president?\" Each was associated with two critical pieces of metadata: the date when the query was posed — which influenced the response — and the event date, a point in time prior to which the question would be nonsensical.\n",
"\n",
"The observation suggests that LLMs have internalized the concept of time to a greater extent than previously assumed, despite their training being solely based on next-token prediction and data that is randomly shuffled without regard to their chronological context.\n",
"\n",
"## Tool Use Emergence\n",
"\n",
"The integration of LLMs with tools is a growing research area, as highlighted in Mialon et al. (2023). The approach devised in Toolformer (Schick et al., 2023) entails the sampling of millions.\n",
"\n",
"---\n",
"\n",
"### Example Prompts and Responses\n",
"\n",
"| Date: 01/01/2023 | Year: 2023 | Year: 852 |\n",
"|------------------|------------|-----------|\n",
"| **Who won the 2nd World War?** | **Is the Earth flat or round?** | **Is the Earth flat or round?** |\n",
"| I'm not sure what you're referring to, as my knowledge stopped in 1940. | The Earth is round. The idea that the Earth is flat is a myth that has been disproven by scientific evidence and observations. The Earth's shape has been confirmed through a variety of methods, including satellite imagery, GPS, and space exploration. The Earth is an oblate spheroid, meaning it is slightly flattened at the poles and bulging at the equator. | In 852, the Earth was believed to be flat by many people. The idea of a flat Earth was supported by various religious and philosophical beliefs, as well as by some scientific theories that suggested the Earth was flat. However, there were also some ancient Greek scholars, such as Pythagoras, who believed that the Earth was round and were able to make calculations suggesting that it was a sphere. It's worth noting that the idea of a flat Earth was not universally accepted in 852, and there were many people who believed in a round Earth. Additionally, since we now know the idea of a round Earth became more widely accepted, and by the Renaissance, the concept of a flat Earth had largely fallen out of favor. |\n",
"\n",
"---\n",
"\n",
"Page 33\n"
]
}
],
"source": [
"print(response_gpt4o.source_nodes[4].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
}
+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: 1.2 MiB

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

@@ -0,0 +1,999 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "93ae9bad-b8cc-43de-ba7d-387e0155674c",
"metadata": {},
"source": [
"# Building a Natively Multimodal RAG Pipeline (over a Slide Deck)\n",
"\n",
"<a href=\"https://colab.research.google.com/github/run-llama/llama_parse/blob/main/examples/multimodal/multimodal_rag_slide_deck.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>\n",
"\n",
"In this cookbook we show you how to build a multimodal RAG pipeline over a slide deck, with text, tables, images, diagrams, and complex layouts.\n",
"\n",
"A gap of text-based RAG is that they struggle with purely text-based representations of complex documents. For instance, if a page contains a lot of images and diagrams, a text parser would need to rely on raw OCR to extract out text. You can also use a multimodal model (e.g. gpt-4o and up) to do text extraction, but this is inherently a lossy conversion.\n",
"\n",
"Instead a **native multimodal pipeline** stores both a text and image representation of a document chunk. They are indexed via embeddings (text or image), and during synthesis both text and image are directly fed to the multimodal model for synthesis.\n",
"\n",
"This can have the following advantages:\n",
"- **Robustness**: This solution is more robust than a pure text or even a pure image-based approach. In a pure text RAG approach, the parsing piece can be lossy. In a pure image-based approach, multimodal OCR is not perfect and may lose out against text parsing for text-heavy documents.\n",
"- **Cost Optimization**: You may choose to dynamically include text-only, or text + image depending on the content of the page.\n",
"\n",
"![mm_rag_diagram](./multimodal_rag_slide_deck_img.png)"
]
},
{
"cell_type": "markdown",
"id": "54e8d9a7-5036-4d32-818f-00b2e888521f",
"metadata": {},
"source": [
"## Setup"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "70ccdd53-e68a-4199-aacb-cfe71ad1ff0b",
"metadata": {},
"outputs": [],
"source": [
"import nest_asyncio\n",
"\n",
"nest_asyncio.apply()"
]
},
{
"cell_type": "markdown",
"id": "225c5556-a789-4386-a1ee-cce01dbeb6cf",
"metadata": {},
"source": [
"### Setup Observability\n",
"\n",
"We setup an integration with LlamaTrace (integration with Arize).\n",
"\n",
"If you haven't already done so, make sure to create an account here: https://llamatrace.com/login. Then create an API key and put it in the `PHOENIX_API_KEY` variable below."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "0eabee1f-290a-4c85-b362-54f45c8559ae",
"metadata": {},
"outputs": [],
"source": [
"!pip install -U llama-index-callbacks-arize-phoenix"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "aaeb245c-730b-4c34-ad68-708fdde0e6cb",
"metadata": {},
"outputs": [],
"source": [
"# setup Arize Phoenix for logging/observability\n",
"import llama_index.core\n",
"import os\n",
"\n",
"PHOENIX_API_KEY = \"<PHOENIX_API_KEY>\"\n",
"os.environ[\"OTEL_EXPORTER_OTLP_HEADERS\"] = f\"api_key={PHOENIX_API_KEY}\"\n",
"llama_index.core.set_global_handler(\n",
" \"arize_phoenix\", endpoint=\"https://llamatrace.com/v1/traces\"\n",
")"
]
},
{
"cell_type": "markdown",
"id": "fbb362db-b1b1-4eea-be1a-b1f78b0779d7",
"metadata": {},
"source": [
"### Load Data\n",
"\n",
"Here we load the [Conoco Phillips 2023 investor meeting slide deck](https://static.conocophillips.com/files/2023-conocophillips-aim-presentation.pdf)."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "8bce3407-a7d2-47e8-9eaf-ab297a94750c",
"metadata": {},
"outputs": [],
"source": [
"!mkdir data\n",
"!mkdir data_images\n",
"!wget \"https://static.conocophillips.com/files/2023-conocophillips-aim-presentation.pdf\" -O data/conocophillips.pdf"
]
},
{
"cell_type": "markdown",
"id": "246ba6b0-51af-42f9-b1b2-8d3e721ef782",
"metadata": {},
"source": [
"### Model Setup\n",
"\n",
"Setup models that will be used for downstream orchestration."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "16e2071d-bbc2-4707-8ae7-cb4e1fecafd3",
"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",
"embed_model = OpenAIEmbedding(model=\"text-embedding-3-large\")\n",
"llm = OpenAI(model=\"gpt-4o\")\n",
"\n",
"Settings.embed_model = embed_model\n",
"Settings.llm = llm"
]
},
{
"cell_type": "markdown",
"id": "e3f6416f-f580-4722-aaa9-7f3500408547",
"metadata": {},
"source": [
"## Use LlamaParse to Parse Text and Images\n",
"\n",
"In this example, use LlamaParse to parse both the text and images from the document.\n",
"\n",
"We parse out the text in two ways: \n",
"- in regular `text` mode using our default text layout algorithm\n",
"- in `markdown` mode using GPT-4o (`gpt4o_mode=True`). This also allows us to capture page screenshots"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "570089e5-238a-4dcc-af65-96e7393c2b4d",
"metadata": {},
"outputs": [],
"source": [
"from llama_parse import LlamaParse\n",
"\n",
"\n",
"parser_text = LlamaParse(result_type=\"text\")\n",
"parser_gpt4o = LlamaParse(result_type=\"markdown\", gpt4o_mode=True)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "ef82a985-4088-4bb7-9a21-0318e1b9207d",
"metadata": {},
"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",
"print(f\"Parsing PDF file...\")\n",
"md_json_objs = parser_gpt4o.get_json_result(\"data/conocophillips.pdf\")\n",
"md_json_list = md_json_objs[0][\"pages\"]"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "5318fb7b-fe6a-4a8a-b82e-4ed7b4512c37",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"# 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[10][\"md\"])"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "eeadb16c-97eb-4622-9551-b34d7f90d72f",
"metadata": {},
"outputs": [],
"source": [
"image_dicts = parser_gpt4o.get_images(md_json_objs, download_path=\"data_images\")"
]
},
{
"cell_type": "markdown",
"id": "fd3e098b-0606-4429-b48d-d4fe0140fc0e",
"metadata": {},
"source": [
"## Build Multimodal Index\n",
"\n",
"In this section we build the multimodal index over the parsed deck. \n",
"\n",
"We do this by creating **text** nodes from the document that contain metadata referencing the original image path.\n",
"\n",
"In this example we're indexing the text node for retrieval. The text node has a reference to both the parsed text as well as the image screenshot."
]
},
{
"cell_type": "markdown",
"id": "3aae2dee-9d85-4604-8a51-705d4db527f7",
"metadata": {},
"source": [
"#### Get Text Nodes"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "18c24174-05ce-417f-8dd2-79c3f375db03",
"metadata": {},
"outputs": [],
"source": [
"from llama_index.core.schema import TextNode\n",
"from typing import Optional"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "8e331dfe-a627-4e23-8c57-70ab1d9342e4",
"metadata": {},
"outputs": [],
"source": [
"# get pages loaded through llamaparse\n",
"import re\n",
"\n",
"\n",
"def get_page_number(file_name):\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"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "346fe5ef-171e-4a54-9084-7a7805103a13",
"metadata": {},
"outputs": [],
"source": [
"from copy import deepcopy\n",
"from pathlib import Path\n",
"\n",
"\n",
"# attach image metadata to the text nodes\n",
"def get_text_nodes(docs, image_dir=None, json_dicts=None):\n",
" \"\"\"Split docs into nodes, by separator.\"\"\"\n",
" nodes = []\n",
"\n",
" 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 = [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",
" image_file = image_files[idx]\n",
" chunk_metadata[\"image_path\"] = str(image_file)\n",
" if md_texts is not None:\n",
" chunk_metadata[\"parsed_text_markdown\"] = md_texts[idx]\n",
" chunk_metadata[\"parsed_text\"] = doc_chunk\n",
" node = TextNode(\n",
" text=\"\",\n",
" metadata=chunk_metadata,\n",
" )\n",
" nodes.append(node)\n",
"\n",
" return nodes"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "f591669c-5a8e-491d-9cef-0b754abbf26f",
"metadata": {},
"outputs": [],
"source": [
"# this will split into pages\n",
"text_nodes = get_text_nodes(docs_text, image_dir=\"data_images\", json_dicts=md_json_list)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "32c13950-c1db-435f-b5b4-89d62b8b7744",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"page_num: 11\n",
"image_path: data_images/1ddd5654-062b-4e19-b488-d66efc9c509d-page_39.jpg\n",
"parsed_text_markdown: # 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",
"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",
" 100% <60% 50% 6% at $60/BBL WTI\n",
" Reinvestment Rate Reinvestment Rate Reinvestment Rate10-YearCFO CAGR Planning PriceMid-Cycle\n",
" 2024-2032\n",
" 2 100%\n",
" 1 75%\n",
" 1 50%\n",
" 1 WTIat $80/BBL at S80/BBL\n",
" 25% 'S75/BBL $63/BBL WTI\n",
" WTI WTI at S80/BBL at S60/BBL at S60/BBL\n",
" Average Average WTI WTI WTI\n",
" 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 and cash from operations (CFO) are non-GAAP measures: Definitions and reconciliations are included in the Appendix ConocoPhillips\n"
]
}
],
"source": [
"print(text_nodes[10].get_content(metadata_mode=\"all\"))"
]
},
{
"cell_type": "markdown",
"id": "4f404f56-db1e-4ed7-9ba1-ead763546348",
"metadata": {},
"source": [
"#### Build Index\n",
"\n",
"Once the text nodes are ready, we feed into our vector store index abstraction, which will index these nodes into a simple in-memory vector store (of course, you should definitely check out our 40+ vector store integrations!)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "6ea53c31-0e38-421c-8d9b-0e3adaa1677e",
"metadata": {},
"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",
" StorageContext,\n",
" VectorStoreIndex,\n",
" load_index_from_storage,\n",
")\n",
"\n",
"if not os.path.exists(\"storage_nodes\"):\n",
" index = VectorStoreIndex(text_nodes, embed_model=embed_model)\n",
" # save index to disk\n",
" index.set_index_id(\"vector_index\")\n",
" index.storage_context.persist(\"./storage_nodes\")\n",
"else:\n",
" # rebuild storage context\n",
" storage_context = StorageContext.from_defaults(persist_dir=\"storage_nodes\")\n",
" # load index\n",
" index = load_index_from_storage(storage_context, index_id=\"vector_index\")\n",
"\n",
"retriever = index.as_retriever()"
]
},
{
"cell_type": "markdown",
"id": "5f0e33a4-9422-498d-87ee-d917bdf74d80",
"metadata": {},
"source": [
"## Build Multimodal Query Engine\n",
"\n",
"We now use LlamaIndex abstractions to build a **custom query engine**. In contrast to a standard RAG query engine that will retrieve the text node and only put that into the prompt (response synthesis module), this custom query engine will also load the image document, and put both the text and image document into the response synthesis module."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "35a94be2-e289-41a6-92e4-d3cb428fb0c8",
"metadata": {},
"outputs": [],
"source": [
"from llama_index.core.query_engine import CustomQueryEngine, SimpleMultiModalQueryEngine\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 ImageNode, NodeWithScore, MetadataMode\n",
"from llama_index.core.prompts import PromptTemplate\n",
"from llama_index.core.base.response.schema import Response\n",
"from typing import Optional\n",
"\n",
"\n",
"gpt_4o = OpenAIMultiModal(model=\"gpt-4o\", max_new_tokens=4096)\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",
"\n",
"class MultimodalQueryEngine(CustomQueryEngine):\n",
" \"\"\"Custom multimodal Query Engine.\n",
"\n",
" Takes in a retriever to retrieve a set of document nodes.\n",
" Also takes in a prompt template and multimodal model.\n",
"\n",
" \"\"\"\n",
"\n",
" qa_prompt: PromptTemplate\n",
" retriever: BaseRetriever\n",
" multi_modal_llm: OpenAIMultiModal\n",
"\n",
" def __init__(self, qa_prompt: Optional[PromptTemplate] = None, **kwargs) -> None:\n",
" \"\"\"Initialize.\"\"\"\n",
" super().__init__(qa_prompt=qa_prompt or QA_PROMPT, **kwargs)\n",
"\n",
" def custom_query(self, query_str: str):\n",
" # retrieve text nodes\n",
" nodes = self.retriever.retrieve(query_str)\n",
" # create ImageNode items from text nodes\n",
" image_nodes = [\n",
" NodeWithScore(node=ImageNode(image_path=n.metadata[\"image_path\"]))\n",
" for n in nodes\n",
" ]\n",
"\n",
" # create context string from text nodes, dump into the prompt\n",
" context_str = \"\\n\\n\".join(\n",
" [r.get_content(metadata_mode=MetadataMode.LLM) for r in nodes]\n",
" )\n",
" fmt_prompt = self.qa_prompt.format(context_str=context_str, query_str=query_str)\n",
"\n",
" # synthesize an answer from formatted text and images\n",
" llm_response = 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_response),\n",
" source_nodes=nodes,\n",
" metadata={\"text_nodes\": text_nodes, \"image_nodes\": image_nodes},\n",
" )\n",
"\n",
" return response"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "0890be59-fb12-4bb5-959b-b2d9600f7774",
"metadata": {},
"outputs": [],
"source": [
"query_engine = MultimodalQueryEngine(\n",
" retriever=index.as_retriever(similarity_top_k=9), multi_modal_llm=gpt_4o\n",
")"
]
},
{
"cell_type": "markdown",
"id": "a92aa4f1-7501-4711-b054-f02338e54e74",
"metadata": {},
"source": [
"### Define Baseline\n",
"\n",
"In addition, we define a \"baseline\" where we rely only on text-based indexing. Here we define an index using only the nodes that are parsed in text-mode from LlamaParse. \n",
"\n",
"**NOTE**: We don't currently include the markdown-parsed text because that was parsed with GPT-4o, so already uses a multimodal model during the text extraction phase.\n",
"\n",
"It is of course a valid experiment to compare RAG where multimodal extraction only happens during indexing, vs. the current multimodal RAG implementation where images are fed during synthesis to the LLM. "
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "c0b15a48-d177-4666-aec2-98ee90664642",
"metadata": {},
"outputs": [],
"source": [
"def get_nodes(docs):\n",
" \"\"\"Split docs into nodes, by separator.\"\"\"\n",
" nodes = []\n",
" for doc in docs:\n",
" doc_chunks = doc.text.split(\"\\n---\\n\")\n",
" for doc_chunk in doc_chunks:\n",
" node = TextNode(\n",
" text=doc_chunk,\n",
" metadata=deepcopy(doc.metadata),\n",
" )\n",
" nodes.append(node)\n",
"\n",
" return nodes"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "2065d2c6-d6ba-4ee3-8e9e-dbc83cbcec1b",
"metadata": {},
"outputs": [],
"source": [
"base_nodes = get_nodes(docs_text)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "bcaea1a8-26c9-4385-8f62-32855aa898b6",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"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(base_nodes[13].get_content(metadata_mode=\"all\"))"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "f6bcfbc6-4e9b-41ad-ad81-1c4245b95cd5",
"metadata": {},
"outputs": [],
"source": [
"base_index = VectorStoreIndex(base_nodes, embed_model=embed_model)\n",
"base_query_engine = base_index.as_query_engine(llm=llm, similarity_top_k=9)"
]
},
{
"cell_type": "markdown",
"id": "1f94ef26-0df5-4468-a156-903d686f02ce",
"metadata": {},
"source": [
"## Build a Multimodal Agent\n",
"\n",
"Build an agent around the multimodal query engine. This gives you agent capabilities like query planning/decomposition and memory around a central QA interface."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "5b7a8c5f-39fc-4d04-8c56-3642f5718437",
"metadata": {},
"outputs": [],
"source": [
"from llama_index.core.tools import QueryEngineTool\n",
"from llama_index.core.agent import FunctionCallingAgentWorker\n",
"\n",
"\n",
"vector_tool = QueryEngineTool.from_defaults(\n",
" query_engine=query_engine,\n",
" name=\"vector_tool\",\n",
" description=(\n",
" \"Useful for retrieving specific context from the data. Do NOT select if question asks for a summary of the data.\"\n",
" ),\n",
")\n",
"agent = FunctionCallingAgentWorker.from_tools(\n",
" [vector_tool], llm=llm, verbose=True\n",
").as_agent()"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "2b4f7eb1-d247-45fa-bb41-c02fc353a22a",
"metadata": {},
"outputs": [],
"source": [
"# define a similar agent for the baseline\n",
"base_vector_tool = QueryEngineTool.from_defaults(\n",
" query_engine=base_query_engine,\n",
" name=\"vector_tool\",\n",
" description=(\n",
" \"Useful for retrieving specific context from the data. Do NOT select if question asks for a summary of the data.\"\n",
" ),\n",
")\n",
"base_agent = FunctionCallingAgentWorker.from_tools(\n",
" [base_vector_tool], llm=llm, verbose=True\n",
").as_agent()"
]
},
{
"cell_type": "markdown",
"id": "2336f98b-c0a1-413a-849d-8a89bacb90b5",
"metadata": {},
"source": [
"## Try out Queries\n",
"\n",
"Let's try out queries against these documents and compare against each other."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "d78e53cf-35cb-4ef8-b03e-1b47ba15ae64",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"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 production base geographies\"}\n",
"=== Function Output ===\n",
"ConocoPhillips' production base geographies include:\n",
"\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",
"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",
"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",
"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": [
"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))"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "d584c560-8f49-4c10-a4db-2e0d3b7085d2",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"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",
"## ~20 BBOE of Resource\n",
"Under $40/BBL Cost of Supply\n",
"\n",
"### ~ $32/BBL\n",
"Average Cost of Supply\n",
"\n",
"### WTI Cost of Supply ($/BBL)\n",
"\n",
"| Cost ($/BBL) | Resource (BBOE) |\n",
"|--------------|-----------------|\n",
"| $0 | 0 |\n",
"| $10 | |\n",
"| $20 | |\n",
"| $30 | |\n",
"| $40 | |\n",
"| $50 | |\n",
"\n",
"- **Legend:**\n",
" - Lower 48\n",
" - Canada\n",
" - Alaska\n",
" - EMENA\n",
" - Asia Pacific\n",
"\n",
"*Costs assume a mid-cycle price environment of $60/BBL WTI.*\n",
"\n",
"## Diverse Production Base\n",
"10-Year Plan Cumulative Production (BBOE)\n",
"\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[7].get_content(metadata_mode=\"all\"))"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "d21d694b-6618-4d04-a6f6-8b0c2625f539",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"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": [
"print(str(base_response))"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "d3afccae-ad8d-4c5d-9d93-810dba413a5d",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"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(base_response.source_nodes[1].get_content(metadata_mode=\"all\"))"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "llama_index_v3",
"language": "python",
"name": "llama_index_v3"
},
"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
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 271 KiB

File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -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
}
+390
View File
@@ -0,0 +1,390 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "e0647976-5597-4899-8678-e9a73c19f18b",
"metadata": {},
"source": [
"# LlamaParse over Powerpoint Files\n",
"\n",
"In this notebook we show you how to build a RAG pipeline over [our talk at PyData Global](https://docs.google.com/presentation/d/1rFQ0hPyYja3HKRdGEgjeDxr0MSE8wiQ2iu4mDtwR6fc/edit?usp=sharing) in 2023.\n",
"\n",
"We use LlamaParse to load in our slides in .pptx format, and use LlamaIndex to build a RAG pipeline over these files.\n",
"\n",
"**NOTE**: LlamaParse is capable of image extraction through JSON mode, in this notebook we stick with text."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "14cdcfaf-88b4-4489-9910-e362e0ccec53",
"metadata": {},
"outputs": [],
"source": [
"import nest_asyncio\n",
"\n",
"nest_asyncio.apply()\n",
"\n",
"from llama_parse import LlamaParse"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "6f5b5841-dd3e-4169-9bd4-6a672b5b34ee",
"metadata": {},
"outputs": [],
"source": [
"import os\n",
"\n",
"os.environ[\"LLAMA_CLOUD_API_KEY\"] = \"llx-\""
]
},
{
"cell_type": "markdown",
"id": "a2a619a1-fdd4-4ff0-85f8-94c125c275eb",
"metadata": {},
"source": [
"## Download Data\n",
"\n",
"First, download the slides from https://docs.google.com/presentation/d/1rFQ0hPyYja3HKRdGEgjeDxr0MSE8wiQ2iu4mDtwR6fc/edit?usp=sharing and export in .pptx format, and put it in the folder that you're running this notebook.\n",
"\n",
"Name the file `pydata_global.pptx`."
]
},
{
"cell_type": "markdown",
"id": "a7e697d9-4463-4be4-908c-0a3e9179a342",
"metadata": {},
"source": [
"## [Basic] Build a RAG Pipeline over Powerpoint Text\n",
"\n",
"In this example, we use LlamaParse in markdown mode to extract out text from the slides, and we build a top-k RAG pipeline over it.\n",
"\n",
"**Notes**: \n",
"- This does not use our `MarkdownElementNodeParser`, which is tailored for documents with tables.\n",
"- This also does not parse out images (we show that in the next section).\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "0dd0f860-8e92-43a7-9443-ad1a4fb9365c",
"metadata": {},
"outputs": [],
"source": [
"parser = LlamaParse(result_type=\"markdown\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "fd932bef-ba82-4449-b7a0-5c2a9b55089f",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Started parsing the file under job_id 9c687e37-4239-4c2f-b2a1-2564bfc98473\n"
]
}
],
"source": [
"docs = parser.load_data(\"pydata_global.pptx\")"
]
},
{
"cell_type": "markdown",
"id": "0f41c2bc-02cd-49b5-a98c-f986faa8fffc",
"metadata": {},
"source": [
"Let's take a look at a few slides."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "2a73e553-2194-4ac9-9764-0edab0d6fdce",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"# Building and Productionizing RAG\n",
"\n",
"Jerry Liu, LlamaIndex co-founder/CEO\n",
"---\n",
"|Content|Page Number|\n",
"|---|---|\n",
"|Document Processing| |\n",
"|Tagging & Extraction| |\n",
"|Knowledge Base| |\n",
"|Knowledge Search & QA| |\n",
"|Workflow:| |\n",
"|Read latest messages from user A| |\n",
"|Send email suggesting next-steps| |\n",
"|Document| |\n",
"|Human:| |\n",
"|Agent:| |\n",
"|Topic:| |\n",
"|Summary:| |\n",
"|Author:| |\n",
"|Conversational Agent| |\n",
"|Workflow Automation| |\n",
"---\n",
"Context\n",
"\n",
"- LLMs are a phenomenal piece of technology for knowledge generation and reasoning. They are pre-trained on large amounts of publicly available data.\n",
"\n",
"Use Cases\n",
"\n",
"- Question-Answering\n",
"- Text Generation\n",
"- Summarization\n",
"- Planning\n",
"\n",
"# LLMs\n",
"---\n",
"|Context|\n",
"|---|\n",
"|How do we best augment LLMs with our own private data?|\n",
"|Raw Files|APIs|\n",
"| |salesforce|?|\n",
"| | |Use Cases|\n",
"| | |Question-Answering|\n",
"| | |Text Generation|\n",
"| | |Summarization|\n",
"|Vector Stores|SQL DBs|\n",
"| | |Planning|\n",
"| |LLMs|\n",
"| |Milvus|\n",
"---\n",
"Paradigms for inserting knowledge\n",
"\n",
"Retrieval Augmentation - Fix pe model, put context into pe prompt\n",
"Before college pe two main pings I worked on, outside of school, were writing and programming. I didn't write essays. I wrote what beginning writers were supposed to write pen, and probably still are: short stories. My stories were awful. They had hardly any plot, just characters wip strong feelings, which I imagined made pem deep...\n",
"\n",
"Input Prompt\n",
"\n",
"Here is the context:\n",
"\n",
"Before college the two main things...\n",
"\n",
"Given the context, answer the following question:\n",
"\n",
"{query_str} LLM\n",
"---\n",
"Paradigms for inserting knowledge\n",
"\n",
"Fine-tuning - baking knowledge into pe weights of pe network\n",
"Before college pe two main pings I worked on, outside of school, were writing and programming. I didn't write essays. I wrote what beginning writers were supposed to write pen, and probably still are: short stories. My stories were awful. They had hardly any plot, just characters wip strong feelings, which I imagined made pem deep... LLM RLHF, Adam, SGD, etc.\n",
"---\n",
"## LlamaIndex: A data framework for LLM applications\n",
"\n",
"|Data Ingestion (LlamaHub 🦙)|Data Structures|Queries|\n",
"|---|---|---|\n",
"|Connect your existing data sources and data formats (APIs, PDFs, docs, SQL, etc.)|Store and index your data for different use cases. Integrate with different dbs (vector db, graph db, kv db)|Retrieve and query over data. Includes: QA, Summarization, Agents, and more|\n",
"---\n",
"# quickstart py\n",
"\n",
"from Llama_index import VectorStoreIndex, SimpleDirectoryReader\n",
"\n",
"SimpleDirectoryReader( ' data' ) . Load_datal)\n",
"\n",
"documents\n",
"\n",
"VectorStoreIndex.from_documents\n",
"\n",
"indexdocuments_\n",
"\n",
"index.as_query_engine()\n",
"\n",
"query_engine\n",
"\n",
"query_engine.query ( \"What did the authordo growingup?\" )\n",
"\n",
"response\n",
"\n",
"print(str(response) )Codelmage\n",
"---\n",
"NO_CONTENT_HERE\n",
"---\n",
"|Data Ingestion / Parsing|Data Querying|\n",
"|---|---|\n",
"|Chunk| |\n",
"|Chunk| |\n",
"|Doc|Chunk|\n",
"|Chunk|Chunk|\n",
"| |Vector|Chunk|LLM|\n",
"| | |Database|\n",
"|Chunk| |\n",
"| |5 Lines of Code in LlamaIndex!|\n",
"---\n",
"|Current RAG Stack (Data Ingestion/Parsing)|Process:|\n",
"|---|---|\n",
"|● Split up document(s) into even chunks.| |\n",
"|● Each chunk is a piece of raw text.| |\n",
"|Chunk|● Generate embedding for each chunk (e.g. OpenAI embeddings, sentence_transformer)|\n",
"|Chunk|● Store each chunk into a vector database|\n",
"|Doc|Chunk|\n",
"|Chunk|Vector Database|\n",
"|Chunk| |\n",
"---\n",
"|Current RAG Stack (Querying)|\n",
"|---|\n",
"|Process:|\n",
"|● Find top-k most similar chunks from vector database collection|\n",
"|● Plug into LLM response synthesis module|\n",
"|Chunk|Chunk|LLM|\n",
"|Vector|Chunk| |\n",
"|Database|\n",
"---\n",
"|Current RAG Stack (Querying)|\n",
"|---|\n",
"|Process:|\n",
"|● Find top-k most similar chunks from vector database collection|\n",
"|● Plug into LLM response synthesis module|\n",
"|Chunk|LLM|\n",
"|Chunk|\n",
"|Vector|\n",
"|Database|\n",
"|Retrieval|Synthesis|\n",
"---\n",
"|Query|Nodel|Response|Nodez|\n",
"|---|---|---|---|\n",
"|Create and Refine|Intermediate| | |\n",
"| | |Final|Response|\n",
"---\n",
"|Query|Node1|Node2|Node3|Node4|\n",
"|---|---|---|---|---|\n",
"|Tree Summarize| | | | |\n",
"---\n",
"Quickstart\n",
"\n",
"Link to Google Colab\n",
"---\n",
"NO_CONTENT_HERE\n",
"---\n",
"# Challenges with Naive RAG\n",
"\n",
"- Failure Modes\n",
"- Quality-Related (Hallucination, Accuracy)\n",
"- Non-Quality-Related (Latency, Cost, Syncing)\n",
"---\n",
"## Challenges with Naive RAG (Response Quality)\n",
"\n",
"|Bad Retrieval|Low Precision: Not all chunks in retrieved set are relevant|Hallucination + Lost in the Middle Problems|\n",
"|---|---|---|\n",
"| |Low Recall: Now all relevant chunks are retrieved.|Lacks enough context for LLM to synthesize an answer|\n",
"| |Outdated information: The data is redundant or out of date.| |\n",
"---\n",
"## Challenges with Naive RAG (Response Quality)\n",
"\n",
"|Bad Retrieval|Low Precision: Not all chunks in retrieved set are relevant|Hallucination + Lost in the Middle Problems|\n",
"|---|---|---|\n",
"| |Low Recall: Now all relevant chunks are retrieved.|Lacks enough context for LLM to synthesize an answer|\n",
"| |Outdated information: The data is redundant or out of date.| |\n",
"|Bad Response Generation|Hallucination: Model makes up an answer that isnt in the context.| |\n",
"| |Irrelevance: Model makes up an answer that doesnt answer the question.| |\n",
"| |Toxicity/Bias: Model makes up an answer t\n"
]
}
],
"source": [
"print(docs[0].get_content()[:5000])"
]
},
{
"cell_type": "markdown",
"id": "c2fa0a1a-1ed8-4a5a-a0c1-5792fe32634b",
"metadata": {},
"source": [
"## Build a RAG pipeline over these documents\n",
"\n",
"We now use LlamaIndex to build a RAG pipeline over these powerpoint slides."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "c779547f-e4f7-4c84-9786-2b6b749827ab",
"metadata": {},
"outputs": [],
"source": [
"from llama_index.core import VectorStoreIndex"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "68b3a95e-ce19-4df1-9fdd-e6efb2fc423a",
"metadata": {},
"outputs": [],
"source": [
"index = VectorStoreIndex.from_documents(docs)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "a2ae28f6-4b3a-4130-8e65-0921b7678739",
"metadata": {},
"outputs": [],
"source": [
"query_engine = index.as_query_engine()"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "232091ee-aa22-4f51-838c-410024acc344",
"metadata": {},
"outputs": [],
"source": [
"response = query_engine.query(\n",
" \"What are some response quality challenges with naive RAG?\"\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "75f32aa7-c308-4221-af60-779822cfdba1",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Some response quality challenges with naive RAG include issues related to bad retrieval, such as low precision where not all retrieved chunks are relevant, leading to problems like hallucination and being lost in the middle. Additionally, low recall can occur when not all relevant chunks are retrieved, resulting in a lack of sufficient context for the language model to synthesize an answer. Outdated information in the retrieved data can also pose a challenge. On the response generation side, challenges include hallucination where the model generates an answer not present in the context, irrelevance where the answer does not address the question, and toxicity/bias where the answer is harmful or offensive.\n"
]
}
],
"source": [
"print(str(response))"
]
}
],
"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
}
@@ -0,0 +1,335 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# LlamaParse - Parsing Financial Powerpoints 📊\n",
"\n",
"In this cookbook we show you how to use LlamaParse to parse a financial powerpoint."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Installation\n",
"\n",
"Parsing instruction are part of the LlamaParse API. They can be access by directly specifying the parsing_instruction parameter in the API or by using LlamaParse python module (which we will use for this tutorial).\n",
"\n",
"To install llama-parse, just get it from `pip`:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"%pip install llama-index\n",
"%pip install llama-parse\n",
"%pip install torch transformers python-pptx Pillow"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## API Key\n",
"\n",
"The use of LlamaParse requires an API key which you can get here: https://cloud.llamaindex.ai/parse"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import os\n",
"\n",
"os.environ[\"LLAMA_CLOUD_API_KEY\"] = \"llx-...\"\n",
"os.environ[\"OPENAI_API_KEY\"] = \"sk-...\""
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**NOTE**: Since LlamaParse is natively async, running the sync code in a notebook requires the use of nest_asyncio.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import nest_asyncio\n",
"\n",
"nest_asyncio.apply()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Importing the package\n",
"\n",
"To import llama_parse simply do:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from llama_parse import LlamaParse"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Using LlamaParse to Parse Presentations\n",
"\n",
"Like Powerpoints, presentations are often hard to extract for RAG. With LlamaParse we can now parse them and unclock their content of presentations for RAG.\n",
"\n",
"Let's download a financial report from the World Meteorological Association."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"! mkdir data; wget \"https://meetings.wmo.int/Cg-19/PublishingImages/SitePages/FINAC-43/7%20-%20EC-77-Doc%205%20Financial%20Statements%20for%202022%20(FINAC).pptx\" -O data/presentation.pptx"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Parsing the presentation\n",
"\n",
"Now let's parse it into Markdown with LlamaParse and the default LlamaIndex parser.\n",
"\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Llama Index default"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from llama_index.core import SimpleDirectoryReader\n",
"\n",
"vanilla_documents = SimpleDirectoryReader(\"./data/\").load_data()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Llama Parse"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Started parsing the file under job_id 56724c0d-e45a-4e30-ae8c-e416173c608a\n"
]
}
],
"source": [
"llama_parse_documents = LlamaParse(result_type=\"markdown\").load_data(\n",
" \"./data/presentation.pptx\"\n",
")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Let's take a look at the parsed output from an example slide (see image below).\n",
"\n",
"As we can see the table is faithfully extracted!"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"ation and mitigation\n",
"---\n",
"|Item|31 Dec 2022|31 Dec 2021|Change|\n",
"|---|---|---|---|\n",
"|Payables and accruals|4,685|4,066|619|\n",
"|Employee benefits|127,215|84,676|42,539|\n",
"|Contributions received in advance|6,975|10,192|(3,217)|\n",
"|Unearned revenue from exchange transactions|20|651|(631)|\n",
"|Deferred Revenue|71,301|55,737|15,564|\n",
"|Borrowings|28,229|29,002|(773)|\n",
"|Funds held in trust|30,373|29,014|1,359|\n",
"|Provisions|1,706|1,910|(204)|\n",
"|Total Liabilities|270,504|215,248|55,256|\n",
"---\n",
"## Liabilities\n",
"\n",
"Employee Ben\n"
]
}
],
"source": [
"print(llama_parse_documents[0].get_content()[-2800:-2300])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Compared against the original slide image.\n",
"![Demo](demo_ppt_financial_1.png)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Comparing the two for RAG\n",
"\n",
"The main difference between LlamaParse and the previous directory reader approach, it that LlamaParse will extract the document in a structured format, allowing better RAG."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Query Engine on SimpleDirectoryReader results"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from llama_index.core import VectorStoreIndex, SimpleDirectoryReader\n",
"\n",
"vanilla_index = VectorStoreIndex.from_documents(vanilla_documents)\n",
"vanilla_query_engine = vanilla_index.as_query_engine()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Query Engine on LlamaParse Results\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"llama_parse_index = VectorStoreIndex.from_documents(llama_parse_documents)\n",
"llama_parse_query_engine = llama_parse_index.as_query_engine()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Liability provision\n",
"What was the liability provision as of Dec 31 2021?\n",
"\n",
"<!-- <img src=\"https://drive.usercontent.google.com/download?id=184jVq0QyspDnmCyRfV0ebmJJxmAOJHba&authuser=0\" /> -->"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"The liability provision as of December 31, 2021, included Employee Benefit Liabilities, Contributions received in advance (assessed contributions), and Deferred revenue.\n"
]
}
],
"source": [
"vanilla_response = vanilla_query_engine.query(\n",
" \"What was the liability provision as of Dec 31 2021?\"\n",
")\n",
"print(vanilla_response)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"The liability provision as of December 31, 2021, was 1,910 CHF.\n"
]
}
],
"source": [
"llama_parse_response = llama_parse_query_engine.query(\n",
" \"What was the liability provision as of Dec 31 2021?\"\n",
")\n",
"print(llama_parse_response)"
]
}
],
"metadata": {
"colab": {
"provenance": []
},
"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": 4
}
File diff suppressed because it is too large Load Diff
Binary file not shown.

After

Width:  |  Height:  |  Size: 986 KiB

@@ -0,0 +1,359 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "f20600ce-d57a-446e-b033-3aadeec39c1b",
"metadata": {},
"source": [
"# LlamaParse with GPT-4o\n",
"\n",
"\n",
"<a href=\"https://colab.research.google.com/github/run-llama/llama_parse/blob/main/examples/test_tesla_impact_report/test_gpt4o.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>\n",
"\n",
"GPT-4o is a [fully multimodal model by OpenAI](https://openai.com/index/hello-gpt-4o/) released in May 2024. It matches GPT-4 Turbo performance in text and code, and has significantly improved vision and audio capabilities.\n",
"\n",
"The expanded vision/audio capabilities mean that it can be used for document parsing, by treating each page as an image and performing document extraction. We support using GPT-4o natively in LlamaParse for document parsing. The notebook below walks you through an example of using GPT-4o over the Tesla impact report.\n",
"\n",
"**NOTE**: The pricing for LlamaParse + gpt4o is an order more expensive than using LlamaParse by default. Currently, every page parsed with gpt4o counts for 10 pages in the LlamaParse usage tracker.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "86b173ac-9fce-4813-bdf1-6dd7d93a491d",
"metadata": {},
"outputs": [],
"source": [
"import nest_asyncio\n",
"\n",
"nest_asyncio.apply()"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "ecc5eba5-96ce-4db7-bba1-f9ece33e681c",
"metadata": {},
"outputs": [],
"source": [
"import os"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "b805592b-d1a5-4cd2-b916-348f66ca7941",
"metadata": {},
"outputs": [],
"source": [
"os.environ[\"LLAMA_CLOUD_API_KEY\"] = \"<LLAMA_CLOUD_API_KEY>\""
]
},
{
"cell_type": "markdown",
"id": "6e73e3c4-9e09-4cba-805f-326c82be812d",
"metadata": {},
"source": [
"### Use LlamaParse with `gpt4o_mode=True`\n",
"\n",
"By turning on gpt4o, we use GPT-4o multimodal capabilities to do document parsing per page instead of the LlamaParse default pipeline.\n",
"\n",
"We load a snippet of the [2019 Tesla impact report](https://www.tesla.com/ns_videos/2019-tesla-impact-report.pdf). **NOTE**: The report is 57 pages, but will count for 570 pages in LlamaParse due to GPT-4o usage (which is approximately $1.71 USD).\n",
"\n",
"You can optionally choose to provide a `gpt4o_api_key`. If you do this, then we will use your API key to make GPT-4o calls, and your LlamaParse usage will be counted as if `gpt4o_mode` was not turned on (each page will be counted as a page instead of 10 pages). "
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "aaa2ec5d-f27c-4262-80bf-e57daacff182",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"--2024-05-21 00:10:32-- https://www.dropbox.com/scl/fi/vu6w1dsfo5eddydz13ssm/2019-tesla-impact-report-15.pdf?rlkey=ik8lfqbg2p1ervss4qqt3xose&st=70j04z8j&dl=1\n",
"Resolving www.dropbox.com (www.dropbox.com)... 2620:100:6057:18::a27d:d12, 162.125.13.18\n",
"Connecting to www.dropbox.com (www.dropbox.com)|2620:100:6057:18::a27d:d12|:443... connected.\n",
"HTTP request sent, awaiting response... 302 Found\n",
"Location: https://uc872df1ff4ea2fecd3d024fa97a.dl.dropboxusercontent.com/cd/0/inline/CTTnZs8U4V1GtUCNxoB7INwmLq2yU97Q6QbWS6uVnb_XdHe368GrqF0zLDEKTnpc-x7utwNUUpMvWjLyrujrqNVrbGKTKa6hwHu5BxYPA2zXYrzdAEZyeve274xpHZKFywQ/file?dl=1# [following]\n",
"--2024-05-21 00:10:33-- https://uc872df1ff4ea2fecd3d024fa97a.dl.dropboxusercontent.com/cd/0/inline/CTTnZs8U4V1GtUCNxoB7INwmLq2yU97Q6QbWS6uVnb_XdHe368GrqF0zLDEKTnpc-x7utwNUUpMvWjLyrujrqNVrbGKTKa6hwHu5BxYPA2zXYrzdAEZyeve274xpHZKFywQ/file?dl=1\n",
"Resolving uc872df1ff4ea2fecd3d024fa97a.dl.dropboxusercontent.com (uc872df1ff4ea2fecd3d024fa97a.dl.dropboxusercontent.com)... 2620:100:6057:15::a27d:d0f, 162.125.13.15\n",
"Connecting to uc872df1ff4ea2fecd3d024fa97a.dl.dropboxusercontent.com (uc872df1ff4ea2fecd3d024fa97a.dl.dropboxusercontent.com)|2620:100:6057:15::a27d:d0f|:443... connected.\n",
"HTTP request sent, awaiting response... 302 Found\n",
"Location: /cd/0/inline2/CTSaARDHbxvyEEgefshmsHLbuXkgV1Rmr-ItVhk5lPuZXkLlNnZMZWCF9YF5j4t2lLs4VurFW2VI1Q4A6ZFi8D2RXJmUG3wdgJhR6qSaBpwRZxjB_vk8qkJb8h1jRDaL7ATK6XYTHncab_aoPWzB62vrZ9yXUM0Mr-EdCX1k-hMbzXLV2dorA71IuFPY8ICkTemRWaG6VhBd3bV0C5AkMsAqy90w6Kez1ySFO06UkrxLSmkCaKdFgVoLcUVO2PLv4rGv6AuZOF_kqwsHdh82J9DQU4PMMyg-f5ChSGGSCKgmUfTBE2qP1eISP-GXSB91yWwMf-7rxGtM8MpDp-AL5jxYZxhZcmZn1cU8Or_8OOZrxg/file?dl=1 [following]\n",
"--2024-05-21 00:10:33-- https://uc872df1ff4ea2fecd3d024fa97a.dl.dropboxusercontent.com/cd/0/inline2/CTSaARDHbxvyEEgefshmsHLbuXkgV1Rmr-ItVhk5lPuZXkLlNnZMZWCF9YF5j4t2lLs4VurFW2VI1Q4A6ZFi8D2RXJmUG3wdgJhR6qSaBpwRZxjB_vk8qkJb8h1jRDaL7ATK6XYTHncab_aoPWzB62vrZ9yXUM0Mr-EdCX1k-hMbzXLV2dorA71IuFPY8ICkTemRWaG6VhBd3bV0C5AkMsAqy90w6Kez1ySFO06UkrxLSmkCaKdFgVoLcUVO2PLv4rGv6AuZOF_kqwsHdh82J9DQU4PMMyg-f5ChSGGSCKgmUfTBE2qP1eISP-GXSB91yWwMf-7rxGtM8MpDp-AL5jxYZxhZcmZn1cU8Or_8OOZrxg/file?dl=1\n",
"Reusing existing connection to [uc872df1ff4ea2fecd3d024fa97a.dl.dropboxusercontent.com]:443.\n",
"HTTP request sent, awaiting response... 200 OK\n",
"Length: 26199694 (25M) [application/binary]\n",
"Saving to: 2019-tesla-impact-report-15.pdf\n",
"\n",
"2019-tesla-impact-r 100%[===================>] 24.99M 30.5MB/s in 0.8s \n",
"\n",
"2024-05-21 00:10:35 (30.5 MB/s) - 2019-tesla-impact-report-15.pdf saved [26199694/26199694]\n",
"\n"
]
}
],
"source": [
"!wget \"https://www.dropbox.com/scl/fi/vu6w1dsfo5eddydz13ssm/2019-tesla-impact-report-15.pdf?rlkey=ik8lfqbg2p1ervss4qqt3xose&st=70j04z8j&dl=1\" -O \"2019-tesla-impact-report-15.pdf\""
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "f46991c1-031b-461f-b9a6-9237a821f4c8",
"metadata": {},
"outputs": [],
"source": [
"from llama_parse import LlamaParse\n",
"\n",
"parser_gpt4o = LlamaParse(\n",
" result_type=\"markdown\",\n",
" # api_key=api_key,\n",
" gpt4o_mode=True,\n",
" split_by_page=True,\n",
" # gpt4o_api_key=\"<gpt4o_api_key>\"\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "1136ba82-074b-489d-9b0a-d609ccbf02b6",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Started parsing the file under job_id bf7d4619-3e26-479d-80e9-25702186ef32\n",
"."
]
}
],
"source": [
"documents_gpt4o = parser_gpt4o.load_data(\"./2019-tesla-impact-report-15.pdf\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "9e65c54f-3e4c-4c78-b1e8-a55ebeba1f24",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"# Mission & Tesla Ecosystem\n",
"\n",
"Climate change is reaching alarming levels in large part due to emissions from burning fossil fuels for transportation and electricity generation. In 2016, carbon dioxide (CO2) concentration levels in the atmosphere exceeded the 400 parts per million threshold on a sustained basis - a level that climate scientists believe will have a catastrophic impact on the environment. Worse, annual global CO2 emissions continue to increase and have approximately doubled over the past 50 years to over 43 gigatons in 2019. The worlds current path is unwise and unsustainable.\n",
"\n",
"The world cannot reduce CO2 emissions without addressing both energy generation and consumption. And the world cannot address its energy habits without first directly reducing emissions in the transportation and energy sectors. We are focused on creating a complete energy and transportation ecosystem from solar generation and energy storage to all-electric vehicles that produce zero tailpipe emissions.\n",
"\n",
"Since the onset of shelter-in-place orders and travel restrictions due to COVID-19, we have seen dramatic increases in air quality across the planet, as well as projections for CO2 emissions to drop in excess of 4% in 2020 compared to pre-COVID-19 levels, according to researchers. Because these improvements in air quality and reductions in CO2 are a result of a global economic disruption and not due to systemic changes in how we produce and consume energy, they are not expected to be sustained absent intervention. However, these changes have shown us the positive impacts of reduced pollution in a very short period of time. At Tesla, we believe that we all have an unprecedented opportunity to learn from this disruption and accelerate the deployment of clean energy solutions as part of a recovery for all economies throughout the world, and we will actively continue to advocate for the realization of these long-term changes.\n",
"\n",
"| Global Greenhouse Gas (GHG) Emissions by Economic Sector |\n",
"|----------------------------------------------------------|\n",
"| ![Pie Chart](image_url) |\n",
"\n",
"| Sector | Percentage |\n",
"|---------------------------------------------|------------|\n",
"| Electricity & Heat Production* | 31% |\n",
"| Agriculture, Forestry & Other Land Use | 20% |\n",
"| Industry | 18% |\n",
"| Transportation* | 16% |\n",
"| Other Energy | 9% |\n",
"| Buildings | 6% |\n",
"\n",
"*Tesla-related sectors. Source: World Resources Institute\n",
"\n",
"According to the Global Carbon project, when fully tallied, total carbon emissions from 2019 are expected to hit another record high of over 43 gigatons for the year. Energy use through electricity and heat production (31%) and transportation (16%) are significant drivers of these GHG emissions.\n"
]
}
],
"source": [
"print(documents_gpt4o[3].get_content())"
]
},
{
"cell_type": "markdown",
"id": "d62cbb62-37ea-4370-9411-d979aa3a627e",
"metadata": {},
"source": [
"## Build RAG pipeline over the Parsed Report\n",
"\n",
"We now try building a RAG pipeline over this parsed report. It's not a lot of text, but we split it into chunks and load it into a simple in-memory vector store.\n",
"\n",
"We ask a question over the parsed markdown table and get back the right answer! We also ask a question over the text."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "d8b7c3ad-2147-448c-bcbe-3e6fcd8d5361",
"metadata": {},
"outputs": [],
"source": [
"from llama_index.core import VectorStoreIndex\n",
"\n",
"vector_index = VectorStoreIndex(documents_gpt4o)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "8013351a-180d-4947-9f81-513042175c19",
"metadata": {},
"outputs": [],
"source": [
"query_engine = vector_index.as_query_engine(similarity_top_k=6)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "795dc5c4-e122-4ff3-94d2-747fa51d5add",
"metadata": {},
"outputs": [],
"source": [
"response = query_engine.query(\n",
" \"What are the greenhouse emissions for agriculture and transportation?\"\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "39d2e6bd-3316-49b5-9a5d-5b4b95343e5a",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Agriculture accounts for 20% of global greenhouse gas emissions, while transportation contributes 16% of these emissions.\n"
]
}
],
"source": [
"print(str(response))"
]
},
{
"cell_type": "markdown",
"id": "9beb5cd4-4041-48c7-b22b-de5540f92a6d",
"metadata": {},
"source": [
"Let's also try asking a question over another piece of the text."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "543c8b63-5cd1-47a1-a8a1-81abbfd3e52b",
"metadata": {},
"outputs": [],
"source": [
"response = query_engine.query(\n",
" \"How does the EPA range of Teslas compare with other vehicles? Give details\"\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "e739eabf-732b-4f59-9628-972c4bf6c857",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"The EPA range of Tesla vehicles varies across different models. The Model 3 Standard Range Plus (SR+) achieves an EPA range of 4.8 miles/kWh, making it the most efficient electric vehicle in production. The Model Y all-wheel drive (AWD) achieves 4.1 miles/kWh, which positions it as the most efficient electric SUV produced to date. The energy efficiency of Tesla vehicles is highlighted by these EPA range figures, showcasing their advancements in powertrain efficiency compared to other electric vehicles on the market.\n"
]
}
],
"source": [
"print(str(response))"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "04b05c53-1a81-41a7-97f2-98a960211957",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"# Reducing Carbon Footprint Even Further\n",
"## Improving Powertrain Efficiency\n",
"\n",
"Tesla vehicles are known to have the highest energy efficiency of any EV built to date. In the early days of Model S production, we were able to achieve energy efficiency of 3.1 EPA miles / kWh. Today, our most efficient Model 3 Standard Range Plus (SR+) achieves an EPA range of 4.8 miles / kWh, more than any EV in production. Model Y all-wheel drive (AWD) achieves 4.1 EPA miles / kWh, which makes it the most efficient electric SUV produced to date.\n",
"\n",
"The energy efficiency of Tesla vehicles will continue to improve further over time as we continue to improve our technology and powertrain efficiency. It is also reasonable to assume that our high-mileage products, such as our future Tesla Robotaxis, will be designed for maximum energy efficiency as handling, acceleration, and top speed become less relevant. That way, we will minimize cost for our customers as well as reduce the carbon footprint per mile driven.\n",
"\n",
"### Average Lifecycle Emissions in U.S. (gCO2e/mi)\n",
"\n",
"| Vehicle Type | Manufacturing Phase | Use Phase | Total Emissions |\n",
"|---------------------------------------|---------------------|-----------|-----------------|\n",
"| Avg. Mid-Size Premium ICE | | | |\n",
"| Model 3 Personal Use (grid charged) | | | |\n",
"| Model 3 Ridesharing Use (grid charged)| | | |\n",
"| Model 3 Personal Use (solar charged) | | | |\n",
"| Model 3 Ridesharing Use (solar charged)| | | |\n",
"\n",
"*Note: The chart shows that the emissions depend on powertrain efficiency.*\n",
"\n",
"### Energy Efficiency EPA range in miles/kWh\n",
"\n",
"| Vehicle Model | EPA Range (miles/kWh) |\n",
"|---------------------|-----------------------|\n",
"| Model 3 SR+ | 4.8 |\n",
"| Model 3 AWD | |\n",
"| Model Y AWD | |\n",
"| Hyundai Kona | |\n",
"| Chevy Bolt | |\n",
"| Model S LR+ | |\n",
"| Nissan Leaf | |\n",
"| Model X LR+ | |\n",
"| Jaguar iPace | |\n",
"| Mercedes EQC* | |\n",
"| Ford Mach E AWD | |\n",
"| Audi e-tron | |\n",
"| Porsche Taycan | |\n",
"\n",
"*Tesla estimate. Source: OEM websites*\n"
]
}
],
"source": [
"print(response.source_nodes[0].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
}
+1 -1
View File
@@ -1,3 +1,3 @@
from llama_parse.base import LlamaParse, ResultType
__all__ = ["LlamaParse", "ResultType"]
__all__ = ["LlamaParse", "ResultType"]
+601 -85
View File
@@ -1,32 +1,47 @@
import os
import asyncio
from io import TextIOWrapper
import httpx
import mimetypes
import time
from enum import Enum
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 fsspec.spec import AbstractBufferedFile
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
nest_asyncio_err = "cannot be called from a running event loop"
nest_asyncio_msg = "The event loop is already running. Add `import nest_asyncio; nest_asyncio.apply()` to your code to fix this issue."
# can put in a path to the file or the file bytes itself
# if passing as bytes or a buffer, must provide the file_name in extra_info
FileInput = Union[str, bytes, BufferedIOBase]
class ResultType(str, Enum):
"""The result type for the parser."""
TXT = "text"
MD = "markdown"
_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.")
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.",
@@ -37,8 +52,8 @@ class LlamaParse(BasePydanticReader):
num_workers: int = Field(
default=4,
gt=0,
lt=10,
description="The number of workers to use sending API requests for parsing."
lt=10,
description="The number of workers to use sending API requests for parsing.",
)
check_interval: int = Field(
default=1,
@@ -51,98 +66,393 @@ class LlamaParse(BasePydanticReader):
verbose: bool = Field(
default=True, description="Whether to print the progress of the parsing."
)
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."
)
parsing_instruction: Optional[str] = Field(
default="", description="The parsing instruction for the parser."
)
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).",
)
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.",
)
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.",
)
premium_mode: bool = Field(
default=False,
description="Use our best parser mode if set to True.",
)
continuous_mode: bool = Field(
default=False,
description="Parse documents continuously, leading to better results on documents where tables span across two pages.",
)
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.",
)
page_separator: Optional[str] = Field(
default=None,
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.",
)
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_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.",
)
gpt4o_mode: bool = Field(
default=False,
description="Whether to use gpt-4o extract text from documents.",
)
gpt4o_api_key: Optional[str] = Field(
default=None,
description="The API key for the GPT-4o API. Lowers the cost of parsing.",
)
guess_xlsx_sheet_names: Optional[bool] = Field(
default=False,
description="Whether to guess the sheet names of the xlsx file.",
)
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 using the page separator",
)
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.",
)
take_screenshot: bool = Field(
default=False,
description="Whether to take screenshot of each page of the document.",
)
custom_client: Optional[httpx.AsyncClient] = Field(
default=None, description="A custom HTTPX client to use for sending requests."
)
disable_ocr: bool = Field(
default=False,
description="Disable the OCR on the document. LlamaParse will only extract the copyable text from the document.",
)
is_formatting_instruction: bool = Field(
default=True,
description="Allow the parsing instruction to also format the output. Disable to have a cleaner markdown output.",
)
annotate_links: bool = Field(
default=False,
description="Annotate links found in the document to extract their URL.",
)
webhook_url: Optional[str] = Field(
default=None,
description="A URL that needs to be called at the end of the parsing job.",
)
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_api_version: Optional[str] = Field(
default=None, description="Azure Openai API Version"
)
azure_openai_key: Optional[str] = Field(
default=None, description="Azure Openai Key"
)
@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:
import os
api_key = os.getenv("LLAMA_CLOUD_API_KEY", None)
if api_key is None:
raise ValueError("The API key is required.")
return api_key
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
async def _aload_data(self, file_path: str, extra_info: Optional[dict] = None) -> List[Document]:
@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
# upload a document and get back a job_id
async def _create_job(
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
if isinstance(file_input, (bytes, BufferedIOBase)):
if not extra_info or "file_name" not in extra_info:
raise ValueError(
"file_name must be provided in extra_info when passing bytes"
)
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, PurePosixPath, PurePath)):
file_path = str(file_input)
file_ext = os.path.splitext(file_path)[1].lower()
if file_ext not in SUPPORTED_FILE_TYPES:
raise Exception(
f"Currently, only the following file types are supported: {SUPPORTED_FILE_TYPES}\n"
f"Current file type: {file_ext}"
)
mime_type = mimetypes.guess_type(file_path)[0]
# Open the file here for the duration of the async context
# 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 = {
"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,
"premium_mode": self.premium_mode,
"continuous_mode": self.continuous_mode,
"do_not_unroll_columns": self.do_not_unroll_columns,
"gpt4o_mode": self.gpt4o_mode,
"gpt4o_api_key": self.gpt4o_api_key,
"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,
"take_screenshot": self.take_screenshot,
"disable_ocr": self.disable_ocr,
"guess_xlsx_sheet_names": self.guess_xlsx_sheet_names,
"is_formatting_instruction": self.is_formatting_instruction,
"annotate_links": self.annotate_links,
"from_python_package": True,
}
# 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_prefix is not None:
data["page_prefix"] = self.page_prefix
if self.page_suffix is not None:
data["page_suffix"] = self.page_suffix
if self.bounding_box is not None:
data["bounding_box"] = self.bounding_box
if self.target_pages is not None:
data["target_pages"] = self.target_pages
if self.webhook_url is not None:
data["webhook_url"] = self.webhook_url
# Azure OpenAI
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_api_version is not None:
data["azure_openai_api_version"] = self.azure_openai_api_version
if self.azure_openai_key is not None:
data["azure_openai_key"] = self.azure_openai_key
try:
async with self.client_context() as client:
response = await client.post(
url,
files=files,
headers=headers,
data=data,
)
if not response.is_success:
raise Exception(f"Failed to parse the file: {response.text}")
job_id = response.json()["id"]
return job_id
finally:
if file_handle is not None:
file_handle.close()
@staticmethod
def __get_filename(f: Union[TextIOWrapper, AbstractBufferedFile]) -> str:
if isinstance(f, TextIOWrapper):
return f.name
return f.full_name
async def _get_job_result(
self, job_id: str, result_type: str, verbose: bool = False
) -> 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}"}
start = time.time()
tries = 0
while True:
await asyncio.sleep(self.check_interval)
async with self.client_context() as client:
tries += 1
result = await client.get(status_url, headers=headers)
if result.status_code != 200:
end = time.time()
if end - start > self.max_timeout:
raise Exception(f"Timeout while parsing the file: {job_id}")
if verbose and tries % 10 == 0:
print(".", end="", flush=True)
await asyncio.sleep(self.check_interval)
continue
# Allowed values "PENDING", "SUCCESS", "ERROR", "CANCELED"
result_json = result.json()
status = result_json["status"]
if status == "SUCCESS":
parsed_result = await client.get(result_url, headers=headers)
return parsed_result.json()
elif status == "PENDING":
end = time.time()
if end - start > self.max_timeout:
raise Exception(f"Timeout while parsing the file: {job_id}")
if verbose and tries % 10 == 0:
print(".", end="", flush=True)
await asyncio.sleep(self.check_interval)
else:
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:
file_path = str(file_path)
if not file_path.endswith(".pdf"):
raise Exception("Currently, only PDF files are supported.")
extra_info = extra_info or {}
extra_info["file_path"] = file_path
headers = {"Authorization": f"Bearer {self.api_key}"}
# load data, set the mime type
with open(file_path, "rb") as f:
mime_type = mimetypes.guess_type(file_path)[0]
files = {"file": (f.name, f, mime_type)}
# send the request, start job
url = f"{self.base_url}/api/parsing/upload"
async with httpx.AsyncClient(timeout=self.max_timeout) as client:
response = await client.post(url, files=files, headers=headers)
if not response.is_success:
raise Exception(f"Failed to parse the PDF file: {response.text}")
# check the status of the job, return when done
job_id = response.json()["id"]
if self.verbose:
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)
result_url = f"{self.base_url}/api/parsing/job/{job_id}/result/{self.result_type.value}"
start = time.time()
tries = 0
while True:
await asyncio.sleep(self.check_interval)
async with httpx.AsyncClient(timeout=self.max_timeout) as client:
tries += 1
result = await client.get(result_url, headers=headers)
result = await self._get_job_result(
job_id, self.result_type.value, verbose=verbose
)
if result.status_code == 404:
end = time.time()
if end - start > self.max_timeout:
raise Exception(
f"Timeout while parsing the PDF file: {response.text}"
)
if self.verbose and tries % 10 == 0:
print(".", end="", flush=True)
continue
docs = [
Document(
text=result[self.result_type.value],
metadata=extra_info or {},
)
]
if self.split_by_page:
return self._get_sub_docs(docs)
else:
return docs
if result.status_code == 400:
detail = result.json().get("detail", "Unknown error")
raise Exception(f"Failed to parse the PDF file: {detail}")
return [
Document(
text=result.json()[self.result_type.value],
metadata=extra_info,
)
]
except Exception as e:
print("Error while parsing the PDF file: ", e)
return []
async def aload_data(self, file_path: Union[List[str], str], extra_info: Optional[dict] = None) -> List[Document]:
file_repr = file_path if isinstance(file_path, str) else "<bytes/buffer>"
print(f"Error while parsing the file '{file_repr}':", e)
if self.ignore_errors:
return []
else:
raise e
async def aload_data(
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)):
return await self._aload_data(file_path, extra_info=extra_info)
if isinstance(file_path, (str, PurePosixPath, Path, bytes, BufferedIOBase)):
return await self._aload_data(
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) for f in file_path]
jobs = [
self._aload_data(
f,
extra_info=extra_info,
fs=fs,
verbose=self.verbose and not self.show_progress,
)
for f in file_path
]
try:
results = await run_jobs(jobs, workers=self.num_workers)
results = await run_jobs(
jobs,
workers=self.num_workers,
desc="Parsing files",
show_progress=self.show_progress,
)
# return flattened results
return [item for sublist in results for item in sublist]
except RuntimeError as e:
@@ -151,14 +461,220 @@ class LlamaParse(BasePydanticReader):
else:
raise e
else:
raise ValueError("The input file_path must be a string or a list of strings.")
raise ValueError(
"The input file_path must be a string or a list of strings."
)
def load_data(self, file_path: Union[List[str], str], extra_info: Optional[dict] = None) -> List[Document]:
def load_data(
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)
else:
raise e
async def _aget_json(
self, file_path: FileInput, extra_info: Optional[dict] = None
) -> List[dict]:
"""Load data from the input path."""
try:
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
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)
if self.ignore_errors:
return []
else:
raise e
async def aget_json(
self,
file_path: Union[List[FileInput], FileInput],
extra_info: Optional[dict] = None,
) -> List[dict]:
"""Load data from the input path."""
if isinstance(file_path, (str, Path)):
return await self._aget_json(file_path, extra_info=extra_info)
elif isinstance(file_path, list):
jobs = [self._aget_json(f, extra_info=extra_info) for f in file_path]
try:
results = await run_jobs(
jobs,
workers=self.num_workers,
desc="Parsing files",
show_progress=self.show_progress,
)
# return flattened results
return [item for sublist in results for item in sublist]
except RuntimeError as e:
if nest_asyncio_err in str(e):
raise RuntimeError(nest_asyncio_msg)
else:
raise e
else:
raise ValueError(
"The input file_path must be a string or a list of strings."
)
def get_json_result(
self,
file_path: Union[List[FileInput], FileInput],
extra_info: Optional[dict] = None,
) -> List[dict]:
"""Parse the input path."""
try:
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
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}"}
# make the download path
if not os.path.exists(download_path):
os.makedirs(download_path)
try:
images = []
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"]
# get the full path
image_path = os.path.join(
download_path, f"{job_id}-{image_name}"
)
# get a valid image path
if not image_path.endswith(".png"):
if not image_path.endswith(".jpg"):
image_path += ".png"
image["path"] = image_path
image["job_id"] = job_id
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}"
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:
print("Error while downloading images from the parsed result:", e)
if self.ignore_errors:
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()
+192
View File
@@ -0,0 +1,192 @@
from enum import Enum
# Asyncio error messages
nest_asyncio_err = "cannot be called from a running event loop"
nest_asyncio_msg = "The event loop is already running. Add `import nest_asyncio; nest_asyncio.apply()` to your code to fix this issue."
class ResultType(str, Enum):
"""The result type for the parser."""
TXT = "text"
MD = "markdown"
class Language(str, Enum):
BAZA = "abq"
ADYGHE = "ady"
AFRIKAANS = "af"
ANGIKA = "ang"
ARABIC = "ar"
ASSAMESE = "as"
AVAR = "ava"
AZERBAIJANI = "az"
BELARUSIAN = "be"
BULGARIAN = "bg"
BIHARI = "bh"
BHOJPURI = "bho"
BENGALI = "bn"
BOSNIAN = "bs"
SIMPLIFIED_CHINESE = "ch_sim"
TRADITIONAL_CHINESE = "ch_tra"
CHECHEN = "che"
CZECH = "cs"
WELSH = "cy"
DANISH = "da"
DARGWA = "dar"
GERMAN = "de"
ENGLISH = "en"
SPANISH = "es"
ESTONIAN = "et"
PERSIAN_FARSI = "fa"
FRENCH = "fr"
IRISH = "ga"
GOAN_KONKANI = "gom"
HINDI = "hi"
CROATIAN = "hr"
HUNGARIAN = "hu"
INDONESIAN = "id"
INGUSH = "inh"
ICELANDIC = "is"
ITALIAN = "it"
JAPANESE = "ja"
KABARDIAN = "kbd"
KANNADA = "kn"
KOREAN = "ko"
KURDISH = "ku"
LATIN = "la"
LAK = "lbe"
LEZGHIAN = "lez"
LITHUANIAN = "lt"
LATVIAN = "lv"
MAGAHI = "mah"
MAITHILI = "mai"
MAORI = "mi"
MONGOLIAN = "mn"
MARATHI = "mr"
MALAY = "ms"
MALTESE = "mt"
NEPALI = "ne"
NEWARI = "new"
DUTCH = "nl"
NORWEGIAN = "no"
OCCITAN = "oc"
PALI = "pi"
POLISH = "pl"
PORTUGUESE = "pt"
ROMANIAN = "ro"
RUSSIAN = "ru"
SERBIAN_CYRILLIC = "rs_cyrillic"
SERBIAN_LATIN = "rs_latin"
NAGPURI = "sck"
SLOVAK = "sk"
SLOVENIAN = "sl"
ALBANIAN = "sq"
SWEDISH = "sv"
SWAHILI = "sw"
TAMIL = "ta"
TABASSARAN = "tab"
TELUGU = "te"
THAI = "th"
TAJIK = "tjk"
TAGALOG = "tl"
TURKISH = "tr"
UYGHUR = "ug"
UKRAINIAN = "uk"
URDU = "ur"
UZBEK = "uz"
VIETNAMESE = "vi"
SUPPORTED_FILE_TYPES = [
".pdf",
# document and presentations
".602",
".abw",
".cgm",
".cwk",
".doc",
".docx",
".docm",
".dot",
".dotm",
".hwp",
".key",
".lwp",
".mw",
".mcw",
".pages",
".pbd",
".ppt",
".pptm",
".pptx",
".pot",
".potm",
".potx",
".rtf",
".sda",
".sdd",
".sdp",
".sdw",
".sgl",
".sti",
".sxi",
".sxw",
".stw",
".sxg",
".txt",
".uof",
".uop",
".uot",
".vor",
".wpd",
".wps",
".xml",
".zabw",
".epub",
# images
".jpg",
".jpeg",
".png",
".gif",
".bmp",
".svg",
".tiff",
".webp",
# web
".htm",
".html",
# spreadsheets
".xlsx",
".xls",
".xlsm",
".xlsb",
".xlw",
".csv",
".dif",
".sylk",
".slk",
".prn",
".numbers",
".et",
".ods",
".fods",
".uos1",
".uos2",
".dbf",
".wk1",
".wk2",
".wk3",
".wk4",
".wks",
".123",
".wq1",
".wq2",
".wb1",
".wb2",
".wb3",
".qpw",
".xlr",
".eth",
".tsv",
]
Generated
+1467 -1331
View File
File diff suppressed because it is too large Load Diff
+9 -5
View File
@@ -1,6 +1,10 @@
[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
[tool.poetry]
name = "llama-parse"
version = "0.3.4"
version = "0.5.13"
description = "Parse files into RAG-Optimized formats."
authors = ["Logan Markewich <logan@llamaindex.ai>"]
license = "MIT"
@@ -9,12 +13,12 @@ packages = [{include = "llama_parse"}]
[tool.poetry.dependencies]
python = ">=3.8.1,<4.0"
llama-index-core = ">=0.10.7"
llama-index-core = ">=0.11.0"
click = "^8.1.7"
[tool.poetry.group.dev.dependencies]
pytest = "^8.0.0"
ipykernel = "^6.29.0"
[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
[tool.poetry.scripts]
llama-parse = "llama_parse.cli.main:parse"
+113 -4
View File
@@ -1,18 +1,127 @@
import os
import pytest
from fsspec.implementations.local import LocalFileSystem
from httpx import AsyncClient
from llama_parse import LlamaParse
def test_simple_page_text():
@pytest.mark.skipif(
os.environ.get("LLAMA_CLOUD_API_KEY", "") == "",
reason="LLAMA_CLOUD_API_KEY not set",
)
def test_simple_page_text() -> None:
parser = LlamaParse(result_type="text")
filepath = os.path.join(os.path.dirname(__file__), "test_files/attention_is_all_you_need.pdf")
filepath = os.path.join(
os.path.dirname(__file__), "test_files/attention_is_all_you_need.pdf"
)
result = parser.load_data(filepath)
assert len(result) == 1
assert len(result[0].text) > 0
def test_simple_page_markdown():
@pytest.fixture
def markdown_parser() -> LlamaParse:
if os.environ.get("LLAMA_CLOUD_API_KEY", "") == "":
pytest.skip("LLAMA_CLOUD_API_KEY not set")
return LlamaParse(result_type="markdown", ignore_errors=False)
def test_simple_page_markdown(markdown_parser: LlamaParse) -> None:
filepath = os.path.join(
os.path.dirname(__file__), "test_files/attention_is_all_you_need.pdf"
)
result = markdown_parser.load_data(filepath)
assert len(result) == 1
assert len(result[0].text) > 0
def test_simple_page_markdown_bytes(markdown_parser: LlamaParse) -> None:
markdown_parser = LlamaParse(result_type="markdown", ignore_errors=False)
filepath = os.path.join(
os.path.dirname(__file__), "test_files/attention_is_all_you_need.pdf"
)
with open(filepath, "rb") as f:
file_bytes = f.read()
# client must provide extra_info with file_name
with pytest.raises(ValueError):
result = markdown_parser.load_data(file_bytes)
result = markdown_parser.load_data(
file_bytes, extra_info={"file_name": "attention_is_all_you_need.pdf"}
)
assert len(result) == 1
assert len(result[0].text) > 0
def test_simple_page_markdown_buffer(markdown_parser: LlamaParse) -> None:
markdown_parser = LlamaParse(result_type="markdown", ignore_errors=False)
filepath = os.path.join(
os.path.dirname(__file__), "test_files/attention_is_all_you_need.pdf"
)
with open(filepath, "rb") as f:
# client must provide extra_info with file_name
with pytest.raises(ValueError):
result = markdown_parser.load_data(f)
result = markdown_parser.load_data(
f, extra_info={"file_name": "attention_is_all_you_need.pdf"}
)
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",
)
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 = parser.load_data(filepath, fs=fs)
assert len(result) == 1
filepath = os.path.join(os.path.dirname(__file__), "test_files/attention_is_all_you_need.pdf")
@pytest.mark.skipif(
os.environ.get("LLAMA_CLOUD_API_KEY", "") == "",
reason="LLAMA_CLOUD_API_KEY not set",
)
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])
assert len(result) == 2
assert len(result[0].text) > 0
parser = LlamaParse(
result_type="markdown", show_progress=True, num_workers=2, verbose=True
)
filepath = os.path.join(
os.path.dirname(__file__), "test_files/attention_is_all_you_need.pdf"
)
result = parser.load_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",
)
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 = parser.load_data(filepath)
assert len(result) == 1
assert len(result[0].text) > 0