timfocus commited on
Commit
3a5cb12
·
verified ·
1 Parent(s): 8f2c076

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +90 -73
app.py CHANGED
@@ -7,13 +7,13 @@ from reportlab.lib.pagesizes import inch
7
  import barcode
8
  from barcode.writer import ImageWriter
9
 
10
- # Folders for generated files
11
  LABELS_DIR = "labels"
12
  BARCODES_DIR = "barcodes"
13
  os.makedirs(LABELS_DIR, exist_ok=True)
14
  os.makedirs(BARCODES_DIR, exist_ok=True)
15
 
16
- # Columns we expect in the CSV/Excel
17
  REQUIRED_COLUMNS = [
18
  "Order ID", "Order Date", "Shipper Name", "Shipper Address", "Shipper Phone",
19
  "Receiver Name", "Receiver Address", "Receiver Phone", "Package Weight (kg)",
@@ -21,19 +21,18 @@ REQUIRED_COLUMNS = [
21
  ]
22
 
23
  ###############################################################################
24
- # 1) Draw the static background ("collage") for a 4x6 USPS label
25
  ###############################################################################
26
  def draw_label_collage(c, width, height):
27
  """
28
- Draws the static elements, like the big "F", USPS text,
29
- placeholder for QR code, horizontal lines, etc.
30
- Coordinates are measured from the bottom-left corner in ReportLab.
31
  """
32
- # Big "F" in top-left
33
  c.setFont("Helvetica-Bold", 80)
34
  c.drawString(15, height - 85, "F")
35
 
36
- # USPS postage info block (under the big "F")
37
  c.setFont("Helvetica", 6)
38
  c.drawString(70, height - 20, "US POSTAGE AND FEES PAID")
39
  c.drawString(70, height - 30, "Apr 12 2018")
@@ -45,23 +44,26 @@ def draw_label_collage(c, width, height):
45
  c.setFont("Helvetica", 6)
46
  c.drawString(width - 50, height - 20, "QR CODE")
47
 
48
- # "USPS FIRST-CLASS PKG" near top, horizontally centered
49
  c.setFont("Helvetica-Bold", 14)
50
  c.drawCentredString(width / 2, height - 110, "USPS FIRST-CLASS PKG")
51
 
52
- # Horizontal line below it
53
  c.setLineWidth(1)
54
  c.line(15, height - 115, width - 15, height - 115)
55
 
56
  ###############################################################################
57
- # 2) Overlay dynamic text from the CSV row
58
  ###############################################################################
59
  def draw_label_text(c, row, width, height):
60
  """
61
- Places the order info, shipper details, receiver details,
62
- shipping details, and a placeholder for tracking text.
 
 
 
63
  """
64
- # Extract row data (with default fallbacks if missing)
65
  order_id = row.get("Order ID", "")
66
  order_date = row.get("Order Date", "")
67
  shipper_name = row.get("Shipper Name", "")
@@ -75,113 +77,129 @@ def draw_label_text(c, row, width, height):
75
  tracking_num = row.get("Tracking Number", "")
76
  eta_date = row.get("Estimated Delivery Date", "")
77
 
78
- # Top-right: Order info
79
- c.setFont("Helvetica-Bold", 9)
80
- c.drawRightString(width - 15, height - 130, f"Order: {order_id}")
81
- c.drawRightString(width - 15, height - 142, f"Date: {order_date}")
82
 
83
- # Shipper block (left side, below the line)
84
- start_y = height - 130
85
- c.setFont("Helvetica-Bold", 10)
86
- c.drawString(15, start_y - 20, "From:")
 
 
87
  c.setFont("Helvetica", 9)
88
- c.drawString(15, start_y - 35, shipper_name)
89
- c.drawString(15, start_y - 50, shipper_addr)
90
- c.drawString(15, start_y - 65, f"Phone: {shipper_phone}")
91
 
92
- # Receiver block (centered)
93
- # We'll place "To:" a bit lower, then name & address below it
94
- rec_start = start_y - 95
95
- c.setFont("Helvetica-Bold", 10)
96
- c.drawString(15, rec_start, "To:")
97
- c.setFont("Helvetica-Bold", 12)
98
- c.drawCentredString(width / 2, rec_start - 20, receiver_name)
99
- c.setFont("Helvetica", 10)
100
- c.drawCentredString(width / 2, rec_start - 35, receiver_addr)
101
- c.drawCentredString(width / 2, rec_start - 50, f"Phone: {receiver_phone}")
 
 
 
 
 
 
 
 
102
 
103
- # Shipping details (Weight, Method, ETA) – place them below the receiver
104
- ship_info_start = rec_start - 70
105
  c.setFont("Helvetica-Bold", 9)
106
- c.drawString(15, ship_info_start, f"Weight: {weight} kg")
107
- c.drawString(15, ship_info_start - 15, f"Method: {ship_method}")
108
- c.drawString(15, ship_info_start - 30, f"ETA: {eta_date}")
109
-
110
- # "USPS TRACKING #" centered, further down
111
- track_label_y = ship_info_start - 60
 
 
 
 
 
 
112
  c.setFont("Helvetica-Bold", 12)
113
- c.drawCentredString(width / 2, track_label_y, "USPS TRACKING #")
114
 
115
- # Tracking number text just below the label
 
 
 
 
116
  c.setFont("Helvetica-Bold", 10)
117
- c.drawCentredString(width / 2, track_label_y - 15, tracking_num)
118
 
119
  ###############################################################################
120
- # 3) Create the 4x6-inch USPS-style label (PDF)
121
  ###############################################################################
122
  def create_usps_label(row, index=1):
123
  """
124
- 1) Generate barcode
125
- 2) Draw static collage
126
- 3) Overlay dynamic text
127
  4) Place barcode near the bottom
128
  """
129
- # Generate barcode image
130
- tracking_number = row.get("Tracking Number", "000000000000")
131
  barcode_filename = os.path.join(BARCODES_DIR, f"barcode_{index}.png")
132
  code128 = barcode.get_barcode_class("code128")
133
  code128_obj = code128(tracking_number, writer=ImageWriter())
134
  code128_obj.save(barcode_filename)
135
 
136
- # Create a 4x6 inch PDF
137
  width, height = 4 * inch, 6 * inch
138
  label_filename = os.path.join(LABELS_DIR, f"label_{index}.pdf")
139
  c = canvas.Canvas(label_filename, pagesize=(width, height))
140
 
141
- # 1) Draw static collage (background)
142
  draw_label_collage(c, width, height)
143
- # 2) Overlay dynamic text
144
  draw_label_text(c, row, width, height)
145
- # 3) Place barcode near bottom (centered horizontally)
 
146
  if os.path.exists(barcode_filename):
147
  barcode_w = 3 * inch
148
  barcode_h = 0.8 * inch
149
  x_pos = (width - barcode_w) / 2
150
- y_pos = 0.6 * inch # ~0.6 inch from bottom
151
  c.drawImage(barcode_filename, x_pos, y_pos, width=barcode_w, height=barcode_h)
152
  else:
153
  c.setFont("Helvetica", 10)
154
- c.drawString(15, 0.6 * inch, "Barcode generation failed.")
155
 
156
  c.showPage()
157
  c.save()
158
  return label_filename
159
 
160
  ###############################################################################
161
- # 4) Gradio function to process file upload
162
  ###############################################################################
163
  def process_file(file_obj):
164
  """
165
- Reads CSV/XLSX, checks required columns,
166
- generates one label per row, zips them up.
167
- Returns (status_message, zip_file_path) for Gradio outputs.
168
  """
169
  try:
170
- # Clear old labels/barcodes
171
  for f in os.listdir(LABELS_DIR):
172
  os.remove(os.path.join(LABELS_DIR, f))
173
  for f in os.listdir(BARCODES_DIR):
174
  os.remove(os.path.join(BARCODES_DIR, f))
175
 
176
- # Read the file
177
  if file_obj.name.endswith(".csv"):
178
  df = pd.read_csv(file_obj)
179
  elif file_obj.name.endswith((".xls", ".xlsx")):
180
  df = pd.read_excel(file_obj)
181
  else:
182
- return "Invalid file format. Please upload .csv, .xls, or .xlsx.", None
183
 
184
- # Check for required columns
185
  missing = [col for col in REQUIRED_COLUMNS if col not in df.columns]
186
  if missing:
187
  return f"Missing columns: {', '.join(missing)}", None
@@ -190,7 +208,7 @@ def process_file(file_obj):
190
  for i, row in df.iterrows():
191
  create_usps_label(row.to_dict(), index=i+1)
192
 
193
- # Zip all PDFs
194
  zip_filename = "usps_labels.zip"
195
  with zipfile.ZipFile(zip_filename, "w") as zf:
196
  for f in os.listdir(LABELS_DIR):
@@ -211,14 +229,13 @@ iface = gr.Interface(
211
  outputs=[gr.Text(label="Status"), gr.File(label="Download Zipped Labels")],
212
  title="USPS-Style Label Generator (4x6)",
213
  description=(
214
- "Upload a CSV/XLS/XLSX file with these columns:\n"
215
- "Order ID, Order Date, Shipper Name, Shipper Address, Shipper Phone\n"
216
- "Receiver Name, Receiver Address, Receiver Phone, Package Weight (kg)\n"
217
- "Shipping Method, Tracking Number, Estimated Delivery Date\n\n"
218
- "One 4x6 USPS-style PDF label is created per row, then zipped for download."
219
  ),
220
  )
221
 
222
- # Launch the Gradio app
223
  if __name__ == "__main__":
224
  iface.launch()
 
7
  import barcode
8
  from barcode.writer import ImageWriter
9
 
10
+ # Directories for generated files
11
  LABELS_DIR = "labels"
12
  BARCODES_DIR = "barcodes"
13
  os.makedirs(LABELS_DIR, exist_ok=True)
14
  os.makedirs(BARCODES_DIR, exist_ok=True)
15
 
16
+ # Required CSV/Excel columns
17
  REQUIRED_COLUMNS = [
18
  "Order ID", "Order Date", "Shipper Name", "Shipper Address", "Shipper Phone",
19
  "Receiver Name", "Receiver Address", "Receiver Phone", "Package Weight (kg)",
 
21
  ]
22
 
23
  ###############################################################################
24
+ # 1) Draw the static collage (top portion) for a 4x6 USPS label
25
  ###############################################################################
26
  def draw_label_collage(c, width, height):
27
  """
28
+ Draws the top portion: big 'F', USPS text, placeholder QR code,
29
+ 'USPS FIRST-CLASS PKG' title, plus a top horizontal line.
 
30
  """
31
+ # Big "F" near top-left
32
  c.setFont("Helvetica-Bold", 80)
33
  c.drawString(15, height - 85, "F")
34
 
35
+ # USPS postage info block (small text under "F")
36
  c.setFont("Helvetica", 6)
37
  c.drawString(70, height - 20, "US POSTAGE AND FEES PAID")
38
  c.drawString(70, height - 30, "Apr 12 2018")
 
44
  c.setFont("Helvetica", 6)
45
  c.drawString(width - 50, height - 20, "QR CODE")
46
 
47
+ # "USPS FIRST-CLASS PKG" in bold, centered near top
48
  c.setFont("Helvetica-Bold", 14)
49
  c.drawCentredString(width / 2, height - 110, "USPS FIRST-CLASS PKG")
50
 
51
+ # Horizontal line across the label, just below the header
52
  c.setLineWidth(1)
53
  c.line(15, height - 115, width - 15, height - 115)
54
 
55
  ###############################################################################
56
+ # 2) Overlay dynamic text + horizontal lines to mimic the sample layout
57
  ###############################################################################
58
  def draw_label_text(c, row, width, height):
59
  """
60
+ Places:
61
+ - Warehouse & Order info, then a horizontal line
62
+ - Recipient address, then another line
63
+ - "USPS TRACKING #" heading, then another line
64
+ - Tracking number below that line
65
  """
66
+ # Convert row to local variables (with fallback)
67
  order_id = row.get("Order ID", "")
68
  order_date = row.get("Order Date", "")
69
  shipper_name = row.get("Shipper Name", "")
 
77
  tracking_num = row.get("Tracking Number", "")
78
  eta_date = row.get("Estimated Delivery Date", "")
79
 
80
+ # We'll start below the top line from the collage
81
+ top_line_y = height - 115
 
 
82
 
83
+ ############################
84
+ # Warehouse + Order Info
85
+ ############################
86
+ # Left: Warehouse lines
87
+ c.setFont("Helvetica-Bold", 9)
88
+ c.drawString(15, top_line_y - 15, shipper_name or "WAREHOUSE 2")
89
  c.setFont("Helvetica", 9)
90
+ c.drawString(15, top_line_y - 30, shipper_addr or "11919 WINK RD")
91
+ c.drawString(15, top_line_y - 45, f"{shipper_phone}" or "HOUSTON TX 77024-7134")
 
92
 
93
+ # Right: "Order: 286"
94
+ c.setFont("Helvetica", 9)
95
+ c.drawRightString(width - 15, top_line_y - 15, f"Order: {order_id}")
96
+ c.drawRightString(width - 15, top_line_y - 30, f"Date: {order_date}")
97
+
98
+ # Horizontal line under Warehouse/Order block
99
+ warehouse_line_y = top_line_y - 60
100
+ c.line(15, warehouse_line_y, width - 15, warehouse_line_y)
101
+
102
+ ############################
103
+ # Recipient Block
104
+ ############################
105
+ # Bold name, address, phone
106
+ c.setFont("Helvetica-Bold", 11)
107
+ c.drawString(15, warehouse_line_y - 15, receiver_name)
108
+ c.setFont("Helvetica", 9)
109
+ c.drawString(15, warehouse_line_y - 30, receiver_addr)
110
+ c.drawString(15, warehouse_line_y - 45, f"Phone: {receiver_phone}")
111
 
112
+ # Possibly show shipping details to the right
 
113
  c.setFont("Helvetica-Bold", 9)
114
+ c.drawRightString(width - 15, warehouse_line_y - 15, f"Weight: {weight} kg")
115
+ c.drawRightString(width - 15, warehouse_line_y - 30, f"Method: {ship_method}")
116
+ c.drawRightString(width - 15, warehouse_line_y - 45, f"ETA: {eta_date}")
117
+
118
+ # Another line below the recipient block
119
+ recipient_line_y = warehouse_line_y - 60
120
+ c.line(15, recipient_line_y, width - 15, recipient_line_y)
121
+
122
+ ############################
123
+ # USPS TRACKING #
124
+ ############################
125
+ # Place "USPS TRACKING #" in bold, centered
126
  c.setFont("Helvetica-Bold", 12)
127
+ c.drawCentredString(width / 2, recipient_line_y - 20, "USPS TRACKING #")
128
 
129
+ # Another line under "USPS TRACKING #"
130
+ tracking_line_y = recipient_line_y - 35
131
+ c.line(15, tracking_line_y, width - 15, tracking_line_y)
132
+
133
+ # Tracking number below that line, centered
134
  c.setFont("Helvetica-Bold", 10)
135
+ c.drawCentredString(width / 2, tracking_line_y - 20, tracking_num)
136
 
137
  ###############################################################################
138
+ # 3) Create the 4x6 USPS-style label
139
  ###############################################################################
140
  def create_usps_label(row, index=1):
141
  """
142
+ 1) Generate a Code128 barcode from 'Tracking Number'
143
+ 2) Draw collage
144
+ 3) Draw dynamic text & lines
145
  4) Place barcode near the bottom
146
  """
147
+ # Barcode
148
+ tracking_number = row.get("Tracking Number", "0000000000")
149
  barcode_filename = os.path.join(BARCODES_DIR, f"barcode_{index}.png")
150
  code128 = barcode.get_barcode_class("code128")
151
  code128_obj = code128(tracking_number, writer=ImageWriter())
152
  code128_obj.save(barcode_filename)
153
 
154
+ # 4x6 inches
155
  width, height = 4 * inch, 6 * inch
156
  label_filename = os.path.join(LABELS_DIR, f"label_{index}.pdf")
157
  c = canvas.Canvas(label_filename, pagesize=(width, height))
158
 
159
+ # Draw the collage
160
  draw_label_collage(c, width, height)
161
+ # Overlay text & lines
162
  draw_label_text(c, row, width, height)
163
+
164
+ # Place barcode near bottom, centered horizontally
165
  if os.path.exists(barcode_filename):
166
  barcode_w = 3 * inch
167
  barcode_h = 0.8 * inch
168
  x_pos = (width - barcode_w) / 2
169
+ y_pos = 0.5 * inch # ~0.5 inch from bottom
170
  c.drawImage(barcode_filename, x_pos, y_pos, width=barcode_w, height=barcode_h)
171
  else:
172
  c.setFont("Helvetica", 10)
173
+ c.drawString(15, 0.5 * inch, "Barcode generation failed.")
174
 
175
  c.showPage()
176
  c.save()
177
  return label_filename
178
 
179
  ###############################################################################
180
+ # 4) Gradio function to process file uploads
181
  ###############################################################################
182
  def process_file(file_obj):
183
  """
184
+ Reads CSV/Excel, checks columns,
185
+ generates one label per row, zips them.
 
186
  """
187
  try:
188
+ # Clean out old labels/barcodes
189
  for f in os.listdir(LABELS_DIR):
190
  os.remove(os.path.join(LABELS_DIR, f))
191
  for f in os.listdir(BARCODES_DIR):
192
  os.remove(os.path.join(BARCODES_DIR, f))
193
 
194
+ # Read the uploaded file
195
  if file_obj.name.endswith(".csv"):
196
  df = pd.read_csv(file_obj)
197
  elif file_obj.name.endswith((".xls", ".xlsx")):
198
  df = pd.read_excel(file_obj)
199
  else:
200
+ return "Invalid file format. Please upload a .csv, .xls, or .xlsx file.", None
201
 
202
+ # Check required columns
203
  missing = [col for col in REQUIRED_COLUMNS if col not in df.columns]
204
  if missing:
205
  return f"Missing columns: {', '.join(missing)}", None
 
208
  for i, row in df.iterrows():
209
  create_usps_label(row.to_dict(), index=i+1)
210
 
211
+ # Zip them up
212
  zip_filename = "usps_labels.zip"
213
  with zipfile.ZipFile(zip_filename, "w") as zf:
214
  for f in os.listdir(LABELS_DIR):
 
229
  outputs=[gr.Text(label="Status"), gr.File(label="Download Zipped Labels")],
230
  title="USPS-Style Label Generator (4x6)",
231
  description=(
232
+ "Upload a CSV/XLS/XLSX file with columns:\n"
233
+ "Order ID, Order Date, Shipper Name, Shipper Address, Shipper Phone,\n"
234
+ "Receiver Name, Receiver Address, Receiver Phone, Package Weight (kg),\n"
235
+ "Shipping Method, Tracking Number, Estimated Delivery Date\n\n"
236
+ "Generates a 4x6 USPS-style PDF label per row, including lines that match the sample."
237
  ),
238
  )
239
 
 
240
  if __name__ == "__main__":
241
  iface.launch()