Build · 3h 20m · ₹0

A forensic analytics platform that detects patterns of systemic neglect in civic complaints, scoring silence metrics (0–100) and pairing Qdrant semantic search with Gemini 2.5 Flash conversational chart generation.

Gemini 2.5 + Qdrant + Flask + Sentence-Transformers + Chart.jssecond buildBy LogixLoopsLive demo \

What it does

The mechanics, data flow, and user interaction model behind SENTINEL.

Every complaint gets scored on a 0–100 'Silence Score' derived from days pending, ignored follow-ups, dismissed escalation attempts, and category-level historical neglect rates. Scores above 70 flag likely systematic silencing. On top of that, a conversational AI agent (Gemini 2.5 Flash, with semantic search over 10,000+ records via Qdrant and BAAI/bge-small-en-v1.5 embeddings) lets investigators ask natural-language questions ('which wards have the highest silence rates?') and get back both an evidence-grounded answer and an interactive Chart.js visualization, with session memory persisted directly in the vector store.

Technical Highlights

  • Multi-dimensional bias scoring: demographic, ward-level geographic, category, and temporal decay combined into an interpretable 0–100 Silence Score
  • Semantic search across 10,000+ complaint records using Qdrant vector database + BAAI/bge-small-en-v1.5 embeddings
  • Conversational forensic agent powered by Gemini 2.5 Flash that synthesizes answers and generates dynamic Chart.js configurations on the fly
  • Persistent multi-turn chat memory stored directly within vector collections without needing an external session cache
  • 13-endpoint Flask REST API cleanly decoupling high-throughput analytical queries from conversational inference

Why it matters

The architectural judgment, practical engineering decisions, and core problems solved.

Institutional bias in complaint-handling is usually invisible precisely because it's diffuse — no single decision looks discriminatory, but aggregate patterns reveal severe demographic, geographic, and temporal disparities. A forensic tool that quantifies 'silence' as an objective, measurable score and lets non-technical oversight teams interrogate datasets conversationally rather than writing complex SQL transforms accountability workflows. Validated against synthetic ground truth (10,000+ records with injected bias distributions) before real-world deployment, ensuring the methodology is provably sound.

01

Civic tech & municipal ombudsman oversight for tracking equitable public service delivery across city wards

02

Consumer protection bureaus auditing complaint resolution delays by vendor category and socioeconomic tier

03

University & institutional grievance committees spotting systemic reporting bottlenecks and unaddressed escalations

04

Methodological baseline for auditing public algorithmic decision-making and administrative intake fairness

System architecture

End-to-end execution pipeline running across Gemini 2.5, Qdrant, Flask, Sentence-Transformers, Chart.js.

01 / ScoringSilence Engine

Calculates 0–100 Silence Score from days pending, missed escalations, and category neglect priors

02 / Embeddingsbge-small-en-v1.5

Transforms complaint narratives and resolution logs into 384-dim dense semantic vectors

03 / RetrievalQdrant Vector DB

Performs cosine similarity search + demographic metadata payload filtering across 10,000+ records

04 / SynthesisGemini 2.5 Flash

Conversational forensic reasoning, evidence cross-referencing, and dynamic Chart.js JSON schema generation

05 / DeliveryFlask API & Chart.js

13-endpoint analytical backend serving interactive forensic dashboards and visualization canvases

The path

Step-by-step implementation guide. Verbatim code snippets, configurations, and prompts.

01

Mathematical Formulation of the Silence Score Metric

Implement the core scoring algorithm weighting unresolved duration, escalation count, ignored messages, and category-level decay rates into a normalized 0–100 score.

Verbatim Code / Config

def calculate_silence_score(row: dict) -> float:
    # Formula: w1*days_pending_norm + w2*escalations_norm + w3*ignored_replies_norm + w4*category_penalty
    # Normalize to [0, 100]. Flag score >= 70.0 as 'HIGH_RISK_SYSTEMIC_SILENCE'
02

Vectorizing Narratives with Qdrant and BGE Embeddings

Embed 10,000+ complaint records using fast Sentence-Transformers bge-small-en-v1.5 and index them into Qdrant collections with rich payload schemas for ward and demographic filters.

Verbatim Code / Config

qdrant.create_collection(
    collection_name='civic_complaints',
    vectors_config=VectorParams(size=384, distance=Distance.COSINE)
)
# Upload points with payload: {ward: int, category: str, silence_score: float, text: str}
03

Gemini 2.5 Flash Chart Generation Tool Schema

Equip Gemini 2.5 Flash with structured output schemas to generate both natural-language forensic analysis and structured Chart.js configuration objects (type, labels, datasets, options).

Verbatim Code / Config

class ForensicResponse(BaseModel):
    analysis: str
    evidence_ids: list[str]
    chart_type: Literal['bar', 'line', 'pie', 'none']
    chart_config: Optional[dict] = None
# Force Gemini to return valid JSON conforming to ForensicResponse
04

Flask Analytical API & Vector Session Memory

Build the 13-endpoint Flask backend handling faceted analytical filtering (demographic, geographic, temporal) and writing user conversation histories into Qdrant for semantic recall.

Verbatim Code / Config

@app.route('/api/chat', methods=['POST'])
def chat():
    query = request.json.get('query')
    history = qdrant.get_chat_history(session_id)
    context = qdrant.similarity_search(query, filter={'silence_score': {'gte': 70}})
    return jsonify(gemini_agent.query(query, context, history))

Where it broke

The failure mode, root-cause breakdown, and resolution discovered during development.

The Tell

The conversational agent frequently hallucinated ward-level totals by summing raw search samples rather than querying complete database aggregations.

Why it failed

Semantic search retrieves top-k relevant complaints (e.g. k=20), which the LLM mistook for the global count across the entire ward, claiming 'Ward 4 has only 12 complaints total'.

The Fix

Separated macro statistical aggregation from semantic narrative retrieval. The agent now calls a deterministic 'get_ward_statistics()' tool for exact counts and percentages, using semantic retrieval strictly for qualitative context and evidence quotes.

What it cost

₹0 to build and run permanently within verified free tiers.

Cost breakdown & free tier limits
Service / ToolCostFree Tier Limits
Google Gemini 2.5 Flash₹0Free tier (15 RPM / 1M TPM) covers all conversational queries
Qdrant Cloud / Local₹0Free 1GB cluster / open-source local Docker container
BAAI/bge-small-en-v1.5₹0Open-source Hugging Face embedding model runs locally on CPU
Flask & Chart.js₹0Open-source Python web server and JavaScript visualization library
Synthetic Data Generator₹0Custom Python script producing 10,000+ benchmark records

Make it yours

Three concrete variations you can build and ship using this exact foundation.

  • 01

    Tenant Rights & Housing Violation Auditor: Analyzes municipal code enforcement records to detect systemic delays in low-income rental inspection requests.

  • 02

    Public Transit Reliability Investigator: Correlates bus cancellation rates and service alerts with neighborhood income and density metrics.

  • 03

    Hospital Patient Feedback Disparity Tracker: Analyzes healthcare service reviews and clinical grievance resolutions across language and insurance barriers.

Where next

Ready to ship SENTINEL?

Review the architecture, clone the prompt and implementation steps, and deploy your live URL for ₹0.