# Project export: HodgePodge: Minimize Waste, Maximize Flavor!

This document was generated by HackStack to give an AI agent context about a hackathon project. Sections are labeled with their provenance; content marked as truncated was cut to keep this document small.

## Project metadata

- Hackathon: TreeHacks 2024
- Tagline: Cook smarter, waste less with HodgePodge– the ultimate inventory management revolution for your family restaurant!
- Devpost: https://devpost.com/software/freshstew
- GitHub: https://github.com/piggybank42130/FoodWaste.git
- Team: 3 GitHub contributor(s) — Peter Zhang (20 commits), rohan-tan-bhowmik (3 commits), piggybank42130 (2 commits)

## Devpost submission (written by the team)

No Devpost description available.

## README (from the GitHub repository)

No README available.

## Detected evidence (automated analysis)

Indexed codebase: 11 recognized source files, 65 KB.
- Python (language) — detected in the code
- Swift (language) — detected in the code
- Flask (technology) — claimed on Devpost, not found in the code
- LangChain (technology) — claimed on Devpost, not found in the code

## Codebase structure (from repository index)

### Files (23 of 23)

```
.DS_Store
.gitattributes
Assets.xcassets/AccentColor.colorset/Contents.json
Assets.xcassets/AppIcon.appiconset/Contents.json
Assets.xcassets/Contents.json
Assets.xcassets/FreshStewLogo.imageset/Contents.json
ContentView.swift
FoodWaste.entitlements
FoodWasteApp.swift
FoodWastePython/.DS_Store
FoodWastePython/barcode.py
FoodWastePython/client.py
FoodWastePython/correctText.py
FoodWastePython/getText.py
FoodWastePython/llm.py
FoodWastePython/rawInv.db
FoodWastePython/rawInventory.py
FoodWastePython/recipeInventory.py
FoodWastePython/run.py
FoodWastePython/test.py
FoodWastePython/zzz
Info.plist
Preview Content/Preview Assets.xcassets/Contents.json
```

### Dependencies

No dependency index available.

### Recent commits (newest first)

- Update ContentView.swift
- python stuff
- Colors all changed
- new changes with colors
- chat doen
- chat is there now
- changed 3 icons
- 12:30
- sort from expiration date
- working but no deletion or editing
- Update ContentView.swift
- updated with quantity
- updated add food item
- Update ContentView.swift
- Summary (required)
- Merge branch 'main' of https://github.com/piggybank42130/FoodWaste
- Create barcode.py
- Update ContentView.swift
- Merge branch 'main' of https://github.com/piggybank42130/FoodWaste
- update with live camera feed

## Key source files (fetched from GitHub, selected and truncated for size)

### FoodWasteApp.swift

```swift
//
//  FoodWasteApp.swift
//  FoodWaste
//
//  Created by Peter Zhang on 2024/2/16.
//

import SwiftUI

@main
struct FoodWasteApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

```

### FoodWastePython/client.py

```python
import requests

def send_data_to_server(data):
    url = 'http://127.0.0.1:5000/sendData'  # Make sure the URL matches your Flask server's address
    headers = {'Content-Type': 'application/json'}
    
    # Attempt to send the data to the server
    response = requests.post(url, json=data, headers=headers)
    
    # Check the server's response
    if response.ok:
        print("Successfully sent data to the server. Server response:", response.json())
    else:
        print("Failed to send data. Status code:", response.status_code)

if __name__ == '__main__':
    # Prompt the user for input
    user_input = input("Enter your message: ")
    
    # Prepare the data to send (convert the user input into a suitable data structure)
    data = {"message": user_input}
    
    # Send the data to the Flask server
    send_data_to_server(data)

```

### FoodWastePython/barcode.py

```python
from pyzbar.pyzbar import decode
import cv2
import requests

def scan_barcode():
    img = cv2.imread('barcode.jpeg')
    img = img[:img.shape[1],:]

    barcodes = decode()

    if barcodes:
        for barcode in barcodes:
            # Extract barcode data
            barcode_data = barcode.data.decode('utf-8')
            barcode_type = barcode.type

            # Print barcode data and type
            print("Barcode Data:", barcode_data)
            print("Barcode Type:", barcode_type)

            return barcode_data


def get_product_name(barcode_id):
    api_key = 'YOUR_API_KEY'
    url = f'https://api.upcitemdb.com/prod/trial/lookup?upc={barcode_id}'

    try:
        response = requests.get(url)
        data = response.json()
        if data['code'] == 'OK':
            
            return data['items'][0]['title']
        else:
            return "Product not found"
    except Exception as e:
        print("Error:", e)
        return "Error occurred"
'''
if __name__ == "__main__":
    # Scan barcodes from the live camera feed
    print(get_product_name(scan_barcode()))
'''
```

### FoodWastePython/getText.py

```python
import cv2
import pytesseract
import easyocr
import matplotlib.pyplot as plt
import re
# Load the image

def getText(imPath):
    image = cv2.imread(imPath)

    image = image[:image.shape[1],:]
    plt.imsave("oihaeuf.jpg", image)

    # Convert the image to grayscale
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

    factor = 4
    gray = cv2.resize(gray, (int(gray.shape[1]/factor),int(gray.shape[0]/factor)))

    # Increase contrast using histogram equalization
    gray = cv2.equalizeHist(gray)

    alpha = 10 # Brightness factor (adjust as needed)
    gray = cv2.convertScaleAbs(gray, alpha=alpha, beta=0)

    # Apply thresholding to binarize the image
    max_output_value = 255  # The value to assign to the pixels for which the condition is satisfied
    neighborhood_size = 11  # Block size, which decides the size of the neighborhood area
    subtract_from_mean = 2  # Constant subtracted from the mean or weighted mean
    gray = cv2.adaptiveThreshold(gray, max_output_value, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, neighborhood_size, subtract_from_mean)


    # Apply Gaussian blur to reduce noise
    gray = cv2.GaussianBlur(gray, (5, 5), 0)
    #plt.imshow(gray)
    #plt.show()

     # Initialize EasyOCR reader 
    reader = easyocr.Reader(['en'])

    # Read text from image
    result = reader.readtext(gray)

    # Extracting text from the result
    editedText = ' '.join([res[1] for res in result])
    
    editedText = ''.join(ch for ch in editedText if ch.isalnum() or ch.isspace())

    return editedText



```

### FoodWastePython/recipeInventory.py

```python
import sqlite3

class RecipeInventory:
     
    def __init__(self):
        self.connect = sqlite3.connect("recipeInv.db")
        self.db = self.connect.cursor()

    def createDatabase(self):
        self.db.execute("CREATE TABLE recipes(id, ingredientId, quantity)")
        self.db.execute("CREATE TABLE recipeNames(id, name)")

        self.connect.commit()

    def addRecipe(self, id: int, name: str):
        self.db.execute("INSERT INTO recipeNames VALUES(?, ?)", (id, name))

        self.connect.commit()

    def addIngredient(self, id: int, ingredientId: int, quantity: float):
        self.db.execute("INSERT INTO recipes VALUE(?, ?, ?)", (id, ingredientId, quantity))

        self.connect.commit()

    def deleteRecipe(self, id: int):
        self.db.execute("DELETE FROM recipes WHERE id=?", (id))
        self.db.execute("DELETE FROM recipeNames WHERE id=?", (id))

        self.connect.commit()

    def deleteIngredient(self, id: int, ingredientId: int):
        self.db.execute("DELETE FROM recipes WHERE id=? AND ingredientId=?", (id, ingredientId))

        self.connect.commit()


    def retrieveIngredients(self, id: int):
        ingredients = {}
        for row in self.db.execute("SELECT ingredientId, quantity FROM inventory WHERE id=? ORDER BY expiration", (id,)):
            id = int(row[0])
            quantity = float(row[1])
            
            ingredients[id] += quantity

        return (ingredients)

    def getAllIds(self):
        ids = set()
        for row in self.db.execute("SELECT id FROM recipeNames"):
            ids.add(int(row[0]))
        return ids

```

### FoodWastePython/llm.py

```python
from langchain_community.agent_toolkits import create_sql_agent
from langchain.sql_database import SQLDatabase
from flask import Flask, request, jsonify

from langchain_openai import ChatOpenAI

app = Flask(__name__)

# Initialize your chatbot outside of the request handling to avoid re-initializing it on every call
llm = ChatOpenAI(model="gpt-3.5-turbo", temperature=0, openai_api_key="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")
db = SQLDatabase.from_uri("sqlite:///rawInv.db")
agent_executor = create_sql_agent(llm, db=db, agent_type="openai-tools", verbose=False)

@app.route('/chat', methods=['POST'])
def chat_with_bot():
    data = request.json
    prompt = data.get('prompt', '')
    # Ensure the prompt adheres to your specified format
    prompt = "Always use the pronoun WE not I. Don't automatically infer what type numbers mean and refer to their name. " + prompt

    try:
        response = agent_executor.invoke(prompt)
        return jsonify({"response": response['output']})
    except Exception as e:
        print(e)
        return jsonify({"error": str(e)}), 500

if __name__ == '__main__':
    app.run(debug=True, port=8080, host='0.0.0.0')

# llm = ChatOpenAI(model="gpt-3.5-turbo", temperature=0, openai_api_key="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")



# db = SQLDatabase.from_uri("sqlite:///rawInv.db")
# agent_executor = create_sql_agent(llm, db=db, agent_type="openai-tools", verbose=False)
# Prompt = "Always use the pronoun WE not I. Don't automatically infer what type numbers mean and refer to their name. "
# response = agent_executor.invoke(
#     Prompt + "How many Chickens do I have?"
# )
# print(response['output'])

# import os
# os.environ["OPENAI_API_KEY"] = "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"

# from langchain_together import Together

# llm = Together(
#     model="meta-llama/Llama-2-13b-chat-hf",
#     temperature=0.7,
#     max_tokens=128,
#     top_k=1,
#     together_api_key= "12a2bbf732c883b5e261b2b5f3e50d17f1e2e8c4ed4ee886e90bd96a5470312d"
# )
```

### FoodWastePython/correctText.py

```python
from datetime import datetime
from rapidfuzz import process
from liveFeed import liveFeed
from getText import getText
from fuzzywuzzy import process
from dateutil.parser import parse, ParserError
from collections import Counter



# Define possible month abbreviations
months = ["jan", "feb", "mar", "apr", "may", "jun", "jul", "aug", "sep", "oct", "nov", "dec"]
def filterTextList(textList):
    filteredTextList = []
    for text in textList:
        corrected_word, score = process.extractOne(text.lower(), months) #return a closeness score
        if text.isalnum() and len(text) <= 4:
            if text.isalpha() and score > 30:
                filteredTextList.append(text)
            elif text.isnumeric() and int(text) > 0 and int(text) < datetime.now().year + 10: #eliminate any numbers that are less than 0, and greater than 10 plus current year
                filteredTextList.append(text)
    return filteredTextList

def correctMonthAbbreviation(text):
    # Split the text into words and process each word
    corrected_text = []
    for word in text.split():
        # Find the closest month abbreviation 
        corrected_word, score = process.extractOne(word.lower(), months) #return a closeness score
        if score > 30:  # You might need to adjust this threshold
            corrected_text.append(corrected_word)
    return " ".join(corrected_text)

def getDate(imPath):
    textList = getText(imPath).split()
    textList = filterTextList(textList)
    # Correct the month abbreviations
    for i in range(len(textList)):
        if textList[i].isalpha():
            textList[i] = correctMonthAbbreviation(textList[i].replace("\n", ""))
            
    def isValidDate(string):
        try:
        # Attempt to parse the string into a date
            parsed_date = parse(string)
            # Optional: Additional validation checks here
            return True
        except ParserError:
            # Parsing failed, the string is not a valid date
            return False
    newDate = ""
    for i in range(len(textList)):
        if textList[i] != "":
            date = textList[i].lower().replace(".", "-").replace("/", "-").replace(",","-")
            print(date)
            if (i == 0):
                newDate += date
            else:
                newDate = newDate + "-" + date 
    if isValidDate(newDate):
        return "Expiration date: " + newDate
    else:
        return "No date found/invalid date"

# Example usage
def main():
    val = getDate('pocky.jpg')
    print(val)

if __name__ == "__main__":
    main()
```

### FoodWastePython/rawInventory.py

```python
import sqlite3
import datetime

class RawInventory:
    def __init__(self):
        self.connect = sqlite3.connect("rawInv.db", check_same_thread=False)
        self.db = self.connect.cursor()

    def createDatabase(self):
        # Modified to include a 'type' column and make 'id' an autoincrement primary key
        self.db.execute("""
            CREATE TABLE IF NOT EXISTS inventory (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                quantity INTEGER,
                name TEXT,
                purchase TEXT,
                expiration TEXT  
            )""")

        self.connect.commit()

    def resetDatabase(self):
        self.db.execute("DROP TABLE IF EXISTS inventory")
        self.createDatabase()
        self.connect.commit()

    # Modified to include 'type' parameter and no longer requires 'id' for adding an item
    def addItem(self, quantity: int, name: str, purchase: datetime.datetime,expiration: datetime.datetime):
        expiration_str = expiration.strftime("%Y-%m-%d %H:%M:%S")
        purchase_str = purchase.strftime("%Y-%m-%d %H:%M:%S")
        self.db.execute("INSERT INTO inventory (quantity, name, purchase, expiration) VALUES(?, ?, ?, ?)", (quantity, name, purchase_str, expiration_str))

        self.connect.commit()

    def deleteItem(self, name: str, purchase: datetime.datetime, expiration: datetime.datetime):
        # Convert datetime objects to strings in the same format as stored in the database
        purchase_str = purchase.strftime("%Y-%m-%d %H:%M:%S")
        expiration_str = expiration.strftime("%Y-%m-%d %H:%M:%S")
        
        # Execute the DELETE statement with the provided criteria
        self.db.execute("DELETE FROM inventory WHERE name = ? AND purchase = ? AND expiration = ?", (name, purchase_str, expiration_str))
        
        # Commit the changes to the database
        self.connect.commit()

    # Modification: 'id' now uniquely identifies an item, not its type
    def getName(self, id: int):
        return self.db.execute("SELECT name FROM inventory WHERE id=?", (id,)).fetchone()[0]

    # This method needs significant changes since 'id' is no longer the type
    # Consider using 'type' to retrieve items of a certain type and aggregate their expiration statuses
    def retrieveItem(self, name: str):
        highExpirationDays = 1
        midExpirationDays = 3
        items = {"count":0, "highExpire":0, "midExpire":0}
        
        for row in self.db.execute("SELECT expiration FROM inventory WHERE name=? ORDER BY expiration", (name,)):
            expiration_str = row[0]
            expiration_datetime = datetime.datetime.strptime(expiration_str, "%Y-%m-%d %H:%M:%S")
            days_until_expiry = (expiration_datetime - datetime.datetime.now()).days
            
            items["count"] += 1

            if days_until_expiry < highExpirationDays:
                items["highExpire"] += 1
            elif days_until_expiry < midExpirationDays:
                items["midExpire"] += 1

        return items

    # New method to get all types (distinct)
    def getAllTypes(self):
        types = set()
        for row in self.db.execute("SELECT DISTINCT type FROM inventory"):
            types.add(int(row[0]))
        return types

```

### FoodWastePython/run.py

```python
from flask import Flask, request, jsonify
import base64
from io import BytesIO
import barcode
import rawInventory
import datetime
import getText

app = Flask(__name__)

global rawInv
rawInv = rawInventory.RawInventory()
rawInv.createDatabase()
rawInv.resetDatabase()

global msg
msg = ""


@app.route('/sendBarcode', methods=['POST'])
def receive_barcode():
    global msg
    data = request.json
    if 'image' in data:
        image_data = data['image']
        image_bytes = base64.b64decode(image_data)
        image = BytesIO(image_bytes)

        # Process the image here (e.g., save to file)
        with open("barcode.jpeg", "wb") as f:
            f.write(image_bytes)

            product_name = barcode.get_product_name(barcode.scan_barcode())
            print(product_name)
            msg = product_name
            send_message()

        return jsonify({"status": "success", "message": "Image received and saved"}), 200
    else:
        return jsonify({"status": "error", "message": "No image data found"}), 400

@app.route('/sendExpiry', methods=['POST'])
def receive_expiry():
    global msg
    data = request.json
    if 'image' in data:
        image_data = data['image']
        image_bytes = base64.b64decode(image_data)
        image = BytesIO(image_bytes)

        # Process the image here (e.g., save to file)
        with open("expiry.jpeg", "wb") as f:
            f.write(image_bytes)

            expirationdate = getText.getText('expiry.jpeg')
            print(expirationdate)
            msg = expirationdate
            send_message()

        return jsonify({"status": "success", "message": "Image received and saved"}), 200
    else:
        return jsonify({"status": "error", "message": "No image data found"}), 400


@app.route('/sendData', methods=['POST'])
def receive_data():
    data = request.json
    print("Data received:", data)
    # Process the data here
    return jsonify({"status": "success", "message": "Data received"}), 200

@app.route('/getData', methods=['GET'])
def send_data():
    # Prepare some data to send
    print("a")
    data = {"message": "Hello from Python!"}
    return jsonify(data), 200

@app.route('/sendInventoryCommand', methods=['POST'])
def receive_inventory_command():
    global rawInv
    data = request.json
    print("Inv command received")
    print("Data received:", data)
    
    message = data['message'].split("`")
    command = message[0]
    itemName = message[1]
    quantity = int(message[2])
    purchaseDate = datetime.datetime.strptime(message[3], "%m/%d/%Y")
    expirationDate = datetime.datetime.strptime(message[4], "%m/%d/%Y")

    #print(command, itemName, quantity, purchaseDate, expirationDate)
    if (command == 'add'):
        rawInv.addItem(quantity=quantity, name=itemName, purchase=purchaseDate, expiration=expirationDate)
    if (command == 'delete'):
        rawInv.deleteItem(quantity=quantity, name=itemName, purchase=purchaseDate, expiration=expirationDate)

    # Process the data here
    return jsonify({"status": "success", "message": "Data received"}), 200

@app.route('/sendChat', methods=['POST'])
def receive_chat():
    data = request.json
    print("Data received:", data)
    # Process the data here
    return jsonify({"status": "success", "message": "Data received"}), 200

@app.route('/getChat', methods=['GET'])
def send_chat():
    # Prepare some data to send
    print("a")
    data = {"message": "Hello from Python!"}
    return jsonify(data), 200

@app.route('/getMessage', methods=['GET'])
def send_message():
    global msg

    # Prepare some data to send
    print(msg)
    data = {"message": msg}
    print("go")
    return jsonify(data), 200

if __name__ == '__main__':
    app.run(debug=True, host='0.0.0.0', port=5000)

```