<< All versions
Skill v1.0.0
currentAutomated scan100/100datadrivenconstruction/ddc_skills_for_ai_agents_in_construction/bid-analysis-comparator
──Details
PublishedSeptember 29, 2026 at 06:58 AM
Content Hashsha256:dcf683a140dd919d...
Git SHAce45bbfbdd63
──Files
Files (1 file, 6.0 KB)
SKILL.md6.0 KBactive
SKILL.md · 191 lines · 6.0 KB
version: "1.0.0" name: "bid-analysis-comparator" description: "Compare and analyze contractor bids. Score proposals, identify scope gaps, and recommend selections." homepage: "https://datadrivenconstruction.io" metadata: {"openclaw": {"emoji": "🛒", "os": ["darwin", "linux", "win32"], "homepage": "https://datadrivenconstruction.io", "requires": {"bins": ["python3"]}}}
Bid Analysis Comparator
Business Case
Bid evaluation requires systematic comparison across multiple criteria. This skill provides structured bid analysis and scoring.
Technical Implementation
python
import pandas as pdfrom datetime import datefrom typing import Dict, Any, Listfrom dataclasses import dataclass, fieldfrom enum import Enumclass BidStatus(Enum):RECEIVED = "received"UNDER_REVIEW = "under_review"SHORTLISTED = "shortlisted"AWARDED = "awarded"REJECTED = "rejected"@dataclassclass EvaluationCriteria:name: strweight: float # 0-1max_score: int = 10@dataclassclass BidScore:criteria: strscore: intnotes: str = ""@dataclassclass Bid:bid_id: strbidder_name: strbid_package: strsubmitted_date: datebase_bid: floatalternates: Dict[str, float]status: BidStatusscores: List[BidScore] = field(default_factory=list)qualifications: List[str] = field(default_factory=list)exclusions: List[str] = field(default_factory=list)@propertydef total_weighted_score(self) -> float:return sum(s.score for s in self.scores)class BidAnalysisComparator:def __init__(self, project_name: str, bid_package: str):self.project_name = project_nameself.bid_package = bid_packageself.bids: Dict[str, Bid] = {}self.criteria: List[EvaluationCriteria] = []self._setup_default_criteria()self._counter = 0def _setup_default_criteria(self):self.criteria = [EvaluationCriteria("Price", 0.35),EvaluationCriteria("Experience", 0.20),EvaluationCriteria("Schedule", 0.15),EvaluationCriteria("Safety Record", 0.10),EvaluationCriteria("References", 0.10),EvaluationCriteria("Capacity", 0.10)]def add_bid(self, bidder_name: str, base_bid: float,submitted_date: date = None,alternates: Dict[str, float] = None) -> Bid:self._counter += 1bid_id = f"BID-{self._counter:03d}"bid = Bid(bid_id=bid_id,bidder_name=bidder_name,bid_package=self.bid_package,submitted_date=submitted_date or date.today(),base_bid=base_bid,alternates=alternates or {},status=BidStatus.RECEIVED)self.bids[bid_id] = bidreturn biddef score_bid(self, bid_id: str, scores: Dict[str, int]):"""Score bid on criteria. scores = {'Price': 8, 'Experience': 7, ...}"""if bid_id not in self.bids:returnbid = self.bids[bid_id]bid.scores = []for criteria, score in scores.items():bid.scores.append(BidScore(criteria, score))bid.status = BidStatus.UNDER_REVIEWdef calculate_weighted_scores(self) -> pd.DataFrame:"""Calculate weighted scores for all bids."""results = []criteria_weights = {c.name: c.weight for c in self.criteria}for bid in self.bids.values():row = {'Bidder': bid.bidder_name,'Base Bid': bid.base_bid,'Status': bid.status.value}total = 0for score in bid.scores:weight = criteria_weights.get(score.criteria, 0)weighted = score.score * weight * 10row[score.criteria] = score.scorerow[f'{score.criteria} (W)'] = round(weighted, 1)total += weightedrow['Total Score'] = round(total, 1)results.append(row)return pd.DataFrame(results).sort_values('Total Score', ascending=False)def get_recommendation(self) -> Dict[str, Any]:"""Get bid recommendation."""df = self.calculate_weighted_scores()if df.empty:return {'recommendation': 'No bids to evaluate'}top = df.iloc[0]lowest = df.sort_values('Base Bid').iloc[0]return {'highest_score': {'bidder': top['Bidder'],'score': top['Total Score'],'bid': top['Base Bid']},'lowest_price': {'bidder': lowest['Bidder'],'bid': lowest['Base Bid']},'total_bids': len(self.bids),'recommendation': top['Bidder']}def export_analysis(self, output_path: str):df = self.calculate_weighted_scores()with pd.ExcelWriter(output_path, engine='openpyxl') as writer:df.to_excel(writer, sheet_name='Comparison', index=False)# Bid detailsdetails = [{'Bidder': b.bidder_name,'Bid': b.base_bid,'Exclusions': '; '.join(b.exclusions),'Qualifications': '; '.join(b.qualifications)} for b in self.bids.values()]pd.DataFrame(details).to_excel(writer, sheet_name='Details', index=False)
Quick Start
python
comparator = BidAnalysisComparator("Office Tower", "Electrical")bid1 = comparator.add_bid("ABC Electric", 850000)bid2 = comparator.add_bid("XYZ Electric", 920000)comparator.score_bid(bid1.bid_id, {'Price': 9, 'Experience': 7, 'Schedule': 8,'Safety Record': 8, 'References': 7, 'Capacity': 8})comparator.score_bid(bid2.bid_id, {'Price': 7, 'Experience': 9, 'Schedule': 7,'Safety Record': 9, 'References': 9, 'Capacity': 9})recommendation = comparator.get_recommendation()print(f"Recommended: {recommendation['recommendation']}")
Resources
- DDC Book: Chapter 3.4 - Procurement