Spaces:
Sleeping
Sleeping
| """ | |
| Citation and sourcing utilities to reduce hallucinations. | |
| When presenting grant information, we cite the source data: | |
| - Grant ID and title | |
| - Specific fields (funding_max, deadline, etc.) | |
| - Field source (from grant record or extracted) | |
| This helps users verify information and trust the system. | |
| """ | |
| from typing import Dict, Any, List, Optional | |
| from datetime import datetime | |
| def cite_grant_fact(grant: Dict[str, Any], field: str, value: Any) -> str: | |
| """ | |
| Create a citation for a fact about a grant. | |
| Args: | |
| grant: The grant record dict | |
| field: Field name (e.g., "funding_max", "close_date") | |
| value: The value to cite | |
| Returns: | |
| Formatted citation like "£50,000 [Source: Grant ID #2315]" | |
| """ | |
| grant_id = grant.get("id") or grant.get("competition_id") or "unknown" | |
| # Special formatting for currency | |
| if field in ("funding_max", "funding_min", "total_pot") and isinstance(value, (int, float)): | |
| return f"£{value:,.0f} [Source: Grant ID #{grant_id}]" | |
| # Special formatting for dates | |
| if field in ("close_date", "open_date", "deadline") and value: | |
| return f"{value} [Source: Grant ID #{grant_id}]" | |
| # Default formatting | |
| if value is None: | |
| return "Not specified" | |
| return f"{value} [Source: Grant ID #{grant_id}]" | |
| def format_grant_with_citations(grant: Dict[str, Any]) -> Dict[str, Any]: | |
| """ | |
| Format a grant record with citations on key fields. | |
| Args: | |
| grant: The grant record | |
| Returns: | |
| Dict with cited versions of key fields | |
| """ | |
| grant_id = grant.get("id") or grant.get("competition_id") or "unknown" | |
| title = grant.get("title", "(untitled)") | |
| cited = { | |
| "id": grant_id, | |
| "title": title, | |
| "url": grant.get("url", ""), | |
| } | |
| # Cite monetary fields | |
| if grant.get("funding_max"): | |
| cited["funding_max"] = cite_grant_fact(grant, "funding_max", grant["funding_max"]) | |
| if grant.get("funding_min"): | |
| cited["funding_min"] = cite_grant_fact(grant, "funding_min", grant["funding_min"]) | |
| if grant.get("total_pot"): | |
| cited["total_pot"] = cite_grant_fact(grant, "total_pot", grant["total_pot"]) | |
| # Cite dates | |
| if grant.get("close_date"): | |
| cited["close_date"] = cite_grant_fact(grant, "close_date", grant["close_date"]) | |
| if grant.get("open_date"): | |
| cited["open_date"] = cite_grant_fact(grant, "open_date", grant["open_date"]) | |
| return cited | |
| def build_citation_summary(grant: Dict[str, Any]) -> str: | |
| """ | |
| Build a markdown summary of grant with citations. | |
| Args: | |
| grant: The grant record | |
| Returns: | |
| Markdown formatted summary with citations | |
| """ | |
| grant_id = grant.get("id") or grant.get("competition_id") or "unknown" | |
| title = grant.get("title", "(untitled)") | |
| url = grant.get("url", "") | |
| lines = [ | |
| f"## {title}", | |
| f"**Grant ID:** #{grant_id}", | |
| "", | |
| ] | |
| if url: | |
| lines.append(f"**Official Link:** {url}") | |
| lines.append("") | |
| # Funding details with citations | |
| if grant.get("funding_max") or grant.get("funding_min"): | |
| min_fund = grant.get("funding_min") | |
| max_fund = grant.get("funding_max") | |
| if min_fund and max_fund: | |
| funding_str = f"£{min_fund:,.0f} – £{max_fund:,.0f}" | |
| elif max_fund: | |
| funding_str = f"up to £{max_fund:,.0f}" | |
| elif min_fund: | |
| funding_str = f"from £{min_fund:,.0f}" | |
| else: | |
| funding_str = "See official page" | |
| lines.append(f"**Funding per project:** {funding_str} [Source: Grant ID #{grant_id}]") | |
| if grant.get("total_pot"): | |
| lines.append(f"**Total available:** £{grant['total_pot']:,.0f} [Source: Grant ID #{grant_id}]") | |
| lines.append("") | |
| # Dates with citations | |
| if grant.get("open_date") or grant.get("close_date"): | |
| close = grant.get("close_date") or grant.get("deadline") | |
| if close: | |
| lines.append(f"**Deadline:** {close} [Source: Grant ID #{grant_id}]") | |
| if grant.get("open_date"): | |
| lines.append(f"**Opens:** {grant['open_date']} [Source: Grant ID #{grant_id}]") | |
| lines.append("") | |
| # Duration with citation | |
| if grant.get("duration_min") or grant.get("duration_max"): | |
| min_dur = grant.get("duration_min") | |
| max_dur = grant.get("duration_max") | |
| if min_dur and max_dur: | |
| duration_str = f"{min_dur}–{max_dur} months" | |
| elif max_dur: | |
| duration_str = f"up to {max_dur} months" | |
| elif min_dur: | |
| duration_str = f"from {min_dur} months" | |
| else: | |
| duration_str = "Variable" | |
| lines.append(f"**Project duration:** {duration_str} [Source: Grant ID #{grant_id}]") | |
| return "\n".join(lines) | |
| def validate_fact_availability(grant: Dict[str, Any], fact_type: str) -> bool: | |
| """ | |
| Check if a fact exists in the grant data before citing it. | |
| Args: | |
| grant: The grant record | |
| fact_type: Type of fact ("funding", "deadline", "duration", "scope", "eligibility") | |
| Returns: | |
| True if the fact is available to cite | |
| Raises assertion/warning if fact is missing | |
| """ | |
| fact_fields = { | |
| "funding": ["funding_max", "funding_min", "total_pot"], | |
| "deadline": ["close_date", "deadline"], | |
| "duration": ["duration_min", "duration_max"], | |
| "scope": ["scope", "scope_raw", "sections"], | |
| "eligibility": ["eligibility", "eligibility_raw"], | |
| } | |
| required_fields = fact_fields.get(fact_type, []) | |
| for field in required_fields: | |
| if grant.get(field): | |
| return True | |
| return False | |