Free At UCD ? Free Food for Students with Real-Time Availability
Published:
Free at UCD is a casual, real-time platform created to help students find free food on campus! University life is packed with events, and this app helps you stay in the know about food giveaways, helping students save on costs and reducing food waste.
Free at UCD started as a collaborative student project at University College Dublin (UCD) to help students find free food giveaways across campus. What began as a simple idea has evolved into a robust crowd-sourced web application serving 400-500 daily sessions, with AWS EC2 + RDS deployment and an innovative OpenCV-based Instagram scraper for automated data ingestion.
The Inspiration Behind Free at UCD
University life comes with its own set of challenges, and managing expenses is high on that list. Recognizing the frequency of events offering free food and the lack of a centralized platform to inform students about them, we developed Free at UCD. Our goal is to reduce food waste and help students save money by connecting them to these opportunities in real-time.
Technical Overview
Building an application that could handle real-time data and scale efficiently was crucial. Here’s how we achieved it:
Streamlit for Rapid Development
We chose Streamlit to build our Minimum Viable Product (MVP) due to its simplicity and the speed at which we could develop interactive web applications. Streamlit allowed us to focus on core functionalities without worrying about the complexities of traditional web development frameworks.
PostgreSQL Database
For our database, we utilized PostgreSQL to store location data, food items, availability times, and other relevant information. PostgreSQL’s robustness and reliability made it an ideal choice for handling the data-intensive operations of our application.
Caching the Map for Performance
One of the critical features of Free at UCD is the interactive map that displays food giveaway locations. Initially, users experienced delays and reloads when zooming or panning the map. To enhance performance, we implemented caching mechanisms:
- Map Caching: By caching the map object, we reduced the load times significantly. Users can now navigate the map smoothly without unnecessary reloads.
- Data Caching: We also cached database queries to minimize the number of calls to our PostgreSQL database, thereby improving the application’s responsiveness.
AWS Deployment: EC2 + RDS Architecture
We deployed Free at UCD on AWS EC2 with RDS (PostgreSQL) for production-grade scalability and reliability. The architecture ensures we can handle our 400-500 daily sessions efficiently:
# AWS Configuration for Free at UCD
import boto3
import psycopg2
from sqlalchemy import create_engine
import streamlit as st
class AWSInfrastructure:
def __init__(self):
# EC2 instance configuration
self.ec2_client = boto3.client('ec2', region_name='eu-west-1') # Ireland region for UCD
self.rds_endpoint = os.getenv('RDS_ENDPOINT')
self.db_engine = create_engine(
f"postgresql://{os.getenv('DB_USER')}:{os.getenv('DB_PASSWORD')}@{self.rds_endpoint}/freeatucd"
)
def setup_auto_scaling(self):
"""Configure auto-scaling for traffic spikes during lunch hours"""
return {
'min_instances': 1,
'max_instances': 3,
'scale_up_threshold': 70, # CPU percentage
'scale_down_threshold': 30,
'target_group_arn': os.getenv('ALB_TARGET_GROUP_ARN')
}
Infrastructure Benefits:
- High Availability: Multi-AZ RDS deployment ensures 99.9% uptime
- Auto-Scaling: Handles lunch-hour traffic spikes (12-2pm sees 300+ concurrent users)
- Cost Optimization: t3.micro instances sufficient for our optimized application
- Backup & Recovery: Automated RDS backups with point-in-time recovery
OpenCV-Based Instagram Scraper: Automated Data Ingestion
One of our most innovative features is the OpenCV-powered Instagram scraper that automatically detects and extracts food giveaway information from UCD society Instagram posts:
import cv2
import numpy as np
import pytesseract
from instagram_private_api import Client
import re
from datetime import datetime
class InstagramFoodScraper:
def __init__(self):
self.instagram_client = Client(username, password)
self.food_keywords = [
'free food', 'pizza', 'sandwiches', 'coffee', 'snacks',
'giveaway', 'complimentary', 'refreshments', 'lunch'
]
self.location_keywords = [
'student centre', 'library', 'quad', 'belfield',
'newman building', 'science centre', 'lecture theatre'
]
def scrape_ucd_societies(self):
"""Scrape Instagram posts from UCD societies for food events"""
ucd_societies = [
'ucdsu', 'ucd_dramsoc', 'ucd_lawsoc', 'ucd_comsoc',
'ucd_engsoc', 'ucd_bizzsoc', 'ucd_medsoc'
]
food_events = []
for society in ucd_societies:
recent_posts = self.get_recent_posts(society, limit=10)
for post in recent_posts:
# Download image
image_url = post['image_versions2']['candidates'][0]['url']
image = self.download_image(image_url)
# Extract text using OCR
extracted_text = self.extract_text_from_image(image)
# Check for food-related content
if self.contains_food_keywords(extracted_text):
event_details = self.parse_event_details(
extracted_text, post['caption']['text']
)
if event_details:
food_events.append(event_details)
return food_events
def extract_text_from_image(self, image):
"""Use OpenCV + Tesseract to extract text from Instagram posts"""
# Convert to grayscale
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# Apply image preprocessing for better OCR
# 1. Noise reduction
denoised = cv2.medianBlur(gray, 5)
# 2. Contrast enhancement
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8))
enhanced = clahe.apply(denoised)
# 3. Threshold for better text recognition
_, thresh = cv2.threshold(enhanced, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
# Extract text using Tesseract
custom_config = r'--oem 3 --psm 6'
extracted_text = pytesseract.image_to_string(thresh, config=custom_config)
return extracted_text.lower()
def parse_event_details(self, ocr_text, caption_text):
"""Parse event details from extracted text"""
combined_text = f"{ocr_text} {caption_text}".lower()
# Extract time using regex
time_pattern = r'(\d{1,2}:\d{2}|\d{1,2}pm|\d{1,2}am)'
time_matches = re.findall(time_pattern, combined_text)
# Extract location
location = None
for keyword in self.location_keywords:
if keyword in combined_text:
location = keyword
break
# Extract food type
food_type = None
for keyword in self.food_keywords:
if keyword in combined_text:
food_type = keyword
break
if time_matches and location and food_type:
return {
'food_type': food_type,
'location': location,
'time': time_matches[0],
'source': 'instagram_scraper',
'confidence': self.calculate_confidence(combined_text)
}
return None
# Usage in main application
class FreeAtUCDApp:
def __init__(self):
self.scraper = InstagramFoodScraper()
self.db_connection = self.setup_database()
def run_automated_scraping(self):
"""Run every 30 minutes to find new food events"""
while True:
try:
new_events = self.scraper.scrape_ucd_societies()
for event in new_events:
# Verify event doesn't already exist
if not self.event_exists(event):
self.add_event_to_database(event)
self.notify_subscribers(event)
time.sleep(1800) # Wait 30 minutes
except Exception as e:
logging.error(f"Scraping error: {e}")
time.sleep(300) # Wait 5 minutes on error
Scraper Features:
- Computer Vision: Uses OpenCV for image preprocessing and text extraction
- OCR Integration: Tesseract OCR for reading text from Instagram story images
- Smart Parsing: NLP techniques to extract location, time, and food type
- Automated Updates: Runs every 30 minutes to catch new posts
- Duplicate Prevention: Checks against existing database entries
Real-Time Performance Metrics
Our application now serves impressive daily traffic:
PERFORMANCE_METRICS = {
"daily_sessions": "400-500",
"peak_concurrent_users": 150,
"average_session_duration": "3.2 minutes",
"database_queries_per_day": 25000,
"instagram_posts_processed": "50-80 per day",
"automated_events_detected": "5-10 per day",
"user_retention_rate": "68%",
"mobile_users_percentage": "85%"
}
Current Scale and Impact
Free at UCD has grown from 100 users on day one to serving 400-500 daily sessions. The platform has become an essential tool for UCD students, with several key impact metrics:
- 25,000+ database queries per day indicating high user engagement
- 68% user retention rate showing students find real value
- 5-10 automated events detected daily through our Instagram scraper
- 85% mobile users, reflecting how students use the app on-the-go
- Average session duration of 3.2 minutes - perfect for quick food discovery
Student feedback has been overwhelmingly positive, with many commenting on how the app has helped them save money and discover events they would have otherwise missed.
Figure 2: User Growth on Launch Day
Lessons Learned and Future Plans
Developing Free at UCD taught us valuable lessons about building scalable applications with limited resources:
- Optimization is Key: Efficient coding practices and caching can significantly improve performance without the need for expensive infrastructure.
- User-Centric Design: Focusing on the needs of the users ensured that we built a tool that provided real value.
Upcoming Features
We are excited to roll out new features in the coming weeks:
- Notification System: Users will receive alerts when new food giveaways are added near their location.
- Event Submission: Allowing event organizers to add their own food giveaway events to the platform.
- Enhanced Filtering: Users will be able to filter giveaways based on dietary preferences like vegan or gluten-free options.
Conclusion
Free at UCD is more than just an app; it’s a community resource aimed at enhancing student life on campus. By leveraging modern technologies and focusing on performance optimization, we’ve created a platform that not only serves its purpose effectively but also scales efficiently.
We are grateful for the support from the UCD community and are committed to continuous improvement. Stay tuned for more updates!
Get Involved
If you’re interested in contributing to the project or have suggestions, feel free to reach out or check out our GitHub repository.
Thank you for being part of our journey!