GodsDevProject commited on
Commit
ac6e700
·
verified ·
1 Parent(s): 66deee7

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +45 -157
app.py CHANGED
@@ -1,176 +1,64 @@
1
- """
2
- Federal FOIA Intelligence Search
3
- Public Electronic Reading Rooms Only
4
- """
5
 
6
- import asyncio
7
  import gradio as gr
8
- import plotly.graph_objects as go
9
- from datetime import datetime
10
-
11
- from ingest.registry import get_enabled_adapters
12
- from ingest.cluster import build_embeddings, cluster_embeddings
13
- from ingest.coverage import build_coverage_heatmap, build_agency_map
14
- from ingest.health import get_health_snapshot
15
- from ingest.export import (
16
- export_journalist_zip,
17
- export_pdf_report,
18
- export_congressional_briefing,
19
- )
20
- from ingest.utils import (
21
- highlight_terms,
22
- classify_foia_exemptions,
23
- format_bluebook_citation,
24
- )
25
- from ingest.timeline import build_timeline_figure
26
- from ingest.graph import build_cluster_graph
27
- from ingest.trends import build_exemption_trend_chart
28
-
29
-
30
- TITLE = "🏛️ Federal FOIA Intelligence Search"
31
- SUBTITLE = "Public Electronic Reading Rooms Only"
32
-
33
-
34
- # ---------------- Async-safe search ----------------
35
 
36
- async def _run_search(query, enable_live, hide_stub):
37
- adapters = get_enabled_adapters(enable_live=enable_live)
38
- tasks = [a.search(query) for a in adapters]
39
- responses = await asyncio.gather(*tasks, return_exceptions=True)
40
 
 
41
  results = []
42
- per_agency_counts = {}
43
-
44
- for adapter, resp in zip(adapters, responses):
45
- if isinstance(resp, Exception):
46
  continue
47
- if hide_stub and adapter.is_stub:
48
- continue
49
-
50
- per_agency_counts[adapter.source_name] = len(resp)
51
-
52
- for r in resp:
53
- r["source"] = adapter.source_name
54
- r["latency"] = adapter.last_latency
55
- r["exemptions"] = classify_foia_exemptions(r.get("snippet", ""))
56
- r["citation"] = format_bluebook_citation(r)
57
- r["date"] = r.get("date", datetime.utcnow().isoformat())
58
- results.append(r)
59
-
60
- embeddings = build_embeddings(results)
61
- clusters = cluster_embeddings(results, embeddings)
62
-
63
- return (
64
- results,
65
- clusters,
66
- build_coverage_heatmap(per_agency_counts),
67
- build_agency_map(per_agency_counts),
68
- build_timeline_figure(results),
69
- build_exemption_trend_chart(results),
70
- build_cluster_graph(results, clusters),
71
- )
72
 
 
 
 
 
73
 
74
- def search_ui(query, enable_live, hide_stub):
75
- loop = asyncio.new_event_loop()
76
- asyncio.set_event_loop(loop)
77
 
78
- (
79
- results,
80
- clusters,
81
- heatmap,
82
- agency_map,
83
- timeline,
84
- exemption_trends,
85
- cluster_graph,
86
- ) = loop.run_until_complete(
87
- _run_search(query, enable_live, hide_stub)
88
- )
89
 
90
- table = []
91
- for r in results:
92
- table.append([
93
- r["source"],
94
- highlight_terms(r["title"], query),
95
- r["url"],
96
- r.get("snippet", ""),
97
- ",".join(r["exemptions"]),
98
- r["citation"],
99
- ])
100
 
101
- return table, heatmap, agency_map, timeline, exemption_trends, cluster_graph
 
102
 
 
 
103
 
104
- # ---------------- UI ----------------
105
-
106
- with gr.Blocks(title="Federal FOIA Intelligence Search") as demo:
107
- gr.Markdown(f"# {TITLE}")
108
- gr.Markdown(f"### {SUBTITLE}")
109
- gr.Markdown(
110
- "**Terms of Use:** Indexes only documents already released via official FOIA Electronic Reading Rooms."
111
- )
112
-
113
- with gr.Row():
114
- query = gr.Textbox(label="Search FOIA documents")
115
- search_btn = gr.Button("Search")
116
-
117
- with gr.Row():
118
- enable_live = gr.Checkbox(label="Enable Live Public Adapters", value=False)
119
- hide_stub = gr.Checkbox(label="Hide Stub Sources", value=True)
120
-
121
- results_table = gr.Dataframe(
122
- headers=["Agency", "Title", "URL", "Snippet", "FOIA Exemptions", "Citation"],
123
- wrap=True,
124
- )
125
-
126
- preview_box = gr.Markdown(label="📄 Document Preview")
127
-
128
- with gr.Tabs():
129
- with gr.Tab("🧠 Cluster Graph"):
130
- cluster_plot = gr.Plot()
131
-
132
- with gr.Tab("🗺️ Agency Coverage Map"):
133
- agency_map_plot = gr.Plot()
134
-
135
- with gr.Tab("📊 Coverage Heatmap"):
136
- heatmap_box = gr.JSON()
137
-
138
- with gr.Tab("🗓️ Timeline"):
139
- timeline_plot = gr.Plot()
140
-
141
- with gr.Tab("⚖️ FOIA Exemption Trends"):
142
- exemption_plot = gr.Plot()
143
-
144
- with gr.Tab("🏥 Health"):
145
- health_box = gr.JSON(value=get_health_snapshot())
146
-
147
- with gr.Row():
148
- export_zip_btn = gr.Button("🧾 Journalist ZIP")
149
- export_pdf_btn = gr.Button("📄 Transparency PDF")
150
- export_congress_btn = gr.Button("🏛️ Congressional Briefing PDF")
151
-
152
- export_status = gr.Textbox(label="Export Status")
153
 
154
  search_btn.click(
155
- fn=search_ui,
156
- inputs=[query, enable_live, hide_stub],
157
- outputs=[
158
- results_table,
159
- heatmap_box,
160
- agency_map_plot,
161
- timeline_plot,
162
- exemption_plot,
163
- cluster_plot,
164
- ],
165
  )
166
 
167
- results_table.select(
168
- lambda df, evt: f"### {df[evt.index][1]}\n\n{df[evt.index][3]}\n\n🔗 {df[evt.index][2]}",
169
- outputs=preview_box,
 
170
  )
171
 
172
- export_zip_btn.click(export_journalist_zip, results_table, export_status)
173
- export_pdf_btn.click(export_pdf_report, results_table, export_status)
174
- export_congress_btn.click(export_congressional_briefing, results_table, export_status)
175
-
176
- demo.queue().launch()
 
1
+ # Federal FOIA Intelligence Search
2
+ # Public Electronic Reading Rooms Only
 
 
3
 
 
4
  import gradio as gr
5
+ import asyncio
6
+ from ingest.registry import get_all_adapters
7
+ from ingest.cluster import semantic_cluster
8
+ from ingest.export import export_zip
9
+ from ingest.foia_request import generate_foia_packet
10
+ from ingest.health import adapter_health
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11
 
12
+ adapters = get_all_adapters()
 
 
 
13
 
14
+ async def run_search(query, live_only):
15
  results = []
16
+ for adapter in adapters:
17
+ if live_only and not adapter.is_live:
 
 
18
  continue
19
+ try:
20
+ r = await adapter.search(query)
21
+ results.extend(r)
22
+ except Exception:
23
+ adapter.health = "down"
24
+ return results
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
25
 
26
+ def search_ui(query, live_only):
27
+ results = asyncio.run(run_search(query, live_only))
28
+ clusters = semantic_cluster(results)
29
+ return results, clusters
30
 
31
+ with gr.Blocks() as demo:
32
+ gr.Markdown("## Federal FOIA Intelligence Search")
33
+ gr.Markdown("*Public Electronic Reading Rooms Only*")
34
 
35
+ query = gr.Textbox(label="Search FOIA Reading Rooms")
36
+ live_toggle = gr.Checkbox(label="Enable Live Agencies (Public Only)")
 
 
 
 
 
 
 
 
 
37
 
38
+ search_btn = gr.Button("Search")
 
 
 
 
 
 
 
 
 
39
 
40
+ results_table = gr.Dataframe(label="Results")
41
+ cluster_plot = gr.Plot(label="Semantic Clusters")
42
 
43
+ with gr.Tab("📄 Document Preview"):
44
+ preview = gr.HTML()
45
 
46
+ with gr.Tab("🧾 FOIA Request Generator"):
47
+ agency = gr.Textbox(label="Agency")
48
+ subject = gr.Textbox(label="Subject")
49
+ packet_btn = gr.Button("Generate FOIA Packet")
50
+ packet_out = gr.File()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
51
 
52
  search_btn.click(
53
+ search_ui,
54
+ inputs=[query, live_toggle],
55
+ outputs=[results_table, cluster_plot]
 
 
 
 
 
 
 
56
  )
57
 
58
+ packet_btn.click(
59
+ generate_foia_packet,
60
+ inputs=[agency, subject],
61
+ outputs=packet_out
62
  )
63
 
64
+ demo.launch()