Spaces:
Running
Running
import gradio as gr | |
import pandas as pd | |
from datetime import datetime | |
import pytz | |
import openpyxl | |
def process_file(file): | |
file_name = file.name.lower() | |
try: | |
if file_name.endswith('.csv'): | |
# CSV files do not have multiple sheets. | |
return "Error: Please upload an Excel file with a UPS sheet.", None | |
elif file_name.endswith(('.xls', '.xlsx', '.xlsm')): | |
# Only read data from the "UPS" sheet. | |
df = pd.read_excel(file.name, sheet_name="UPS") | |
else: | |
return f"Unsupported file format: {file_name}", None | |
except Exception as e: | |
return f"Error reading file: {str(e)}", None | |
# Define the new header list as specified. | |
output_headers = [ | |
"Contact Name", "Company or Name", "Country", "Address 1", "Address 2", "Address 3", | |
"City", "State/Prov/Other", "Postal Code", "Telephone", "Ext", "Residential Ind", | |
"Consignee Email", "Packaging Type", "Customs Value", "Weight", "Length", "Width", | |
"Height", "Unit of Measure", "Description of Goods", "Documents of No Commercial Value", | |
"GNIFC", "Pkg Decl Value", "Service", "Delivery Confirm", "Shipper Release", "Ret of Documents", | |
"Saturday Deliver", "Carbon Neutral", "Large Package", "Addl handling", "Reference 1", | |
"Reference 2", "Reference 3", "QV Notif 1-Addr", "QV Notif 1-Ship", "QV Notif 1-Excp", | |
"QV Notif 1-Delv", "QV Notif 2-Addr", "QV Notif 2-Ship", "QV Notif 2-Excp", "QV Notif 2-Delv", | |
"QV Notif 3-Addr", "QV Notif 3-Ship", "QV Notif 3-Excp", "QV Notif 3-Delv", "QV Notif 4-Addr", | |
"QV Notif 4-Ship", "QV Notif 4-Excp", "QV Notif 4-Delv", "QV Notif 5-Addr", "QV Notif 5-Ship", | |
"QV Notif 5-Excp", "QV Notif 5-Delv", "QV Notif Msg", "QV Failure Addr", "UPS Premium Care", | |
"ADL Location ID", "ADL Media Type", "ADL Language", "ADL Notification Addr", "ADL Failure Addr", | |
"ADL COD Value", "ADL Deliver to Addressee", "ADL Shipper Media Type", "ADL Shipper Language", | |
"ADL Shipper Notification Addr", "ADL Direct Delivery Only", "Electronic Package Release Authentication", | |
"Lithium Ion Alone", "Lithium Ion In Equipment", "Lithium Ion With_Equipment", "Lithium Metal Alone", | |
"Lithium Metal In Equipment", "Lithium Metal With Equipment", "Weekend Commercial Delivery", | |
"Dry Ice Weight", "Merchandise Description", "UPS SurePost®Limited Quantity/Lithium Battery" | |
] | |
# Create an output DataFrame with the new header list. | |
output_df = pd.DataFrame("", index=range(len(df)), columns=output_headers) | |
# Mapping from input file to output based on provided rules: | |
# 1. Shipping First Name + Shipping Last Name + Shipping Company -> Contact Name and Company or Name | |
if {"Shipping First Name", "Shipping Last Name", "Shipping Company"}.issubset(df.columns): | |
first_name = df["Shipping First Name"].fillna("").astype(str).str.strip() | |
last_name = df["Shipping Last Name"].fillna("").astype(str).str.strip() | |
company = df["Shipping Company"].fillna("").astype(str).str.strip() | |
combined = (first_name + " " + last_name + " " + company).str.strip() | |
output_df["Contact Name"] = combined | |
output_df["Company or Name"] = combined | |
# 2. Shipping Country Code -> Country | |
if "Shipping Country Code" in df.columns: | |
output_df["Country"] = df["Shipping Country Code"].fillna("").astype(str).str.strip() | |
# 3. Shipping Address 1 -> Address 1 | |
if "Shipping Address 1" in df.columns: | |
output_df["Address 1"] = df["Shipping Address 1"].fillna("").astype(str).str.strip() | |
# 4. Shipping Address 2 -> Address 2 | |
if "Shipping Address 2" in df.columns: | |
output_df["Address 2"] = df["Shipping Address 2"].fillna("").astype(str).str.strip() | |
# 5. Shipping City -> City | |
if "Shipping City" in df.columns: | |
output_df["City"] = df["Shipping City"].fillna("").astype(str).str.strip() | |
# 6. Shipping Province -> State/Prov/Other | |
if "Shipping Province" in df.columns: | |
output_df["State/Prov/Other"] = df["Shipping Province"].fillna("").astype(str).str.strip() | |
# Convert full US state names to their 2-letter abbreviations if applicable. | |
us_states = { | |
'alabama': 'AL', | |
'alaska': 'AK', | |
'arizona': 'AZ', | |
'arkansas': 'AR', | |
'california': 'CA', | |
'colorado': 'CO', | |
'connecticut': 'CT', | |
'delaware': 'DE', | |
'florida': 'FL', | |
'georgia': 'GA', | |
'hawaii': 'HI', | |
'idaho': 'ID', | |
'illinois': 'IL', | |
'indiana': 'IN', | |
'iowa': 'IA', | |
'kansas': 'KS', | |
'kentucky': 'KY', | |
'louisiana': 'LA', | |
'maine': 'ME', | |
'maryland': 'MD', | |
'massachusetts': 'MA', | |
'michigan': 'MI', | |
'minnesota': 'MN', | |
'mississippi': 'MS', | |
'missouri': 'MO', | |
'montana': 'MT', | |
'nebraska': 'NE', | |
'nevada': 'NV', | |
'new hampshire': 'NH', | |
'new jersey': 'NJ', | |
'new mexico': 'NM', | |
'new york': 'NY', | |
'north carolina': 'NC', | |
'north dakota': 'ND', | |
'ohio': 'OH', | |
'oklahoma': 'OK', | |
'oregon': 'OR', | |
'pennsylvania': 'PA', | |
'rhode island': 'RI', | |
'south carolina': 'SC', | |
'south dakota': 'SD', | |
'tennessee': 'TN', | |
'texas': 'TX', | |
'utah': 'UT', | |
'vermont': 'VT', | |
'virginia': 'VA', | |
'washington': 'WA', | |
'west virginia': 'WV', | |
'wisconsin': 'WI', | |
'wyoming': 'WY' | |
} | |
def convert_state(state): | |
if state: | |
state_lower = state.lower() | |
return us_states.get(state_lower, state) | |
return state | |
output_df["State/Prov/Other"] = output_df["State/Prov/Other"].apply(convert_state) | |
# 7. Shipping ZIP -> Postal Code | |
if "Shipping ZIP" in df.columns: | |
output_df["Postal Code"] = df["Shipping ZIP"].fillna("").astype(str).str.strip() | |
# 8. Shipping Address Phone -> Telephone | |
if "Shipping Address Phone" in df.columns: | |
output_df["Telephone"] = df["Shipping Address Phone"].fillna("").astype(str).str.strip() | |
# 9. Email -> Consignee Email | |
if "Email" in df.columns: | |
output_df["Consignee Email"] = df["Email"].fillna("").astype(str).str.strip() | |
# 10. Total Weight -> Weight (divide by 1000) | |
if "Total Weight" in df.columns: | |
def convert_weight(x): | |
try: | |
if pd.isna(x) or x == "": | |
return "" | |
return float(x) / 1000 | |
except: | |
return "" | |
output_df["Weight"] = df["Total Weight"].apply(convert_weight) | |
# Fixed value mapping (applied for rows with data in Contact Name) | |
mask = output_df["Contact Name"].notna() & (output_df["Contact Name"] != "") | |
output_df.loc[mask, "Packaging Type"] = "2" | |
output_df.loc[mask, "Unit of Measure"] = "KG" | |
output_df.loc[mask, "Description of Goods"] = "Eyes Beauty Color Cosmetics" | |
output_df.loc[mask, "Service"] = "7" | |
# Delete duplicate rows based on "Contact Name", keeping the first occurrence. | |
output_df = output_df.drop_duplicates(subset=["Contact Name"], keep="first") | |
# Generate the output file name using the current Hong Kong date. | |
hk_timezone = pytz.timezone("Asia/Hong_Kong") | |
current_date_hk = datetime.now(hk_timezone).strftime("%y%m%d") | |
output_file_name = f"UPS {current_date_hk}.csv" | |
# Save the output DataFrame to a CSV file without the header. | |
output_df.to_csv(output_file_name, index=False, header=False) | |
return output_df, output_file_name | |
with gr.Blocks(title="Shipping - UPS") as demo: | |
gr.Markdown("# Shipping - UPS") | |
with gr.Row(): | |
file_input = gr.File(label="Upload Excel File with a UPS sheet") | |
process_button = gr.Button("Process Data") | |
with gr.Row(): | |
output_data = gr.DataFrame() | |
output_file_component = gr.File(label="Download Processed File") | |
process_button.click(fn=process_file, inputs=[file_input], outputs=[output_data, output_file_component]) | |
# Updated hyperlink block with separate sections for Shipping Tools and Administration Tools. | |
gr.HTML( | |
""" | |
<div style="text-align: center; font-size: 16px; margin-top: 20px;"> | |
<h3>Shipping Tools</h3> | |
<a href="https://huggingface.co/spaces/leadingbridge/shipping-dhl-e-commerce">DHL</a> | | |
<a href="https://huggingface.co/spaces/leadingbridge/shipping-ec-ship">EC-Ship</a> | | |
<a href="https://huggingface.co/spaces/leadingbridge/shipping-fedex">Fedex</a> | | |
<a href="https://huggingface.co/spaces/leadingbridge/shipping-UPS">UPS</a> | |
</div> | |
<div style="text-align: center; font-size: 16px; margin-top: 20px;"> | |
<h3>Administration Tools</h3> | |
<a href="https://huggingface.co/spaces/leadingbridge/email-template">Email Template</a> | | |
<a href="https://huggingface.co/spaces/leadingbridge/product-feed">Google Merchant</a> | | |
<a href="https://huggingface.co/spaces/leadingbridge/tss-order">Order Processing</a> | |
</div> | |
""" | |
) | |
demo.launch() | |