File size: 8,818 Bytes
135a99c 8dae95d 135a99c 9f014de 135a99c 9f014de 135a99c 8dae95d 135a99c | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 | """
Central config for the JanMat RAG chatbot backend.
Everything secret comes from the environment (HF Space repository secrets in
prod, .env locally — see .env.example). Nothing here should hold a real key.
"""
import os
from dotenv import load_dotenv
load_dotenv() # harmless no-op if you never create a .env file
import os
from dotenv import load_dotenv
load_dotenv() # harmless no-op if you never create a .env file — see note below
# ==============================================================================
# All secrets are read from environment variables, NEVER hardcoded here.
# This file is safe to commit to GitHub (public or private) as-is.
#
# Where the environment variables actually come from depends on where you run:
# - Locally: `export SUPABASE_URL="..."` etc. in your terminal before running
# `python main.py` (see MIGRATION_GUIDE.md for the exact commands).
# - Hugging Face Space: Settings -> Variables and secrets -> add each one
# under "Secrets". HF injects them as environment variables automatically
# at runtime — nothing in this file needs to change.
# ==============================================================================
# --- Supabase (knowledge base + chat history) --------------------------------
SUPABASE_URL = os.getenv("SUPABASE_URL", "")
SUPABASE_SERVICE_KEY = os.getenv("SUPABASE_SERVICE_KEY", "") # service_role key, backend-only
# --- Groq (answer generation) -------------------------------------------------
GROQ_API_KEY = os.getenv("GROQ_API_KEY", "")
GROQ_CHAT_MODEL = os.getenv("GROQ_CHAT_MODEL", "openai/gpt-oss-20b")
# --- Sarvam AI (voice: speech-to-text + text-to-speech) -----------------------
SARVAM_API_KEY = os.getenv("SARVAM_API_KEY", "")
SARVAM_STT_MODEL = os.getenv("SARVAM_STT_MODEL", "saaras:v3")
SARVAM_TTS_MODEL = os.getenv("SARVAM_TTS_MODEL", "bulbul:v3")
SARVAM_DEFAULT_SPEAKER = os.getenv("SARVAM_DEFAULT_SPEAKER", "anushka")
SARVAM_DEFAULT_LANGUAGE = os.getenv("SARVAM_DEFAULT_LANGUAGE", "en-IN")
# --- TinyFish (live web: Search, Fetch, Agent) -------------------------------
# Optional. Leave unset and JanMat behaves exactly as before.
TINYFISH_API_KEY = os.getenv("TINYFISH_API_KEY", "")
# --- Cron / admin protection ---------------------------------------------------
CRON_SECRET = os.getenv("CRON_SECRET", "")
# --- Embedding model (local, free, no API key needed) -------------------------
EMBEDDING_MODEL_NAME = os.getenv("EMBEDDING_MODEL_NAME", "sentence-transformers/all-MiniLM-L6-v2")
EMBEDDING_DIM = 384
# --- Chunking -------------------------------------------------------------------
CHUNK_WORDS = int(os.getenv("CHUNK_WORDS", "220"))
CHUNK_OVERLAP_WORDS = int(os.getenv("CHUNK_OVERLAP_WORDS", "40"))
# --- Retrieval / generation -------------------------------------------------------
# Broader than a typical minimal RAG setup: more candidate chunks per query,
# and a larger context budget, so answers draw on more of the ingested
# material per question rather than a bare top-5. Still cheap — this is a
# few dozen KB of text per Groq call, not the whole knowledge base.
TOP_K_CHUNKS = int(os.getenv("TOP_K_CHUNKS", "20"))
MAX_CONTEXT_CHARS = int(os.getenv("MAX_CONTEXT_CHARS", "20000"))
# --- Sources to ingest ------------------------------------------------------------
CONFIG = {
"prs": {
"name": "PRS Legislative Research",
"base_url": "https://prsindia.org",
"listing_url": "https://prsindia.org/billtrack",
"bill_link_pattern": r"^/billtrack/[^/]+$",
"bill_link_exclude_prefixes": ("/billtrack/category/", "/billtrack/field_bill_category/"),
"rate_limit_seconds": 2,
# Rolling window: JanMat keeps the newest N bills (PRS lists newest first). Each ingestion
# adds any new bills and then deletes the oldest ones beyond N, with their PDFs and text.
"max_bills_kept": 25,
"listing_pages": 6, # how many ?page=N listing pages to read to find N bills
"delete_comments_with_bill": False, # True = also delete user comments on bills that rotate out
"license_note": (
"PRS's disclaimer permits reproduction for non-commercial purposes "
"with due acknowledgement of PRS Legislative Research."
),
},
# The rest of the PRS website (everything beyond the first page of bills).
# The crawler visits each section's index pages (following ?page=N pagination),
# collects links whose path matches `item_pattern`, and ingests each page plus
# any PDFs it links to. Add or remove sections freely.
"prs_library": {
"enabled": True,
# Each run ingests at most this many NEW documents, then stops. Documents
# already stored are skipped without being fetched, so just click
# "Run ingestion now" repeatedly and the library grows until it is complete.
# (Free Supabase = 500 MB; roughly 4 KB per chunk, ~100 chunks per document.)
"max_new_docs_per_run": 60,
"max_index_pages": 5, # pagination depth per index URL
"sections": [
{"key": "policy_review", "label": "Policy Reviews",
"index_urls": ["https://prsindia.org/policy/monthly-policy-review",
"https://prsindia.org/policy/annual-policy-review"],
"item_pattern": r"^/policy/(monthly|annual)-policy-review/[^/]+$"},
{"key": "committee_report", "label": "Committee Reports",
"index_urls": ["https://prsindia.org/policy/report-summaries",
"https://prsindia.org/parliamenttrack/report-summaries"],
"item_pattern": r"^/(policy|parliamenttrack)/report-summaries/[^/]+$"},
{"key": "session", "label": "Session Wraps",
"index_urls": ["https://prsindia.org/sessiontrack"],
"item_pattern": r"^/sessiontrack/[^/]+(/[^/]+)?$"},
{"key": "discussion_paper", "label": "Discussion Papers",
"index_urls": ["https://prsindia.org/policy/discussion-papers",
"https://prsindia.org/legislatures/discussion-papers",
"https://prsindia.org/budgets/discussionpapers"],
"item_pattern": r"^/(policy|legislatures|budgets)/(discussion-papers|discussionpapers)/[^/]+$"},
{"key": "blog", "label": "Blog",
"index_urls": ["https://prsindia.org/theprsblog"],
"item_pattern": r"^/theprsblog/(?!blog-author)[^/]+$"},
{"key": "article", "label": "Articles",
"index_urls": ["https://prsindia.org/articles-by-prs-team/2026",
"https://prsindia.org/articles-by-prs-team/2025",
"https://prsindia.org/articles-by-prs-team/2024"],
"item_pattern": r"^/articles-by-prs-team/(?!\d{4}$)[^/]+$"},
{"key": "act", "label": "Acts",
"index_urls": ["https://prsindia.org/acts/parliament", "https://prsindia.org/recent-acts"],
"item_pattern": r"^/(acts/[^/]+|recent-acts)/[^/]+$"},
{"key": "state_bill", "label": "State Bills",
"index_urls": ["https://prsindia.org/bills/states",
"https://prsindia.org/bills/state-legislative-briefs"],
"item_pattern": r"^/bills/(states|state-legislative-briefs)/[^/]+$"},
{"key": "budget", "label": "Budgets",
"index_urls": ["https://prsindia.org/budgets/parliament", "https://prsindia.org/budgets/states"],
"item_pattern": r"^/budgets/(parliament|states)/[^/]+$"},
],
# "Comments invited on ..." notices (bill name, deadline, link to submit).
"announcement_urls": ["https://prsindia.org/", "https://prsindia.org/announcements"],
},
# Add more sources here as plain "seed URL lists" — the ingestion pipeline
# treats any HTTP(S) URL the same way: fetch, detect PDF vs HTML, extract
# full text, chunk, embed, store. See scraper.py:ArticleSource.
# Used only when TINYFISH_API_KEY is set.
"tinyfish": {
# Search API: finds drafts / news / stakeholder reactions beyond PRS.
"search_queries": [
"draft bill public consultation stakeholder comments India",
"Ministry of Corporate Affairs draft amendment comments invited",
],
"results_per_query": 5,
# Agent API: pages whose public comments should be extracted. Add the
# consultation pages you are allowed to read (e.g. MCA draft pages).
"consultation_urls": [],
# Also run the agent on this many PRS bill pages per run (Agent runs are billed).
"agent_max_bill_pages": 3,
},
"article_seed_urls": [
# "https://example-news-site.com/article-about-a-bill",
],
}
|