From 5184f777ec8f053e9cdaf35b7591a0912c56227a Mon Sep 17 00:00:00 2001 From: Rachel Hu Date: Sat, 6 Apr 2024 17:47:51 -0700 Subject: [PATCH 1/5] Add a test image file. --- examples/test3.png | Bin 0 -> 39038 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 examples/test3.png diff --git a/examples/test3.png b/examples/test3.png new file mode 100644 index 0000000000000000000000000000000000000000..6fc943d5d7e60e6d13d71c2ba5a7ff05475b639c GIT binary patch literal 39038 zcmbSy1yo$!vL>##K7G!%+Eul8)&8nZl&Z2U1{x6>3=9m0yquIe3=Co;3=HfP3KH~*SLAUd z3{1MTyp*`6C+snh*4IFh@Y{4;oKNkl_e&&0I^8o?h!OWXPigrN11&VJFPyExe3ro4 zo+xxz_pAL#yumJZuBT-Kss6N+oV3*;f_aK=9qCW1&re`%{4Oc;-UNx_|GAr-$t7!ix*sPX`E&d3a50$o&%eJH z6yTq`zZVLdKfMO#V?00odx80HsuIBck2})%Gok;l(f*Hwxl{fj;eXPR@XP-(^{#(t z5u19JI1G$9@qb^s-b%vml%Y4@%(LJ4i37gkAOptNm4M@)B3jyra$U;YWJKxqR%cKw0^ z`f#bsXR>f14JvC2E9mr~91Z3b)0mY{=7ttpX=-b~GB@9e;^9`k&c{&Qm}1{4ruEC- zPUfW;j;&Z+E9`kXZgYK?^hyu3?9D$B)3d&+Gkkm6-^yjge5HN<^F=zNO_{6I6cU0% zetF2{kxD!4BI#zgL>;M0Abt~~1C#{_4ivKmW)>FQ;SsW_=YC=`CvU1991it7e4%YZ zi`*s6i}Ep0fMUGCmtaAU!uC?SOYjQ0ik|+#!>!NNiL8U+TK^)}ix(58O%$3!z84Jf z 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 URAH;GyBA2#)78&qol`;+0G&e-5&!@I literal 0 HcmV?d00001 From 9a32f2a902b061781c6eb1a2dbf9002a2f541d19 Mon Sep 17 00:00:00 2001 From: Rachel Hu Date: Sat, 6 Apr 2024 18:34:41 -0700 Subject: [PATCH 2/5] Fix test_example.py broken example_local_file path. --- examples/test_example.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/test_example.py b/examples/test_example.py index 04712f5..09a7756 100755 --- a/examples/test_example.py +++ b/examples/test_example.py @@ -14,7 +14,7 @@ example_apikey = os.getenv("CAMBIO_API_KEY") - example_local_file = "./test2.pdf" + example_local_file = "./sample_data/test2.pdf" op = OpenParser(example_apikey) From 95bcc2d18a9d6d6bc13c0f3a6f3e4842761476b6 Mon Sep 17 00:00:00 2001 From: Rachel Hu Date: Sat, 6 Apr 2024 19:31:45 -0700 Subject: [PATCH 3/5] Update basic mode extract. --- ...pt_to_extract_table_from_pdf_to_json.ipynb | 89 ++++++++++--------- examples/test_example.py | 2 +- open_parser/base.py | 9 +- 3 files changed, 54 insertions(+), 46 deletions(-) diff --git a/examples/prompt_to_extract_table_from_pdf_to_json.ipynb b/examples/prompt_to_extract_table_from_pdf_to_json.ipynb index a0e3ef5..347735b 100644 --- a/examples/prompt_to_extract_table_from_pdf_to_json.ipynb +++ b/examples/prompt_to_extract_table_from_pdf_to_json.ipynb @@ -25,24 +25,9 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": 4, "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/var/folders/mb/7wp0k3g17jd11kk9xlv5mh3m0000gn/T/ipykernel_67864/3281231558.py:2: DeprecationWarning: \n", - "Pyarrow will become a required dependency of pandas in the next major release of pandas (pandas 3.0),\n", - "(to allow more performant data types, such as the Arrow string type, and better interoperability with other libraries)\n", - "but was not found to be installed on your system.\n", - "If this would cause problems for you,\n", - "please provide us feedback at https://github.com/pandas-dev/pandas/issues/54466\n", - " \n", - " import pandas as pd\n" - ] - } - ], + "outputs": [], "source": [ "import os\n", "import pandas as pd\n", @@ -70,7 +55,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 5, "metadata": {}, "outputs": [], "source": [ @@ -91,7 +76,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 6, "metadata": {}, "outputs": [ { @@ -108,33 +93,38 @@ "example_prompt = \"Return table in a JSON format with each box's key and value.\"\n", "\n", "op = OpenParser(example_apikey)\n", - "qa_result = op.parse(example_local_file, example_prompt)\n" + "# mode can be \"basic\" or \"advanced\"\n", + "qa_result = op.parse(example_local_file, example_prompt, mode=\"basic\")\n" ] }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "[{'result': [{\"Employee's social security number\": '758-58-5787'},\n", - " {'Employer identification number (EIN)': '78-8778788'},\n", - " {\"Employer's name, address, and ZIP code\": 'DesignNext\\nKatham Dorbosto, Kashiani, Gopalganj\\nGopalganj, AK 8133'},\n", - " {'Control number': '9'},\n", - " {\"Employee's first name and initial\": 'Jesan'},\n", - " {'Last name': 'Rahaman'},\n", - " {\"State, Employer's state ID number\": 'AL,877878878'},\n", - " {'State wages, tips, etc.': '80000.00'},\n", - " {'Federal income tax withheld': '3835.00'}],\n", + "[{'result': [{\"Employee's social security number\": '758-58-5787',\n", + " 'Employer identification number (EIN)': '78-8778788',\n", + " \"Employer's name, address, and ZIP code\": 'DesignNext\\nKatham Dorbosto, Kashiani, Gopalganj\\nGopalganj, AK 8133',\n", + " 'Control number': '9',\n", + " \"Employee's first name and initial\": 'Jesan',\n", + " 'Last name': 'Rahaman',\n", + " \"State, Employer's state ID number\": 'AL',\n", + " 'Wages, tips, etc.': '80000.00',\n", + " 'Federal income tax withheld': '10368.00',\n", + " 'Social security tax withheld': '4960.00',\n", + " 'Medicare wages and tips': '80000.00',\n", + " 'Medicare tax withheld': '1160.00'}],\n", " 'log': {'instruction': \"Return table in a JSON format with each box's key and value.\",\n", " 'source': '',\n", - " 'usage': {'input_tokens': 1750, 'output_tokens': 232}},\n", + " 'usage': {'input_tokens': 1752, 'output_tokens': 226},\n", + " 'source_log': None},\n", " 'page_num': 0}]" ] }, - "execution_count": 6, + "execution_count": 7, "metadata": {}, "output_type": "execute_result" } @@ -145,7 +135,7 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 8, "metadata": {}, "outputs": [ { @@ -199,15 +189,27 @@ " \n", " \n", " State, Employer's state ID number\n", - " AL,877878878\n", + " AL\n", " \n", " \n", - " State wages, tips, etc.\n", + " Wages, tips, etc.\n", " 80000.00\n", " \n", " \n", " Federal income tax withheld\n", - " 3835.00\n", + " 10368.00\n", + " \n", + " \n", + " Social security tax withheld\n", + " 4960.00\n", + " \n", + " \n", + " Medicare wages and tips\n", + " 80000.00\n", + " \n", + " \n", + " Medicare tax withheld\n", + " 1160.00\n", " \n", " \n", "\n", @@ -221,20 +223,23 @@ "Control number 9\n", "Employee's first name and initial Jesan\n", "Last name Rahaman\n", - "State, Employer's state ID number AL,877878878\n", - "State wages, tips, etc. 80000.00\n", - "Federal income tax withheld 3835.00" + "State, Employer's state ID number AL\n", + "Wages, tips, etc. 80000.00\n", + "Federal income tax withheld 10368.00\n", + "Social security tax withheld 4960.00\n", + "Medicare wages and tips 80000.00\n", + "Medicare tax withheld 1160.00" ] }, - "execution_count": 11, + "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "data = qa_result[0]['result']\n", - "keys = [list(item.keys())[0] for item in data]\n", - "values = [list(item.values())[0] for item in data]\n", + "keys = [list(item.keys()) for item in data][0]\n", + "values = [list(item.values()) for item in data][0]\n", "\n", "# Create a DataFrame\n", "df = pd.DataFrame(values, index=keys, columns=['Value'])\n", diff --git a/examples/test_example.py b/examples/test_example.py index 09a7756..8a06e41 100755 --- a/examples/test_example.py +++ b/examples/test_example.py @@ -25,6 +25,6 @@ print("information extraction test:") example_prompt = "Return table under Investor Metrics in JSON format with year as the key and the column as subkeys." - qa_result = op.parse(example_local_file, example_prompt) + qa_result = op.parse(example_local_file, example_prompt, mode="basic") print(type(qa_result)) print(qa_result) diff --git a/open_parser/base.py b/open_parser/base.py index bd18cb6..b22a235 100644 --- a/open_parser/base.py +++ b/open_parser/base.py @@ -28,9 +28,9 @@ def extract(self, file_path): result = self._request_file_extraction(user_id, job_id, s3_key) return result["file_content"] - def parse(self, file_path, prompt): + def parse(self, file_path, prompt, mode="advanced"): user_id, job_id, s3_key = self._request_and_upload_by_apiKey(file_path, prompt) - result = self._request_info_extraction(user_id, job_id, s3_key) + result = self._request_info_extraction(user_id, job_id, s3_key, mode) return result["results"] def _error_handler(self, response): @@ -77,11 +77,14 @@ def _request_file_extraction(self, user_id, job_id, s3_key): self._error_handler(response) - def _request_info_extraction(self, user_id, job_id, s3_key): + def _request_info_extraction(self, user_id, job_id, s3_key, mode): + if mode not in ["advanced", "basic"]: + raise ValueError("Invalid mode. Choose either 'advanced' or 'basic'.") payload = { "userId": user_id, "jobId": job_id, "fileKey": s3_key, + "extract": True if mode == "advanced" else False, } response = requests.post( self._parseurl, headers=self._request_header, json=payload From 92ee6d84f73fd5abe6b064a1dbf2f32b163c436e Mon Sep 17 00:00:00 2001 From: Rachel Hu Date: Sat, 6 Apr 2024 19:35:58 -0700 Subject: [PATCH 4/5] Update advanced mode extract. --- ...table_from_pdf_to_json_advanced_mode.ipynb | 364 ++++++++++++++++++ 1 file changed, 364 insertions(+) create mode 100644 examples/prompt_to_extract_table_from_pdf_to_json_advanced_mode.ipynb diff --git a/examples/prompt_to_extract_table_from_pdf_to_json_advanced_mode.ipynb b/examples/prompt_to_extract_table_from_pdf_to_json_advanced_mode.ipynb new file mode 100644 index 0000000..54ce7f5 --- /dev/null +++ b/examples/prompt_to_extract_table_from_pdf_to_json_advanced_mode.ipynb @@ -0,0 +1,364 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Prompt to Extract Key-values into JSON from W2 (PDF)\n", + "\n", + "Below it's an example of using OpenParser to extract key-values from a W2 PDF into JSON format. (Note: the model is still in beta and is NOT robust enough to generate the same output. Please bear with it!)\n", + "\n", + "### 1. Load the libraries\n", + "\n", + "If you have install `open_parser`, uncomment the below line." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "# !pip3 install python-dotenv\n", + "# !pip3 install --upgrade open_parser" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import pandas as pd\n", + "\n", + "from dotenv import load_dotenv\n", + "from open_parser import OpenParser\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 2. Set up your OpenParser API key\n", + "\n", + "To set up your `CAMBIO_API_KEY` API key, you will:\n", + "\n", + "1. create a `.env` file in your root folder;\n", + "2. add the following one line to your `.env file:\n", + " ```\n", + " CAMBIO_API_KEY=17b************************\n", + " ```\n", + "\n", + "Then run the below line to load your API key." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "load_dotenv(override=True)\n", + "example_apikey = os.getenv(\"CAMBIO_API_KEY\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 3. Load sample data and Run OpenParser\n", + "\n", + "OpenParser supports both image and PDF. First let's load a sample data to test OpenParser's capabilities.\n", + "\n", + "Now we can run OpenParser on our sample data and then display it in the Markdown format." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Upload response: 204\n", + "Extraction success.\n" + ] + } + ], + "source": [ + "example_local_file = \"./sample_data/test1.pdf\"\n", + "example_prompt = \"Return table in a JSON format with each box's key and value.\"\n", + "\n", + "op = OpenParser(example_apikey)\n", + "# mode can be \"basic\" or \"advanced\"\n", + "qa_result = op.parse(example_local_file, example_prompt, mode=\"advanced\")\n" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[{\"a Employee's social security number\": '758-58-5787',\n", + " 'b Employer identification number (EIN)': '78-8778788',\n", + " \"c Employer's name, address, and ZIP code\": 'DesignNext\\nKatham Dorbosto, Kashiani, Gopalganj\\nGopalganj, AK 8133',\n", + " 'd Control number': '9',\n", + " \"e Employee's first name and initial\": 'Jesan',\n", + " \"e Employee's last name\": 'Rahaman',\n", + " \"f Employee's address and ZIP code\": 'AL 877878878',\n", + " '1 Wages, tips, other compensation': '80000.00',\n", + " '2 Federal income tax withheld': '10368.00',\n", + " '3 Social security wages': '80000.00',\n", + " '4 Social security tax withheld': '4960.00',\n", + " '5 Medicare wages and tips': '80000.00',\n", + " '6 Medicare tax withheld': '1160.00',\n", + " '7 Social security tips': 'NA',\n", + " '8 Allocated tips': 'NA',\n", + " '10 Dependent care benefits': 'NA',\n", + " '11 Nonqualified plans': 'NA',\n", + " '13 Statutory Retroment employee plan': 'NA',\n", + " '13 Third-party sick pay': 'NA',\n", + " '14 Other': 'NA',\n", + " \"15 State Employer's state ID number\": 'AL',\n", + " '16 State wages, tips, etc.': '80000.00',\n", + " '17 State income tax': '3835.00',\n", + " '18 Local wages, tips, etc.': 'NA',\n", + " '19 Local income tax': 'NA',\n", + " '20 Locality name': 'NA'}]" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "qa_result[0]['result']" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Value
a Employee's social security number758-58-5787
b Employer identification number (EIN)78-8778788
c Employer's name, address, and ZIP codeDesignNext\\nKatham Dorbosto, Kashiani, Gopalga...
d Control number9
e Employee's first name and initialJesan
e Employee's last nameRahaman
f Employee's address and ZIP codeAL 877878878
1 Wages, tips, other compensation80000.00
2 Federal income tax withheld10368.00
3 Social security wages80000.00
4 Social security tax withheld4960.00
5 Medicare wages and tips80000.00
6 Medicare tax withheld1160.00
7 Social security tipsNA
8 Allocated tipsNA
10 Dependent care benefitsNA
11 Nonqualified plansNA
13 Statutory Retroment employee planNA
13 Third-party sick payNA
14 OtherNA
15 State Employer's state ID numberAL
16 State wages, tips, etc.80000.00
17 State income tax3835.00
18 Local wages, tips, etc.NA
19 Local income taxNA
20 Locality nameNA
\n", + "
" + ], + "text/plain": [ + " Value\n", + "a Employee's social security number 758-58-5787\n", + "b Employer identification number (EIN) 78-8778788\n", + "c Employer's name, address, and ZIP code DesignNext\\nKatham Dorbosto, Kashiani, Gopalga...\n", + "d Control number 9\n", + "e Employee's first name and initial Jesan\n", + "e Employee's last name Rahaman\n", + "f Employee's address and ZIP code AL 877878878\n", + "1 Wages, tips, other compensation 80000.00\n", + "2 Federal income tax withheld 10368.00\n", + "3 Social security wages 80000.00\n", + "4 Social security tax withheld 4960.00\n", + "5 Medicare wages and tips 80000.00\n", + "6 Medicare tax withheld 1160.00\n", + "7 Social security tips NA\n", + "8 Allocated tips NA\n", + "10 Dependent care benefits NA\n", + "11 Nonqualified plans NA\n", + "13 Statutory Retroment employee plan NA\n", + "13 Third-party sick pay NA\n", + "14 Other NA\n", + "15 State Employer's state ID number AL\n", + "16 State wages, tips, etc. 80000.00\n", + "17 State income tax 3835.00\n", + "18 Local wages, tips, etc. NA\n", + "19 Local income tax NA\n", + "20 Locality name NA" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "data = qa_result[0]['result']\n", + "keys = [list(item.keys()) for item in data][0]\n", + "values = [list(item.values()) for item in data][0]\n", + "\n", + "# Create a DataFrame\n", + "df = pd.DataFrame(values, index=keys, columns=['Value'])\n", + "\n", + "df" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## End of the notebook\n", + "\n", + "Check more [case studies](https://www.cambioml.com/blog) of CambioML!\n", + "\n", + "\n", + " \n", + "" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "open-parser", + "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", + "version": "3.10.14" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} From d844d90520662d85b663664e8c73b1b15dbca232 Mon Sep 17 00:00:00 2001 From: Rachel Hu Date: Sat, 6 Apr 2024 19:36:06 -0700 Subject: [PATCH 5/5] Update advanced mode extract. --- ...prompt_to_extract_table_from_pdf_to_json_advanced_mode.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/prompt_to_extract_table_from_pdf_to_json_advanced_mode.ipynb b/examples/prompt_to_extract_table_from_pdf_to_json_advanced_mode.ipynb index 54ce7f5..915eaae 100644 --- a/examples/prompt_to_extract_table_from_pdf_to_json_advanced_mode.ipynb +++ b/examples/prompt_to_extract_table_from_pdf_to_json_advanced_mode.ipynb @@ -4,7 +4,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# Prompt to Extract Key-values into JSON from W2 (PDF)\n", + "# Prompt to Extract Key-values into JSON from W2 (PDF) using advanced mode\n", "\n", "Below it's an example of using OpenParser to extract key-values from a W2 PDF into JSON format. (Note: the model is still in beta and is NOT robust enough to generate the same output. Please bear with it!)\n", "\n",