diff --git a/backend/bot.py b/backend/bot.py index 062d7b53..328cb474 100644 --- a/backend/bot.py +++ b/backend/bot.py @@ -64,11 +64,7 @@ async def receive_description(update: Update, context: ContextTypes.DEFAULT_TYPE ) return CATEGORY -def save_issue_to_db(description, category, photo_path): - """ - Synchronous helper to save issue to DB. - To be run in a threadpool to avoid blocking the async event loop. - """ +def save_issue_db_blocking(description, category, photo_path): db = SessionLocal() try: new_issue = Issue( @@ -81,12 +77,29 @@ def save_issue_to_db(description, category, photo_path): db.commit() db.refresh(new_issue) return new_issue.id - except Exception as e: - logging.error(f"Error saving to DB: {e}") - raise e finally: db.close() +async def receive_category(update: Update, context: ContextTypes.DEFAULT_TYPE): + category = update.message.text + photo_path = context.user_data.get('photo_path') + description = context.user_data.get('description') + + # Save to Database (using threadpool to avoid blocking event loop) + from fastapi.concurrency import run_in_threadpool + + try: + issue_id = await run_in_threadpool( + save_issue_db_blocking, + description, + category, + photo_path + ) + except Exception as e: + logging.error(f"Error saving to DB: {e}") + await update.message.reply_text("Sorry, something went wrong while saving your issue.") + return ConversationHandler.END + async def receive_category(update: Update, context: ContextTypes.DEFAULT_TYPE): category = update.message.text photo_path = context.user_data.get('photo_path') diff --git a/backend/maharashtra_locator.py b/backend/maharashtra_locator.py index d69e6a7c..eac71235 100644 --- a/backend/maharashtra_locator.py +++ b/backend/maharashtra_locator.py @@ -55,7 +55,7 @@ def load_maharashtra_pincode_data() -> Dict[str, Dict[str, Any]]: Load and cache Maharashtra pincode to constituency mapping data. Returns: - dict: Dictionary mapping pincode to data + dict: Dictionary of pincode mapping keyed by pincode """ file_path = os.path.join( os.path.dirname(__file__), @@ -65,8 +65,8 @@ def load_maharashtra_pincode_data() -> Dict[str, Dict[str, Any]]: with open(file_path, "r", encoding="utf-8") as f: data_list = json.load(f) - # Convert list to dictionary for O(1) lookup - return {item["pincode"]: item for item in data_list} + # Convert list to dict for O(1) lookup + return {item.get("pincode"): item for item in data_list if item.get("pincode")} @lru_cache(maxsize=1) @@ -75,7 +75,7 @@ def load_maharashtra_mla_data() -> Dict[str, Dict[str, Any]]: Load and cache Maharashtra MLA information data. Returns: - dict: Dictionary mapping constituency to MLA data + dict: Dictionary of MLA information keyed by assembly_constituency """ file_path = os.path.join( os.path.dirname(__file__), @@ -85,37 +85,8 @@ def load_maharashtra_mla_data() -> Dict[str, Dict[str, Any]]: with open(file_path, "r", encoding="utf-8") as f: data_list = json.load(f) - # Convert list to dictionary for O(1) lookup - return {item["assembly_constituency"]: item for item in data_list} - - -def get_district_by_pincode_range(pincode: int) -> Optional[str]: - """ - Find district by checking pincode ranges. - This is an O(N) fallback where N is number of ranges (~35). - """ - for start, end, district in DISTRICT_RANGES: - if start <= pincode <= end: - return district - return None - - -@lru_cache(maxsize=1) -def _load_maharashtra_pincode_map() -> Dict[str, Dict[str, Any]]: - """ - Load and cache Maharashtra pincode to constituency mapping as a dict for O(1) lookup. - """ - pincode_data = load_maharashtra_pincode_data() - return {entry["pincode"]: entry for entry in pincode_data if "pincode" in entry} - - -@lru_cache(maxsize=1) -def _load_maharashtra_mla_map() -> Dict[str, Dict[str, Any]]: - """ - Load and cache Maharashtra MLA information as a dict for O(1) lookup. - """ - mla_data = load_maharashtra_mla_data() - return {entry["assembly_constituency"]: entry for entry in mla_data if "assembly_constituency" in entry} + # Convert list to dict for O(1) lookup + return {item.get("assembly_constituency"): item for item in data_list if item.get("assembly_constituency")} def find_constituency_by_pincode(pincode: str) -> Optional[Dict[str, Any]]: @@ -131,8 +102,7 @@ def find_constituency_by_pincode(pincode: str) -> Optional[Dict[str, Any]]: if not pincode or len(pincode) != 6 or not pincode.isdigit(): return None - # Use O(1) map lookup instead of O(n) list iteration - pincode_map = _load_maharashtra_pincode_map() + pincode_map = load_maharashtra_pincode_data() entry = pincode_map.get(pincode) if entry: @@ -158,8 +128,7 @@ def find_mla_by_constituency(constituency_name: str) -> Optional[Dict[str, Any]] if not constituency_name: return None - # Use O(1) map lookup instead of O(n) list iteration - mla_map = _load_maharashtra_mla_map() + mla_map = load_maharashtra_mla_data() entry = mla_map.get(constituency_name) if entry: @@ -167,8 +136,7 @@ def find_mla_by_constituency(constituency_name: str) -> Optional[Dict[str, Any]] "mla_name": entry.get("mla_name"), "party": entry.get("party"), "phone": entry.get("phone"), - "email": entry.get("email"), - "twitter": entry.get("twitter") + "email": entry.get("email") } return None diff --git a/backend/main.py b/backend/main.py index 784073d2..c0edc5d1 100644 --- a/backend/main.py +++ b/backend/main.py @@ -221,9 +221,8 @@ def save_file_blocking(file_obj, path): async def create_issue( description: str = Form(...), category: str = Form(...), - source: str = Form("web"), - user_email: Optional[str] = Form(None), - image: UploadFile = File(...), + user_email: str = Form(None), + image: UploadFile = File(None), db: Session = Depends(get_db) ): try: @@ -235,8 +234,14 @@ async def create_issue( # Write to disk in a threadpool to avoid blocking event loop await run_in_threadpool(save_file_blocking, image.file, file_location) - # Analyze with AI - ai_analysis = await analyze_issue_image(file_location) + # Save to DB + new_issue = Issue( + description=description, + category=category, + user_email=user_email, + image_path=image_path, + source="web" + ) # Generate Action Plan (AI) action_plan = await generate_action_plan(description, category, file_location) diff --git a/backend/models.py b/backend/models.py index a9bb8d89..10481dff 100644 --- a/backend/models.py +++ b/backend/models.py @@ -117,9 +117,7 @@ class Issue(Base): description = Column(String) category = Column(String, index=True) image_path = Column(String) - source = Column(String, index=True) # 'telegram', 'web', etc. - status = Column(String, default="open", index=True) - created_at = Column(DateTime, default=datetime.datetime.utcnow, index=True) - user_email = Column(String, nullable=True, index=True) - upvotes = Column(Integer, default=0, index=True) - action_plan = Column(Text, nullable=True) + user_email = Column(String, nullable=True) + source = Column(String) # 'telegram', 'web', etc. + status = Column(String, default="open") + created_at = Column(DateTime, default=datetime.datetime.utcnow)