import streamlit as st from core import bidder_processor, evaluator from core.config import BIDDER_NAMES, DATA_DIR from core.fallback import load_criteria from core.schemas import Criterion from ui.components import category_badge, confidence_bar, mandatory_badge, ocr_tier_badge, verdict_pill _BIDDER_META = { "bidder_a": ("Apex Constructions Pvt. Ltd.", "Clearly Eligible", "#22C55E"), "bidder_b": ("BuildRight Enterprises", "Ineligible — Low Turnover", "#EF4444"), "bidder_c": ("Shree Constructions & Services", "Needs Review — Scanned Cert", "#F59E0B"), } def _get_criteria() -> list[Criterion]: data = st.session_state.get("criteria") return [Criterion(**c) for c in data] if data else load_criteria() def _overall(verdicts: list[dict], crit_map: dict) -> str: mand = [v for v in verdicts if crit_map.get(v["criterion_id"]) and crit_map[v["criterion_id"]].mandatory] src = mand or verdicts if any(v["verdict"] == "not_eligible" for v in src): return "not_eligible" if any(v["verdict"] == "needs_review" for v in src): return "needs_review" return "eligible" def render() -> None: st.markdown( '
' 'Evaluate each bidder against all extracted criteria.
', unsafe_allow_html=True, ) selected = st.multiselect( "Select bidders", options=list(BIDDER_NAMES.keys()), default=list(BIDDER_NAMES.keys()), format_func=lambda x: _BIDDER_META.get(x, (x, "", ""))[0], ) criteria_loaded = bool(st.session_state.get("criteria")) if not criteria_loaded: st.info( "**Criteria not loaded yet.** Go to **Tender Analysis** and click " "**Extract Criteria**, or use **Load Pre-computed Demo** on the Overview tab." ) if st.button("▶ Run Evaluation", type="primary", disabled=not criteria_loaded): criteria = _get_criteria() prog = st.progress(0, text="Starting…") total = len(selected) * len(criteria) done, vd = 0, {} for bid in selected: files = sorted(f for f in (DATA_DIR / "bidders" / bid).iterdir() if f.suffix.lower() in {".pdf", ".png", ".jpg"}) with st.spinner(f"Indexing {_BIDDER_META.get(bid,(bid,'',''))[0]}…"): bidder_processor.process_bidder(bid, files) vlist = [] for c in criteria: v = evaluator.evaluate(bid, c) vlist.append(v.model_dump()) done += 1 prog.progress(done / total, text=f"{c.id} · {_BIDDER_META.get(bid,(bid,'',''))[0]}") vd[bid] = vlist st.session_state["verdicts"] = vd prog.empty() st.success("Evaluation complete.") st.rerun() vdata = st.session_state.get("verdicts", {}) criteria = _get_criteria() crit_map = {c.id: c for c in criteria} if not vdata: st.info("No results yet — click **Run Evaluation** above, or load the demo from Overview.") return if st.session_state.get("fallback_active"): st.warning("⚠ Live API unavailable — showing pre-computed results.") for bid in (selected or list(vdata.keys())): if bid not in vdata: continue verdicts = vdata[bid] name, tagline, accent = _BIDDER_META.get(bid, (bid, "", "#3B82F6")) ov = _overall(verdicts, crit_map) passed = sum(1 for v in verdicts if v["verdict"] == "eligible" and crit_map.get(v["criterion_id"]) and crit_map[v["criterion_id"]].mandatory) total_m = sum(1 for v in verdicts if crit_map.get(v["criterion_id"]) and crit_map[v["criterion_id"]].mandatory) st.markdown("", unsafe_allow_html=True) with st.container(border=True): # Header st.markdown( f'