Spaces:
Running
Running
| from typing import List, Dict | |
| from models import StrategyResult, SelectedVendor, RFQItem, VendorOffer | |
| class VendorOptimizer: | |
| def __init__(self, rfq_items: List[RFQItem], vendor_offers: List[VendorOffer]): | |
| self.rfq_items = {item.id: item for item in rfq_items} | |
| self.vendors = vendor_offers | |
| def _calculate_item_quality(self, offer: dict) -> float: | |
| score = 5.0 | |
| trust_bonus = (offer['rating'] / 5.0) * 5.0 | |
| score += trust_bonus | |
| return min(round(score, 1), 10.0) | |
| def _calculate_strategy(self, strategy_name: str) -> StrategyResult: | |
| item_offers = {i_id: [] for i_id in self.rfq_items} | |
| for vendor in self.vendors: | |
| for offer in vendor.offers: | |
| if offer.rfq_item_id in item_offers: | |
| offer_data = { | |
| "vendor_id": vendor.vendor_id, | |
| "vendor_name": vendor.vendor_name, | |
| "price": offer.unit_price, | |
| "delivery": offer.delivery_days, | |
| "rating": vendor.rating, | |
| "brand": offer.brand, | |
| "manufacturer": offer.manufacturer | |
| } | |
| offer_data['quality_score'] = self._calculate_item_quality(offer_data) | |
| item_offers[offer.rfq_item_id].append(offer_data) | |
| selected_map = {} | |
| total_rfq_cost = 0.0 | |
| total_delivery_days = 0 | |
| total_quality_accum = 0.0 | |
| fulfilled_count = 0 | |
| total_market_cost = 0.0 | |
| for item_id, item_req in self.rfq_items.items(): | |
| offers = item_offers.get(item_id, []) | |
| if not offers: | |
| continue | |
| max_price_for_item = max(o['price'] for o in offers) | |
| total_market_cost += (max_price_for_item * item_req.quantity) | |
| if strategy_name == "lowest_cost": | |
| offers.sort(key=lambda x: (x['price'], -x['quality_score'])) | |
| elif strategy_name == "fastest_delivery": | |
| offers.sort(key=lambda x: (x['delivery'], x['price'])) | |
| elif strategy_name == "best_quality": | |
| offers.sort(key=lambda x: (-x['quality_score'], x['price'])) | |
| elif strategy_name == "balanced": | |
| offers.sort(key=lambda x: ( | |
| x['price'] * 0.6 + | |
| x['delivery'] * 2.0 + | |
| (10.0 - x['quality_score']) * 15.0 | |
| )) | |
| best = offers[0] | |
| vid = best['vendor_id'] | |
| if vid not in selected_map: | |
| selected_map[vid] = { | |
| "vendor_id": vid, | |
| "vendor_name": best['vendor_name'], | |
| "total_cost": 0.0, | |
| "item_ids": [], | |
| "quality_sum": 0.0 | |
| } | |
| line_cost = best['price'] * item_req.quantity | |
| selected_map[vid]["total_cost"] += line_cost | |
| selected_map[vid]["item_ids"].append(item_id) | |
| selected_map[vid]["quality_sum"] += best['quality_score'] | |
| total_rfq_cost += line_cost | |
| total_delivery_days += best['delivery'] | |
| total_quality_accum += best['quality_score'] | |
| fulfilled_count += 1 | |
| allocations = [] | |
| for vid, data in selected_map.items(): | |
| v_avg_qual = data["quality_sum"] / len(data["item_ids"]) if data["item_ids"] else 0 | |
| allocations.append(SelectedVendor( | |
| vendor_id=data['vendor_id'], | |
| vendor_name=data['vendor_name'], | |
| total_cost=round(data['total_cost'], 2), | |
| items_count=len(data['item_ids']), | |
| item_ids=data['item_ids'], | |
| avg_quality_score=round(v_avg_qual, 1) | |
| )) | |
| avg_delivery = round(total_delivery_days / fulfilled_count, 1) if fulfilled_count else 0 | |
| overall_quality = round(total_quality_accum / fulfilled_count, 1) if fulfilled_count else 0 | |
| savings = round(total_market_cost - total_rfq_cost, 2) | |
| ui_score = 70.0 | |
| ui_score += (overall_quality - 5.0) * 6.0 | |
| if total_market_cost > 0: | |
| savings_pct = (savings / total_market_cost) | |
| ui_score += (savings_pct * 100) | |
| return StrategyResult( | |
| strategy_name=strategy_name, | |
| total_cost=round(total_rfq_cost, 2), | |
| avg_delivery_days=avg_delivery, | |
| vendor_count=len(allocations), | |
| allocations=allocations, | |
| savings=savings, | |
| score=max(min(round(ui_score, 1), 100), 40), | |
| quality_score=overall_quality | |
| ) | |
| def run_all(self): | |
| return { | |
| "lowest_cost": self._calculate_strategy("lowest_cost"), | |
| "fastest_delivery": self._calculate_strategy("fastest_delivery"), | |
| "best_quality": self._calculate_strategy("best_quality"), | |
| "balanced": self._calculate_strategy("balanced"), | |
| } |