File size: 9,383 Bytes
31bfcac
273a8ca
e508c3f
273a8ca
059d856
273a8ca
059d856
 
 
3a5cb12
e508c3f
 
 
 
059d856
3a5cb12
f6b843b
 
 
 
 
 
8f2c076
3a5cb12
8f2c076
273a8ca
 
3a5cb12
 
273a8ca
3a5cb12
8f2c076
 
 
3a5cb12
8f2c076
 
 
 
 
 
273a8ca
f6b843b
273a8ca
8f2c076
273a8ca
3a5cb12
273a8ca
8f2c076
 
3a5cb12
273a8ca
 
 
8f2c076
3a5cb12
8f2c076
273a8ca
 
3a5cb12
 
 
 
 
273a8ca
3a5cb12
8f2c076
 
 
 
 
 
 
 
 
 
 
 
 
3a5cb12
 
8f2c076
3a5cb12
 
 
 
 
 
8f2c076
3a5cb12
 
8f2c076
3a5cb12
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8f2c076
3a5cb12
8f2c076
3a5cb12
 
 
 
 
 
 
 
 
 
 
 
f6b843b
3a5cb12
8f2c076
3a5cb12
 
 
 
 
273a8ca
3a5cb12
273a8ca
8f2c076
3a5cb12
8f2c076
273a8ca
 
3a5cb12
 
 
8f2c076
273a8ca
3a5cb12
 
273a8ca
 
 
 
 
3a5cb12
273a8ca
 
 
 
3a5cb12
273a8ca
3a5cb12
273a8ca
3a5cb12
 
273a8ca
8f2c076
 
 
3a5cb12
8f2c076
273a8ca
 
3a5cb12
8f2c076
273a8ca
 
 
 
8f2c076
3a5cb12
8f2c076
273a8ca
8f2c076
3a5cb12
 
8f2c076
e508c3f
3a5cb12
273a8ca
 
 
 
 
3a5cb12
273a8ca
 
 
 
e508c3f
3a5cb12
059d856
3a5cb12
f6b843b
273a8ca
d8a38a8
059d856
8f2c076
e508c3f
273a8ca
a919f44
3a5cb12
273a8ca
 
 
 
 
a919f44
d8a38a8
a3a8092
a919f44
8f2c076
a919f44
8f2c076
 
 
a919f44
 
a3a8092
d8a38a8
273a8ca
 
3a5cb12
 
 
 
 
273a8ca
a919f44
 
273a8ca
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
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()