Label / app.py
timfocus's picture
Update app.py
3a5cb12 verified
import os
import zipfile
import gradio as gr
import pandas as pd
from reportlab.pdfgen import canvas
from reportlab.lib.pagesizes import inch
import barcode
from barcode.writer import ImageWriter
# Directories for generated files
LABELS_DIR = "labels"
BARCODES_DIR = "barcodes"
os.makedirs(LABELS_DIR, exist_ok=True)
os.makedirs(BARCODES_DIR, exist_ok=True)
# Required CSV/Excel columns
REQUIRED_COLUMNS = [
"Order ID", "Order Date", "Shipper Name", "Shipper Address", "Shipper Phone",
"Receiver Name", "Receiver Address", "Receiver Phone", "Package Weight (kg)",
"Shipping Method", "Tracking Number", "Estimated Delivery Date"
]
###############################################################################
# 1) Draw the static collage (top portion) for a 4x6 USPS label
###############################################################################
def draw_label_collage(c, width, height):
"""
Draws the top portion: big 'F', USPS text, placeholder QR code,
'USPS FIRST-CLASS PKG' title, plus a top horizontal line.
"""
# Big "F" near top-left
c.setFont("Helvetica-Bold", 80)
c.drawString(15, height - 85, "F")
# USPS postage info block (small text under "F")
c.setFont("Helvetica", 6)
c.drawString(70, height - 20, "US POSTAGE AND FEES PAID")
c.drawString(70, height - 30, "Apr 12 2018")
c.drawString(70, height - 40, "Mailed from ZIP 77024")
c.drawString(70, height - 50, "First-Class Pkg Svc")
c.drawString(70, height - 60, "CommercialBasePrice")
# Placeholder for QR code in top-right
c.setFont("Helvetica", 6)
c.drawString(width - 50, height - 20, "QR CODE")
# "USPS FIRST-CLASS PKG" in bold, centered near top
c.setFont("Helvetica-Bold", 14)
c.drawCentredString(width / 2, height - 110, "USPS FIRST-CLASS PKG")
# Horizontal line across the label, just below the header
c.setLineWidth(1)
c.line(15, height - 115, width - 15, height - 115)
###############################################################################
# 2) Overlay dynamic text + horizontal lines to mimic the sample layout
###############################################################################
def draw_label_text(c, row, width, height):
"""
Places:
- Warehouse & Order info, then a horizontal line
- Recipient address, then another line
- "USPS TRACKING #" heading, then another line
- Tracking number below that line
"""
# Convert row to local variables (with fallback)
order_id = row.get("Order ID", "")
order_date = row.get("Order Date", "")
shipper_name = row.get("Shipper Name", "")
shipper_addr = row.get("Shipper Address", "")
shipper_phone = row.get("Shipper Phone", "")
receiver_name = row.get("Receiver Name", "")
receiver_addr = row.get("Receiver Address", "")
receiver_phone = row.get("Receiver Phone", "")
weight = row.get("Package Weight (kg)", "")
ship_method = row.get("Shipping Method", "")
tracking_num = row.get("Tracking Number", "")
eta_date = row.get("Estimated Delivery Date", "")
# We'll start below the top line from the collage
top_line_y = height - 115
############################
# Warehouse + Order Info
############################
# Left: Warehouse lines
c.setFont("Helvetica-Bold", 9)
c.drawString(15, top_line_y - 15, shipper_name or "WAREHOUSE 2")
c.setFont("Helvetica", 9)
c.drawString(15, top_line_y - 30, shipper_addr or "11919 WINK RD")
c.drawString(15, top_line_y - 45, f"{shipper_phone}" or "HOUSTON TX 77024-7134")
# Right: "Order: 286"
c.setFont("Helvetica", 9)
c.drawRightString(width - 15, top_line_y - 15, f"Order: {order_id}")
c.drawRightString(width - 15, top_line_y - 30, f"Date: {order_date}")
# Horizontal line under Warehouse/Order block
warehouse_line_y = top_line_y - 60
c.line(15, warehouse_line_y, width - 15, warehouse_line_y)
############################
# Recipient Block
############################
# Bold name, address, phone
c.setFont("Helvetica-Bold", 11)
c.drawString(15, warehouse_line_y - 15, receiver_name)
c.setFont("Helvetica", 9)
c.drawString(15, warehouse_line_y - 30, receiver_addr)
c.drawString(15, warehouse_line_y - 45, f"Phone: {receiver_phone}")
# Possibly show shipping details to the right
c.setFont("Helvetica-Bold", 9)
c.drawRightString(width - 15, warehouse_line_y - 15, f"Weight: {weight} kg")
c.drawRightString(width - 15, warehouse_line_y - 30, f"Method: {ship_method}")
c.drawRightString(width - 15, warehouse_line_y - 45, f"ETA: {eta_date}")
# Another line below the recipient block
recipient_line_y = warehouse_line_y - 60
c.line(15, recipient_line_y, width - 15, recipient_line_y)
############################
# USPS TRACKING #
############################
# Place "USPS TRACKING #" in bold, centered
c.setFont("Helvetica-Bold", 12)
c.drawCentredString(width / 2, recipient_line_y - 20, "USPS TRACKING #")
# Another line under "USPS TRACKING #"
tracking_line_y = recipient_line_y - 35
c.line(15, tracking_line_y, width - 15, tracking_line_y)
# Tracking number below that line, centered
c.setFont("Helvetica-Bold", 10)
c.drawCentredString(width / 2, tracking_line_y - 20, tracking_num)
###############################################################################
# 3) Create the 4x6 USPS-style label
###############################################################################
def create_usps_label(row, index=1):
"""
1) Generate a Code128 barcode from 'Tracking Number'
2) Draw collage
3) Draw dynamic text & lines
4) Place barcode near the bottom
"""
# Barcode
tracking_number = row.get("Tracking Number", "0000000000")
barcode_filename = os.path.join(BARCODES_DIR, f"barcode_{index}.png")
code128 = barcode.get_barcode_class("code128")
code128_obj = code128(tracking_number, writer=ImageWriter())
code128_obj.save(barcode_filename)
# 4x6 inches
width, height = 4 * inch, 6 * inch
label_filename = os.path.join(LABELS_DIR, f"label_{index}.pdf")
c = canvas.Canvas(label_filename, pagesize=(width, height))
# Draw the collage
draw_label_collage(c, width, height)
# Overlay text & lines
draw_label_text(c, row, width, height)
# Place barcode near bottom, centered horizontally
if os.path.exists(barcode_filename):
barcode_w = 3 * inch
barcode_h = 0.8 * inch
x_pos = (width - barcode_w) / 2
y_pos = 0.5 * inch # ~0.5 inch from bottom
c.drawImage(barcode_filename, x_pos, y_pos, width=barcode_w, height=barcode_h)
else:
c.setFont("Helvetica", 10)
c.drawString(15, 0.5 * inch, "Barcode generation failed.")
c.showPage()
c.save()
return label_filename
###############################################################################
# 4) Gradio function to process file uploads
###############################################################################
def process_file(file_obj):
"""
Reads CSV/Excel, checks columns,
generates one label per row, zips them.
"""
try:
# Clean out old labels/barcodes
for f in os.listdir(LABELS_DIR):
os.remove(os.path.join(LABELS_DIR, f))
for f in os.listdir(BARCODES_DIR):
os.remove(os.path.join(BARCODES_DIR, f))
# Read the uploaded file
if file_obj.name.endswith(".csv"):
df = pd.read_csv(file_obj)
elif file_obj.name.endswith((".xls", ".xlsx")):
df = pd.read_excel(file_obj)
else:
return "Invalid file format. Please upload a .csv, .xls, or .xlsx file.", None
# Check required columns
missing = [col for col in REQUIRED_COLUMNS if col not in df.columns]
if missing:
return f"Missing columns: {', '.join(missing)}", None
# Generate labels
for i, row in df.iterrows():
create_usps_label(row.to_dict(), index=i+1)
# Zip them up
zip_filename = "usps_labels.zip"
with zipfile.ZipFile(zip_filename, "w") as zf:
for f in os.listdir(LABELS_DIR):
if f.endswith(".pdf"):
zf.write(os.path.join(LABELS_DIR, f), f)
return "Labels generated successfully.", zip_filename
except Exception as e:
return f"Error: {str(e)}", None
###############################################################################
# 5) Gradio Interface for Hugging Face
###############################################################################
iface = gr.Interface(
fn=process_file,
inputs=gr.File(type="filepath"),
outputs=[gr.Text(label="Status"), gr.File(label="Download Zipped Labels")],
title="USPS-Style Label Generator (4x6)",
description=(
"Upload a CSV/XLS/XLSX file with columns:\n"
"Order ID, Order Date, Shipper Name, Shipper Address, Shipper Phone,\n"
"Receiver Name, Receiver Address, Receiver Phone, Package Weight (kg),\n"
"Shipping Method, Tracking Number, Estimated Delivery Date\n\n"
"Generates a 4x6 USPS-style PDF label per row, including lines that match the sample."
),
)
if __name__ == "__main__":
iface.launch()