From 75a010b45563f59283196b52a08c788e2013354d Mon Sep 17 00:00:00 2001 From: "K. Allagbe" Date: Tue, 22 Oct 2024 09:51:14 -0400 Subject: [PATCH 1/3] issue #60: format website fields --- all_inspections.pkl | Bin 0 -> 8797 bytes pipeline/inspection.py | 32 +++- pyproject.toml | 2 +- requirements.txt | 2 +- test.ipynb | 326 +++++++++++++++++++++++++++++++++++++++++ 5 files changed, 352 insertions(+), 10 deletions(-) create mode 100644 all_inspections.pkl create mode 100644 test.ipynb diff --git a/all_inspections.pkl b/all_inspections.pkl new file mode 100644 index 0000000000000000000000000000000000000000..e2dfe6c0865053d9b5ae0ed556b86060567506c2 GIT binary patch literal 8797 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 F{{r^=1.0 pydantic>=2.7.1 python-dotenv diff --git a/test.ipynb b/test.ipynb new file mode 100644 index 0000000..9e1b574 --- /dev/null +++ b/test.ipynb @@ -0,0 +1,326 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import pickle\n", + "import shutil\n", + "import tempfile\n", + "from glob import glob\n", + "\n", + "from dotenv import load_dotenv\n", + "\n", + "from pipeline import GPT, OCR, LabelStorage, analyze\n", + "from pipeline.inspection import FertilizerInspection\n" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Backup directory created at: /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpuwj3w81v\n", + "Copied test_data/labels/label_001/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpuwj3w81v/img_001.png\n", + "\n", + "Label: label_001\n", + " Company website: www.soil-aid.com\n", + " Manufacturer website: www.soil-aid.com\n", + "Copied test_data/labels/label_002/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpuwj3w81v/img_001.png\n", + "\n", + "Label: label_002\n", + " Company website: None\n", + " Manufacturer website: None\n", + "Copied test_data/labels/label_003/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpuwj3w81v/img_001.png\n", + "\n", + "Label: label_003\n", + " Company website: None\n", + " Manufacturer website: None\n", + "Copied test_data/labels/label_004/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpuwj3w81v/img_001.png\n", + "\n", + "Label: label_004\n", + " Company website: None\n", + " Manufacturer website: None\n", + "Copied test_data/labels/label_005/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpuwj3w81v/img_001.png\n", + "\n", + "Label: label_005\n", + " Company website: None\n", + " Manufacturer website: None\n", + "Copied test_data/labels/label_006/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpuwj3w81v/img_001.png\n", + "\n", + "Label: label_006\n", + " Company website: www.activeagriscience.com\n", + " Manufacturer website: None\n", + "Copied test_data/labels/label_007/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpuwj3w81v/img_001.png\n", + "\n", + "Label: label_007\n", + " Company website: www.activeagriscience.com\n", + " Manufacturer website: None\n", + "Copied test_data/labels/label_008/img_001.jpg to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpuwj3w81v/img_001.jpg\n", + "\n", + "Label: label_008\n", + " Company website: www.easygardener.com\n", + " Manufacturer website: None\n", + "Copied test_data/labels/label_009/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpuwj3w81v/img_001.png\n", + "\n", + "Label: label_009\n", + " Company website: None\n", + " Manufacturer website: None\n", + "Copied test_data/labels/label_010/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpuwj3w81v/img_001.png\n", + "\n", + "Label: label_010\n", + " Company website: None\n", + " Manufacturer website: None\n", + "Copied test_data/labels/label_011/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpuwj3w81v/img_001.png\n", + "\n", + "Label: label_011\n", + " Company website: www.advancingecoag.com\n", + " Manufacturer website: None\n", + "Copied test_data/labels/label_012/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpuwj3w81v/img_001.png\n", + "Copied test_data/labels/label_012/img_002.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpuwj3w81v/img_002.png\n", + "\n", + "Label: label_012\n", + " Company website: None\n", + " Manufacturer website: None\n", + "Copied test_data/labels/label_013/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpuwj3w81v/img_001.png\n", + "Copied test_data/labels/label_013/img_002.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpuwj3w81v/img_002.png\n", + "\n", + "Label: label_013\n", + " Company website: None\n", + " Manufacturer website: None\n", + "Copied test_data/labels/label_014/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpuwj3w81v/img_001.png\n", + "Copied test_data/labels/label_014/img_003.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpuwj3w81v/img_003.png\n", + "Copied test_data/labels/label_014/img_002.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpuwj3w81v/img_002.png\n", + "\n", + "Label: label_014\n", + " Company website: None\n", + " Manufacturer website: None\n", + "Copied test_data/labels/label_015/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpuwj3w81v/img_001.png\n", + "Copied test_data/labels/label_015/img_002.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpuwj3w81v/img_002.png\n", + "\n", + "Label: label_015\n", + " Company website: www.bionik.ca\n", + " Manufacturer website: None\n", + "Copied test_data/labels/label_016/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpuwj3w81v/img_001.png\n", + "Copied test_data/labels/label_016/img_002.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpuwj3w81v/img_002.png\n", + "\n", + "Label: label_016\n", + " Company website: None\n", + " Manufacturer website: None\n", + "Copied test_data/labels/label_017/img_001.jpg to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpuwj3w81v/img_001.jpg\n", + "Copied test_data/labels/label_017/img_003.jpg to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpuwj3w81v/img_003.jpg\n", + "Copied test_data/labels/label_017/img_002.jpg to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpuwj3w81v/img_002.jpg\n", + "\n", + "Label: label_017\n", + " Company website: www.golfgreen.ca\n", + " Manufacturer website: None\n", + "Copied test_data/labels/label_018/img_001.jpg to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpuwj3w81v/img_001.jpg\n", + "Copied test_data/labels/label_018/img_002.jpg to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpuwj3w81v/img_002.jpg\n", + "\n", + "Label: label_018\n", + " Company website: www.golfgreen.ca\n", + " Manufacturer website: None\n", + "Copied test_data/labels/label_019/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpuwj3w81v/img_001.png\n", + "Copied test_data/labels/label_019/img_003.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpuwj3w81v/img_003.png\n", + "Copied test_data/labels/label_019/img_002.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpuwj3w81v/img_002.png\n", + "Copied test_data/labels/label_019/img_004.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpuwj3w81v/img_004.png\n", + "\n", + "Label: label_019\n", + " Company website: www.plantresponse.com\n", + " Manufacturer website: www.plantresponse.com\n", + "Copied test_data/labels/label_020/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpuwj3w81v/img_001.png\n", + "Copied test_data/labels/label_020/img_003.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpuwj3w81v/img_003.png\n", + "Copied test_data/labels/label_020/img_002.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpuwj3w81v/img_002.png\n", + "Copied test_data/labels/label_020/img_004.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpuwj3w81v/img_004.png\n", + "\n", + "Label: label_020\n", + " Company website: None\n", + " Manufacturer website: None\n", + "Copied test_data/labels/label_021/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpuwj3w81v/img_001.png\n", + "\n", + "Label: label_021\n", + " Company website: www.mlp-solutions.ca\n", + " Manufacturer website: www.bigbluebooster.com\n", + "Copied test_data/labels/label_022/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpuwj3w81v/img_001.png\n", + "Copied test_data/labels/label_022/img_002.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpuwj3w81v/img_002.png\n", + "\n", + "Label: label_022\n", + " Company website: www.sustane.com\n", + " Manufacturer website: www.sustane.com\n", + "Copied test_data/labels/label_023/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpuwj3w81v/img_001.png\n", + "Copied test_data/labels/label_023/img_002.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpuwj3w81v/img_002.png\n", + "\n", + "Label: label_023\n", + " Company website: www.myplantvantage.com\n", + " Manufacturer website: None\n", + "Copied test_data/labels/label_024/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpuwj3w81v/img_001.png\n", + "\n", + "Label: label_024\n", + " Company website: www.savaria.ca\n", + " Manufacturer website: None\n", + "Copied test_data/labels/label_025/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpuwj3w81v/img_001.png\n", + "\n", + "Label: label_025\n", + " Company website: None\n", + " Manufacturer website: None\n", + "Copied test_data/labels/label_026/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpuwj3w81v/img_001.png\n", + "\n", + "Label: label_026\n", + " Company website: None\n", + " Manufacturer website: None\n", + "Copied test_data/labels/label_027/img_001.jpg to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpuwj3w81v/img_001.jpg\n" + ] + }, + { + "ename": "HttpResponseError", + "evalue": "(InvalidRequest) Invalid request.\nCode: InvalidRequest\nMessage: Invalid request.\nInner error: {\n \"code\": \"InvalidContent\",\n \"message\": \"The file is corrupted or format is unsupported. Refer to documentation for the list of supported formats.\"\n}", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mHttpResponseError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m/var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/ipykernel_67308/3360134268.py\u001b[0m in \u001b[0;36m?\u001b[0;34m()\u001b[0m\n\u001b[1;32m 50\u001b[0m \u001b[0mlabel_storage\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0madd_image\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mbackup_path\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 51\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 52\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mlabel_storage\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mimages\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 53\u001b[0m \u001b[0;31m# Run the analyze function using the copied images\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 54\u001b[0;31m \u001b[0minspection\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0manalyze\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mlabel_storage\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mocr\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mgpt\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 55\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 56\u001b[0m \u001b[0;31m# Store the result in the dictionary with the label number as the key\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 57\u001b[0m \u001b[0mall_inspections\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34mf\"\u001b[0m\u001b[0;34mlabel_\u001b[0m\u001b[0;34m{\u001b[0m\u001b[0mlabel_num\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m03d\u001b[0m\u001b[0;34m}\u001b[0m\u001b[0;34m\"\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0minspection\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/github/fertiscan-pipeline/pipeline/__init__.py\u001b[0m in \u001b[0;36m?\u001b[0;34m(label_storage, ocr, gpt, log_dir_path)\u001b[0m\n\u001b[1;32m 30\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'create path'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 31\u001b[0m \u001b[0mos\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mmkdir\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mlog_dir_path\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 32\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 33\u001b[0m \u001b[0mdocument\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mlabel_storage\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mget_document\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 34\u001b[0;31m \u001b[0mresult\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mocr\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mextract_text\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdocument\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mdocument\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 35\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 36\u001b[0m \u001b[0;31m# Logs the results from document intelligence\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 37\u001b[0m \u001b[0mnow\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mdatetime\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mnow\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mstrftime\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'%Y-%m-%d_%H-%M-%S'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/github/fertiscan-pipeline/pipeline/ocr.py\u001b[0m in \u001b[0;36m?\u001b[0;34m(self, document)\u001b[0m\n\u001b[1;32m 15\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mextract_text\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mdocument\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0mbytes\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m->\u001b[0m \u001b[0mAnalyzeResult\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 16\u001b[0;31m poller = self.client.begin_analyze_document(\n\u001b[0m\u001b[1;32m 17\u001b[0m \u001b[0mmodel_id\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m\"prebuilt-layout\"\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 18\u001b[0m \u001b[0manalyze_request\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mAnalyzeDocumentRequest\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mbytes_source\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mdocument\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 19\u001b[0m \u001b[0moutput_content_format\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mContentFormat\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mMARKDOWN\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m/opt/homebrew/Caskroom/miniconda/base/envs/fertiscan-pipeline/lib/python3.12/site-packages/azure/core/tracing/decorator.py\u001b[0m in \u001b[0;36m?\u001b[0;34m(*args, **kwargs)\u001b[0m\n\u001b[1;32m 90\u001b[0m \u001b[0mpassed_in_parent\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mkwargs\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpop\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"parent_span\"\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;32mNone\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 91\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 92\u001b[0m \u001b[0mspan_impl_type\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0msettings\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtracing_implementation\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 93\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mspan_impl_type\u001b[0m \u001b[0;32mis\u001b[0m \u001b[0;32mNone\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 94\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mfunc\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 95\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 96\u001b[0m \u001b[0;31m# Merge span is parameter is set, but only if no explicit parent are passed\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 97\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mmerge_span\u001b[0m \u001b[0;32mand\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0mpassed_in_parent\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m/opt/homebrew/Caskroom/miniconda/base/envs/fertiscan-pipeline/lib/python3.12/site-packages/azure/ai/documentintelligence/_operations/_operations.py\u001b[0m in \u001b[0;36m?\u001b[0;34m(self, model_id, analyze_request, pages, locale, string_index_type, features, query_fields, output_content_format, **kwargs)\u001b[0m\n\u001b[1;32m 3623\u001b[0m \u001b[0mpolling\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0mUnion\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mbool\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mPollingMethod\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mkwargs\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpop\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"polling\"\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;32mTrue\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3624\u001b[0m \u001b[0mlro_delay\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mkwargs\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpop\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"polling_interval\"\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_config\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpolling_interval\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3625\u001b[0m \u001b[0mcont_token\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0mOptional\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mstr\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mkwargs\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpop\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"continuation_token\"\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;32mNone\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3626\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mcont_token\u001b[0m \u001b[0;32mis\u001b[0m \u001b[0;32mNone\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 3627\u001b[0;31m raw_result = self._analyze_document_initial( # type: ignore\n\u001b[0m\u001b[1;32m 3628\u001b[0m \u001b[0mmodel_id\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mmodel_id\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3629\u001b[0m \u001b[0manalyze_request\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0manalyze_request\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3630\u001b[0m \u001b[0mpages\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mpages\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m/opt/homebrew/Caskroom/miniconda/base/envs/fertiscan-pipeline/lib/python3.12/site-packages/azure/ai/documentintelligence/_operations/_operations.py\u001b[0m in \u001b[0;36m?\u001b[0;34m(self, model_id, analyze_request, pages, locale, string_index_type, features, query_fields, output_content_format, **kwargs)\u001b[0m\n\u001b[1;32m 514\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0m_stream\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 515\u001b[0m \u001b[0mresponse\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mread\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;31m# Load the body in memory and close the socket\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 516\u001b[0m \u001b[0mmap_error\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mstatus_code\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mresponse\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mstatus_code\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mresponse\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mresponse\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0merror_map\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0merror_map\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 517\u001b[0m \u001b[0merror\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0m_deserialize\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0m_models\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mErrorResponse\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mresponse\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mjson\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 518\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mHttpResponseError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mresponse\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mresponse\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmodel\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0merror\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 519\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 520\u001b[0m \u001b[0mresponse_headers\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m{\u001b[0m\u001b[0;34m}\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 521\u001b[0m \u001b[0mresponse_headers\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m\"Retry-After\"\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_deserialize\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"int\"\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mresponse\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mheaders\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mget\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"Retry-After\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mHttpResponseError\u001b[0m: (InvalidRequest) Invalid request.\nCode: InvalidRequest\nMessage: Invalid request.\nInner error: {\n \"code\": \"InvalidContent\",\n \"message\": \"The file is corrupted or format is unsupported. Refer to documentation for the list of supported formats.\"\n}" + ] + } + ], + "source": [ + "# Load environment variables\n", + "load_dotenv()\n", + "\n", + "# Define label folder numbers dynamically from 1 to 35\n", + "label_folders = range(1, 36)\n", + "# label_folders = [1, 6, 8]\n", + "\n", + "# Define possible image extensions\n", + "image_extensions = [\".jpg\", \".png\"]\n", + "\n", + "# Mock environment setup for OCR and GPT\n", + "api_endpoint_ocr = os.getenv(\"AZURE_API_ENDPOINT\")\n", + "api_key_ocr = os.getenv(\"AZURE_API_KEY\")\n", + "api_endpoint_gpt = os.getenv(\"AZURE_OPENAI_ENDPOINT\")\n", + "api_key_gpt = os.getenv(\"AZURE_OPENAI_KEY\")\n", + "api_deployment_gpt = os.getenv(\"AZURE_OPENAI_DEPLOYMENT\")\n", + "\n", + "# Initialize OCR and GPT objects (reusable)\n", + "ocr = OCR(api_endpoint=api_endpoint_ocr, api_key=api_key_ocr)\n", + "gpt = GPT(\n", + " api_endpoint=api_endpoint_gpt, api_key=api_key_gpt, deployment_id=api_deployment_gpt\n", + ")\n", + "\n", + "# Create a temporary directory for image copies\n", + "with tempfile.TemporaryDirectory() as backup_dir:\n", + " print(f\"Backup directory created at: {backup_dir}\")\n", + "\n", + " # Dictionary to store inspection results for all labels\n", + " all_inspections = {}\n", + "\n", + " # Loop through each label folder\n", + " for label_num in label_folders:\n", + " label_folder = f\"test_data/labels/label_{label_num:03d}\" # Format as label_001, label_002, etc.\n", + " label_storage = (\n", + " LabelStorage()\n", + " ) # Initialize a new LabelStorage for each label folder\n", + "\n", + " # Find relevant image files in the label folder\n", + " for ext in image_extensions:\n", + " pattern = os.path.join(label_folder, f\"img_*{ext}\")\n", + " image_files = glob(pattern)\n", + "\n", + " # Copy found images to the backup directory and use copies for processing\n", + " for image_path in image_files:\n", + " backup_path = os.path.join(backup_dir, os.path.basename(image_path))\n", + " shutil.copy(image_path, backup_path)\n", + " print(f\"Copied {image_path} to {backup_path}\")\n", + "\n", + " # Add the copied image to the label storage\n", + " label_storage.add_image(backup_path)\n", + "\n", + " if label_storage.images:\n", + " # Run the analyze function using the copied images\n", + " inspection = analyze(label_storage, ocr, gpt)\n", + "\n", + " # Store the result in the dictionary with the label number as the key\n", + " all_inspections[f\"label_{label_num:03d}\"] = inspection\n", + "\n", + " # Print the inspection results as they are processed\n", + " print(f\"\\nLabel: label_{label_num:03d}\")\n", + " print(f\" Company website: {inspection.company_website}\")\n", + " print(f\" Manufacturer website: {inspection.manufacturer_website}\")\n", + "\n", + " # Pickle all the results in a single file\n", + " pickle.dump(all_inspections, open(\"all_inspections.pkl\", \"wb\"))\n", + "\n", + "print(\"\\nAll inspections have been processed and saved to all_inspections.pkl\")\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Analysis\n", + "\n", + "Do not mind the error. It's probably due to using `tempfile`. Will investigate later.\n", + "\n", + "Before the fix, the main problems were: \n", + "- `www.` missing in some websites\n", + "- mix of lowercase and uppercase chars\n", + "\n", + "After the fix, from the results, we can see that the llm is handling pretty well the website fields formatting.\n", + "\n", + "My concern is that, we can't be sure how it will react when all the other fields are loaded with descriptions (prompts). Will it be cognitively overloaded and hallucinate?\n", + "\n", + "Should we just code the formatting? The lower case is already coded (post processing) and we can add `www.` when it is missing, but how cool is it to let the llm do it!" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# # Load the pickled data\n", + "# with open(\"all_inspections.pkl\", \"rb\") as f:\n", + "# all_inspections: dict[str, FertilizerInspection] = pickle.load(f)\n", + "\n", + "# for label, inspection in all_inspections.items():\n", + "# print(f\"Label: {label}\")\n", + "# print(f\" Company website: {inspection.company_website}\")\n", + "# print(f\" Manufacturer website: {inspection.manufacturer_website}\")\n", + "# print()\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "fertiscan-pipeline", + "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.12.4" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} From d5a9a5cec42e980cc6a5bd7cc02f9c9ad384f29e Mon Sep 17 00:00:00 2001 From: "K. Allagbe" Date: Tue, 22 Oct 2024 11:30:18 -0400 Subject: [PATCH 2/3] issue #60: integration tests --- all_inspections.pkl | Bin 8797 -> 111602 bytes test.ipynb | 159 +++++++++++++++++++++++---------------- tests/test_pipeline.py | 164 ++++++++++++++++++++++++++++++++++------- 3 files changed, 235 insertions(+), 88 deletions(-) diff --git a/all_inspections.pkl b/all_inspections.pkl index e2dfe6c0865053d9b5ae0ed556b86060567506c2..7d1518f74e0c1b7ddff2abc54f87a8df8eb5ddbf 100644 GIT binary patch literal 111602 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 delta 46 zcmV+}0MY;Q=LX$G27m;WQX&Ac21OCGGA&vGldB^alRmT;li$ZMv+FKr3A5Hh@dW~P EE~LZ~EdT%j diff --git a/test.ipynb b/test.ipynb index 9e1b574..127289a 100644 --- a/test.ipynb +++ b/test.ipynb @@ -20,178 +20,213 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "Backup directory created at: /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpuwj3w81v\n", - "Copied test_data/labels/label_001/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpuwj3w81v/img_001.png\n", + "Backup directory created at: /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8\n", + "Copied test_data/labels/label_001/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_001.png\n", "\n", "Label: label_001\n", " Company website: www.soil-aid.com\n", " Manufacturer website: www.soil-aid.com\n", - "Copied test_data/labels/label_002/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpuwj3w81v/img_001.png\n", + "Copied test_data/labels/label_002/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_001.png\n", "\n", "Label: label_002\n", " Company website: None\n", " Manufacturer website: None\n", - "Copied test_data/labels/label_003/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpuwj3w81v/img_001.png\n", + "Copied test_data/labels/label_003/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_001.png\n", "\n", "Label: label_003\n", " Company website: None\n", " Manufacturer website: None\n", - "Copied test_data/labels/label_004/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpuwj3w81v/img_001.png\n", + "Copied test_data/labels/label_004/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_001.png\n", "\n", "Label: label_004\n", " Company website: None\n", " Manufacturer website: None\n", - "Copied test_data/labels/label_005/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpuwj3w81v/img_001.png\n", + "Copied test_data/labels/label_005/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_001.png\n", "\n", "Label: label_005\n", " Company website: None\n", " Manufacturer website: None\n", - "Copied test_data/labels/label_006/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpuwj3w81v/img_001.png\n", + "Copied test_data/labels/label_006/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_001.png\n", "\n", "Label: label_006\n", " Company website: www.activeagriscience.com\n", " Manufacturer website: None\n", - "Copied test_data/labels/label_007/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpuwj3w81v/img_001.png\n", + "Copied test_data/labels/label_007/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_001.png\n", "\n", "Label: label_007\n", " Company website: www.activeagriscience.com\n", " Manufacturer website: None\n", - "Copied test_data/labels/label_008/img_001.jpg to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpuwj3w81v/img_001.jpg\n", + "Copied test_data/labels/label_008/img_001.jpg to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_001.jpg\n", "\n", "Label: label_008\n", " Company website: www.easygardener.com\n", " Manufacturer website: None\n", - "Copied test_data/labels/label_009/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpuwj3w81v/img_001.png\n", + "Copied test_data/labels/label_009/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_001.png\n", "\n", "Label: label_009\n", " Company website: None\n", " Manufacturer website: None\n", - "Copied test_data/labels/label_010/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpuwj3w81v/img_001.png\n", + "Copied test_data/labels/label_010/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_001.png\n", "\n", "Label: label_010\n", " Company website: None\n", " Manufacturer website: None\n", - "Copied test_data/labels/label_011/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpuwj3w81v/img_001.png\n", + "Copied test_data/labels/label_011/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_001.png\n", "\n", "Label: label_011\n", " Company website: www.advancingecoag.com\n", " Manufacturer website: None\n", - "Copied test_data/labels/label_012/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpuwj3w81v/img_001.png\n", - "Copied test_data/labels/label_012/img_002.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpuwj3w81v/img_002.png\n", + "Copied test_data/labels/label_012/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_001.png\n", + "Copied test_data/labels/label_012/img_002.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_002.png\n", "\n", "Label: label_012\n", " Company website: None\n", " Manufacturer website: None\n", - "Copied test_data/labels/label_013/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpuwj3w81v/img_001.png\n", - "Copied test_data/labels/label_013/img_002.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpuwj3w81v/img_002.png\n", + "Copied test_data/labels/label_013/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_001.png\n", + "Copied test_data/labels/label_013/img_002.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_002.png\n", "\n", "Label: label_013\n", " Company website: None\n", " Manufacturer website: None\n", - "Copied test_data/labels/label_014/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpuwj3w81v/img_001.png\n", - "Copied test_data/labels/label_014/img_003.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpuwj3w81v/img_003.png\n", - "Copied test_data/labels/label_014/img_002.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpuwj3w81v/img_002.png\n", + "Copied test_data/labels/label_014/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_001.png\n", + "Copied test_data/labels/label_014/img_003.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_003.png\n", + "Copied test_data/labels/label_014/img_002.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_002.png\n", "\n", "Label: label_014\n", " Company website: None\n", " Manufacturer website: None\n", - "Copied test_data/labels/label_015/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpuwj3w81v/img_001.png\n", - "Copied test_data/labels/label_015/img_002.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpuwj3w81v/img_002.png\n", + "Copied test_data/labels/label_015/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_001.png\n", + "Copied test_data/labels/label_015/img_002.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_002.png\n", "\n", "Label: label_015\n", " Company website: www.bionik.ca\n", " Manufacturer website: None\n", - "Copied test_data/labels/label_016/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpuwj3w81v/img_001.png\n", - "Copied test_data/labels/label_016/img_002.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpuwj3w81v/img_002.png\n", + "Copied test_data/labels/label_016/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_001.png\n", + "Copied test_data/labels/label_016/img_002.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_002.png\n", "\n", "Label: label_016\n", " Company website: None\n", " Manufacturer website: None\n", - "Copied test_data/labels/label_017/img_001.jpg to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpuwj3w81v/img_001.jpg\n", - "Copied test_data/labels/label_017/img_003.jpg to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpuwj3w81v/img_003.jpg\n", - "Copied test_data/labels/label_017/img_002.jpg to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpuwj3w81v/img_002.jpg\n", + "Copied test_data/labels/label_017/img_001.jpg to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_001.jpg\n", + "Copied test_data/labels/label_017/img_003.jpg to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_003.jpg\n", + "Copied test_data/labels/label_017/img_002.jpg to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_002.jpg\n", "\n", "Label: label_017\n", " Company website: www.golfgreen.ca\n", " Manufacturer website: None\n", - "Copied test_data/labels/label_018/img_001.jpg to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpuwj3w81v/img_001.jpg\n", - "Copied test_data/labels/label_018/img_002.jpg to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpuwj3w81v/img_002.jpg\n", + "Copied test_data/labels/label_018/img_001.jpg to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_001.jpg\n", + "Copied test_data/labels/label_018/img_002.jpg to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_002.jpg\n", "\n", "Label: label_018\n", " Company website: www.golfgreen.ca\n", " Manufacturer website: None\n", - "Copied test_data/labels/label_019/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpuwj3w81v/img_001.png\n", - "Copied test_data/labels/label_019/img_003.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpuwj3w81v/img_003.png\n", - "Copied test_data/labels/label_019/img_002.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpuwj3w81v/img_002.png\n", - "Copied test_data/labels/label_019/img_004.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpuwj3w81v/img_004.png\n", + "Copied test_data/labels/label_019/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_001.png\n", + "Copied test_data/labels/label_019/img_003.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_003.png\n", + "Copied test_data/labels/label_019/img_002.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_002.png\n", + "Copied test_data/labels/label_019/img_004.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_004.png\n", "\n", "Label: label_019\n", " Company website: www.plantresponse.com\n", " Manufacturer website: www.plantresponse.com\n", - "Copied test_data/labels/label_020/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpuwj3w81v/img_001.png\n", - "Copied test_data/labels/label_020/img_003.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpuwj3w81v/img_003.png\n", - "Copied test_data/labels/label_020/img_002.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpuwj3w81v/img_002.png\n", - "Copied test_data/labels/label_020/img_004.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpuwj3w81v/img_004.png\n", + "Copied test_data/labels/label_020/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_001.png\n", + "Copied test_data/labels/label_020/img_003.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_003.png\n", + "Copied test_data/labels/label_020/img_002.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_002.png\n", + "Copied test_data/labels/label_020/img_004.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_004.png\n", "\n", "Label: label_020\n", " Company website: None\n", " Manufacturer website: None\n", - "Copied test_data/labels/label_021/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpuwj3w81v/img_001.png\n", + "Copied test_data/labels/label_021/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_001.png\n", "\n", "Label: label_021\n", " Company website: www.mlp-solutions.ca\n", " Manufacturer website: www.bigbluebooster.com\n", - "Copied test_data/labels/label_022/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpuwj3w81v/img_001.png\n", - "Copied test_data/labels/label_022/img_002.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpuwj3w81v/img_002.png\n", + "Copied test_data/labels/label_022/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_001.png\n", + "Copied test_data/labels/label_022/img_002.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_002.png\n", "\n", "Label: label_022\n", " Company website: www.sustane.com\n", " Manufacturer website: www.sustane.com\n", - "Copied test_data/labels/label_023/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpuwj3w81v/img_001.png\n", - "Copied test_data/labels/label_023/img_002.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpuwj3w81v/img_002.png\n", + "Copied test_data/labels/label_023/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_001.png\n", + "Copied test_data/labels/label_023/img_002.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_002.png\n", "\n", "Label: label_023\n", " Company website: www.myplantvantage.com\n", " Manufacturer website: None\n", - "Copied test_data/labels/label_024/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpuwj3w81v/img_001.png\n", + "Copied test_data/labels/label_024/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_001.png\n", "\n", "Label: label_024\n", " Company website: www.savaria.ca\n", " Manufacturer website: None\n", - "Copied test_data/labels/label_025/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpuwj3w81v/img_001.png\n", + "Copied test_data/labels/label_025/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_001.png\n", "\n", "Label: label_025\n", " Company website: None\n", " Manufacturer website: None\n", - "Copied test_data/labels/label_026/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpuwj3w81v/img_001.png\n", + "Copied test_data/labels/label_026/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_001.png\n", "\n", "Label: label_026\n", " Company website: None\n", " Manufacturer website: None\n", - "Copied test_data/labels/label_027/img_001.jpg to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpuwj3w81v/img_001.jpg\n" - ] - }, - { - "ename": "HttpResponseError", - "evalue": "(InvalidRequest) Invalid request.\nCode: InvalidRequest\nMessage: Invalid request.\nInner error: {\n \"code\": \"InvalidContent\",\n \"message\": \"The file is corrupted or format is unsupported. Refer to documentation for the list of supported formats.\"\n}", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mHttpResponseError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m/var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/ipykernel_67308/3360134268.py\u001b[0m in \u001b[0;36m?\u001b[0;34m()\u001b[0m\n\u001b[1;32m 50\u001b[0m \u001b[0mlabel_storage\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0madd_image\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mbackup_path\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 51\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 52\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mlabel_storage\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mimages\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 53\u001b[0m \u001b[0;31m# Run the analyze function using the copied images\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 54\u001b[0;31m \u001b[0minspection\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0manalyze\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mlabel_storage\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mocr\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mgpt\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 55\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 56\u001b[0m \u001b[0;31m# Store the result in the dictionary with the label number as the key\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 57\u001b[0m \u001b[0mall_inspections\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34mf\"\u001b[0m\u001b[0;34mlabel_\u001b[0m\u001b[0;34m{\u001b[0m\u001b[0mlabel_num\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m03d\u001b[0m\u001b[0;34m}\u001b[0m\u001b[0;34m\"\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0minspection\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m~/github/fertiscan-pipeline/pipeline/__init__.py\u001b[0m in \u001b[0;36m?\u001b[0;34m(label_storage, ocr, gpt, log_dir_path)\u001b[0m\n\u001b[1;32m 30\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'create path'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 31\u001b[0m \u001b[0mos\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mmkdir\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mlog_dir_path\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 32\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 33\u001b[0m \u001b[0mdocument\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mlabel_storage\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mget_document\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 34\u001b[0;31m \u001b[0mresult\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mocr\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mextract_text\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdocument\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mdocument\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 35\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 36\u001b[0m \u001b[0;31m# Logs the results from document intelligence\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 37\u001b[0m \u001b[0mnow\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mdatetime\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mnow\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mstrftime\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'%Y-%m-%d_%H-%M-%S'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m~/github/fertiscan-pipeline/pipeline/ocr.py\u001b[0m in \u001b[0;36m?\u001b[0;34m(self, document)\u001b[0m\n\u001b[1;32m 15\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mextract_text\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mdocument\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0mbytes\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m->\u001b[0m \u001b[0mAnalyzeResult\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 16\u001b[0;31m poller = self.client.begin_analyze_document(\n\u001b[0m\u001b[1;32m 17\u001b[0m \u001b[0mmodel_id\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m\"prebuilt-layout\"\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 18\u001b[0m \u001b[0manalyze_request\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mAnalyzeDocumentRequest\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mbytes_source\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mdocument\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 19\u001b[0m \u001b[0moutput_content_format\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mContentFormat\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mMARKDOWN\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m/opt/homebrew/Caskroom/miniconda/base/envs/fertiscan-pipeline/lib/python3.12/site-packages/azure/core/tracing/decorator.py\u001b[0m in \u001b[0;36m?\u001b[0;34m(*args, **kwargs)\u001b[0m\n\u001b[1;32m 90\u001b[0m \u001b[0mpassed_in_parent\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mkwargs\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpop\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"parent_span\"\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;32mNone\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 91\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 92\u001b[0m \u001b[0mspan_impl_type\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0msettings\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtracing_implementation\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 93\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mspan_impl_type\u001b[0m \u001b[0;32mis\u001b[0m \u001b[0;32mNone\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 94\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mfunc\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 95\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 96\u001b[0m \u001b[0;31m# Merge span is parameter is set, but only if no explicit parent are passed\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 97\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mmerge_span\u001b[0m \u001b[0;32mand\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0mpassed_in_parent\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m/opt/homebrew/Caskroom/miniconda/base/envs/fertiscan-pipeline/lib/python3.12/site-packages/azure/ai/documentintelligence/_operations/_operations.py\u001b[0m in \u001b[0;36m?\u001b[0;34m(self, model_id, analyze_request, pages, locale, string_index_type, features, query_fields, output_content_format, **kwargs)\u001b[0m\n\u001b[1;32m 3623\u001b[0m \u001b[0mpolling\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0mUnion\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mbool\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mPollingMethod\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mkwargs\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpop\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"polling\"\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;32mTrue\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3624\u001b[0m \u001b[0mlro_delay\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mkwargs\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpop\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"polling_interval\"\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_config\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpolling_interval\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3625\u001b[0m \u001b[0mcont_token\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0mOptional\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mstr\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mkwargs\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpop\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"continuation_token\"\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;32mNone\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3626\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mcont_token\u001b[0m \u001b[0;32mis\u001b[0m \u001b[0;32mNone\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 3627\u001b[0;31m raw_result = self._analyze_document_initial( # type: ignore\n\u001b[0m\u001b[1;32m 3628\u001b[0m \u001b[0mmodel_id\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mmodel_id\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3629\u001b[0m \u001b[0manalyze_request\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0manalyze_request\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3630\u001b[0m \u001b[0mpages\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mpages\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m/opt/homebrew/Caskroom/miniconda/base/envs/fertiscan-pipeline/lib/python3.12/site-packages/azure/ai/documentintelligence/_operations/_operations.py\u001b[0m in \u001b[0;36m?\u001b[0;34m(self, model_id, analyze_request, pages, locale, string_index_type, features, query_fields, output_content_format, **kwargs)\u001b[0m\n\u001b[1;32m 514\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0m_stream\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 515\u001b[0m \u001b[0mresponse\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mread\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;31m# Load the body in memory and close the socket\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 516\u001b[0m \u001b[0mmap_error\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mstatus_code\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mresponse\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mstatus_code\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mresponse\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mresponse\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0merror_map\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0merror_map\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 517\u001b[0m \u001b[0merror\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0m_deserialize\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0m_models\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mErrorResponse\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mresponse\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mjson\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 518\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mHttpResponseError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mresponse\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mresponse\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmodel\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0merror\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 519\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 520\u001b[0m \u001b[0mresponse_headers\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m{\u001b[0m\u001b[0;34m}\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 521\u001b[0m \u001b[0mresponse_headers\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m\"Retry-After\"\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_deserialize\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"int\"\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mresponse\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mheaders\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mget\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"Retry-After\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;31mHttpResponseError\u001b[0m: (InvalidRequest) Invalid request.\nCode: InvalidRequest\nMessage: Invalid request.\nInner error: {\n \"code\": \"InvalidContent\",\n \"message\": \"The file is corrupted or format is unsupported. Refer to documentation for the list of supported formats.\"\n}" + "Copied test_data/labels/label_027/img_001.jpg to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_001.jpg\n", + "\n", + "Label: label_027\n", + " Company website: None\n", + " Manufacturer website: None\n", + "Copied test_data/labels/label_028/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_001.png\n", + "\n", + "Label: label_028\n", + " Company website: None\n", + " Manufacturer website: None\n", + "Copied test_data/labels/label_029/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_001.png\n", + "\n", + "Label: label_029\n", + " Company website: None\n", + " Manufacturer website: None\n", + "Copied test_data/labels/label_030/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_001.png\n", + "\n", + "Label: label_030\n", + " Company website: None\n", + " Manufacturer website: None\n", + "Copied test_data/labels/label_031/img_002.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_002.png\n", + "\n", + "Label: label_031\n", + " Company website: www.lfp-solutions.ca\n", + " Manufacturer website: www.bigbluebooster.com\n", + "Copied test_data/labels/label_032/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_001.png\n", + "Copied test_data/labels/label_032/img_003.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_003.png\n", + "Copied test_data/labels/label_032/img_002.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_002.png\n", + "\n", + "Label: label_032\n", + " Company website: None\n", + " Manufacturer website: None\n", + "Copied test_data/labels/label_033/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_001.png\n", + "Copied test_data/labels/label_033/img_002.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_002.png\n", + "\n", + "Label: label_033\n", + " Company website: None\n", + " Manufacturer website: None\n", + "Copied test_data/labels/label_034/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_001.png\n", + "Copied test_data/labels/label_034/img_002.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_002.png\n", + "\n", + "Label: label_034\n", + " Company website: www.advancednutrients.com/growersupport\n", + " Manufacturer website: None\n", + "Copied test_data/labels/label_035/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_001.png\n", + "Copied test_data/labels/label_035/img_002.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_002.png\n", + "\n", + "Label: label_035\n", + " Company website: www.bionik.ca\n", + " Manufacturer website: None\n", + "\n", + "All inspections have been processed and saved to all_inspections.pkl\n" ] } ], diff --git a/tests/test_pipeline.py b/tests/test_pipeline.py index 50d6591..c1a8272 100644 --- a/tests/test_pipeline.py +++ b/tests/test_pipeline.py @@ -1,41 +1,52 @@ import os +import shutil +import tempfile import unittest +from datetime import datetime -from tests import curl_file from dotenv import load_dotenv -from datetime import datetime -from tests import levenshtein_similarity + +from pipeline import GPT, OCR, LabelStorage, analyze from pipeline.inspection import FertilizerInspection, Value -from pipeline import LabelStorage, OCR, GPT, analyze +from tests import curl_file, levenshtein_similarity -class TestPipeline(unittest.TestCase): +class TestPipeline(unittest.TestCase): @classmethod def setUpClass(self): load_dotenv() # Set up the required objects - self.log_dir_path = './test_logs' - self.image_path = f'{self.log_dir_path}/test_image.jpg' # Path to your test image - + self.log_dir_path = "./test_logs" + self.image_path = ( + f"{self.log_dir_path}/test_image.jpg" # Path to your test image + ) + # Ensure the log directory exists if not os.path.exists(self.log_dir_path): os.mkdir(self.log_dir_path) - + # Download the test image - curl_file(url='https://tlhort.com/cdn/shop/products/10-52-0MAP.jpg', path=self.image_path) - + curl_file( + url="https://tlhort.com/cdn/shop/products/10-52-0MAP.jpg", + path=self.image_path, + ) + # Mock environment setup for OCR and GPT - self.api_endpoint_ocr = os.getenv('AZURE_API_ENDPOINT') - self.api_key_ocr = os.getenv('AZURE_API_KEY') - self.api_endpoint_gpt = os.getenv('AZURE_OPENAI_ENDPOINT') - self.api_key_gpt = os.getenv('AZURE_OPENAI_KEY') - self.api_deployment_gpt = os.getenv('AZURE_OPENAI_DEPLOYMENT') - + self.api_endpoint_ocr = os.getenv("AZURE_API_ENDPOINT") + self.api_key_ocr = os.getenv("AZURE_API_KEY") + self.api_endpoint_gpt = os.getenv("AZURE_OPENAI_ENDPOINT") + self.api_key_gpt = os.getenv("AZURE_OPENAI_KEY") + self.api_deployment_gpt = os.getenv("AZURE_OPENAI_DEPLOYMENT") + # Initialize the objects self.label_storage = LabelStorage() self.label_storage.add_image(self.image_path) self.ocr = OCR(api_endpoint=self.api_endpoint_ocr, api_key=self.api_key_ocr) - self.gpt = GPT(api_endpoint=self.api_endpoint_gpt, api_key=self.api_key_gpt, deployment_id=self.api_deployment_gpt) + self.gpt = GPT( + api_endpoint=self.api_endpoint_gpt, + api_key=self.api_key_gpt, + deployment_id=self.api_deployment_gpt, + ) @classmethod def tearDownClass(cls): @@ -48,23 +59,124 @@ def tearDownClass(cls): def test_analyze(self): # Run the analyze function - inspection = analyze(self.label_storage, self.ocr, self.gpt, log_dir_path=self.log_dir_path) - + inspection = analyze( + self.label_storage, self.ocr, self.gpt, log_dir_path=self.log_dir_path + ) + # Perform assertions self.assertIsInstance(inspection, FertilizerInspection, inspection) - self.assertIn(Value(value='25', unit='kg'), inspection.weight, inspection) - self.assertGreater(levenshtein_similarity(inspection.manufacturer_name, "TerraLink"), 0.95, inspection) - self.assertGreater(levenshtein_similarity(inspection.npk, "10-52-0"), 0.90, inspection) + self.assertIn(Value(value="25", unit="kg"), inspection.weight, inspection) + self.assertGreater( + levenshtein_similarity(inspection.manufacturer_name, "TerraLink"), + 0.95, + inspection, + ) + self.assertGreater( + levenshtein_similarity(inspection.npk, "10-52-0"), 0.90, inspection + ) # Ensure logs are created and then deleted - now = datetime.now().strftime('%Y-%m-%d %H:%M:%S') + now = datetime.now().strftime("%Y-%m-%d %H:%M:%S") md_log_path = f"{self.log_dir_path}/{now}.md" json_log_path = f"{self.log_dir_path}/{now}.json" txt_log_path = f"{self.log_dir_path}/{now}.txt" - + self.assertFalse(os.path.exists(md_log_path)) self.assertFalse(os.path.exists(json_log_path)) self.assertFalse(os.path.exists(txt_log_path)) -if __name__ == '__main__': + +class TestWebsiteFields(unittest.TestCase): + @classmethod + def setUpClass(cls): + # Load environment variables + load_dotenv() + + # Mock environment setup for OCR and GPT + cls.api_endpoint_ocr = os.getenv("AZURE_API_ENDPOINT") + cls.api_key_ocr = os.getenv("AZURE_API_KEY") + cls.api_endpoint_gpt = os.getenv("AZURE_OPENAI_ENDPOINT") + cls.api_key_gpt = os.getenv("AZURE_OPENAI_KEY") + cls.api_deployment_gpt = os.getenv("AZURE_OPENAI_DEPLOYMENT") + + # Initialize OCR and GPT objects (real instances) + cls.ocr = OCR(api_endpoint=cls.api_endpoint_ocr, api_key=cls.api_key_ocr) + cls.gpt = GPT( + api_endpoint=cls.api_endpoint_gpt, + api_key=cls.api_key_gpt, + deployment_id=cls.api_deployment_gpt, + ) + + # Supported image extensions + cls.image_extensions = [".jpg", ".png"] + + # Create a temporary directory for image copies + cls.temp_dir = tempfile.mkdtemp() + + @classmethod + def tearDownClass(cls): + # Clean up the temporary directory after tests are done + shutil.rmtree(cls.temp_dir) + + def copy_images_to_temp_dir(self, label_folder): + copied_files = [] + for file_name in os.listdir(label_folder): + _, ext = os.path.splitext(file_name) + if ext.lower() in self.image_extensions: + image_path = os.path.join(label_folder, file_name) + temp_image_path = os.path.join(self.temp_dir, file_name) + shutil.copy(image_path, temp_image_path) + copied_files.append(temp_image_path) + return copied_files + + def add_images_to_storage(self, image_paths, label_storage): + for image_path in image_paths: + label_storage.add_image(image_path) + + def test_label_001_website_inspection(self): + label_folder = "test_data/labels/label_001" + label_storage = LabelStorage() + + # Copy images to temporary directory and add to storage + image_paths = self.copy_images_to_temp_dir(label_folder) + self.add_images_to_storage(image_paths, label_storage) + + # Run the analyze function + inspection = analyze(label_storage, self.ocr, self.gpt) + + # Assertions for website fields + self.assertEqual(inspection.company_website, "www.soil-aid.com") + + def test_label_006_website_inspection(self): + label_folder = "test_data/labels/label_006" + label_storage = LabelStorage() + + # Copy images to temporary directory and add to storage + image_paths = self.copy_images_to_temp_dir(label_folder) + self.add_images_to_storage(image_paths, label_storage) + + # Run the analyze function + inspection = analyze(label_storage, self.ocr, self.gpt) + + # Assertions for website fields + self.assertEqual(inspection.company_website, "www.activeagriscience.com") + + def test_label_034_website_inspection(self): + label_folder = "test_data/labels/label_034" + label_storage = LabelStorage() + + # Copy images to temporary directory and add to storage + image_paths = self.copy_images_to_temp_dir(label_folder) + self.add_images_to_storage(image_paths, label_storage) + + # Run the analyze function + inspection = analyze(label_storage, self.ocr, self.gpt) + + # Assertions for website fields + self.assertEqual( + inspection.company_website, "www.advancednutrients.com/growersupport" + ) + + +if __name__ == "__main__": unittest.main() From 1a5e455cd1e92cbc73402132f69a5526152d13a5 Mon Sep 17 00:00:00 2001 From: "K. Allagbe" Date: Tue, 22 Oct 2024 11:46:17 -0400 Subject: [PATCH 3/3] issue #61: remove testing files --- all_inspections.pkl | Bin 111602 -> 0 bytes test.ipynb | 361 -------------------------------------------- 2 files changed, 361 deletions(-) delete mode 100644 all_inspections.pkl delete mode 100644 test.ipynb diff --git a/all_inspections.pkl b/all_inspections.pkl deleted file mode 100644 index 7d1518f74e0c1b7ddff2abc54f87a8df8eb5ddbf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 111602 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 diff --git a/test.ipynb b/test.ipynb deleted file mode 100644 index 127289a..0000000 --- a/test.ipynb +++ /dev/null @@ -1,361 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "import os\n", - "import pickle\n", - "import shutil\n", - "import tempfile\n", - "from glob import glob\n", - "\n", - "from dotenv import load_dotenv\n", - "\n", - "from pipeline import GPT, OCR, LabelStorage, analyze\n", - "from pipeline.inspection import FertilizerInspection\n" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Backup directory created at: /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8\n", - "Copied test_data/labels/label_001/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_001.png\n", - "\n", - "Label: label_001\n", - " Company website: www.soil-aid.com\n", - " Manufacturer website: www.soil-aid.com\n", - "Copied test_data/labels/label_002/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_001.png\n", - "\n", - "Label: label_002\n", - " Company website: None\n", - " Manufacturer website: None\n", - "Copied test_data/labels/label_003/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_001.png\n", - "\n", - "Label: label_003\n", - " Company website: None\n", - " Manufacturer website: None\n", - "Copied test_data/labels/label_004/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_001.png\n", - "\n", - "Label: label_004\n", - " Company website: None\n", - " Manufacturer website: None\n", - "Copied test_data/labels/label_005/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_001.png\n", - "\n", - "Label: label_005\n", - " Company website: None\n", - " Manufacturer website: None\n", - "Copied test_data/labels/label_006/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_001.png\n", - "\n", - "Label: label_006\n", - " Company website: www.activeagriscience.com\n", - " Manufacturer website: None\n", - "Copied test_data/labels/label_007/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_001.png\n", - "\n", - "Label: label_007\n", - " Company website: www.activeagriscience.com\n", - " Manufacturer website: None\n", - "Copied test_data/labels/label_008/img_001.jpg to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_001.jpg\n", - "\n", - "Label: label_008\n", - " Company website: www.easygardener.com\n", - " Manufacturer website: None\n", - "Copied test_data/labels/label_009/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_001.png\n", - "\n", - "Label: label_009\n", - " Company website: None\n", - " Manufacturer website: None\n", - "Copied test_data/labels/label_010/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_001.png\n", - "\n", - "Label: label_010\n", - " Company website: None\n", - " Manufacturer website: None\n", - "Copied test_data/labels/label_011/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_001.png\n", - "\n", - "Label: label_011\n", - " Company website: www.advancingecoag.com\n", - " Manufacturer website: None\n", - "Copied test_data/labels/label_012/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_001.png\n", - "Copied test_data/labels/label_012/img_002.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_002.png\n", - "\n", - "Label: label_012\n", - " Company website: None\n", - " Manufacturer website: None\n", - "Copied test_data/labels/label_013/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_001.png\n", - "Copied test_data/labels/label_013/img_002.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_002.png\n", - "\n", - "Label: label_013\n", - " Company website: None\n", - " Manufacturer website: None\n", - "Copied test_data/labels/label_014/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_001.png\n", - "Copied test_data/labels/label_014/img_003.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_003.png\n", - "Copied test_data/labels/label_014/img_002.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_002.png\n", - "\n", - "Label: label_014\n", - " Company website: None\n", - " Manufacturer website: None\n", - "Copied test_data/labels/label_015/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_001.png\n", - "Copied test_data/labels/label_015/img_002.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_002.png\n", - "\n", - "Label: label_015\n", - " Company website: www.bionik.ca\n", - " Manufacturer website: None\n", - "Copied test_data/labels/label_016/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_001.png\n", - "Copied test_data/labels/label_016/img_002.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_002.png\n", - "\n", - "Label: label_016\n", - " Company website: None\n", - " Manufacturer website: None\n", - "Copied test_data/labels/label_017/img_001.jpg to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_001.jpg\n", - "Copied test_data/labels/label_017/img_003.jpg to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_003.jpg\n", - "Copied test_data/labels/label_017/img_002.jpg to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_002.jpg\n", - "\n", - "Label: label_017\n", - " Company website: www.golfgreen.ca\n", - " Manufacturer website: None\n", - "Copied test_data/labels/label_018/img_001.jpg to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_001.jpg\n", - "Copied test_data/labels/label_018/img_002.jpg to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_002.jpg\n", - "\n", - "Label: label_018\n", - " Company website: www.golfgreen.ca\n", - " Manufacturer website: None\n", - "Copied test_data/labels/label_019/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_001.png\n", - "Copied test_data/labels/label_019/img_003.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_003.png\n", - "Copied test_data/labels/label_019/img_002.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_002.png\n", - "Copied test_data/labels/label_019/img_004.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_004.png\n", - "\n", - "Label: label_019\n", - " Company website: www.plantresponse.com\n", - " Manufacturer website: www.plantresponse.com\n", - "Copied test_data/labels/label_020/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_001.png\n", - "Copied test_data/labels/label_020/img_003.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_003.png\n", - "Copied test_data/labels/label_020/img_002.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_002.png\n", - "Copied test_data/labels/label_020/img_004.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_004.png\n", - "\n", - "Label: label_020\n", - " Company website: None\n", - " Manufacturer website: None\n", - "Copied test_data/labels/label_021/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_001.png\n", - "\n", - "Label: label_021\n", - " Company website: www.mlp-solutions.ca\n", - " Manufacturer website: www.bigbluebooster.com\n", - "Copied test_data/labels/label_022/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_001.png\n", - "Copied test_data/labels/label_022/img_002.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_002.png\n", - "\n", - "Label: label_022\n", - " Company website: www.sustane.com\n", - " Manufacturer website: www.sustane.com\n", - "Copied test_data/labels/label_023/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_001.png\n", - "Copied test_data/labels/label_023/img_002.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_002.png\n", - "\n", - "Label: label_023\n", - " Company website: www.myplantvantage.com\n", - " Manufacturer website: None\n", - "Copied test_data/labels/label_024/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_001.png\n", - "\n", - "Label: label_024\n", - " Company website: www.savaria.ca\n", - " Manufacturer website: None\n", - "Copied test_data/labels/label_025/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_001.png\n", - "\n", - "Label: label_025\n", - " Company website: None\n", - " Manufacturer website: None\n", - "Copied test_data/labels/label_026/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_001.png\n", - "\n", - "Label: label_026\n", - " Company website: None\n", - " Manufacturer website: None\n", - "Copied test_data/labels/label_027/img_001.jpg to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_001.jpg\n", - "\n", - "Label: label_027\n", - " Company website: None\n", - " Manufacturer website: None\n", - "Copied test_data/labels/label_028/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_001.png\n", - "\n", - "Label: label_028\n", - " Company website: None\n", - " Manufacturer website: None\n", - "Copied test_data/labels/label_029/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_001.png\n", - "\n", - "Label: label_029\n", - " Company website: None\n", - " Manufacturer website: None\n", - "Copied test_data/labels/label_030/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_001.png\n", - "\n", - "Label: label_030\n", - " Company website: None\n", - " Manufacturer website: None\n", - "Copied test_data/labels/label_031/img_002.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_002.png\n", - "\n", - "Label: label_031\n", - " Company website: www.lfp-solutions.ca\n", - " Manufacturer website: www.bigbluebooster.com\n", - "Copied test_data/labels/label_032/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_001.png\n", - "Copied test_data/labels/label_032/img_003.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_003.png\n", - "Copied test_data/labels/label_032/img_002.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_002.png\n", - "\n", - "Label: label_032\n", - " Company website: None\n", - " Manufacturer website: None\n", - "Copied test_data/labels/label_033/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_001.png\n", - "Copied test_data/labels/label_033/img_002.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_002.png\n", - "\n", - "Label: label_033\n", - " Company website: None\n", - " Manufacturer website: None\n", - "Copied test_data/labels/label_034/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_001.png\n", - "Copied test_data/labels/label_034/img_002.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_002.png\n", - "\n", - "Label: label_034\n", - " Company website: www.advancednutrients.com/growersupport\n", - " Manufacturer website: None\n", - "Copied test_data/labels/label_035/img_001.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_001.png\n", - "Copied test_data/labels/label_035/img_002.png to /var/folders/43/4zssf0gs6sj_j_kzmzgdzx0m0000gn/T/tmpn25r_zy8/img_002.png\n", - "\n", - "Label: label_035\n", - " Company website: www.bionik.ca\n", - " Manufacturer website: None\n", - "\n", - "All inspections have been processed and saved to all_inspections.pkl\n" - ] - } - ], - "source": [ - "# Load environment variables\n", - "load_dotenv()\n", - "\n", - "# Define label folder numbers dynamically from 1 to 35\n", - "label_folders = range(1, 36)\n", - "# label_folders = [1, 6, 8]\n", - "\n", - "# Define possible image extensions\n", - "image_extensions = [\".jpg\", \".png\"]\n", - "\n", - "# Mock environment setup for OCR and GPT\n", - "api_endpoint_ocr = os.getenv(\"AZURE_API_ENDPOINT\")\n", - "api_key_ocr = os.getenv(\"AZURE_API_KEY\")\n", - "api_endpoint_gpt = os.getenv(\"AZURE_OPENAI_ENDPOINT\")\n", - "api_key_gpt = os.getenv(\"AZURE_OPENAI_KEY\")\n", - "api_deployment_gpt = os.getenv(\"AZURE_OPENAI_DEPLOYMENT\")\n", - "\n", - "# Initialize OCR and GPT objects (reusable)\n", - "ocr = OCR(api_endpoint=api_endpoint_ocr, api_key=api_key_ocr)\n", - "gpt = GPT(\n", - " api_endpoint=api_endpoint_gpt, api_key=api_key_gpt, deployment_id=api_deployment_gpt\n", - ")\n", - "\n", - "# Create a temporary directory for image copies\n", - "with tempfile.TemporaryDirectory() as backup_dir:\n", - " print(f\"Backup directory created at: {backup_dir}\")\n", - "\n", - " # Dictionary to store inspection results for all labels\n", - " all_inspections = {}\n", - "\n", - " # Loop through each label folder\n", - " for label_num in label_folders:\n", - " label_folder = f\"test_data/labels/label_{label_num:03d}\" # Format as label_001, label_002, etc.\n", - " label_storage = (\n", - " LabelStorage()\n", - " ) # Initialize a new LabelStorage for each label folder\n", - "\n", - " # Find relevant image files in the label folder\n", - " for ext in image_extensions:\n", - " pattern = os.path.join(label_folder, f\"img_*{ext}\")\n", - " image_files = glob(pattern)\n", - "\n", - " # Copy found images to the backup directory and use copies for processing\n", - " for image_path in image_files:\n", - " backup_path = os.path.join(backup_dir, os.path.basename(image_path))\n", - " shutil.copy(image_path, backup_path)\n", - " print(f\"Copied {image_path} to {backup_path}\")\n", - "\n", - " # Add the copied image to the label storage\n", - " label_storage.add_image(backup_path)\n", - "\n", - " if label_storage.images:\n", - " # Run the analyze function using the copied images\n", - " inspection = analyze(label_storage, ocr, gpt)\n", - "\n", - " # Store the result in the dictionary with the label number as the key\n", - " all_inspections[f\"label_{label_num:03d}\"] = inspection\n", - "\n", - " # Print the inspection results as they are processed\n", - " print(f\"\\nLabel: label_{label_num:03d}\")\n", - " print(f\" Company website: {inspection.company_website}\")\n", - " print(f\" Manufacturer website: {inspection.manufacturer_website}\")\n", - "\n", - " # Pickle all the results in a single file\n", - " pickle.dump(all_inspections, open(\"all_inspections.pkl\", \"wb\"))\n", - "\n", - "print(\"\\nAll inspections have been processed and saved to all_inspections.pkl\")\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Analysis\n", - "\n", - "Do not mind the error. It's probably due to using `tempfile`. Will investigate later.\n", - "\n", - "Before the fix, the main problems were: \n", - "- `www.` missing in some websites\n", - "- mix of lowercase and uppercase chars\n", - "\n", - "After the fix, from the results, we can see that the llm is handling pretty well the website fields formatting.\n", - "\n", - "My concern is that, we can't be sure how it will react when all the other fields are loaded with descriptions (prompts). Will it be cognitively overloaded and hallucinate?\n", - "\n", - "Should we just code the formatting? The lower case is already coded (post processing) and we can add `www.` when it is missing, but how cool is it to let the llm do it!" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# # Load the pickled data\n", - "# with open(\"all_inspections.pkl\", \"rb\") as f:\n", - "# all_inspections: dict[str, FertilizerInspection] = pickle.load(f)\n", - "\n", - "# for label, inspection in all_inspections.items():\n", - "# print(f\"Label: {label}\")\n", - "# print(f\" Company website: {inspection.company_website}\")\n", - "# print(f\" Manufacturer website: {inspection.manufacturer_website}\")\n", - "# print()\n" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "fertiscan-pipeline", - "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.12.4" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -}