From 8c9233220177eb37fbd2b736fce588f85d3377ed Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Wed, 24 Dec 2025 10:36:19 +0000 Subject: [PATCH] Optimize MLA lookup and fix tests - Refactored `backend/maharashtra_locator.py` to use dictionaries for O(1) lookups instead of list iteration. - Added in-memory caching to `backend/gemini_summary.py` to reduce redundant AI API calls. - Updated `tests/test_mh_endpoint.py` to match real-world data in the JSON files. - Suppressed `FutureWarning` from `google.generativeai` package. - Updated `tests/test_maharashtra_locator.py` to verify dictionary data structures. --- backend/gemini_summary.py | 24 ++++++++++++++-- backend/maharashtra_locator.py | 48 +++++++++++++++++-------------- tests/test_maharashtra_locator.py | 4 +-- tests/test_mh_endpoint.py | 7 +++-- 4 files changed, 54 insertions(+), 29 deletions(-) diff --git a/backend/gemini_summary.py b/backend/gemini_summary.py index 16e9ba8c..c1da8240 100644 --- a/backend/gemini_summary.py +++ b/backend/gemini_summary.py @@ -4,9 +4,19 @@ Uses Gemini AI to generate human-readable summaries about MLAs and their roles. """ import os -import google.generativeai as genai +import warnings from typing import Dict, Optional +# Suppress the Future Warning from google.generativeai +warnings.filterwarnings("ignore", category=FutureWarning, module="google.generativeai") + +import google.generativeai as genai + +# Simple in-memory cache to store generated summaries +# Key: (district, assembly_constituency, mla_name, issue_category) +# Value: Summary string +_summary_cache: Dict[tuple, str] = {} + # Configure Gemini (reuses existing configuration) api_key = os.environ.get("GEMINI_API_KEY") @@ -51,6 +61,11 @@ async def generate_mla_summary( Returns: A short paragraph describing the MLA's role and responsibilities """ + # Check cache first + cache_key = (district, assembly_constituency, mla_name, issue_category) + if cache_key in _summary_cache: + return _summary_cache[cache_key] + if not api_key: return _get_fallback_summary(mla_name, assembly_constituency, district) @@ -70,7 +85,12 @@ async def generate_mla_summary( """ response = await model.generate_content_async(prompt) - return response.text.strip() + summary = response.text.strip() + + # Store in cache + _summary_cache[cache_key] = summary + + return summary except Exception as e: print(f"Gemini Summary Error: {e}") diff --git a/backend/maharashtra_locator.py b/backend/maharashtra_locator.py index e228b1e3..259f3e70 100644 --- a/backend/maharashtra_locator.py +++ b/backend/maharashtra_locator.py @@ -11,12 +11,12 @@ @lru_cache(maxsize=1) -def load_maharashtra_pincode_data() -> list: +def load_maharashtra_pincode_data() -> Dict[str, Dict[str, Any]]: """ Load and cache Maharashtra pincode to constituency mapping data. Returns: - list: List of pincode mapping dictionaries + dict: Dictionary mapping pincode -> constituency info """ file_path = os.path.join( os.path.dirname(__file__), @@ -25,16 +25,18 @@ def load_maharashtra_pincode_data() -> list: ) with open(file_path, "r", encoding="utf-8") as f: - return json.load(f) + data_list = json.load(f) + # Convert list to dictionary keyed by pincode + return {item["pincode"]: item for item in data_list} @lru_cache(maxsize=1) -def load_maharashtra_mla_data() -> list: +def load_maharashtra_mla_data() -> Dict[str, Dict[str, Any]]: """ Load and cache Maharashtra MLA information data. Returns: - list: List of MLA information dictionaries + dict: Dictionary mapping assembly_constituency -> MLA info """ file_path = os.path.join( os.path.dirname(__file__), @@ -43,7 +45,9 @@ def load_maharashtra_mla_data() -> list: ) with open(file_path, "r", encoding="utf-8") as f: - return json.load(f) + data_list = json.load(f) + # Convert list to dictionary keyed by assembly_constituency + return {item["assembly_constituency"]: item for item in data_list} def find_constituency_by_pincode(pincode: str) -> Optional[Dict[str, Any]]: @@ -61,13 +65,13 @@ def find_constituency_by_pincode(pincode: str) -> Optional[Dict[str, Any]]: pincode_data = load_maharashtra_pincode_data() - for entry in pincode_data: - if entry.get("pincode") == pincode: - return { - "district": entry.get("district"), - "state": entry.get("state"), - "assembly_constituency": entry.get("assembly_constituency") - } + entry = pincode_data.get(pincode) + if entry: + return { + "district": entry.get("district"), + "state": entry.get("state"), + "assembly_constituency": entry.get("assembly_constituency") + } return None @@ -87,14 +91,14 @@ def find_mla_by_constituency(constituency_name: str) -> Optional[Dict[str, Any]] mla_data = load_maharashtra_mla_data() - for entry in mla_data: - if entry.get("assembly_constituency") == constituency_name: - return { - "mla_name": entry.get("mla_name"), - "party": entry.get("party"), - "phone": entry.get("phone"), - "email": entry.get("email"), - "twitter": entry.get("twitter") - } + entry = mla_data.get(constituency_name) + if entry: + return { + "mla_name": entry.get("mla_name"), + "party": entry.get("party"), + "phone": entry.get("phone"), + "email": entry.get("email"), + "twitter": entry.get("twitter") + } return None diff --git a/tests/test_maharashtra_locator.py b/tests/test_maharashtra_locator.py index 706016d1..c3ec0102 100644 --- a/tests/test_maharashtra_locator.py +++ b/tests/test_maharashtra_locator.py @@ -24,13 +24,13 @@ class TestMaharashtraLocator: def test_load_pincode_data(self): """Test loading pincode data""" data = load_maharashtra_pincode_data() - assert isinstance(data, list) + assert isinstance(data, dict) assert len(data) > 0 def test_load_mla_data(self): """Test loading MLA data""" data = load_maharashtra_mla_data() - assert isinstance(data, list) + assert isinstance(data, dict) assert len(data) > 0 def test_find_constituency_valid_pincode(self): diff --git a/tests/test_mh_endpoint.py b/tests/test_mh_endpoint.py index 1ed8885a..971cd623 100644 --- a/tests/test_mh_endpoint.py +++ b/tests/test_mh_endpoint.py @@ -35,7 +35,8 @@ def test_maharashtra_endpoint(): print(f" Party: {data['mla'].get('party')}") assert data['pincode'] == '411001' assert data['district'] == 'Pune' - assert data['mla']['name'] == 'Sample MLA Pune' + # The data was updated to real world data + assert data['mla']['name'] == 'Ravindra Dhangekar' else: print(f" ✗ Failed: {response.json()}") return False @@ -52,8 +53,8 @@ def test_maharashtra_endpoint(): print(f" Constituency: {data.get('assembly_constituency')}") print(f" MLA: {data['mla'].get('name')}") assert data['pincode'] == '400001' - assert data['district'] == 'Mumbai' - assert data['mla']['name'] == 'Sample MLA Colaba' + assert data['district'] == 'Mumbai City' + assert data['mla']['name'] == 'Rahul Narwekar' else: print(f" ✗ Failed: {response.json()}") return False