Skip to content

Commit

Permalink
Merge pull request #1 from software-students-spring2024/Jacklyn22
Browse files Browse the repository at this point in the history
Original codes added and new html pages added.
  • Loading branch information
ebc5802 authored Apr 30, 2024
2 parents 1588fbe + 6f384e7 commit 6e52b51
Show file tree
Hide file tree
Showing 18 changed files with 899 additions and 0 deletions.
34 changes: 34 additions & 0 deletions docker-compose.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
version: '3.8'

services:
web-app:
build:
context: ./web-app
dockerfile: ./Dockerfile
ports:
- "10000:5000"
env_file:
- .env
depends_on:
- db

machine-learning-client:
build:
context: ./machine-learning-client
dockerfile: ./Dockerfile
ports:
- "5002:5002"
env_file:
- .env
depends_on:
- db


db:
image: mongo
ports:
- "27017:27017"
volumes:
- ./data:/data/db


18 changes: 18 additions & 0 deletions machine-learning-client/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# in Docker, it is common to base a new image on a previously-created image
# Use an official Python runtime image as a parent image to base this image on
FROM python:3
# Set the working directory within the image to /app
WORKDIR /main
# the ADD command is how you add files from your local machine into a Docker image
# Copy the current directory contents into the container at /app
ADD . /main
# Install any needed packages specified in requirements.txt
# in Python, a requirements.txt file is a way of indicating dependencies in a way that the package manager, pip, can understand
RUN pip install --trusted-host pypi.python.org -r requirements.txt
# by default Docker containers are closed off to the external world
# Make port 80 available to the world outside this container
EXPOSE 5002
# Define an environment variable... this will be available to programs running inside the container
ENV NAME World
# Run app.py when the container launches
CMD ["python", "main.py"]
13 changes: 13 additions & 0 deletions machine-learning-client/Pipfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[[source]]
url = "https://pypi.org/simple"
verify_ssl = true
name = "pypi"

[packages]
pylint = "*"
black = "*"

[dev-packages]

[requires]
python_version = "3.10"
Binary file added machine-learning-client/RestaurantReceipt1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
123 changes: 123 additions & 0 deletions machine-learning-client/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
import os
from flask import Flask, request, jsonify
import requests
import pymongo
from pymongo import MongoClient
import json
from dotenv import load_dotenv
from bson import ObjectId

import logging

logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger(__name__)

# Use receipt-OCR.py to get response1.json
# (can only do this a couple times an hour with the test API key)

# Load response1.json
with open("response1.json", "r") as f:
data = json.load(f)

print('Receipt Keys:', data['receipts'][0].keys())
items = data['receipts'][0]['items']
print()
print(f"Your purchase at {data['receipts'][0]['merchant_name']}")

for item in items:
print(f"{item['description']} - {data['receipts'][0]['currency']} {item['amount']}")
print("-" * 20)
print(f"Subtotal: {data['receipts'][0]['currency']} {data['receipts'][0]['subtotal']}")
print(f"Tax: {data['receipts'][0]['currency']} {data['receipts'][0]['tax']}")
print("-" * 20)
print(f"Total: {data['receipts'][0]['currency']} {data['receipts'][0]['total']}")
# print(data['receipts'])


# load credentials and configuration options from .env file
# if you do not yet have a file named .env, make one based on the templatpip e in env.example
load_dotenv() # take environment variables from .env.

# instantiate the app
app = Flask(__name__)
app.secret_key = 'a_unique_and_secret_key'
# # turn on debugging if in development mode
if os.getenv("FLASK_ENV", "development") == "development":
# # turn on debugging, if in development
app.debug = True # debug mnode

# connect to the database
cxn = pymongo.MongoClient(os.getenv("MONGO_URI"))
db = cxn[os.getenv("MONGO_DBNAME")] # store a reference to the database

@app.route('/predict', methods=['POST'])
def pretdict_endpoint():
# Get the image data from the request
request_data = request.get_json() # Extract JSON data from the request
if 'Object_ID' not in request_data:
return jsonify({'error': 'Object_ID not found in request data'}), 400

Object_ID = ObjectId(request_data['Object_ID'])
logger.debug('OBJECT_ID MESSAGE:', Object_ID)
#image = db.receipts.find_one({"_id": Object_ID})['image']

# Here, you would add the code to perform OCR on the image
# For now, let's assume you have a function called perform_ocr that does this

# Uncomment next line to perform OCR
data = perform_ocr(Object_ID)
#data = json.load(open("response1.json", "r"))

# Connect to your collection (replace 'mycollection' with your collection name)
collection = db['receipts']

# Prepare the data to be inserted into the database
receipt = data['receipts'][0]
receipt_data = {
'receipt_name': receipt['merchant_name'],
'currency': receipt['currency'],
'items': [{'description': item['description'], 'amount': item['amount']} for item in receipt['items']],
'total': receipt['total'],
'tax': receipt['tax'],
'tip': receipt['tip'],
'subtotal': receipt['subtotal'],
}
logger.debug(receipt_data)

# Update the document with given ObjectId
collection.update_one({'_id': Object_ID}, {'$set': receipt_data})
inserted_id = Object_ID

# Return the inserted_id as a JSON response
return jsonify({'_id': str(inserted_id)})

def perform_ocr(Object_ID):
logger.debug("starting perform_ocr function...") # debug
url = "https://ocr.asprise.com/api/v1/receipt"
image_data = db.receipts.find_one({"_id": Object_ID})['image']
file_path = f"receipt_{Object_ID}.jpg" # Set the file path to save the image
logger.debug("file path: %s", file_path) # debug
with open(file_path, "wb") as f:
f.write(image_data)
file_path = file_path.replace('\x00', '') # Remove any null bytes from the file path


# Get response (can only do this a couple times with the test API key)
res = requests.post(url,
data = {
'api_key': 'TEST',
'recognizer': 'auto',
'ref_no': 'ocr_python_123'
},

files = {
'file': open(file_path, "rb")
})

with open("response.json", "w") as f:
f.write(res.text)

return res.json()

if __name__ == '__main__':
app.run(host='0.0.0.0', port=5002) # Run the app
6 changes: 6 additions & 0 deletions machine-learning-client/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
pymongo
pylint
black
requests
Flask
python-dotenv
166 changes: 166 additions & 0 deletions machine-learning-client/response1.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
{
"ocr_type" : "receipts",
"request_id" : "P_72.80.97.228_luxbmz9s_bz6",
"ref_no" : "ocr_python_123",
"file_name" : "RestaurantReceipt1.png",
"request_received_on" : 1712965847825,
"success" : true,
"image_width" : 812,
"image_height" : 1354,
"image_rotation" : 0,
"recognition_completed_on" : 1712965848215,
"receipts" : [ {
"merchant_name" : "HARBOR LANE CAFE",
"merchant_address" : "HARBOR LANE CAFE",
"merchant_phone" : null,
"merchant_website" : null,
"merchant_tax_reg_no" : null,
"merchant_company_reg_no" : null,
"region" : null,
"mall" : null,
"country" : "US",
"state" : "IL",
"city" : "CHICAGO",
"receipt_no" : null,
"date" : "2019-11-20",
"time" : null,
"items" : [ {
"amount" : 14.98,
"category" : null,
"description" : "Tacos Del Mal Shrimp",
"flags" : "",
"qty" : 1,
"remarks" : null,
"tags" : null,
"unitPrice" : null
}, {
"amount" : 12.50,
"category" : null,
"description" : "Especial Salad Chicken",
"flags" : "",
"qty" : 1,
"remarks" : null,
"tags" : null,
"unitPrice" : null
}, {
"amount" : 1.99,
"category" : null,
"description" : "Fountain Beverage",
"flags" : "",
"qty" : 1,
"remarks" : null,
"tags" : null,
"unitPrice" : null
} ],
"currency" : "USD",
"total" : 31.39,
"subtotal" : 29.47,
"tax" : 1.92,
"service_charge" : null,
"tip" : null,
"payment_method" : null,
"payment_details" : null,
"credit_card_type" : null,
"credit_card_number" : null,
"ocr_text" : " HARBOR LANE CAFE\n 3941 GREEN OAKS BLVD\n CHICAGO, IL\n SALE\n 11/20/2019 11:05 AM\n BATCH #: 01A2A\n APPR #: 34362\n TRACE #: 9\n VISA 3483\n 1 Tacos Del Mal Shrimp $14.98\n 1 Especial Salad Chicken $12.50\n 1 Fountain Beverage $1.99\n SUBTOTAL: $29.47\n TAX: $1.92\n TOTAL: $31.39\n TIP:\n TOTAL:\n APPROVED\n THANK YOU\n CUSTOMER COPY",
"ocr_confidence" : 98.50,
"width" : 596,
"height" : 1111,
"avg_char_width" : 16.9954,
"avg_line_height" : 28.3333,
"conf_amount" : 83,
"source_locations" : {
"date" : [ [ {
"x" : 46,
"y" : 216
}, {
"x" : 240,
"y" : 216
}, {
"x" : 240,
"y" : 246
}, {
"x" : 46,
"y" : 246
} ] ],
"total" : [ [ {
"x" : 275,
"y" : 696
}, {
"x" : 381,
"y" : 696
}, {
"x" : 381,
"y" : 726
}, {
"x" : 275,
"y" : 726
} ] ],
"subtotal" : [ [ {
"x" : 276,
"y" : 615
}, {
"x" : 384,
"y" : 615
}, {
"x" : 384,
"y" : 646
}, {
"x" : 276,
"y" : 646
} ] ],
"merchant_name" : [ [ {
"x" : 40,
"y" : 13
}, {
"x" : 357,
"y" : 15
}, {
"x" : 357,
"y" : 47
}, {
"x" : 40,
"y" : 46
} ] ],
"doc" : [ [ {
"x" : 24,
"y" : -40
}, {
"x" : 679,
"y" : -40
}, {
"x" : 679,
"y" : 1181
}, {
"x" : 24,
"y" : 1181
} ] ],
"tax" : [ [ {
"x" : 277,
"y" : 656
}, {
"x" : 361,
"y" : 656
}, {
"x" : 361,
"y" : 685
}, {
"x" : 277,
"y" : 685
} ] ],
"merchant_address" : [ [ {
"x" : 24,
"y" : 11
}, {
"x" : 373,
"y" : 13
}, {
"x" : 373,
"y" : 49
}, {
"x" : 24,
"y" : 48
} ] ]
}
} ]
}
12 changes: 12 additions & 0 deletions web-app/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# docs: https://hub.docker.com/_/python
FROM python:3.8-slim-buster

WORKDIR /web_app

COPY requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt

COPY . .

EXPOSE 10000
CMD [ "python3", "-m" , "flask", "run", "--host=0.0.0.0"]
13 changes: 13 additions & 0 deletions web-app/Pipfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[[source]]
url = "https://pypi.org/simple"
verify_ssl = true
name = "pypi"

[packages]
pylint = "*"
black = "*"

[dev-packages]

[requires]
python_version = "3.10"
Loading

0 comments on commit 6e52b51

Please sign in to comment.