Spaces:
Sleeping
Sleeping
| import gradio as gr | |
| import asyncio | |
| from ingest.registry import get_live_adapters, get_stub_adapters | |
| from ingest.export import export_results_zip | |
| LIVE_ADAPTERS = get_live_adapters() | |
| STUB_ADAPTERS = get_stub_adapters() | |
| async def federated_search(query: str, include_stubs: bool): | |
| results = [] | |
| for adapter in LIVE_ADAPTERS.values(): | |
| try: | |
| res = await adapter.search(query) | |
| results.extend(res) | |
| except Exception: | |
| continue | |
| if include_stubs: | |
| for adapter in STUB_ADAPTERS.values(): | |
| try: | |
| res = await adapter.search(query) | |
| results.extend(res) | |
| except Exception: | |
| continue | |
| return results | |
| def search_handler(query, include_stubs, confirm_extended): | |
| if include_stubs and not confirm_extended: | |
| return [], "⚠️ You must acknowledge the Extended Features warning." | |
| if not query.strip(): | |
| return [], "⚠️ Enter a search term." | |
| results = asyncio.run(federated_search(query, include_stubs)) | |
| rows = [ | |
| [r["source"], r["title"], r["url"], r["snippet"]] | |
| for r in results | |
| ] | |
| return rows, "" | |
| with gr.Blocks() as app: | |
| gr.Markdown( | |
| "# **Federal FOIA Intelligence Search**\n" | |
| "### Public Electronic Reading Rooms Only\n\n" | |
| "Live, robots-compliant search across U.S. government FOIA libraries.\n\n" | |
| "**Default mode queries only agencies that explicitly permit automated access.**" | |
| ) | |
| query = gr.Textbox( | |
| label="Search term", | |
| placeholder="e.g. UAP, procurement, surveillance" | |
| ) | |
| include_stubs = gr.Checkbox( | |
| label="Include Stub Results (Non-Live, Informational Only)", | |
| value=False | |
| ) | |
| with gr.Accordion("⚠️ Extended Features (Advanced – Read Carefully)", open=False): | |
| gr.Markdown( | |
| "**The following agencies do NOT permit automated querying or do not " | |
| "provide public FOIA search endpoints:**\n\n" | |
| "- NSA\n- NRO\n- SAP / Special Access Programs\n- TEN-CAP\n" | |
| "- AATIP\n- Special Activities\n- DIA\n- NGA\n\n" | |
| "If enabled, these sources return **clearly labeled stub results only**. " | |
| "**No live requests are made.**" | |
| ) | |
| confirm_extended = gr.Checkbox( | |
| label="I understand and want to include stub-only results", | |
| value=False | |
| ) | |
| search_btn = gr.Button("Search") | |
| status = gr.Markdown("") | |
| results_table = gr.Dataframe( | |
| headers=["Source", "Title", "URL", "Snippet"], | |
| wrap=True, | |
| interactive=False | |
| ) | |
| search_btn.click( | |
| fn=search_handler, | |
| inputs=[query, include_stubs, confirm_extended], | |
| outputs=[results_table, status] | |
| ) | |
| gr.Markdown("### Export") | |
| export_btn = gr.Button("Export Results (ZIP)") | |
| export_file = gr.File(label="Download ZIP") | |
| export_btn.click( | |
| fn=lambda rows: export_results_zip([ | |
| { | |
| "source": r[0], | |
| "title": r[1], | |
| "url": r[2], | |
| "snippet": r[3] | |
| } for r in rows | |
| ]), | |
| inputs=results_table, | |
| outputs=export_file | |
| ) | |
| app.launch() |