Spaces:
Sleeping
Sleeping
| import streamlit as st | |
| import json | |
| import copy | |
| from receipt_gen_agent import receipt_agent | |
| from PIL import Image | |
| from huggingface_hub import HfApi | |
| from os import listdir | |
| from os.path import isfile, join | |
| from io import BytesIO | |
| from dotenv import load_dotenv | |
| import os | |
| import base64 | |
| load_dotenv() | |
| token=os.getenv('hf_token') | |
| api = HfApi() | |
| repo_id = "wolf1997/receipt_scanner" | |
| agent=receipt_agent() | |
| def capture_or_upload_image(): | |
| """ | |
| Provides options to capture or upload an image using Streamlit. | |
| Returns: | |
| PIL.Image.Image or None: The captured/uploaded image | |
| """ | |
| st.sidebar.header("📸 Image Capture / Upload") | |
| # Choose method | |
| image_source = st.sidebar.radio( | |
| "Choose Image Source", | |
| ["Upload", "Camera Capture"], | |
| key="image_source" | |
| ) | |
| # Image upload | |
| if image_source == "Upload": | |
| uploaded_file = st.sidebar.file_uploader( | |
| "Upload Receipt Image", | |
| type=['png', 'jpg', 'jpeg', 'gif'], | |
| help="Upload an image of the receipt", | |
| key="uploaded_file" | |
| ) | |
| if uploaded_file is not None: | |
| # Convert to PIL Image | |
| pil_image = Image.open(uploaded_file) | |
| # Store in session state | |
| st.session_state.receipt_image = pil_image | |
| return pil_image | |
| # Camera capture | |
| else: | |
| captured_image = st.camera_input( | |
| "Take a picture of the receipt", | |
| key="camera_input" | |
| ) | |
| if captured_image is not None: | |
| # Convert to PIL Image | |
| pil_image = Image.open(captured_image) | |
| # Store in session state | |
| st.session_state.receipt_image = pil_image | |
| return pil_image | |
| # Return image from session state if available | |
| return st.session_state.get("receipt_image", None) | |
| def parse_receipt_data(receipt_str): | |
| """Parse the receipt dictionary from a string or dict.""" | |
| if isinstance(receipt_str, str): | |
| try: | |
| return json.loads(receipt_str.replace("'", '"')) | |
| except json.JSONDecodeError: | |
| return {} | |
| return receipt_str | |
| def receipt_editor_app(): | |
| # Initialize session state variables if they don't exist | |
| if "receipt_dict" not in st.session_state: | |
| # Default initial receipt data | |
| initial_receipt_str = { | |
| "loc_name": "someplace", | |
| "table":"some table", | |
| "address": "somewhere", | |
| "date": "someday", | |
| "time": "sometime", | |
| "items": [ | |
| { | |
| "name": "something", | |
| "price": 3.0, | |
| "quantity": 1 | |
| } | |
| ], | |
| "subtotal": 51.9, | |
| "tax": 4.68, | |
| "total": 56.58 | |
| } | |
| st.session_state.receipt_dict = parse_receipt_data(initial_receipt_str) | |
| st.session_state.edited_receipt = copy.deepcopy(st.session_state.receipt_dict) | |
| if "receipt_image" not in st.session_state: | |
| st.session_state.receipt_image = None | |
| if "show_receipt_image" not in st.session_state: | |
| st.session_state.show_receipt_image = True | |
| # Set page title and layout | |
| st.set_page_config(page_title="Receipt Editor", layout="wide") | |
| # Capture or upload image | |
| receipt_image = capture_or_upload_image() | |
| if receipt_image is not None: | |
| # Option to display image | |
| show_image = st.sidebar.checkbox( | |
| "Show Receipt Image", | |
| value=st.session_state.show_receipt_image, | |
| key="show_image_checkbox" | |
| ) | |
| st.session_state.show_receipt_image = show_image | |
| if show_image: | |
| # Create two columns for image and details | |
| col1, col2 = st.sidebar.columns([1, 1]) | |
| with col1: | |
| # Resize image to fit sidebar | |
| resized_image = receipt_image.copy() | |
| resized_image.thumbnail((600, 600)) | |
| st.image(resized_image, caption="Uploaded Receipt") | |
| with col2: | |
| # Basic image details | |
| st.write(f"Image Size: {receipt_image.size}") | |
| st.write(f"Image Format: {receipt_image.format if hasattr(receipt_image, 'format') else 'Unknown'}") | |
| st.write(f"Color Mode: {receipt_image.mode}") | |
| if st.sidebar.button("Process Image"): | |
| initial_receipt_str = agent.receipt_gen(receipt_image) | |
| # Parse initial receipt data | |
| st.session_state.receipt_dict = parse_receipt_data(initial_receipt_str) | |
| # Update edited receipt in session state | |
| st.session_state.edited_receipt = copy.deepcopy(st.session_state.receipt_dict) | |
| st.sidebar.success("Receipt processed!") | |
| # Create a reference to session state for cleaner code | |
| edited_receipt = st.session_state.edited_receipt | |
| # Title | |
| st.title("Receipt Editor") | |
| # Basic Information Section | |
| st.header("Basic Information") | |
| col1, col2 = st.columns(2) | |
| with col1: | |
| edited_receipt['loc_name'] = st.text_input( | |
| "Location Name", | |
| value=edited_receipt['loc_name'], | |
| key="loc_name" | |
| ) | |
| edited_receipt['date'] = st.text_input( | |
| "Date", | |
| value=edited_receipt['date'], | |
| key="date" | |
| ) | |
| edited_receipt['table'] = st.text_input( | |
| "Table", | |
| value=edited_receipt['table'], | |
| key="table" | |
| ) | |
| with col2: | |
| edited_receipt['address'] = st.text_area( | |
| "Address", | |
| value=edited_receipt['address'], | |
| key="address" | |
| ) | |
| edited_receipt['time'] = st.text_input( | |
| "Time", | |
| value=edited_receipt['time'], | |
| key="time" | |
| ) | |
| # Items Section | |
| st.header("Items") | |
| # Expandable section for items | |
| with st.expander("Edit Items"): | |
| # Allow adding new items | |
| add_item = st.checkbox("Add New Item", key="add_item_checkbox") | |
| if add_item: | |
| with st.form(key="add_item_form"): | |
| new_item_name = st.text_input("New Item Name", key="new_item_name") | |
| new_item_price = st.number_input("New Item Price", min_value=0.0, step=0.01, key="new_item_price") | |
| new_item_quantity = st.number_input("New Item Quantity", min_value=1, step=1, value=1, key="new_item_quantity") | |
| submit_button = st.form_submit_button(label="Add to Receipt") | |
| if submit_button: | |
| new_item = { | |
| 'name': new_item_name, | |
| 'price': new_item_price, | |
| 'quantity': new_item_quantity | |
| } | |
| edited_receipt['items'].append(new_item) | |
| st.session_state.edited_receipt = edited_receipt | |
| # Edit existing items | |
| for i, item in enumerate(edited_receipt['items']): | |
| with st.expander(f"Item {i+1}: {item['name']}"): | |
| col1, col2, col3 = st.columns(3) | |
| with col1: | |
| item['name'] = st.text_input( | |
| f"Item {i+1} Name", | |
| value=item['name'], | |
| key=f"name_{i}" | |
| ) | |
| with col2: | |
| item['price'] = st.number_input( | |
| f"Item {i+1} Price", | |
| min_value=0.0, | |
| value=item['price'], | |
| step=0.01, | |
| key=f"price_{i}" | |
| ) | |
| with col3: | |
| item['quantity'] = st.number_input( | |
| f"Item {i+1} Quantity", | |
| min_value=1, | |
| value=item['quantity'], | |
| step=1, | |
| key=f"quantity_{i}" | |
| ) | |
| # Option to remove item | |
| if st.button(f"Remove Item {i+1}", key=f"remove_{i}"): | |
| del edited_receipt['items'][i] | |
| st.session_state.edited_receipt = edited_receipt | |
| # Totals Section | |
| st.header("Totals") | |
| col1, col2, col3 = st.columns(3) | |
| edited_receipt=st.session_state.edited_receipt | |
| with col1: | |
| edited_receipt['subtotal'] = st.number_input( | |
| "Subtotal", | |
| min_value=0.0, | |
| value=edited_receipt['subtotal'], | |
| step=0.01, | |
| key="subtotal" | |
| ) | |
| with col2: | |
| edited_receipt['tax'] = st.number_input( | |
| "Tax", | |
| min_value=0.0, | |
| value=edited_receipt['tax'], | |
| step=0.01, | |
| key="tax" | |
| ) | |
| with col3: | |
| edited_receipt['total'] = st.number_input( | |
| "Total", | |
| min_value=0.0, | |
| value=edited_receipt['total'], | |
| step=0.01, | |
| key="total" | |
| ) | |
| # Recalculate totals button | |
| if st.button("Recalculate Totals", key="recalc_button"): | |
| edited_receipt=st.session_state.edited_receipt | |
| # Automatically calculate subtotal | |
| edited_receipt['subtotal'] = sum(item['price'] * item['quantity'] for item in edited_receipt['items']) | |
| # Recalculate total | |
| edited_receipt['total'] = edited_receipt['subtotal'] + edited_receipt['tax'] | |
| # Update session state | |
| st.session_state.edited_receipt = edited_receipt | |
| # Display final edited receipt | |
| st.header("Edited Receipt") | |
| st.json(st.session_state.edited_receipt) | |
| # Handle file saving | |
| data_list = [f for f in listdir('new_receipt_data') if isfile(join('new_receipt_data', f))] | |
| if not data_list: | |
| st.session_state.data_list = [] | |
| else: | |
| with open(f'new_receipt_data/{data_list[0]}', 'r') as openfile: | |
| # Reading from json file | |
| st.session_state.data_list = json.load(openfile) | |
| st.session_state.image_name = f'{len(st.session_state.data_list)+1}_new_receipt.jpg' | |
| # Option to save or export | |
| if st.button("Save Receipt Data", key="save_button"): | |
| try: | |
| # Create directories if they don't exist | |
| # Save receipt data | |
| data_list=st.session_state.data_list | |
| data_list.append({ | |
| 'receipt_name':st.session_state.image_name, | |
| 'receipt_data': st.session_state.edited_receipt | |
| }) | |
| # with open("new_receipt_data/receipt_data_list.json", "w") as f: | |
| # json.dump(data_list, f, indent=2) | |
| json_string = json.dumps(data_list) | |
| bytes_data = json_string.encode('utf-8') | |
| api.upload_file(path_or_fileobj=bytes_data, repo_id=repo_id, repo_type="space", path_in_repo="new_receipt_data/receipt_data_list.json",token=token) | |
| # Save image if available | |
| if st.session_state.receipt_image: | |
| # save_path = f'new_images/{st.session_state.image_name}' | |
| # st.session_state.receipt_image.save(save_path) | |
| buffered=BytesIO() | |
| image=st.session_state.receipt_image | |
| image.save(buffered, format='JPEG') | |
| # image_data = base64.b64encode(buffered.getvalue()).decode("utf-8") | |
| api.upload_file(path_or_fileobj=buffered.getvalue(), repo_id=repo_id,repo_type="space", path_in_repo=f'new_images/{st.session_state.image_name}',token=token) | |
| st.success(f"Receipt data and image saved successfully!") | |
| else: | |
| st.success("Receipt data saved (no image available)") | |
| except Exception as e: | |
| st.error(f"Error saving receipt: {str(e)}") | |
| # Reset button to clear session state | |
| if st.sidebar.button("Reset All", key="reset_button"): | |
| # Clear specific session state values | |
| for key in list(st.session_state.keys()): | |
| del st.session_state[key] | |
| def main(): | |
| receipt_editor_app() | |
| if __name__ == "__main__": | |
| main() |