Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 21 additions & 8 deletions backend/bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand All @@ -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')
Expand Down
50 changes: 9 additions & 41 deletions backend/maharashtra_locator.py
Original file line number Diff line number Diff line change
Expand Up @@ -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__),
Expand All @@ -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)
Expand All @@ -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__),
Expand All @@ -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]]:
Expand All @@ -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:
Expand All @@ -158,17 +128,15 @@ 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:
return {
"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
15 changes: 10 additions & 5 deletions backend/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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)
Expand Down
10 changes: 4 additions & 6 deletions backend/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Loading