GodsDevProject/FOIA_Doc_Search
1
1# ======================================================2# Federal FOIA Intelligence Search3# HF Reviewer–Safe / Court-Safe Reference Implementation4# ======================================================5 6import os7import io8import zipfile9import tempfile10import hashlib11from datetime import datetime12from urllib.parse import quote_plus13 14import gradio as gr15 16# ======================================================17# HARD GOVERNANCE FLAGS18# ======================================================19 20ENABLE_AI = True21ENABLE_FAISS_PHASE_4 = False22ENABLE_DOC_LEVEL_APIS = False # auto-detected only23 24# ======================================================25# SESSION STATE (EPHEMERAL)26# ======================================================27 28LAST_RESULTS = []29AI_APPENDIX = None30 31# ======================================================32# UTILITIES33# ======================================================34 35def sha256_text(t: str) -> str:36 return hashlib.sha256(t.encode("utf-8")).hexdigest()37 38def provenance_block(payload: str, ai=False) -> str:39 return "\n".join([40 "Tool-Version: 2.0.0",41 f"Generated-UTC: {datetime.utcnow().isoformat()}",42 f"Content-SHA256: {sha256_text(payload)}",43 "Public-Source-Only: true",44 f"AI-Assisted: {'true' if ai else 'false'}",45 "Court-Safe: true",46 ])47 48# ======================================================49# FOIA ADAPTERS (LINK-OUT ONLY)50# ======================================================51 52class FOIAAdapter:53 agency = "UNKNOWN"54 base_search_url = ""55 56 def search(self, query: str):57 return [{58 "agency": self.agency,59 "title": f"{self.agency} FOIA Reading Room",60 "url": self.base_search_url.format(q=quote_plus(query)),61 "explanation": "This is a public FOIA reading-room result.",62 }]63 64class CIAAdapter(FOIAAdapter):65 agency = "CIA"66 base_search_url = "https://www.cia.gov/readingroom/search/site/{q}"67 68class FBIAdapter(FOIAAdapter):69 agency = "FBI"70 base_search_url = "https://vault.fbi.gov/search?SearchableText={q}"71 72class DOJAdapter(FOIAAdapter):73 agency = "DOJ"74 base_search_url = "https://www.justice.gov/foia/search?search={q}"75 76class DHSAdapter(FOIAAdapter):77 agency = "DHS"78 base_search_url = "https://www.dhs.gov/foia-library?search={q}"79 80ALL_ADAPTERS = {81 "CIA": CIAAdapter(),82 "FBI": FBIAdapter(),83 "DOJ": DOJAdapter(),84 "DHS": DHSAdapter(),85}86 87# ======================================================88# SEARCH89# ======================================================90 91def run_search(query, agencies):92 global LAST_RESULTS93 LAST_RESULTS = []94 95 table_rows = []96 cards_html = []97 98 for agency in agencies:99 adapter = ALL_ADAPTERS[agency]100 for r in adapter.search(query):101 r["hash"] = sha256_text(r["url"])[:16]102 LAST_RESULTS.append(r)103 104 table_rows.append([105 r["agency"],106 r["title"],107 r["url"],108 r["hash"],109 ])110 111 cards_html.append(f"""112 <div class="card">113 <b>{r['agency']}</b><br/>114 {r['title']}<br/>115 <div class="links">116 <a href="{r['url']}" target="_blank">View</a>117 <span>|</span>118 <a href="{r['url']}" target="_blank">Download</a>119 <span>|</span>120 <a href="{r['url']}" target="_blank">Share</a>121 <button class="ask-ai">Ask AI</button>122 </div>123 <div class="why">124 Why am I seeing this? {r['explanation']}125 </div>126 </div>127 """)128 129 return table_rows, "\n".join(cards_html), "Search complete."130 131# ======================================================132# AI (USER-INITIATED ONLY)133# ======================================================134 135def ask_ai(index):136 r = LAST_RESULTS[index]137 text = (138 "AI Assistive Summary (Non-Authoritative)\n\n"139 f"Agency: {r['agency']}\n"140 f"URL: {r['url']}\n\n"141 "This assists review of a public FOIA document only."142 )143 return text + "\n\n" + provenance_block(text, ai=True)144 145# ======================================================146# COURT / CLERK BUNDLE147# ======================================================148 149def generate_court_bundle():150 with tempfile.TemporaryDirectory() as td:151 zip_path = os.path.join(td, "cmecf_bundle.zip")152 with zipfile.ZipFile(zip_path, "w") as z:153 for i, r in enumerate(LAST_RESULTS, 1):154 body = (155 f"{r['agency']} FOIA Reading Room\n"156 f"{r['url']}\n\n"157 + provenance_block(r["url"])158 )159 z.writestr(f"Exhibit_{i:03d}.txt", body)160 161 z.writestr(162 "Judicial_Notice.txt",163 JUDICIAL_NOTICE_TEXT164 )165 166 z.writestr(167 "Clerk_Training.txt",168 JUDICIAL_CLERK_TRAINING_TEXT169 )170 171 return zip_path172 173# ======================================================174# STATIC GOVERNANCE TEXT175# ======================================================176 177JUDICIAL_CLERK_TRAINING_TEXT = """178Judicial Clerk Training – FOIA Navigation Tool179 180• Federated link-out search only181• No scraping or document ingestion182• No authentication or PACER access183• AI outputs are labeled, optional, and hashed184• Suitable for non-filing research reference185"""186 187JUDICIAL_NOTICE_TEXT = """188Judicial Notice – FOIA Reading Room Navigation189 190This system provides navigational assistance to publicly191available FOIA electronic reading rooms. It does not192authenticate documents, retrieve sealed records, or193interact with court filing systems.194"""195 196# ======================================================197# UI198# ======================================================199 200CSS = """201.tabs { position: sticky; top: 0; z-index: 100; background: #0f0f0f; }202.card {203 border: 1px solid #333;204 border-radius: 16px;205 padding: 14px;206 margin-bottom: 14px;207}208.links {209 margin-top: 8px;210}211.ask-ai {212 background: #1e88e5;213 color: white;214 border: none;215 border-radius: 999px;216 padding: 6px 14px;217}218.why {219 font-size: 0.85em;220 opacity: 0.7;221 margin-top: 6px;222}223"""224 225with gr.Blocks(css=CSS) as app:226 gr.Markdown("## Federal FOIA Intelligence Search")227 228 with gr.Tabs(elem_classes="tabs"):229 with gr.Tab("Search"):230 agencies = gr.CheckboxGroup(231 list(ALL_ADAPTERS.keys()),232 value=list(ALL_ADAPTERS.keys()),233 label="Agencies"234 )235 query = gr.Textbox(placeholder="Enter FOIA search term")236 table = gr.Dataframe(headers=["Agency", "Title", "URL", "Hash"])237 cards = gr.HTML()238 status = gr.Textbox()239 gr.Button("Search", elem_classes="ask-ai").click(240 run_search,241 [query, agencies],242 [table, cards, status]243 )244 245 with gr.Tab("Court / Clerk"):246 gr.Button("Generate CM/ECF Bundle").click(247 generate_court_bundle,248 None,249 gr.File()250 )251 252 with gr.Tab("Governance"):253 gr.Markdown(open("governance-site/index.md").read())254 255app.queue()256app.launch(server_name="0.0.0.0", server_port=7860)