Spaces:
Running
Running
| import os | |
| import sys | |
| sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) | |
| from loguru import logger | |
| WEIGHTS = { | |
| "politician_company_overlap": 0.35, | |
| "contract_concentration": 0.25, | |
| "audit_mention_frequency": 0.20, | |
| "asset_growth_anomaly": 0.15, | |
| "criminal_case_presence": 0.05, | |
| } | |
| MAX_SCORE = 100 | |
| def indicator_politician_company_overlap(entity_id: str, session) -> dict: | |
| row = session.run( | |
| """ | |
| MATCH (p {id: $id})-[:DIRECTOR_OF]->(c:Company)-[:WON_CONTRACT]->(ct:Contract) | |
| RETURN count(ct) AS cnt, sum(ct.amount_crore) AS total | |
| """, | |
| id=entity_id | |
| ).single() | |
| cnt = row["cnt"] if row and row["cnt"] else 0 | |
| total = row["total"] if row and row["total"] else 0.0 | |
| raw = min(int(cnt * 10), 35) | |
| return { | |
| "name": "politician_company_overlap", | |
| "raw_score": raw, | |
| "weight": WEIGHTS["politician_company_overlap"], | |
| "weighted": round(raw * WEIGHTS["politician_company_overlap"], 2), | |
| "description": ( | |
| f"Entity linked to {cnt} contract(s) totalling Rs {total:.1f} Cr " | |
| "through company directorships." | |
| ), | |
| "evidence": [ | |
| f"{cnt} contract(s) found via DIRECTOR_OF -> WON_CONTRACT path", | |
| f"Total contract value: Rs {round(total, 2)} Cr", | |
| "Source: Government e-Marketplace procurement records", | |
| ], | |
| "source_institution": "Government e-Marketplace", | |
| "source_url": "https://gem.gov.in", | |
| } | |
| def indicator_contract_concentration(entity_id: str, session) -> dict: | |
| row = session.run( | |
| """ | |
| MATCH (c {id: $id})-[:WON_CONTRACT]->(ct:Contract) | |
| RETURN count(ct) AS cnt, sum(ct.amount_crore) AS total | |
| """, | |
| id=entity_id | |
| ).single() | |
| cnt = row["cnt"] if row and row["cnt"] else 0 | |
| total = row["total"] if row and row["total"] else 0.0 | |
| raw = min(int(cnt * 8), 25) | |
| return { | |
| "name": "contract_concentration", | |
| "raw_score": raw, | |
| "weight": WEIGHTS["contract_concentration"], | |
| "weighted": round(raw * WEIGHTS["contract_concentration"], 2), | |
| "description": ( | |
| f"Entity awarded {cnt} government contract(s) totalling Rs {total:.1f} Cr. " | |
| "Repeated awards to the same entity indicate concentration." | |
| ), | |
| "evidence": [ | |
| f"{cnt} contract(s) via WON_CONTRACT relationships", | |
| f"Total value: Rs {round(total, 2)} Cr", | |
| "Source: Government e-Marketplace procurement records", | |
| ], | |
| "source_institution": "Government e-Marketplace", | |
| "source_url": "https://gem.gov.in", | |
| } | |
| def indicator_audit_mention_frequency(entity_id: str, entity_name: str, | |
| session) -> dict: | |
| row = session.run( | |
| """ | |
| MATCH (a:AuditReport) | |
| WHERE toLower(a.title) CONTAINS toLower($name) | |
| RETURN count(a) AS cnt, sum(a.amount_crore) AS total | |
| """, | |
| name=entity_name | |
| ).single() | |
| cnt = row["cnt"] if row and row["cnt"] else 0 | |
| total = row["total"] if row and row["total"] else 0.0 | |
| raw = min(int(cnt * 10), 20) | |
| return { | |
| "name": "audit_mention_frequency", | |
| "raw_score": raw, | |
| "weight": WEIGHTS["audit_mention_frequency"], | |
| "weighted": round(raw * WEIGHTS["audit_mention_frequency"], 2), | |
| "description": ( | |
| f"Entity or associated names appear in {cnt} CAG audit report(s). " | |
| f"Total amount flagged in those reports: Rs {total:.1f} Cr." | |
| ), | |
| "evidence": [ | |
| f"{cnt} CAG report mention(s)", | |
| f"Total flagged amount: Rs {round(total, 2)} Cr", | |
| "Source: Comptroller and Auditor General of India, cag.gov.in", | |
| ], | |
| "source_institution": "Comptroller and Auditor General of India", | |
| "source_url": "https://cag.gov.in/en/audit-report", | |
| } | |
| def indicator_asset_growth_anomaly(entity_id: str, session) -> dict: | |
| row = session.run( | |
| """ | |
| MATCH (p:Politician {id: $id}) | |
| RETURN p.total_assets AS assets | |
| """, | |
| id=entity_id | |
| ).single() | |
| assets_str = row["assets"] if row else "" | |
| raw = 0 | |
| description = "Insufficient asset declaration data for growth analysis." | |
| if assets_str and any(c.isdigit() for c in str(assets_str)): | |
| raw = 5 | |
| description = ( | |
| "Asset declaration data available from election affidavit. " | |
| "Multi-cycle comparison requires affidavit data from consecutive elections." | |
| ) | |
| return { | |
| "name": "asset_growth_anomaly", | |
| "raw_score": raw, | |
| "weight": WEIGHTS["asset_growth_anomaly"], | |
| "weighted": round(raw * WEIGHTS["asset_growth_anomaly"], 2), | |
| "description": description, | |
| "evidence": [ | |
| f"Declared assets: {assets_str or 'not available'}", | |
| "Source: Election Commission of India candidate affidavit", | |
| ], | |
| "source_institution": "Election Commission of India", | |
| "source_url": "https://myneta.info", | |
| } | |
| def indicator_criminal_case_presence(entity_id: str, session) -> dict: | |
| row = session.run( | |
| """ | |
| MATCH (p:Politician {id: $id}) | |
| RETURN toInteger(p.criminal_cases) AS cases | |
| """, | |
| id=entity_id | |
| ).single() | |
| cases = row["cases"] if row and row["cases"] else 0 | |
| raw = min(int(cases * 3), 5) | |
| return { | |
| "name": "criminal_case_presence", | |
| "raw_score": raw, | |
| "weight": WEIGHTS["criminal_case_presence"], | |
| "weighted": round(raw * WEIGHTS["criminal_case_presence"], 2), | |
| "description": ( | |
| f"Entity has declared {cases} criminal case(s) in their " | |
| "Election Commission of India candidate affidavit." | |
| ), | |
| "evidence": [ | |
| f"{cases} declared criminal case(s)", | |
| "Source: Election Commission of India candidate affidavit (self-declared)", | |
| ], | |
| "source_institution": "Election Commission of India", | |
| "source_url": "https://eci.gov.in", | |
| } | |
| ALL_INDICATORS = [ | |
| indicator_politician_company_overlap, | |
| indicator_contract_concentration, | |
| indicator_audit_mention_frequency, | |
| indicator_asset_growth_anomaly, | |
| indicator_criminal_case_presence, | |
| ] | |