From 027710ba2fe01942c6b37d9b25ef92baf7bc57c6 Mon Sep 17 00:00:00 2001 From: Shihaam Abdul Rahman Date: Fri, 8 Nov 2024 20:34:14 +0500 Subject: [PATCH] it works now --- .build/Dockerfile | 36 ++++++++ .build/compose.yml | 7 ++ app.py | 208 +++++++++++++++++++++++++++++++++++++++++++++ compose.yml | 14 +++ requirements.txt | 3 + 5 files changed, 268 insertions(+) create mode 100644 .build/Dockerfile create mode 100644 .build/compose.yml create mode 100644 app.py create mode 100644 compose.yml create mode 100644 requirements.txt diff --git a/.build/Dockerfile b/.build/Dockerfile new file mode 100644 index 0000000..505a144 --- /dev/null +++ b/.build/Dockerfile @@ -0,0 +1,36 @@ +FROM python:3.12-slim + +# Set working directory +WORKDIR /app + +# Set environment variables +#ENV PYTHONDONTWRITEBYTECODE=1 \ +# PYTHONUNBUFFERED=1 \ +# STREAMLIT_SERVER_PORT=8501 \ +# STREAMLIT_SERVER_ADDRESS=0.0.0.0 +ARG PYTHONDONTWRITEBYTECODE=1 \ + PYTHONUNBUFFERED=1 \ + STREAMLIT_SERVER_PORT=8501 \ + STREAMLIT_SERVER_ADDRESS=0.0.0.0 + +# Install system dependencies +#RUN apt-get update && \ +# apt-get install -y --no-install-recommends \ +# build-essential \ +# curl \ +# && rm -rf /var/lib/apt/lists/* + +# Copy requirements first to leverage Docker cache +COPY requirements.txt . + +# Install Python dependencies +RUN pip install --no-cache-dir -r requirements.txt + +# Copy the application code +COPY . . + +# Expose the port Streamlit runs on +EXPOSE 8501 + +# Command to run the application +CMD ["streamlit", "run", "app.py"] diff --git a/.build/compose.yml b/.build/compose.yml new file mode 100644 index 0000000..29d89b2 --- /dev/null +++ b/.build/compose.yml @@ -0,0 +1,7 @@ +services: + mvpost-package-no-finder: + build: + context: .. + dockerfile: .build/Dockerfile + image: git.shihaam.dev/shihaam/mvpost-package-no-finder + container_name: mvpost-package-no-finder diff --git a/app.py b/app.py new file mode 100644 index 0000000..53a6043 --- /dev/null +++ b/app.py @@ -0,0 +1,208 @@ +import streamlit as st +import pandas as pd +import os +from typing import Dict, Tuple + +class TrackingLookup: + def __init__(self): + self.tracking_data: Dict[str, Tuple[str, str]] = {} # {tracking_no: (mailbag_no, #)} + + def extract_mailbag_no(self, df: pd.DataFrame) -> str: + """Extract Mail Bag No from the DataFrame""" + for _, row in df.iterrows(): + for col in df.columns: + val = str(row[col]) + if 'HDOD-' in val: + return val.strip() + return 'unknown_mailbag' + + def clean_tracking_numbers(self, df: pd.DataFrame) -> pd.DataFrame: + """Extract only # and Tracking No columns, removing any empty rows""" + tracking_col = None + number_col = None + + # First try to find by exact column names + if '#' in df.columns and 'Tracking No' in df.columns: + return df[['#', 'Tracking No']] + + # Try to find tracking number column + for col in df.columns: + # Check if column contains any tracking number patterns + if df[col].astype(str).str.contains('UV|UW|LP|LORD', na=False, regex=True).any(): + tracking_col = col + break + + # Find the number column (usually the first column with 1,2,3...) + for col in df.columns: + if df[col].astype(str).str.match('^\d+$', na=False).any(): + number_col = col + break + + # If we found both columns + if tracking_col is not None and number_col is not None: + df = df[[number_col, tracking_col]] + df.columns = ['#', 'Tracking No'] + + # Clean data + df = df[df['Tracking No'].notna()] + # Updated pattern to include LORD format + df = df[df['Tracking No'].str.match(r'^[A-Z0-9]+$', na=False)] + return df + + # If we couldn't find the required columns, return empty DataFrame + return pd.DataFrame(columns=['#', 'Tracking No']) + + def process_excel_file(self, uploaded_file) -> bool: + """Process uploaded Excel file and store tracking data""" + try: + # Read all sheets + xl = pd.ExcelFile(uploaded_file) + + processed_sheets = 0 + for sheet_name in xl.sheet_names: + try: + df = pd.read_excel(uploaded_file, sheet_name=sheet_name) + + # Skip empty sheets or sheets without the expected structure + if df.empty or 'Domestic Letter Bill' not in str(df.iloc[0:5].values): + continue + + mailbag_no = self.extract_mailbag_no(df) + cleaned_df = self.clean_tracking_numbers(df) + + if not cleaned_df.empty: + # Store tracking numbers with their mailbag and sequence numbers + for _, row in cleaned_df.iterrows(): + self.tracking_data[row['Tracking No']] = (mailbag_no, row['#']) + processed_sheets += 1 + + except Exception as e: + st.warning(f"Warning: Could not process sheet '{sheet_name}': {str(e)}") + continue + + if processed_sheets > 0: + st.info(f"Successfully processed {processed_sheets} sheet(s)") + return True + else: + st.error("No valid sheets were found in the file") + return False + + except Exception as e: + st.error(f"Error processing file: {str(e)}") + return False + + def lookup_tracking(self, tracking_no: str) -> Tuple[str, str]: + """Look up mailbag number and sequence number for a tracking number""" + return self.tracking_data.get(tracking_no, (None, None)) + +def main(): + # Configure the page + st.set_page_config( + page_title="Mail Tracking Lookup", + layout="wide", + initial_sidebar_state="collapsed" + ) + + # Custom CSS for dark theme + st.markdown(""" + + """, unsafe_allow_html=True) + + st.title("📬 Mail Tracking Lookup System") + + # Initialize tracker in session state if it doesn't exist + if 'tracker' not in st.session_state: + st.session_state['tracker'] = TrackingLookup() + + # File upload section + st.header("1. Upload Excel File") + uploaded_file = st.file_uploader("Choose an Excel file", type=['xlsx', 'xls']) + + if uploaded_file: + col1, col2, col3 = st.columns([1, 2, 1]) + with col2: + if st.button("Process File", use_container_width=True): + success = st.session_state.tracker.process_excel_file(uploaded_file) + if success: + st.success("✅ File processed successfully!") + st.session_state.file_processed = True + + # Tracking number lookup section + st.header("2. Lookup Tracking Number") + + tracking_input = st.text_input( + "Enter tracking number:", + placeholder="e.g., UV743594518UZ or LORD04012", + help="Enter the tracking number and press Enter" + ) + + if tracking_input: + mailbag_no, sequence_no = st.session_state.tracker.lookup_tracking(tracking_input) + + if mailbag_no: + st.markdown( + f"""
+

📦 Tracking Details

+

Mail Bag No: {mailbag_no}

+

Sequence #: {sequence_no}

+
""", + unsafe_allow_html=True + ) + else: + st.warning("❌ Tracking number not found in the uploaded data") + +if __name__ == "__main__": + main() diff --git a/compose.yml b/compose.yml new file mode 100644 index 0000000..f6051fa --- /dev/null +++ b/compose.yml @@ -0,0 +1,14 @@ +version: '3.8' + +services: + mvpost-package-no-finder: + image: git.shihaam.dev/shihaam/mvpost-package-no-finder + container_name: mvpost-package-no-finder + ports: + - "8501:8501" + volumes: + - .:/app + environment: + - STREAMLIT_SERVER_PORT=8501 + - STREAMLIT_SERVER_ADDRESS=0.0.0.0 + restart: unless-stopped diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..bc18198 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,3 @@ +streamlit>=1.31.0 +pandas>=2.2.0 +openpyxl>=3.1.2