Do0rMaMu's picture
Update app.py
72726e0 verified
raw
history blame
5.87 kB
import pandas as pd
from itertools import permutations
from fastapi import FastAPI, File, UploadFile, Form, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel
from typing import List
app = FastAPI()
app.add_middleware(
CORSMiddleware,
allow_origins=["*"], # Allows all origins
allow_credentials=True,
allow_methods=["*"], # Allows all methods
allow_headers=["*"], # Allows all headers
)
class Box:
def __init__(self, length, width, height, quantity, box_type):
self.length = length
self.width = width
self.height = height
self.quantity = quantity if quantity > 0 else 1 # Ensure at least 1 box if quantity is not specified
self.type = box_type
def rotated_dimensions(self):
# Return rotations that maximize base area and minimize height
possible_rotations = [
(self.length, self.width, self.height),
(self.length, self.height, self.width),
(self.width, self.length, self.height),
(self.width, self.height, self.length),
(self.height, self.length, self.width),
(self.height, self.width, self.length)
]
# Sort by volume and base area to prioritize the best fit
return sorted(possible_rotations, key=lambda x: (x[0] * x[1], x[2]), reverse=True)
def volume(self):
return self.length * self.width * self.height
class Truck:
def __init__(self, length, width, height):
self.length = length
self.width = width
self.height = height
self.volume = length * width * height
self.placed_boxes = []
self.available_space = [(0, 0, 0, length, width, height)] # (x, y, z, l, w, h)
def add_box(self, box):
best_fit = None
best_fit_space_index = -1
for rotation in box.rotated_dimensions():
for i, space in enumerate(self.available_space):
x, y, z, l, w, h = space
# Check if the box can fit in the current space
if rotation[0] <= l and rotation[1] <= w and rotation[2] <= h:
if not best_fit or (rotation[0] * rotation[1] > best_fit[0] * best_fit[1]):
best_fit = rotation
best_fit_space_index = i
if best_fit:
x, y, z, l, w, h = self.available_space[best_fit_space_index]
box_position = (x, y, z)
# Place the box in the truck
self.placed_boxes.append((best_fit, box_position))
# Update available space after placing the box
self.available_space.pop(best_fit_space_index)
self.update_space(best_fit, box_position, l, w, h)
return box_position
else:
return None
def update_space(self, box, position, l, w, h):
x, y, z = position
bl, bw, bh = box
# Create new spaces based on the placement of the new box
new_spaces = [
(x + bl, y, z, l - bl, w, h), # Space to the right
(x, y + bw, z, bl, w - bw, h), # Space in front
(x, y, z + bh, bl, bw, h - bh), # Space above
]
# Filter out invalid spaces
new_spaces = [space for space in new_spaces if space[3] > 0 and space[4] > 0 and space[5] > 0]
# Add new valid spaces to the available_space list
self.available_space.extend(new_spaces)
# Sort available spaces to prioritize lower and more central spaces for stacking
self.available_space.sort(key=lambda space: (space[2], space[1], space[0]))
def pack_boxes(truck, boxes):
packed_positions = []
# Sort all boxes by volume (largest first)
boxes.sort(key=lambda b: b.volume(), reverse=True)
# Pack all boxes, ensuring practical stacking
for box in boxes:
for _ in range(box.quantity):
position = truck.add_box(box)
if position is None:
break
packed_positions.append((box, position))
return packed_positions
@app.post("/upload/")
async def upload_file(
file: UploadFile = File(...),
length: float = Form(...),
width: float = Form(...),
height: float = Form(...),
):
if not file:
raise HTTPException(status_code=400, detail="No file uploaded")
ext = file.filename.split('.')[-1].lower()
if ext == 'csv':
data = pd.read_csv(file.file)
elif ext in ['xls', 'xlsx']:
data = pd.read_excel(file.file)
else:
raise HTTPException(status_code=400, detail="Unsupported file format")
# Convert dimensions from CM to inches
data['PieceLength'] = data['PieceLength'] / 2.54
data['PieceBreadth'] = data['PieceBreadth'] / 2.54
data['PieceHeight'] = data['PieceHeight'] / 2.54
# Create Box objects with quantity considered
boxes = [
Box(row['PieceLength'], row['PieceBreadth'], row['PieceHeight'], row.get('Quantity', 1), f"{row['PieceNo']}-{row['Priority']}")
for _, row in data.iterrows()
]
# Convert truck dimensions from feet to inches
truck_length = length * 12 # Convert to inches
truck_width = width * 12 # Convert to inches
truck_height = height * 12 # Convert to inches
truck = Truck(truck_length, truck_width, truck_height)
# Pack the boxes into the truck
packed_positions = pack_boxes(truck, boxes)
box_data = [
{
'length': box.length,
'width': box.width,
'height': box.height,
'type': box.type,
'quantity': box.quantity,
'position': {'x': pos[0], 'y': pos[1], 'z': pos[2]}
}
for box, pos in packed_positions
]
print(f"quantity {[box_data[i]['quantity'] for i in range(len(box_data))]}")
return {"boxes": box_data}