Skip to content

ashsweet/MultiPlatform_Ride_aggregator

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

4 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Ride Aggregator Agent

A production-grade agentic AI system for aggregating ride fares across multiple cab booking platforms (Uber, Ola, Rapido, InDrive) using LangGraph orchestration and Playwright web scraping.

Architecture

User Input
    │
    ▼
┌─────────────────┐
│  NLP Parser     │  (LangChain + GPT-4o-mini or regex fallback)
│  Extract intent │
└────────┬────────┘
         │
         ▼
┌─────────────────────────────────────────────────────────────┐
│                    LangGraph Workflow                        │
│                                                              │
│  ┌──────────────┐    ┌──────────────┐    ┌──────────────┐  │
│  │ Geolocation  │───▶│  Parallel    │───▶│ Negotiation  │  │
│  │    Node      │    │  Scrape Node │    │    Node      │  │
│  └──────────────┘    └──────────────┘    └──────────────┘  │
│         │                   │                   │           │
│         │            ┌──────┴──────┐           │           │
│         │            │   Scrapers   │           │           │
│         │            │  ┌────────┐  │           │           │
│         │            │  │  Uber  │  │           │           │
│         │            │  │  Ola   │  │           │           │
│         │            │  │ Rapido │  │           │           │
│         │            │  │InDrive │  │           │           │
│         │            │  └────────┘  │           │           │
│         │            └─────────────┘           │           │
│         │                                       │           │
│         ▼                                       ▼           │
│  ┌──────────────┐                      ┌──────────────┐    │
│  │  Decision    │◀─────────────────────│  Ranking     │    │
│  │    Node      │                      │   Matrix     │    │
│  └──────────────┘                      └──────────────┘    │
│         │                                                   │
│         ▼                                                   │
│  ┌──────────────┐                                          │
│  │ Notification │  (Deep link + Push notification)         │
│  │    Node      │                                          │
│  └──────────────┘                                          │
└─────────────────────────────────────────────────────────────┘

Features

  • Natural language ride request parsing
  • Parallel fare scraping from 4 platforms
  • Geolocation resolution (Nominatim/Google Maps)
  • Intelligent ranking based on user priorities (speed/cost/balanced)
  • InDrive automated price negotiation
  • Deep link generation for one-tap booking
  • Local/webhook notification support

Installation

# Clone and install
cd ride-aggregator
pip install -e ".[dev]"

# Install Playwright browsers
playwright install chromium

# Configure environment
cp .env.example .env
# Edit .env with your API keys

Configuration

Create a .env file:

# LLM Provider: "regex" (default, no API needed), "ollama" (free, local), or "openai"
LLM_PROVIDER=regex

# For Ollama (free, runs locally)
# Install: https://ollama.ai then run: ollama pull llama3.2
OLLAMA_MODEL=llama3.2
OLLAMA_BASE_URL=http://localhost:11434

# For OpenAI (paid, optional)
OPENAI_API_KEY=optional_if_using_ollama_or_regex

# Other settings
GOOGLE_MAPS_API_KEY=optional_for_better_geocoding
HEADLESS_BROWSER=true
REQUEST_TIMEOUT=30
MAX_RETRIES=3
LOG_LEVEL=INFO

LLM Options

  1. Regex (default, free): Works out of the box, no setup needed

    LLM_PROVIDER=regex
  2. Ollama (free, local): Better NL understanding, runs on your machine

    # Install Ollama from https://ollama.ai
    ollama pull llama3.2  # or mistral, phi3, etc.
    pip install langchain-ollama
    LLM_PROVIDER=ollama
    OLLAMA_MODEL=llama3.2
  3. OpenAI (paid): Best accuracy

    pip install langchain-openai
    LLM_PROVIDER=openai
    OPENAI_API_KEY=your_key

Usage

Natural Language Query

ride-agent "Get me a ride from Connaught Place to the airport. Prioritize speed, keep it under 400"

Explicit Arguments

ride-agent --pickup "Connaught Place, Delhi" --dropoff "IGI Airport Terminal 3" --max-price 400 --priority speed

Interactive Mode

ride-agent --interactive

Python API

from ride_aggregator import RideAggregatorAgent, RideRequest, Location, UserPreferences, Priority

request = RideRequest(
    pickup=Location(address="Connaught Place, Delhi"),
    dropoff=Location(address="Indira Gandhi International Airport"),
    preferences=UserPreferences(
        priority=Priority.SPEED,
        max_price=400,
    ),
)

agent = RideAggregatorAgent()
result = agent.run(request)

if result.get("decision"):
    print(result["decision"].explanation)
    print(f"Book here: {result['decision'].deep_link}")

Project Structure

src/ride_aggregator/
├── __init__.py
├── cli.py                    # Command-line interface
├── core/
│   ├── __init__.py
│   ├── agent.py              # LangGraph workflow orchestration
│   ├── config.py             # Configuration management
│   ├── logging.py            # Structured logging
│   └── models.py             # Pydantic data models
├── nlp/
│   ├── __init__.py
│   └── parser.py             # Natural language parsing
├── nodes/
│   ├── __init__.py
│   ├── geolocation.py        # Location resolution node
│   ├── scraper.py            # Parallel scraping node
│   ├── negotiation.py        # InDrive negotiation node
│   ├── decision.py           # Ranking and decision node
│   └── notification.py       # Notification node
├── scrapers/
│   ├── __init__.py
│   ├── base.py               # Abstract scraper base class
│   ├── manager.py            # Scraper orchestration
│   ├── uber.py               # Uber fare scraper
│   ├── ola.py                # Ola fare scraper
│   ├── rapido.py             # Rapido fare scraper
│   └── indrive.py            # InDrive fare scraper + negotiation
└── services/
    ├── __init__.py
    ├── geolocation.py        # Geocoding service
    ├── decision.py           # Ranking/decision logic
    └── notification.py       # Notification handling

NLP Parser & Intent Extraction

The NLP parser extracts ride booking intent from natural language using a dual-mode approach:

User Input: "Get me a ride from Connaught Place to the airport. Prioritize speed, under 400"
                                    │
                                    ▼
                    ┌───────────────────────────────┐
                    │      RequestParser            │
                    │  ┌─────────────────────────┐  │
                    │  │ LLM Mode (Ollama/OpenAI)│  │ ◄── Primary (if configured)
                    │  └───────────┬─────────────┘  │
                    │              │ fallback       │
                    │  ┌───────────▼─────────────┐  │
                    │  │   Regex Mode            │  │ ◄── Fallback (always works)
                    │  └─────────────────────────┘  │
                    └───────────────┬───────────────┘
                                    │
                                    ▼
                    ParsedRideRequest:
                    - pickup: "Connaught Place"
                    - dropoff: "airport"  
                    - priority: "speed"
                    - max_price: 400

Regex Algorithm (No LLM Required)

1. Location Extraction

# Pattern: "from X to Y"
r"from\s+(.+?)\s+to\s+(.+?)(?:\.|,|$|prioritize|keep|under)"

# Input: "from Connaught Place to the airport"
# Output: pickup="Connaught Place", dropoff="airport"

2. Priority Detection

# Speed keywords: ["prioritize speed", "fastest", "quick", "asap", "urgent"]
# Cost keywords: ["cheapest", "lowest price", "budget", "cheap"]

# "Prioritize speed" → priority="speed"
# "cheapest option" → priority="cost"
# Default → priority="balanced"

3. Price Constraint Extraction

# Patterns:
r"under\s*(?:rs\.?|inr|₹)?\s*(\d+)"   # "under 400"
r"keep\s+it\s+under\s*(\d+)"           # "keep it under 400"
r"budget\s*(?:of|is)?\s*(\d+)"         # "budget 500"

# "keep it under 400" → max_price=400

4. Provider Exclusion

# Pattern:
r"(?:no|exclude|avoid|skip)\s+(uber|ola|rapido|indrive)"

# "no rapido" → excluded_providers=["rapido"]

LLM Mode (Optional)

When Ollama or OpenAI is configured, uses structured prompting:

SYSTEM_PROMPT = """Extract from natural language:
- pickup_address: starting location
- dropoff_address: destination
- priority: "speed", "cost", or "balanced"
- max_price: budget limit in INR
- excluded_providers: list of providers to avoid

Return valid JSON."""

Why Dual Mode?

Mode Pros Cons
Regex No API needed, fast, deterministic Limited to known patterns
LLM Handles typos, variations, complex sentences Requires setup, slower

The system tries LLM first, automatically falls back to regex if unavailable.

How It Works

  1. NLP Parsing: User input is parsed using the dual-mode parser to extract pickup, dropoff, priority, and constraints.

  2. Geolocation: Addresses are converted to lat/lng coordinates using Nominatim (free) or Google Maps API.

  3. Parallel Scraping: Playwright launches headless browsers to scrape fare estimates from all providers simultaneously.

  4. Negotiation: For InDrive, calculates the average price from other providers and submits a counter-offer (85% of average).

  5. Decision Matrix: Ranks options using weighted scoring based on user priority:

    • Speed priority: 70% ETA weight, 20% price weight
    • Cost priority: 20% ETA weight, 70% price weight
    • Balanced: 50/50 split
  6. Notification: Generates a deep link for the recommended option and displays/sends the recommendation.

Scraping Notes

Note on Architecture: This project utilizes local Playwright browser automation to circumvent restricted production APIs. While functional in a local residential environment, production deployment would transition to a dedicated API gateway using rotated residential proxies to bypass data-center IP blocking.

The scrapers use Playwright to simulate real browser interactions:

  • Launches headless Chromium with mobile user agent
  • Types addresses with human-like delays
  • Waits for DOM elements to load
  • Extracts prices from rendered HTML
  • Handles dynamic content and popups

Website selectors may need updates as platforms change their UI.

Limitations

  • Scraping depends on website structure (selectors may break)
  • Rate limiting may apply from provider websites
  • Actual booking requires manual confirmation via deep link
  • Surge pricing detection is approximate

Development

# Install dev dependencies
pip install -e ".[dev]"

# Run tests
pytest

# Type checking
mypy src/ride_aggregator

# Linting
ruff check src/

License

MIT

About

Compare ride fares across Uber, Ola, Rapido & InDrive. Built with LangGraph, FastAPI, and Playwright. Features distance-based fare estimates, priority-based ranking, and deep links for one-tap booking.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors