Deploy Agenda Parser
Browse files- samples/baycity-928.titles.json +42 -0
- samples/oakland-1570.titles.json +118 -0
- webapp/backend.py +38 -3
samples/baycity-928.titles.json
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[
|
| 2 |
+
{
|
| 3 |
+
"orig": "1 Proclamation - Pride Month - June 2026",
|
| 4 |
+
"name": "Proclamation - Pride Month - June 2026."
|
| 5 |
+
},
|
| 6 |
+
{
|
| 7 |
+
"orig": "2 FY 26/27 Budget Presentation",
|
| 8 |
+
"name": "FY 26/27 Budget Presentation."
|
| 9 |
+
},
|
| 10 |
+
{
|
| 11 |
+
"orig": "1 MINUTES",
|
| 12 |
+
"name": "City Commission (5/18/26) and Work Session (5/26/26)."
|
| 13 |
+
},
|
| 14 |
+
{
|
| 15 |
+
"orig": "2 ACCOUNTS & CLAIMS",
|
| 16 |
+
"name": "City Manager presenting Accounts and Claims in the amount of $788,294.23 and Investments and Wire Transfers in the amount of $1,212,663.41 (5/26/26), and Accounts and Claims in the amount of $582,328.31 and Investments and Wire Transfers in the amount of $809,185.98 (6/1/26)."
|
| 17 |
+
},
|
| 18 |
+
{
|
| 19 |
+
"orig": "3 PAYROLL",
|
| 20 |
+
"name": "City Manager presenting Payroll in the amount of $1,363,127.22 (5/21/26)."
|
| 21 |
+
},
|
| 22 |
+
{
|
| 23 |
+
"orig": "4 REPORTS OF OFFICERS",
|
| 24 |
+
"name": "REPORTS OF OFFICERS"
|
| 25 |
+
},
|
| 26 |
+
{
|
| 27 |
+
"orig": "5 REPORTS OF COMMITTEES",
|
| 28 |
+
"name": "REPORTS OF COMMITTEES"
|
| 29 |
+
},
|
| 30 |
+
{
|
| 31 |
+
"orig": "6 RESOLUTIONS",
|
| 32 |
+
"name": "RESOLUTIONS"
|
| 33 |
+
},
|
| 34 |
+
{
|
| 35 |
+
"orig": "1 Breaking Bread - to allocate $9,162.50 to meet unm",
|
| 36 |
+
"name": "Commissioner Tenney's resolution allocating $9,162.50 to pay for the unmet costs of the Breaking Bread Village's Pulse Series."
|
| 37 |
+
},
|
| 38 |
+
{
|
| 39 |
+
"orig": "2 Budget Amendments",
|
| 40 |
+
"name": "City Manager recommending budget amendments in the amount of $25,133 for the Fiscal Year 2025/2026 budget."
|
| 41 |
+
}
|
| 42 |
+
]
|
samples/oakland-1570.titles.json
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[
|
| 2 |
+
{
|
| 3 |
+
"orig": "a. Proclamation - Family Reunification and Preservati",
|
| 4 |
+
"name": "Proclamation - Family Reunification and Preservation Day"
|
| 5 |
+
},
|
| 6 |
+
{
|
| 7 |
+
"orig": "b. Presentation - Oakland Community Health Network Up",
|
| 8 |
+
"name": "Presentation - Oakland Community Health Network Update"
|
| 9 |
+
},
|
| 10 |
+
{
|
| 11 |
+
"orig": "a. Appointment to SEMCOG's Finance and Budget Committ",
|
| 12 |
+
"name": "Appointment to SEMCOG's Finance and Budget Committee"
|
| 13 |
+
},
|
| 14 |
+
{
|
| 15 |
+
"orig": "10. Public Comment",
|
| 16 |
+
"name": "Public Comment (three minutes max per speaker, related only to items on the agenda)"
|
| 17 |
+
},
|
| 18 |
+
{
|
| 19 |
+
"orig": "a. Fiscal Year 2026 Appropriation with the City of Ro",
|
| 20 |
+
"name": "Board of Commissioners - Fiscal Year 2026 Appropriation with the City of Rochester for Tri-Party Road Improvement Program – Project No. 58601"
|
| 21 |
+
},
|
| 22 |
+
{
|
| 23 |
+
"orig": "b. Authorize the Issuance of Bonds for the Pontiac Wo",
|
| 24 |
+
"name": "Water Resources Commissioner - Authorize the Issuance of Bonds for the Pontiac Woodward Loop Sewage Disposal Improvement Project"
|
| 25 |
+
},
|
| 26 |
+
{
|
| 27 |
+
"orig": "c. Grant Acceptance with U.S. Environmental Protectio",
|
| 28 |
+
"name": "Water Resources Commissioner - Grant Acceptance with U.S. Environmental Protection Agency for the RainSmart Rebates Program"
|
| 29 |
+
},
|
| 30 |
+
{
|
| 31 |
+
"orig": "d. Contract Amendment with Auger, Klein and Aller Arc",
|
| 32 |
+
"name": "Water Resources Commissioner - Contract Amendment with Auger, Klein and Aller Architects"
|
| 33 |
+
},
|
| 34 |
+
{
|
| 35 |
+
"orig": "e. Funding for In-Line Skating Rink at Harding Park w",
|
| 36 |
+
"name": "Board of Commissioners - Funding for In-Line Skating Rink at Harding Park with the City of Ferndale"
|
| 37 |
+
},
|
| 38 |
+
{
|
| 39 |
+
"orig": "f. Fiscal Year 2026 Appropriation for Local Road Impr",
|
| 40 |
+
"name": "Board of Commissioners - Fiscal Year 2026 Appropriation for Local Road Improvement Program"
|
| 41 |
+
},
|
| 42 |
+
{
|
| 43 |
+
"orig": "a. Sponsorship of the Village of Wolverine Lake 39th",
|
| 44 |
+
"name": "Board of Commissioners - Sponsorship of the Village of Wolverine Lake 39th Annual Fireworks Display"
|
| 45 |
+
},
|
| 46 |
+
{
|
| 47 |
+
"orig": "b. FY 2026 Second Quarter Financial Forecast and Budg",
|
| 48 |
+
"name": "Fiscal Services - FY 2026 Second Quarter Financial Forecast and Budget Amendments"
|
| 49 |
+
},
|
| 50 |
+
{
|
| 51 |
+
"orig": "c. Reallocation of American Rescue Plan Act Local Fis",
|
| 52 |
+
"name": "Executive's Office - Reallocation of American Rescue Plan Act Local Fiscal Recovery Funds"
|
| 53 |
+
},
|
| 54 |
+
{
|
| 55 |
+
"orig": "a. Interlocal Agreement with Bloomfield Hills Schools",
|
| 56 |
+
"name": "Parks & Recreation - Interlocal Agreement with Bloomfield Hills Schools for Transition Services and Operational Continuity at Discovery Oaks and Bloomfield Oaks"
|
| 57 |
+
},
|
| 58 |
+
{
|
| 59 |
+
"orig": "b. Memorandum of Understanding with the Huron-Clinton",
|
| 60 |
+
"name": "Parks & Recreation - Memorandum of Understanding with the Huron-Clinton Metropolitan Authority for the 2026 Water Safety and Swim Lesson Partnership"
|
| 61 |
+
},
|
| 62 |
+
{
|
| 63 |
+
"orig": "c. Grant Acceptance from the State of Michigan for th",
|
| 64 |
+
"name": "Parks & Recreation - Grant Acceptance from the State of Michigan for the FY 2026 Great Lakes Management Grant Program"
|
| 65 |
+
},
|
| 66 |
+
{
|
| 67 |
+
"orig": "d. Grant Acceptance from the State of Michigan for th",
|
| 68 |
+
"name": "Parks & Recreation - Grant Acceptance from the State of Michigan for the FY 2026 Invasive Species Grant Program"
|
| 69 |
+
},
|
| 70 |
+
{
|
| 71 |
+
"orig": "a. Grant Application to the Department of Housing and",
|
| 72 |
+
"name": "Health & Human Services - Neighborhood and Housing Development - Grant Application to the Department of Housing and Urban Development for the Program Year 2026 Annual Action Plan"
|
| 73 |
+
},
|
| 74 |
+
{
|
| 75 |
+
"orig": "b. Request to Create One (1) GF/GP FTE Office Support",
|
| 76 |
+
"name": "Circuit Court - Request to Create One (1) GF/GP FTE Office Support Clerk Senior for Personal Protection Order Office"
|
| 77 |
+
},
|
| 78 |
+
{
|
| 79 |
+
"orig": "c. Grant Acceptance from the Michigan State Housing D",
|
| 80 |
+
"name": "Health & Human Services - Neighborhood and Housing Development - Grant Acceptance from the Michigan State Housing Development Authority for the FY 2026 Enhancement Grant"
|
| 81 |
+
},
|
| 82 |
+
{
|
| 83 |
+
"orig": "d. Amendment #1 to the Oakland Schools FY 2025 Home V",
|
| 84 |
+
"name": "Health & Human Services - Health Division - Amendment #1 to the Oakland Schools FY 2025 Home Visitation Grant Program"
|
| 85 |
+
},
|
| 86 |
+
{
|
| 87 |
+
"orig": "e. Request for Staffing Modification within the Healt",
|
| 88 |
+
"name": "Health & Human Services - Health Division - Request for Staffing Modification within the Health Division for the Deletion of Seven (7) Special Revenue Positions"
|
| 89 |
+
},
|
| 90 |
+
{
|
| 91 |
+
"orig": "f. Amendment #4 to the FY 2026 Local Health Departmen",
|
| 92 |
+
"name": "Health & Human Services - Health Division - Amendment #4 to the FY 2026 Local Health Department Agreement from the Michigan Department of Health and Human Services"
|
| 93 |
+
},
|
| 94 |
+
{
|
| 95 |
+
"orig": "g. Grant Application to the Michigan Department of Co",
|
| 96 |
+
"name": "Public Services - Pretrial & Justice Services - Grant Application to the Michigan Department of Corrections for the FY 2027 Community Corrections Comprehensive Plan Program"
|
| 97 |
+
},
|
| 98 |
+
{
|
| 99 |
+
"orig": "h. Memorandum of Understanding with the United States",
|
| 100 |
+
"name": "Sheriff’s Office - Memorandum of Understanding with the United States Capitol Police for Security Services for Members of Congress"
|
| 101 |
+
},
|
| 102 |
+
{
|
| 103 |
+
"orig": "i. Amendment #1 to the FY 2026 Emergency Response Sup",
|
| 104 |
+
"name": "Sheriff’s Office - Amendment #1 to the FY 2026 Emergency Response Support Program for the Rochester Hills Splash Pad Shooting from Oakland County Health Network"
|
| 105 |
+
},
|
| 106 |
+
{
|
| 107 |
+
"orig": "j. Amendment #3 to the Interlocal Agreement with Oakl",
|
| 108 |
+
"name": "Sheriff’s Office - Amendment #3 to the Interlocal Agreement with Oakland Community Health Network for Jail Alliance with Support Program"
|
| 109 |
+
},
|
| 110 |
+
{
|
| 111 |
+
"orig": "a. Appointment to the Land Bank Authority",
|
| 112 |
+
"name": "Board of Commissioners - Appointment to the Land Bank Authority"
|
| 113 |
+
},
|
| 114 |
+
{
|
| 115 |
+
"orig": "18. Public Comment",
|
| 116 |
+
"name": "Public Comment (three minutes max per speaker, any topic)"
|
| 117 |
+
}
|
| 118 |
+
]
|
webapp/backend.py
CHANGED
|
@@ -122,14 +122,49 @@ def list_samples() -> list[dict]:
|
|
| 122 |
|
| 123 |
|
| 124 |
def ingest_sample(sample_id: str) -> dict:
|
| 125 |
-
"""Parse a bundled sample agenda packet (same return shape as upload_packet).
|
| 126 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 127 |
if s is None:
|
| 128 |
return {"error": f"Unknown sample '{sample_id}'."}
|
| 129 |
path = _SAMPLES_DIR / s["file"]
|
| 130 |
if not path.exists():
|
| 131 |
return {"error": f"Sample '{sample_id}' is not bundled on this server."}
|
| 132 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 133 |
|
| 134 |
|
| 135 |
# --------------------------------------------------------------------------- #
|
|
|
|
| 122 |
|
| 123 |
|
| 124 |
def ingest_sample(sample_id: str) -> dict:
|
| 125 |
+
"""Parse a bundled sample agenda packet (same return shape as upload_packet).
|
| 126 |
+
|
| 127 |
+
If a pre-baked ``{id}.titles.json`` sidecar is bundled (the enhanced-title logic
|
| 128 |
+
run once offline), its full titles are applied to the parsed items so samples show
|
| 129 |
+
complete titles immediately — no per-click LLM window. Users can still run "Improve
|
| 130 |
+
titles" or edit by hand afterward.
|
| 131 |
+
"""
|
| 132 |
+
sid = (sample_id or "").strip()
|
| 133 |
+
s = _SAMPLE_BY_ID.get(sid)
|
| 134 |
if s is None:
|
| 135 |
return {"error": f"Unknown sample '{sample_id}'."}
|
| 136 |
path = _SAMPLES_DIR / s["file"]
|
| 137 |
if not path.exists():
|
| 138 |
return {"error": f"Sample '{sample_id}' is not bundled on this server."}
|
| 139 |
+
res = upload_packet(path.read_bytes(), s["file"], s["agenda_pages"])
|
| 140 |
+
_apply_sample_titles(sid, res.get("items", []))
|
| 141 |
+
return res
|
| 142 |
+
|
| 143 |
+
|
| 144 |
+
def _apply_sample_titles(sample_id: str, items: list[dict]) -> None:
|
| 145 |
+
"""Overwrite parsed item names from a pre-baked ``{id}.titles.json`` sidecar.
|
| 146 |
+
|
| 147 |
+
The sidecar is a list of ``{"orig": "<number> <name>", "name": "<full title>"}``;
|
| 148 |
+
we match each parsed item by its exact ``"<number> <name>"`` line and replace the
|
| 149 |
+
name. Missing/garbled sidecar is non-fatal (items keep their bookmark titles).
|
| 150 |
+
"""
|
| 151 |
+
import json
|
| 152 |
+
|
| 153 |
+
path = _SAMPLES_DIR / f"{sample_id}.titles.json"
|
| 154 |
+
if not path.exists():
|
| 155 |
+
return
|
| 156 |
+
try:
|
| 157 |
+
overrides = {
|
| 158 |
+
o["orig"]: o["name"]
|
| 159 |
+
for o in json.loads(path.read_text())
|
| 160 |
+
if isinstance(o, dict) and o.get("orig") and o.get("name")
|
| 161 |
+
}
|
| 162 |
+
except Exception: # noqa: BLE001 - a bad sidecar just means no overrides
|
| 163 |
+
return
|
| 164 |
+
for it in items:
|
| 165 |
+
key = f"{it.get('number', '')} {it.get('name', '')}".strip()
|
| 166 |
+
if key in overrides:
|
| 167 |
+
it["name"] = overrides[key]
|
| 168 |
|
| 169 |
|
| 170 |
# --------------------------------------------------------------------------- #
|