SeriousSam07 commited on
Commit
f26ea36
·
0 Parent(s):

Upgrade: Nyaya Agent 2.0 - Judicial Lockdown, Aura Themes, and Export Suite

Browse files
.gitignore ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Environments
2
+ .env
3
+ .venv/
4
+ __pycache__/
5
+ *.pyc
6
+
7
+ # Local Data
8
+ data/
9
+ chroma/
10
+ *.db
11
+
12
+ # Logs
13
+ *.log
14
+
15
+ # Docker/Podman local files
16
+ .dockerignore
17
+ docker-compose.yml
Dockerfile ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.11-slim
2
+
3
+ # Create a non-root user for Hugging Face security
4
+ RUN useradd -m -u 1000 user
5
+ USER user
6
+ ENV PATH="/home/user/.local/bin:$PATH"
7
+
8
+ WORKDIR /app
9
+
10
+ # Switch to root temporarily to install system packages
11
+ USER root
12
+ RUN apt-get update && apt-get install -y \
13
+ build-essential \
14
+ && rm -rf /var/lib/apt/lists/*
15
+
16
+ # Switch back to the non-root user
17
+ USER user
18
+
19
+ # Copy project files and set ownership
20
+ COPY --chown=user . .
21
+
22
+ # Install dependencies
23
+ RUN pip install --no-cache-dir chromadb pypdf google-genai[embeddings] python-dotenv fastapi uvicorn pydantic-settings python-multipart
24
+
25
+ # Expose port (Hugging Face uses 7860)
26
+ EXPOSE 7860
27
+
28
+ # Command to run the application
29
+ CMD ["python", "server.py"]
README.md ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: Nyaya Agent Legal Platform
3
+ emoji: 🏛️
4
+ colorFrom: yellow
5
+ colorTo: gray
6
+ sdk: docker
7
+ pinned: false
8
+ app_port: 7860
9
+ ---
10
+
11
+ # 🏛️ Nyaya Agent: Premium Legal AI Platform
12
+
13
+ A glassmorphic, persona-aware legal assistant for the Indian Judiciary.
14
+
15
+ ## Features:
16
+ - **⚖️ BNS-IPC Bridge**: Instant mapping of IPC sections to Bharatiya Nyaya Sanhita 2023.
17
+ - **🛡️ DPDPA Audit**: Automated Privacy Policy compliance auditing.
18
+ - **🔍 Case Network**: Live judgments and legal research via Indian Kanoon.
19
+ - **📜 Document Drafting**: RTI and Legal Notice automation.
20
+
21
+ ## Deployment:
22
+ This app is hosted as a Docker container. API Keys are managed via Space Secrets.
app.py ADDED
@@ -0,0 +1,53 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import sys
2
+ import os
3
+
4
+ # Add the current directory to path for imports
5
+ sys.path.append(os.getcwd())
6
+
7
+ from core.agent import NyayaAgent
8
+ from tools.search_tool import search_indian_kanoon, get_act_details, search_legal_documents
9
+ from tools.legal_tools import draft_rti_query, draft_legal_notice, analyze_case_summary, suggest_sc_followup
10
+ from tools.compliance import audit_privacy_policy
11
+ from tools.law_bridge import ipc_to_bns_lookup
12
+ from google.genai import types
13
+
14
+ def main():
15
+ print("--- Nyaya Agent: Indian Legal Assistant ---")
16
+ print("Type 'exit' to quit.\n")
17
+
18
+ agent = NyayaAgent()
19
+
20
+ # Define tools for function calling
21
+ tools = [
22
+ search_indian_kanoon,
23
+ get_act_details,
24
+ search_legal_documents,
25
+ draft_rti_query,
26
+ draft_legal_notice,
27
+ analyze_case_summary,
28
+ suggest_sc_followup,
29
+ audit_privacy_policy,
30
+ ipc_to_bns_lookup
31
+ ]
32
+
33
+ config = types.GenerateContentConfig(
34
+ system_instruction=agent.system_instruction,
35
+ tools=tools,
36
+ temperature=0.2,
37
+ )
38
+
39
+ while True:
40
+ user_input = input("You: ")
41
+ if user_input.lower() in ['exit', 'quit']:
42
+ break
43
+
44
+ try:
45
+ # Using the agent's wrapper which includes retry logic
46
+ response_text = agent.generate_response(user_input, config=config)
47
+ print(f"\nNyaya Agent: {response_text}")
48
+
49
+ except Exception as e:
50
+ print(f"An error occurred: {e}")
51
+
52
+ if __name__ == "__main__":
53
+ main()
backups/v1_production/Dockerfile ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.11-slim
2
+
3
+ # Create a non-root user for Hugging Face security
4
+ RUN useradd -m -u 1000 user
5
+ USER user
6
+ ENV PATH="/home/user/.local/bin:$PATH"
7
+
8
+ WORKDIR /app
9
+
10
+ # Switch to root temporarily to install system packages
11
+ USER root
12
+ RUN apt-get update && apt-get install -y \
13
+ build-essential \
14
+ && rm -rf /var/lib/apt/lists/*
15
+
16
+ # Switch back to the non-root user
17
+ USER user
18
+
19
+ # Copy project files and set ownership
20
+ COPY --chown=user . .
21
+
22
+ # Install dependencies
23
+ RUN pip install --no-cache-dir chromadb pypdf google-genai[embeddings] python-dotenv fastapi uvicorn pydantic-settings python-multipart
24
+
25
+ # Expose port (Hugging Face uses 7860)
26
+ EXPOSE 7860
27
+
28
+ # Command to run the application
29
+ CMD ["python", "server.py"]
backups/v1_production/app.py ADDED
@@ -0,0 +1,53 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import sys
2
+ import os
3
+
4
+ # Add the current directory to path for imports
5
+ sys.path.append(os.getcwd())
6
+
7
+ from core.agent import NyayaAgent
8
+ from tools.search_tool import search_indian_kanoon, get_act_details, search_legal_documents
9
+ from tools.legal_tools import draft_rti_query, draft_legal_notice, analyze_case_summary, suggest_sc_followup
10
+ from tools.compliance import audit_privacy_policy
11
+ from tools.law_bridge import ipc_to_bns_lookup
12
+ from google.genai import types
13
+
14
+ def main():
15
+ print("--- Nyaya Agent: Indian Legal Assistant ---")
16
+ print("Type 'exit' to quit.\n")
17
+
18
+ agent = NyayaAgent()
19
+
20
+ # Define tools for function calling
21
+ tools = [
22
+ search_indian_kanoon,
23
+ get_act_details,
24
+ search_legal_documents,
25
+ draft_rti_query,
26
+ draft_legal_notice,
27
+ analyze_case_summary,
28
+ suggest_sc_followup,
29
+ audit_privacy_policy,
30
+ ipc_to_bns_lookup
31
+ ]
32
+
33
+ config = types.GenerateContentConfig(
34
+ system_instruction=agent.system_instruction,
35
+ tools=tools,
36
+ temperature=0.2,
37
+ )
38
+
39
+ while True:
40
+ user_input = input("You: ")
41
+ if user_input.lower() in ['exit', 'quit']:
42
+ break
43
+
44
+ try:
45
+ # Using the agent's wrapper which includes retry logic
46
+ response_text = agent.generate_response(user_input, config=config)
47
+ print(f"\nNyaya Agent: {response_text}")
48
+
49
+ except Exception as e:
50
+ print(f"An error occurred: {e}")
51
+
52
+ if __name__ == "__main__":
53
+ main()
backups/v1_production/core/agent.py ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ from google import genai
3
+ from google.genai import types
4
+ from dotenv import load_dotenv
5
+
6
+ load_dotenv(override=True)
7
+
8
+ class NyayaAgent:
9
+ def __init__(self, model_id='gemini-flash-lite-latest'):
10
+ self.client = genai.Client(api_key=os.getenv("GEMINI_API_KEY"))
11
+ self.model_id = model_id
12
+ self.system_instruction = (
13
+ "You are 'Nyaya Agent', a specialized Legal & Judiciary Assistant for the Indian Legal System. "
14
+ "You serve Citizens, Law Students, and Lawyers. Your tone and technicality must adapt based on the user's background.\n\n"
15
+ "ADAPTATION RULES:\n"
16
+ "1. CITIZEN/NON-PROFESSIONAL: Use simple language, avoid jargon, and explain concepts like 'Writ' or 'Affidavit'. Always suggest drafting an RTI query if they need data from a government body.\n"
17
+ "2. LAW STUDENT: Provide technical details, refer to specific case precedents (e.g., Kesavananda Bharati), and suggest checking the latest Supreme Court filings.\n"
18
+ "3. LAWYER/PROFESSIONAL: Provide high-technicality analysis, cite specific Acts/Sections (IPC, BNS, etc.), and discuss procedural nuances.\n\n"
19
+ "MANDATORY GUIDELINES:\n"
20
+ "- Be proactive: If a query involves government inaction or data, suggest an RTI.\n"
21
+ "- If a query involves a complex constitutional point, suggest checking Supreme Court updates.\n"
22
+ "- Be precise and refer to specific sections of Indian Acts/Statutes.\n"
23
+ "- BE GUIDED BY TRUTH: Your underlying principle is 'Satyameva Jayate' (Truth alone triumphs). Ensure your research is accurate and evidence-based.\n"
24
+ "- DO NOT provide definitive legal advice; clarify that you are a research assistant."
25
+ )
26
+
27
+ def generate_response(self, prompt, config=None):
28
+ import time
29
+ max_retries = 5
30
+ retry_delay = 10 # Increased delay for free tier stability
31
+
32
+ if config is None:
33
+ config = types.GenerateContentConfig(
34
+ system_instruction=self.system_instruction,
35
+ temperature=0.2,
36
+ )
37
+
38
+ for attempt in range(max_retries):
39
+ try:
40
+ response = self.client.models.generate_content(
41
+ model=self.model_id,
42
+ contents=prompt,
43
+ config=config
44
+ )
45
+ return response.text
46
+ except Exception as e:
47
+ if "503" in str(e) or "429" in str(e):
48
+ if attempt < max_retries - 1:
49
+ print(f"\n[System] Gemini is busy. Retrying in {retry_delay}s... (Attempt {attempt + 1}/{max_retries})", flush=True)
50
+ time.sleep(retry_delay)
51
+ retry_delay *= 2 # Exponential backoff
52
+ continue
53
+ raise e
54
+
55
+ if __name__ == "__main__":
56
+ # Quick test
57
+ agent = NyayaAgent()
58
+ print(agent.generate_response("Introduce yourself briefly."))
backups/v1_production/frontend/index.html ADDED
@@ -0,0 +1,116 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Nyaya Agent | Indian Legal Assistant</title>
7
+ <link rel="stylesheet" href="style.css">
8
+ <!-- Google Fonts -->
9
+ <link href="https://fonts.googleapis.com/css2?family=Playfair+Display:wght@700&family=Inter:wght@300;400;600&display=swap" rel="stylesheet">
10
+ <!-- Lucide Icons -->
11
+ <script src="https://unpkg.com/lucide@latest"></script>
12
+ <!-- Marked.js for Markdown -->
13
+ <script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
14
+ </head>
15
+ <body>
16
+ <!-- Onboarding Overlay -->
17
+ <div id="onboarding-overlay" class="onboarding-container glass">
18
+ <div class="onboarding-card">
19
+ <h2 class="playfair">Welcome to Nyaya</h2>
20
+ <p class="onboarding-sub">सत्यमेव जयते</p>
21
+ <p class="instruction">To provide the most accurate legal assistance, please select your profile:</p>
22
+
23
+ <div class="persona-grid">
24
+ <button class="persona-btn" data-persona="lawyer">
25
+ <i data-lucide="briefcase"></i>
26
+ <span>Lawyer / Judge</span>
27
+ <small>High Technicality & Procedural Analysis</small>
28
+ </button>
29
+ <button class="persona-btn" data-persona="student">
30
+ <i data-lucide="graduation-cap"></i>
31
+ <span>Law Student</span>
32
+ <small>Landmark Cases & Legal Theory</small>
33
+ </button>
34
+ <button class="persona-btn" data-persona="citizen">
35
+ <i data-lucide="user"></i>
36
+ <span>Citizen</span>
37
+ <small>Simple Language & RTI Support</small>
38
+ </button>
39
+ <button class="persona-btn" data-persona="explorer">
40
+ <i data-lucide="compass"></i>
41
+ <span>Explorer</span>
42
+ <small>History & System Overview</small>
43
+ </button>
44
+ </div>
45
+ </div>
46
+ </div>
47
+
48
+ <div class="app-container blur-background">
49
+ <!-- Sidebar -->
50
+ <aside class="sidebar glass">
51
+ <div class="logo-section">
52
+ <div class="legal-tech-logo">
53
+ <i data-lucide="scale" class="gold-icon scales"></i>
54
+ <i data-lucide="pen-tool" class="gold-icon pen"></i>
55
+ </div>
56
+ <h1 class="playfair">Nyaya</h1>
57
+ </div>
58
+ <nav class="nav-menu">
59
+ <button class="nav-item active" data-tool="chat"><i data-lucide="message-square"></i> Legal Chat</button>
60
+ <button class="nav-item" data-tool="search"><i data-lucide="search"></i> Case Search</button>
61
+ <button class="nav-item" data-tool="notice"><i data-lucide="file-text"></i> Draft Notice</button>
62
+ <button class="nav-item" data-tool="rti"><i data-lucide="scroll"></i> RTI Portal</button>
63
+ <button class="nav-item" data-tool="compliance"><i data-lucide="shield-check"></i> Compliance Audit</button>
64
+ <button class="nav-item" data-tool="bridge"><i data-lucide="git-branch"></i> Law Bridge</button>
65
+ <button class="nav-item switch-profile" id="switch-btn"><i data-lucide="user-cog"></i> Switch Profile</button>
66
+ </nav>
67
+ <div class="motto-section">
68
+ <div id="motto-container">
69
+ <p class="motto" id="motto-text">सत्यमेव जयते</p>
70
+ <span class="motto-en" id="motto-lang">HINDI</span>
71
+ </div>
72
+ </div>
73
+ </aside>
74
+
75
+ <!-- Main Content -->
76
+ <main class="main-content">
77
+ <header class="top-bar glass">
78
+ <div class="status-indicator">
79
+ <span class="dot online"></span>
80
+ <span>Judicial Network Online</span>
81
+ </div>
82
+ <div class="user-profile">
83
+ <i data-lucide="user" class="profile-icon"></i>
84
+ <span id="profile-status">Professional Dashboard</span>
85
+ </div>
86
+ </header>
87
+
88
+ <div class="chat-wrapper">
89
+ <div id="chat-messages" class="chat-container">
90
+ <div class="message system glass">
91
+ <p>Greetings. I am <strong>Nyaya Agent</strong>. I am ready to assist with your legal research, drafting, or compliance queries.</p>
92
+ </div>
93
+ </div>
94
+
95
+ <div class="input-area glass">
96
+ <input type="file" id="file-upload" style="display: none;" accept=".pdf,.txt">
97
+ <button id="attach-btn" class="icon-btn" title="Attach Document">
98
+ <i data-lucide="paperclip"></i>
99
+ </button>
100
+ <input type="text" id="user-input" placeholder="Enter your legal query here..." autocomplete="off">
101
+ <button id="send-btn" class="gold-btn">
102
+ <i data-lucide="gavel"></i>
103
+ <span>Execute</span>
104
+ </button>
105
+ </div>
106
+ </div>
107
+ </main>
108
+ </div>
109
+
110
+ <script src="script.js"></script>
111
+ <script>
112
+ // Initialize icons
113
+ lucide.createIcons();
114
+ </script>
115
+ </body>
116
+ </html>
backups/v1_production/frontend/script.js ADDED
@@ -0,0 +1,221 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // API Configuration
2
+ const API_BASE_URL = '/api';
3
+ let userPersona = 'explorer'; // Default
4
+
5
+ const chatMessages = document.getElementById('chat-messages');
6
+ const userInput = document.getElementById('user-input');
7
+ const sendBtn = document.getElementById('send-btn');
8
+ const onboardingOverlay = document.getElementById('onboarding-overlay');
9
+ const appContainer = document.querySelector('.app-container');
10
+ const switchBtn = document.getElementById('switch-btn');
11
+ const profileStatus = document.getElementById('profile-status');
12
+ const attachBtn = document.getElementById('attach-btn');
13
+ const fileUpload = document.getElementById('file-upload');
14
+
15
+ // Handle File Upload
16
+ attachBtn.addEventListener('click', () => fileUpload.click());
17
+
18
+ fileUpload.addEventListener('change', async (e) => {
19
+ const file = e.target.files[0];
20
+ if (!file) return;
21
+
22
+ addMessage(`Uploading ${file.name}...`, 'user');
23
+
24
+ const formData = new FormData();
25
+ formData.append('file', file);
26
+
27
+ try {
28
+ const response = await fetch(`${API_BASE_URL}/upload`, {
29
+ method: 'POST',
30
+ body: formData
31
+ });
32
+
33
+ const data = await response.json();
34
+ if (data.text) {
35
+ userInput.value = `Audit this document: \n\n ${data.text.substring(0, 1000)}...`;
36
+ addMessage(`Document ${file.name} processed. I have extracted the text. Click Execute to start the audit.`, 'system');
37
+ }
38
+ } catch (err) {
39
+ addMessage(`Error uploading file: ${err.message}`, 'system');
40
+ }
41
+ });
42
+ document.querySelectorAll('.persona-btn').forEach(btn => {
43
+ btn.addEventListener('click', () => {
44
+ userPersona = btn.getAttribute('data-persona');
45
+ console.log('Selected Persona:', userPersona);
46
+
47
+ // Hide onboarding and remove blur
48
+ onboardingOverlay.style.display = 'none';
49
+ appContainer.classList.remove('blur-background');
50
+
51
+ // Update top bar status
52
+ profileStatus.innerText = userPersona.charAt(0).toUpperCase() + userPersona.slice(1) + " Dashboard";
53
+
54
+ addMessage(`Welcome! You are now connected as a **${userPersona.toUpperCase()}**. How can I help you navigate the legal system today?`, 'system');
55
+ });
56
+ });
57
+
58
+ switchBtn.addEventListener('click', () => {
59
+ onboardingOverlay.style.display = 'flex';
60
+ appContainer.classList.add('blur-background');
61
+ });
62
+
63
+ // Motto Carousel Data
64
+ const mottos = [
65
+ { text: "सत्यमेव जयते", lang: "Hindi" },
66
+ { text: "সত্যমেব জয়তে", lang: "Bengali" },
67
+ { text: "सत्यमेव जयते", lang: "Marathi" },
68
+ { text: "సత్యమేవ జయతే", lang: "Telugu" },
69
+ { text: "சத்யமேவ ஜெயதே", lang: "Tamil" },
70
+ { text: "સત્યમેવ જયતે", lang: "Gujarati" },
71
+ { text: "ستیہ میو جیتے", lang: "Urdu" },
72
+ { text: "ಸತ್ಯಮೇವ ಜಯತೇ", lang: "Kannada" },
73
+ { text: "ସତ୍ୟମେବ ଜୟତେ", lang: "Odia" },
74
+ { text: "സത്യമേവ ജയതേ", lang: "Malayalam" }
75
+ ];
76
+
77
+ let currentMottoIndex = 0;
78
+ const mottoText = document.getElementById('motto-text');
79
+ const mottoLang = document.getElementById('motto-lang');
80
+
81
+ function updateMotto() {
82
+ mottoText.classList.add('fade-out');
83
+ mottoLang.classList.add('fade-out');
84
+
85
+ setTimeout(() => {
86
+ currentMottoIndex = (currentMottoIndex + 1) % mottos.length;
87
+ mottoText.innerText = mottos[currentMottoIndex].text;
88
+ mottoLang.innerText = mottos[currentMottoIndex].lang;
89
+
90
+ mottoText.classList.remove('fade-out');
91
+ mottoLang.classList.remove('fade-out');
92
+ }, 500);
93
+ }
94
+
95
+ setInterval(updateMotto, 4000); // Change every 4 seconds
96
+
97
+ function addMessage(text, sender) {
98
+ const msgDiv = document.createElement('div');
99
+ msgDiv.classList.add('message', sender, 'glass');
100
+
101
+ // Render Markdown using Marked.js
102
+ let formattedText = marked.parse(text);
103
+ msgDiv.innerHTML = formattedText;
104
+
105
+ // Action Button Detection (Proactive Agent Feature)
106
+ if (sender === 'system') {
107
+ const actionArea = document.createElement('div');
108
+ actionArea.classList.add('action-area');
109
+
110
+ if (text.toLowerCase().includes('rti query') || text.toLowerCase().includes('rti act')) {
111
+ const btn = createActionButton('scroll', 'Draft RTI Query', () => {
112
+ userInput.value = "Draft an RTI query for this matter.";
113
+ handleSendMessage();
114
+ });
115
+ actionArea.appendChild(btn);
116
+ }
117
+
118
+ if (text.toLowerCase().includes('legal notice')) {
119
+ const btn = createActionButton('file-text', 'Prepare Legal Notice', () => {
120
+ userInput.value = "Help me prepare a formal legal notice for this.";
121
+ handleSendMessage();
122
+ });
123
+ actionArea.appendChild(btn);
124
+ }
125
+
126
+ // New: Copy Draft Detection
127
+ if (text.includes('LEGAL NOTICE') || text.includes('Subject: Application under RTI') || text.includes('Facts:')) {
128
+ const btn = createActionButton('copy', 'Copy Draft', () => {
129
+ navigator.clipboard.writeText(text);
130
+ alert('Draft copied to clipboard! (Satyameva Jayate)');
131
+ });
132
+ actionArea.appendChild(btn);
133
+ }
134
+
135
+ if (actionArea.children.length > 0) {
136
+ msgDiv.appendChild(actionArea);
137
+ }
138
+ }
139
+
140
+ chatMessages.appendChild(msgDiv);
141
+ chatMessages.scrollTop = chatMessages.scrollHeight;
142
+ lucide.createIcons();
143
+ }
144
+
145
+ function createActionButton(icon, label, callback) {
146
+ const btn = document.createElement('button');
147
+ btn.classList.add('action-btn');
148
+ btn.innerHTML = `<i data-lucide="${icon}"></i> <span>${label}</span>`;
149
+ btn.onclick = callback;
150
+ return btn;
151
+ }
152
+
153
+ async function handleSendMessage() {
154
+ const text = userInput.value.trim();
155
+ if (!text) return;
156
+
157
+ // Add user message to UI
158
+ addMessage(text, 'user');
159
+ userInput.value = '';
160
+
161
+ // Show animated loading indicator
162
+ const loadingId = 'loading-' + Date.now();
163
+ const loadingDiv = document.createElement('div');
164
+ loadingDiv.id = loadingId;
165
+ loadingDiv.classList.add('message', 'system', 'glass', 'legal-loader');
166
+ loadingDiv.innerHTML = `
167
+ <div class="gavel-animate"><i data-lucide="gavel"></i></div>
168
+ <div class="loader-text">Order in the Court... Analyzing</div>
169
+ `;
170
+ chatMessages.appendChild(loadingDiv);
171
+ lucide.createIcons();
172
+
173
+ try {
174
+ const response = await fetch(`${API_BASE_URL}/chat`, {
175
+ method: 'POST',
176
+ headers: {
177
+ 'Content-Type': 'application/json'
178
+ },
179
+ body: JSON.stringify({
180
+ message: text,
181
+ persona: userPersona
182
+ })
183
+ });
184
+
185
+ const data = await response.json();
186
+
187
+ // Remove loading indicator
188
+ document.getElementById(loadingId).remove();
189
+
190
+ if (data.response) {
191
+ addMessage(data.response, 'system');
192
+ } else if (data.detail) {
193
+ addMessage(`Error: ${data.detail}`, 'system');
194
+ }
195
+ } catch (error) {
196
+ document.getElementById(loadingId).remove();
197
+ addMessage(`Connection Error: Could not reach the Judicial Network. Ensure the server is running.`, 'system');
198
+ console.error('API Error:', error);
199
+ }
200
+ }
201
+
202
+ sendBtn.addEventListener('click', handleSendMessage);
203
+
204
+ userInput.addEventListener('keypress', (e) => {
205
+ if (e.key === 'Enter') {
206
+ handleSendMessage();
207
+ }
208
+ });
209
+
210
+ // Sidebar Navigation
211
+ document.querySelectorAll('.nav-item').forEach(item => {
212
+ item.addEventListener('click', () => {
213
+ document.querySelectorAll('.nav-item').forEach(btn => btn.classList.remove('active'));
214
+ item.classList.add('active');
215
+
216
+ const tool = item.getAttribute('data-tool');
217
+ if (tool !== 'chat') {
218
+ addMessage(`Switched to **${tool.toUpperCase()}** module. Please enter your specific request.`, 'system');
219
+ }
220
+ });
221
+ });
backups/v1_production/frontend/style.css ADDED
@@ -0,0 +1,515 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ :root {
2
+ --advocate-black: #0d0d0d;
3
+ --sidebar-black: #141414;
4
+ --judicial-gold: #c5a059;
5
+ --gold-glow: rgba(197, 160, 89, 0.2);
6
+ --courtroom-maroon: #4a0e0e;
7
+ --parchment: #f5f5dc;
8
+ --glass: rgba(255, 255, 255, 0.05);
9
+ --glass-border: rgba(255, 255, 255, 0.1);
10
+ }
11
+
12
+ * {
13
+ margin: 0;
14
+ padding: 0;
15
+ box-sizing: border-box;
16
+ }
17
+
18
+ body {
19
+ font-family: 'Inter', sans-serif;
20
+ background-color: var(--advocate-black);
21
+ color: var(--parchment);
22
+ height: 100vh;
23
+ overflow: hidden;
24
+ }
25
+
26
+ .app-container {
27
+ display: flex;
28
+ height: 100%;
29
+ }
30
+
31
+ /* Glassmorphism Utility */
32
+ .glass {
33
+ background: var(--glass);
34
+ backdrop-filter: blur(12px);
35
+ -webkit-backdrop-filter: blur(12px);
36
+ border: 1px solid var(--glass-border);
37
+ }
38
+
39
+ /* Sidebar */
40
+ .sidebar {
41
+ width: 280px;
42
+ height: 100%;
43
+ background: var(--sidebar-black);
44
+ padding: 2rem;
45
+ display: flex;
46
+ flex-direction: column;
47
+ border-right: 1px solid var(--glass-border);
48
+ }
49
+
50
+ .logo-section {
51
+ display: flex;
52
+ align-items: center;
53
+ gap: 1.2rem;
54
+ margin-bottom: 3rem;
55
+ }
56
+
57
+ .legal-tech-logo {
58
+ position: relative;
59
+ width: 45px;
60
+ height: 45px;
61
+ }
62
+
63
+ .legal-tech-logo .scales {
64
+ position: absolute;
65
+ top: 0;
66
+ left: 0;
67
+ z-index: 2;
68
+ animation: balance 4s infinite ease-in-out;
69
+ }
70
+
71
+ .legal-tech-logo .pen {
72
+ position: absolute;
73
+ bottom: -5px;
74
+ right: -5px;
75
+ width: 20px;
76
+ height: 20px;
77
+ opacity: 0.8;
78
+ animation: write-glow 3s infinite ease-in-out;
79
+ }
80
+
81
+ @keyframes balance {
82
+ 0%, 100% { transform: rotate(-5deg); }
83
+ 50% { transform: rotate(5deg); }
84
+ }
85
+
86
+ @keyframes write-glow {
87
+ 0%, 100% { filter: drop-shadow(0 0 2px var(--judicial-gold)); opacity: 0.6; }
88
+ 50% { filter: drop-shadow(0 0 10px var(--judicial-gold)); opacity: 1; }
89
+ }
90
+
91
+ .playfair {
92
+ font-family: 'Playfair Display', serif;
93
+ font-size: 1.8rem;
94
+ color: var(--judicial-gold);
95
+ letter-spacing: 1px;
96
+ background: linear-gradient(
97
+ to right,
98
+ var(--judicial-gold) 20%,
99
+ #fff 40%,
100
+ var(--judicial-gold) 60%
101
+ );
102
+ background-size: 200% auto;
103
+ background-clip: text;
104
+ -webkit-background-clip: text;
105
+ -webkit-text-fill-color: transparent;
106
+ animation: shine 5s linear infinite;
107
+ }
108
+
109
+ @keyframes shine {
110
+ to { background-position: 200% center; }
111
+ }
112
+
113
+ .gold-icon {
114
+ color: var(--judicial-gold);
115
+ width: 32px;
116
+ height: 32px;
117
+ filter: drop-shadow(0 0 5px var(--gold-glow));
118
+ }
119
+
120
+ .nav-menu {
121
+ display: flex;
122
+ flex-direction: column;
123
+ gap: 0.5rem;
124
+ flex-grow: 1;
125
+ }
126
+
127
+ .nav-item {
128
+ background: transparent;
129
+ border: none;
130
+ color: rgba(245, 245, 220, 0.6);
131
+ padding: 1rem;
132
+ display: flex;
133
+ align-items: center;
134
+ gap: 1rem;
135
+ cursor: pointer;
136
+ border-radius: 8px;
137
+ transition: all 0.3s ease;
138
+ font-size: 0.95rem;
139
+ }
140
+
141
+ .nav-item i {
142
+ width: 18px;
143
+ }
144
+
145
+ .nav-item:hover, .nav-item.active {
146
+ background: var(--glass);
147
+ color: var(--judicial-gold);
148
+ border-left: 3px solid var(--judicial-gold);
149
+ }
150
+
151
+ .motto-section {
152
+ margin-top: auto;
153
+ text-align: center;
154
+ padding-top: 2rem;
155
+ border-top: 1px solid var(--glass-border);
156
+ }
157
+
158
+ .motto {
159
+ font-family: 'Playfair Display', serif;
160
+ font-size: 1.2rem;
161
+ color: var(--judicial-gold);
162
+ transition: opacity 0.5s ease-in-out;
163
+ }
164
+
165
+ .motto.fade-out {
166
+ opacity: 0;
167
+ }
168
+
169
+ .motto-en {
170
+ font-size: 0.7rem;
171
+ text-transform: uppercase;
172
+ letter-spacing: 2px;
173
+ opacity: 0.5;
174
+ transition: opacity 0.5s ease-in-out;
175
+ }
176
+
177
+ .motto-en.fade-out {
178
+ opacity: 0;
179
+ }
180
+
181
+ /* Main Content */
182
+ .main-content {
183
+ flex-grow: 1;
184
+ display: flex;
185
+ flex-direction: column;
186
+ min-height: 0; /* Ensures child flex containers can scroll */
187
+ background: radial-gradient(circle at top right, #1a0a0a, var(--advocate-black));
188
+ }
189
+
190
+ .top-bar {
191
+ padding: 1rem 2rem;
192
+ display: flex;
193
+ justify-content: space-between;
194
+ align-items: center;
195
+ border-bottom: 1px solid var(--glass-border);
196
+ }
197
+
198
+ .status-indicator {
199
+ display: flex;
200
+ align-items: center;
201
+ gap: 0.8rem;
202
+ font-size: 0.8rem;
203
+ opacity: 0.8;
204
+ }
205
+
206
+ .dot {
207
+ width: 8px;
208
+ height: 8px;
209
+ border-radius: 50%;
210
+ }
211
+
212
+ .dot.online {
213
+ background-color: #4caf50;
214
+ box-shadow: 0 0 10px #4caf50;
215
+ }
216
+
217
+ .chat-wrapper {
218
+ flex-grow: 1;
219
+ display: flex;
220
+ flex-direction: column;
221
+ padding: 2rem;
222
+ max-width: 1000px;
223
+ margin: 0 auto;
224
+ width: 100%;
225
+ min-height: 0; /* Crucial for flex scroll */
226
+ }
227
+
228
+ .chat-container {
229
+ flex-grow: 1;
230
+ overflow-y: auto;
231
+ display: flex;
232
+ flex-direction: column;
233
+ gap: 1.5rem;
234
+ padding-bottom: 2rem;
235
+ padding-right: 1rem; /* Space for scrollbar */
236
+ }
237
+
238
+ .message {
239
+ padding: 1.2rem;
240
+ border-radius: 12px;
241
+ max-width: 85%;
242
+ line-height: 1.6;
243
+ }
244
+
245
+ /* Markdown Styling */
246
+ .message h1, .message h2, .message h3 {
247
+ color: var(--judicial-gold);
248
+ margin-bottom: 0.8rem;
249
+ font-family: 'Playfair Display', serif;
250
+ }
251
+
252
+ .message ul, .message ol {
253
+ margin-left: 1.5rem;
254
+ margin-bottom: 1rem;
255
+ }
256
+
257
+ .message p {
258
+ margin-bottom: 0.8rem;
259
+ }
260
+
261
+ /* Action Buttons */
262
+ .action-area {
263
+ display: flex;
264
+ gap: 0.8rem;
265
+ margin-top: 1rem;
266
+ padding-top: 1rem;
267
+ border-top: 1px solid var(--glass-border);
268
+ }
269
+
270
+ .action-btn {
271
+ background: rgba(197, 160, 89, 0.1);
272
+ border: 1px solid var(--judicial-gold);
273
+ color: var(--judicial-gold);
274
+ padding: 0.5rem 1rem;
275
+ border-radius: 6px;
276
+ display: flex;
277
+ align-items: center;
278
+ gap: 0.5rem;
279
+ font-size: 0.85rem;
280
+ cursor: pointer;
281
+ transition: all 0.2s ease;
282
+ }
283
+
284
+ .action-btn:hover {
285
+ background: var(--judicial-gold);
286
+ color: var(--advocate-black);
287
+ }
288
+
289
+ .message.system {
290
+ align-self: flex-start;
291
+ border-left: 4px solid var(--judicial-gold);
292
+ }
293
+
294
+ .message.user {
295
+ align-self: flex-end;
296
+ background: var(--judicial-gold);
297
+ color: var(--advocate-black);
298
+ font-weight: 500;
299
+ }
300
+
301
+ .input-area {
302
+ display: flex;
303
+ gap: 1rem;
304
+ padding: 1rem;
305
+ border-radius: 15px;
306
+ margin-top: auto;
307
+ align-items: center;
308
+ }
309
+
310
+ .icon-btn {
311
+ background: none;
312
+ border: none;
313
+ color: var(--judicial-gold);
314
+ cursor: pointer;
315
+ opacity: 0.7;
316
+ transition: all 0.2s;
317
+ padding: 0.5rem;
318
+ display: flex;
319
+ align-items: center;
320
+ justify-content: center;
321
+ }
322
+
323
+ .icon-btn:hover {
324
+ opacity: 1;
325
+ transform: scale(1.1);
326
+ }
327
+
328
+ #user-input {
329
+ flex-grow: 1;
330
+ background: transparent;
331
+ border: none;
332
+ color: var(--parchment);
333
+ font-size: 1rem;
334
+ outline: none;
335
+ }
336
+
337
+ .gold-btn {
338
+ background: var(--judicial-gold);
339
+ color: var(--advocate-black);
340
+ border: none;
341
+ padding: 0.8rem 1.5rem;
342
+ border-radius: 8px;
343
+ display: flex;
344
+ align-items: center;
345
+ gap: 0.8rem;
346
+ font-weight: 600;
347
+ cursor: pointer;
348
+ transition: transform 0.2s ease, box-shadow 0.2s ease;
349
+ }
350
+
351
+ .gold-btn:hover {
352
+ transform: translateY(-2px);
353
+ box-shadow: 0 5px 15px var(--gold-glow);
354
+ }
355
+
356
+ /* Legal Loader Animations */
357
+ .legal-loader {
358
+ display: flex;
359
+ flex-direction: column;
360
+ align-items: center;
361
+ gap: 1rem;
362
+ padding: 1rem;
363
+ position: relative;
364
+ }
365
+
366
+ .legal-loader::after {
367
+ content: '';
368
+ position: absolute;
369
+ top: 50%;
370
+ left: 50%;
371
+ width: 20px;
372
+ height: 20px;
373
+ background: var(--judicial-gold);
374
+ border-radius: 50%;
375
+ transform: translate(-50%, -50%);
376
+ animation: ripple 2s infinite;
377
+ z-index: -1;
378
+ opacity: 0;
379
+ }
380
+
381
+ @keyframes ripple {
382
+ 0% { width: 0; height: 0; opacity: 0.5; }
383
+ 100% { width: 200px; height: 200px; opacity: 0; }
384
+ }
385
+
386
+ .gavel-animate {
387
+ font-size: 2.5rem;
388
+ color: var(--judicial-gold);
389
+ animation: strike 1.2s infinite ease-in-out;
390
+ display: inline-block;
391
+ }
392
+
393
+ .loader-text {
394
+ font-size: 0.8rem;
395
+ text-transform: uppercase;
396
+ letter-spacing: 2px;
397
+ color: var(--judicial-gold);
398
+ animation: pulse 1.5s infinite;
399
+ }
400
+
401
+ @keyframes strike {
402
+ 0% { transform: rotate(0deg); }
403
+ 30% { transform: rotate(-45deg); }
404
+ 50% { transform: rotate(10deg); }
405
+ 100% { transform: rotate(0deg); }
406
+ }
407
+
408
+ @keyframes pulse {
409
+ 0%, 100% { opacity: 0.4; }
410
+ 50% { opacity: 1; }
411
+ }
412
+
413
+ /* Onboarding Overlay */
414
+ .onboarding-container {
415
+ position: fixed;
416
+ top: 0;
417
+ left: 0;
418
+ width: 100%;
419
+ height: 100%;
420
+ z-index: 1000;
421
+ display: flex;
422
+ justify-content: center;
423
+ align-items: center;
424
+ background: rgba(13, 13, 13, 0.95);
425
+ backdrop-filter: blur(20px);
426
+ }
427
+
428
+ .onboarding-card {
429
+ background: var(--sidebar-black);
430
+ padding: 3rem;
431
+ border-radius: 20px;
432
+ border: 1px solid var(--judicial-gold);
433
+ text-align: center;
434
+ max-width: 600px;
435
+ width: 90%;
436
+ box-shadow: 0 0 50px rgba(197, 160, 89, 0.1);
437
+ }
438
+
439
+ .onboarding-sub {
440
+ color: var(--judicial-gold);
441
+ font-size: 1.5rem;
442
+ margin: 1rem 0;
443
+ font-family: 'Playfair Display', serif;
444
+ }
445
+
446
+ .instruction {
447
+ opacity: 0.7;
448
+ margin-bottom: 2rem;
449
+ }
450
+
451
+ .persona-grid {
452
+ display: grid;
453
+ grid-template-columns: 1fr 1fr;
454
+ gap: 1.5rem;
455
+ }
456
+
457
+ .persona-btn {
458
+ background: var(--glass);
459
+ border: 1px solid var(--glass-border);
460
+ color: var(--parchment);
461
+ padding: 1.5rem;
462
+ border-radius: 12px;
463
+ cursor: pointer;
464
+ display: flex;
465
+ flex-direction: column;
466
+ align-items: center;
467
+ gap: 0.8rem;
468
+ transition: all 0.3s ease;
469
+ }
470
+
471
+ .persona-btn i {
472
+ width: 24px;
473
+ height: 24px;
474
+ color: var(--judicial-gold);
475
+ }
476
+
477
+ .persona-btn:hover {
478
+ background: var(--gold-glow);
479
+ border-color: var(--judicial-gold);
480
+ transform: translateY(-5px);
481
+ }
482
+
483
+ .persona-btn small {
484
+ font-size: 0.7rem;
485
+ opacity: 0.6;
486
+ margin-top: 0.3rem;
487
+ }
488
+
489
+ .switch-profile {
490
+ margin-top: 2rem;
491
+ border-top: 1px solid var(--glass-border) !important;
492
+ border-radius: 0 !important;
493
+ }
494
+
495
+ .blur-background {
496
+ filter: blur(10px);
497
+ }
498
+
499
+ /* Custom Scrollbar */
500
+ ::-webkit-scrollbar {
501
+ width: 6px;
502
+ }
503
+
504
+ ::-webkit-scrollbar-track {
505
+ background: transparent;
506
+ }
507
+
508
+ ::-webkit-scrollbar-thumb {
509
+ background: var(--glass-border);
510
+ border-radius: 10px;
511
+ }
512
+
513
+ ::-webkit-scrollbar-thumb:hover {
514
+ background: var(--judicial-gold);
515
+ }
backups/v1_production/server.py ADDED
@@ -0,0 +1,95 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import FastAPI, HTTPException, File, UploadFile
2
+ from pydantic import BaseModel
3
+ from fastapi.middleware.cors import CORSMiddleware
4
+ from fastapi.staticfiles import StaticFiles
5
+ import io
6
+ import os
7
+ import pypdf
8
+ import traceback
9
+ from core.agent import NyayaAgent
10
+ from tools.search_tool import search_indian_kanoon, get_act_details, search_legal_documents
11
+ from tools.legal_tools import draft_rti_query, draft_legal_notice, analyze_case_summary
12
+ from tools.compliance import audit_privacy_policy
13
+ from tools.law_bridge import ipc_to_bns_lookup
14
+ from google.genai import types
15
+
16
+ # Initialize Agent and App
17
+ agent = NyayaAgent()
18
+ app = FastAPI(title="Nyaya Agent")
19
+
20
+ # CORS
21
+ app.add_middleware(
22
+ CORSMiddleware,
23
+ allow_origins=["*"],
24
+ allow_credentials=True,
25
+ allow_methods=["*"],
26
+ allow_headers=["*"],
27
+ )
28
+
29
+ class ChatRequest(BaseModel):
30
+ message: str
31
+ persona: str = "explorer"
32
+
33
+ # API ROUTES MUST COME BEFORE STATIC MOUNT
34
+ @app.post("/api/chat")
35
+ async def chat(request: ChatRequest):
36
+ try:
37
+ custom_instruction = f"{agent.system_instruction}\n\nCURRENT USER PERSONA: {request.persona.upper()}. "
38
+ if request.persona == "lawyer":
39
+ custom_instruction += "Provide highly technical legal analysis with specific sections and procedural details."
40
+ elif request.persona == "student":
41
+ custom_instruction += "Provide academic analysis, citing landmark cases and legal theory."
42
+ else:
43
+ custom_instruction += "Use simple language, avoid jargon, and explain basic legal concepts clearly."
44
+
45
+ tools = [
46
+ search_indian_kanoon,
47
+ get_act_details,
48
+ search_legal_documents,
49
+ draft_rti_query,
50
+ draft_legal_notice,
51
+ analyze_case_summary,
52
+ audit_privacy_policy,
53
+ ipc_to_bns_lookup
54
+ ]
55
+
56
+ config = types.GenerateContentConfig(
57
+ system_instruction=custom_instruction,
58
+ tools=tools,
59
+ temperature=0.2,
60
+ )
61
+
62
+ response_text = agent.generate_response(request.message, config=config)
63
+ return {"response": response_text}
64
+ except Exception as e:
65
+ print(f"ERROR IN CHAT: {str(e)}", flush=True)
66
+ traceback.print_exc()
67
+ raise HTTPException(status_code=500, detail=str(e))
68
+
69
+ @app.post("/api/upload")
70
+ async def upload_file(file: UploadFile = File(...)):
71
+ try:
72
+ content = await file.read()
73
+ text = ""
74
+ if file.filename.endswith(".pdf"):
75
+ reader = pypdf.PdfReader(io.BytesIO(content))
76
+ for page in reader.pages:
77
+ text += page.extract_text() + "\n"
78
+ else:
79
+ text = content.decode("utf-8")
80
+ return {"filename": file.filename, "text": text}
81
+ except Exception as e:
82
+ raise HTTPException(status_code=500, detail=f"Error processing file: {str(e)}")
83
+
84
+ @app.get("/api/status")
85
+ async def status():
86
+ return {"status": "Satyameva Jayate - Online"}
87
+
88
+ # MOUNT STATIC FILES LAST
89
+ app.mount("/", StaticFiles(directory="frontend", html=True), name="frontend")
90
+
91
+ if __name__ == "__main__":
92
+ import uvicorn
93
+ # Hugging Face uses 7860
94
+ port = int(os.getenv("PORT", 7860))
95
+ uvicorn.run(app, host="0.0.0.0", port=port)
backups/v1_production/tools/compliance.py ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ def audit_privacy_policy(policy_text: str):
2
+ """
3
+ Analyzes a Privacy Policy against the Digital Personal Data Protection Act (DPDPA) 2023.
4
+
5
+ Args:
6
+ policy_text: The full text of the privacy policy to audit.
7
+ """
8
+ # This tool will be called by the agent to perform a structured audit.
9
+ # The agent will use its internal knowledge of DPDPA 2023 to identify gaps.
10
+ return (
11
+ "DPDPA 2023 AUDIT REPORT\n"
12
+ "-----------------------\n"
13
+ "1. NOTICE (Section 5): Analyzing if purpose and data types are specified...\n"
14
+ "2. CONSENT (Section 6): Checking for 'Clear and Affirmative' consent language...\n"
15
+ "3. GRIEVANCE REDRESSAL (Section 12): Searching for Grievance Officer contact details...\n\n"
16
+ "Please provide the policy text, and I will highlight the specific compliance gaps."
17
+ )
backups/v1_production/tools/ingest.py ADDED
@@ -0,0 +1,66 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import chromadb
3
+ from chromadb.utils import embedding_functions
4
+ from pypdf import PdfReader
5
+ from dotenv import load_dotenv
6
+
7
+ load_dotenv(override=True)
8
+
9
+ # Configuration
10
+ CHROMA_PATH = "data/chroma_db"
11
+ COLLECTION_NAME = "nyaya_legal_docs"
12
+
13
+ # Initialize ChromaDB
14
+ client = chromadb.PersistentClient(path=CHROMA_PATH)
15
+
16
+ # Use Gemini embeddings via a custom wrapper or OpenAI-compatible one if available
17
+ # For simplicity in this workshop, we'll use a default sentence-transformer if available,
18
+ # or a simple placeholder.
19
+ # Better yet: Use Chroma's built-in default for now.
20
+ embedding_func = embedding_functions.DefaultEmbeddingFunction()
21
+
22
+ collection = client.get_or_create_collection(
23
+ name=COLLECTION_NAME,
24
+ embedding_function=embedding_func
25
+ )
26
+
27
+ def ingest_pdf(file_path):
28
+ """Reads a PDF, chunks it, and adds it to the vector database."""
29
+ print(f"Ingesting: {file_path}")
30
+ reader = PdfReader(file_path)
31
+
32
+ doc_id = os.path.basename(file_path)
33
+ chunks = []
34
+ metadata = []
35
+ ids = []
36
+
37
+ for i, page in enumerate(reader.pages):
38
+ text = page.extract_text()
39
+ if text.strip():
40
+ # Basic chunking by page for now
41
+ chunks.append(text)
42
+ metadata.append({"source": doc_id, "page": i + 1})
43
+ ids.append(f"{doc_id}_page_{i+1}")
44
+
45
+ if chunks:
46
+ collection.add(
47
+ documents=chunks,
48
+ metadatas=metadata,
49
+ ids=ids
50
+ )
51
+ print(f"Successfully added {len(chunks)} pages from {doc_id}")
52
+
53
+ def search_docs(query, n_results=3):
54
+ """Searches the collection for relevant snippets."""
55
+ results = collection.query(
56
+ query_texts=[query],
57
+ n_results=n_results
58
+ )
59
+ return results
60
+
61
+ if __name__ == "__main__":
62
+ # Test with any PDFs in the data folder
63
+ data_dir = "data"
64
+ for file in os.listdir(data_dir):
65
+ if file.endswith(".pdf"):
66
+ ingest_pdf(os.path.join(data_dir, file))
backups/v1_production/tools/law_bridge.py ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ def ipc_to_bns_lookup(ipc_section: str):
2
+ """
3
+ Maps an Indian Penal Code (IPC) section to the corresponding Bharatiya Nyaya Sanhita (BNS) 2023 section.
4
+
5
+ Args:
6
+ ipc_section: The IPC section number (e.g., '302', '420').
7
+ """
8
+ # Key Mappings (Sample for MVP)
9
+ mappings = {
10
+ "302": {"bns": "101", "name": "Punishment for Murder", "change": "Punishment remains life/death; restructuring of clauses for clarity."},
11
+ "420": {"bns": "318", "name": "Cheating and dishonestly inducing delivery of property", "change": "Merged with other cheating sections; broader definition of 'property'."},
12
+ "498A": {"bns": "85/86", "name": "Cruelty by husband or relatives", "change": "Split into two sections; Section 85 defines cruelty, Section 86 defines punishment."},
13
+ "376": {"bns": "64-70", "name": "Punishment for Rape", "change": "Extensively expanded; separate sections for aggravated cases and gang rape."},
14
+ "124A": {"bns": "152", "name": "Sedition (now 'Acts endangering sovereignty')", "change": "The word 'Sedition' is removed; focuses on acts against the state/sovereignty."}
15
+ }
16
+
17
+ clean_section = ipc_section.upper().replace("IPC", "").strip()
18
+
19
+ if clean_section in mappings:
20
+ m = mappings[clean_section]
21
+ return (
22
+ f"--- BNS-IPC CROSS-REFERENCE ---\n"
23
+ f"Old Section: IPC {clean_section} ({m['name']})\n"
24
+ f"New Section: BNS {m['bns']}\n"
25
+ f"Key Change: {m['change']}\n"
26
+ f"--------------------------------"
27
+ )
28
+ else:
29
+ return f"Section IPC {clean_section} not found in the immediate lookup table. Please consult the full BNS Schedule or ask me to search for the specific offense name."
backups/v1_production/tools/legal_tools.py ADDED
@@ -0,0 +1,52 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ def draft_rti_query(subject: str, department: str = "Relevant Public Authority"):
2
+ """
3
+ Drafts a formal RTI (Right to Information) query for a given subject.
4
+ """
5
+ template = (
6
+ f"Subject: Application under RTI Act, 2005 - Regarding {subject}\n\n"
7
+ f"To,\nThe Public Information Officer,\n{department}\n\n"
8
+ f"Sir/Madam,\n"
9
+ f"I request you to provide the following information under the RTI Act, 2005:\n"
10
+ f"1. Detailed records/notifications regarding {subject}.\n"
11
+ f"2. Any internal circulars or guidelines issued concerning this matter.\n"
12
+ f"3. Time period of the requested data: [Specify Period].\n\n"
13
+ f"I am a citizen of India. I have attached the prescribed fee of Rs. 10/-\n\n"
14
+ f"Regards,\n[Your Name]"
15
+ )
16
+ return template
17
+
18
+ def draft_legal_notice(sender: str, receiver: str, grievance: str, relief: str):
19
+ """
20
+ Prepares a formal legal notice for a specific grievance.
21
+
22
+ Args:
23
+ sender: Name and address of the sender.
24
+ receiver: Name and address of the receiver.
25
+ grievance: Detailed description of the legal grievance/dispute.
26
+ relief: The action or compensation demanded from the receiver.
27
+ """
28
+ notice = (
29
+ f"LEGAL NOTICE\n\n"
30
+ f"From: {sender}\n"
31
+ f"To: {receiver}\n\n"
32
+ f"Under instructions from my client {sender}, I hereby serve you with this legal notice:\n\n"
33
+ f"1. THE GRIEVANCE: {grievance}\n"
34
+ f"2. LEGAL VIOLATION: This act is a violation of relevant Indian laws.\n"
35
+ f"3. THE RELIEF: You are hereby called upon to {relief} within 15 days of receipt of this notice.\n\n"
36
+ f"Failing which, my client shall be constrained to initiate civil/criminal proceedings against you.\n\n"
37
+ f"Regards,\n[Advocate Name]"
38
+ )
39
+ return notice
40
+
41
+ def analyze_case_summary(case_text: str):
42
+ """
43
+ Analyzes a legal case and provides a structured summary (Facts, Issues, Ratio).
44
+
45
+ Args:
46
+ case_text: The full text or excerpt of the judgment to analyze.
47
+ """
48
+ return "Case Analysis Placeholder: I will provide Facts, Issues, Arguments, and the Ratio Decidendi here."
49
+
50
+ def suggest_sc_followup():
51
+ """Provides a suggestion to check the latest Supreme Court filings."""
52
+ return "Would you like me to check the latest Supreme Court filings or judgments related to this matter?"
backups/v1_production/tools/search_tool.py ADDED
@@ -0,0 +1,79 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import chromadb
3
+ from chromadb.utils import embedding_functions
4
+
5
+ # Configuration
6
+ CHROMA_PATH = "data/chroma_db"
7
+ COLLECTION_NAME = "nyaya_legal_docs"
8
+
9
+ def get_vector_collection():
10
+ client = chromadb.PersistentClient(path=CHROMA_PATH)
11
+ embedding_func = embedding_functions.DefaultEmbeddingFunction()
12
+ return client.get_or_create_collection(
13
+ name=COLLECTION_NAME,
14
+ embedding_function=embedding_func
15
+ )
16
+
17
+ def search_legal_documents(query: str):
18
+ """
19
+ Search across the indexed legal documents (Gazettes, Circulars, etc.) using semantic search.
20
+
21
+ Args:
22
+ query: The natural language query to search for in local documents.
23
+ """
24
+ try:
25
+ collection = get_vector_collection()
26
+ results = collection.query(
27
+ query_texts=[query],
28
+ n_results=3
29
+ )
30
+ if results['documents']:
31
+ return "\n\n".join(results['documents'][0])
32
+ return "No relevant local documents found."
33
+ except Exception as e:
34
+ return f"Error searching local documents: {e}"
35
+
36
+ import os
37
+ import requests
38
+
39
+ def search_indian_kanoon(query: str):
40
+ """
41
+ Search for legal cases, acts, and statutes on Indian Kanoon (Online).
42
+ """
43
+ token = os.getenv("INDIANKANOON_API_KEY")
44
+ if not token:
45
+ return f"Search result placeholder for: {query}. (API Token missing in .env. Using internal model knowledge.)"
46
+
47
+ try:
48
+ headers = {
49
+ "Authorization": f"Token {token}",
50
+ "Accept": "application/json"
51
+ }
52
+ params = {"formInput": query, "pagenum": 0}
53
+ # Searching for the query
54
+ response = requests.get(
55
+ f"https://api.indiankanoon.org/search/",
56
+ headers=headers,
57
+ params=params
58
+ )
59
+ data = response.json()
60
+
61
+ if "results" in data:
62
+ results = data["results"][:3]
63
+ summary = "Found these cases on Indian Kanoon:\n"
64
+ for res in results:
65
+ summary += f"- {res['title']} ({res['docid']})\n"
66
+ return summary
67
+ return "No results found on Indian Kanoon."
68
+ except Exception as e:
69
+ return f"Error connecting to Indian Kanoon: {e}"
70
+
71
+ def get_act_details(act_name: str, section: str = None):
72
+ """
73
+ Retrieve details of a specific Indian Act or Section.
74
+
75
+ Args:
76
+ act_name: Name of the Act (e.g., 'IPC', 'DPDPA').
77
+ section: Specific section number (optional).
78
+ """
79
+ return f"Details for {act_name} Section {section if section else 'All'}. (Data retrieval pending)"
core/agent.py ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ from google import genai
3
+ from google.genai import types
4
+ from dotenv import load_dotenv
5
+
6
+ load_dotenv(override=True)
7
+
8
+ class NyayaAgent:
9
+ def __init__(self, model_id='gemini-flash-lite-latest'):
10
+ self.client = genai.Client(api_key=os.getenv("GEMINI_API_KEY"))
11
+ self.model_id = model_id
12
+ self.system_instruction = (
13
+ "You are 'Nyaya Agent', a specialized Legal & Judiciary Assistant for the Indian Legal System. "
14
+ "You serve Citizens, Law Students, and Lawyers. Your tone and technicality must adapt based on the user's background.\n\n"
15
+ "ADAPTATION RULES:\n"
16
+ "1. CITIZEN/NON-PROFESSIONAL: Use simple language, avoid jargon, and explain concepts like 'Writ' or 'Affidavit'. Always suggest drafting an RTI query if they need data from a government body.\n"
17
+ "2. LAW STUDENT: Provide technical details, refer to specific case precedents (e.g., Kesavananda Bharati), and suggest checking the latest Supreme Court filings.\n"
18
+ "3. LAWYER/PROFESSIONAL: Provide high-technicality analysis, cite specific Acts/Sections (IPC, BNS, etc.), and discuss procedural nuances.\n\n"
19
+ "MANDATORY GUIDELINES:\n"
20
+ "- Be proactive: If a query involves government inaction or data, suggest an RTI.\n"
21
+ "- If a query involves a complex constitutional point, suggest checking Supreme Court updates.\n"
22
+ "- Be precise and refer to specific sections of Indian Acts/Statutes.\n"
23
+ "- BE GUIDED BY TRUTH: Your underlying principle is 'Satyameva Jayate' (Truth alone triumphs). Ensure your research is accurate and evidence-based.\n"
24
+ "- DO NOT provide definitive legal advice; clarify that you are a research assistant."
25
+ )
26
+
27
+ def generate_response(self, prompt, config=None):
28
+ import time
29
+ max_retries = 5
30
+ retry_delay = 10 # Increased delay for free tier stability
31
+
32
+ if config is None:
33
+ config = types.GenerateContentConfig(
34
+ system_instruction=self.system_instruction,
35
+ temperature=0.2,
36
+ )
37
+
38
+ for attempt in range(max_retries):
39
+ try:
40
+ response = self.client.models.generate_content(
41
+ model=self.model_id,
42
+ contents=prompt,
43
+ config=config
44
+ )
45
+ return response.text
46
+ except Exception as e:
47
+ if "503" in str(e) or "429" in str(e):
48
+ if attempt < max_retries - 1:
49
+ print(f"\n[System] Gemini is busy. Retrying in {retry_delay}s... (Attempt {attempt + 1}/{max_retries})", flush=True)
50
+ time.sleep(retry_delay)
51
+ retry_delay *= 2 # Exponential backoff
52
+ continue
53
+ raise e
54
+
55
+ if __name__ == "__main__":
56
+ # Quick test
57
+ agent = NyayaAgent()
58
+ print(agent.generate_response("Introduce yourself briefly."))
frontend/index.html ADDED
@@ -0,0 +1,133 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Nyaya Agent | Indian Legal Assistant</title>
7
+ <link rel="stylesheet" href="style.css">
8
+ <!-- Google Fonts -->
9
+ <link href="https://fonts.googleapis.com/css2?family=Playfair+Display:wght@700&family=Inter:wght@300;400;600&display=swap" rel="stylesheet">
10
+ <!-- Lucide Icons -->
11
+ <script src="https://unpkg.com/lucide@latest"></script>
12
+ <!-- Marked.js for Markdown -->
13
+ <script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
14
+ </head>
15
+ <body>
16
+ <!-- Onboarding Overlay -->
17
+ <div id="onboarding-overlay" class="onboarding-container glass">
18
+ <div class="onboarding-card">
19
+ <div class="judicial-emblem">
20
+ <i data-lucide="scale"></i>
21
+ </div>
22
+ <h2 class="playfair">Welcome to Nyaya</h2>
23
+ <p class="onboarding-sub">सत्यमेव जयते</p>
24
+ <p class="instruction">To provide the most accurate legal assistance, please select your profile:</p>
25
+
26
+ <div class="persona-grid">
27
+ <button class="persona-btn" data-persona="lawyer">
28
+ <i data-lucide="briefcase"></i>
29
+ <span>Lawyer / Judge</span>
30
+ <small>High Technicality & Procedural Analysis</small>
31
+ </button>
32
+ <button class="persona-btn" data-persona="student">
33
+ <i data-lucide="graduation-cap"></i>
34
+ <span>Law Student</span>
35
+ <small>Landmark Cases & Legal Theory</small>
36
+ </button>
37
+ <button class="persona-btn" data-persona="citizen">
38
+ <i data-lucide="user"></i>
39
+ <span>Citizen</span>
40
+ <small>Simple Language & RTI Support</small>
41
+ </button>
42
+ <button class="persona-btn" data-persona="explorer">
43
+ <i data-lucide="compass"></i>
44
+ <span>Explorer</span>
45
+ <small>History & System Overview</small>
46
+ </button>
47
+ </div>
48
+
49
+ <div class="onboarding-footer">
50
+ <p>⚠️ <strong>Legal Disclaimer:</strong> Nyaya Agent is an AI assistant and may occasionally provide inaccurate information. This tool is for research and drafting assistance only and is NOT a substitute for professional legal advice.</p>
51
+ </div>
52
+ </div>
53
+ </div>
54
+
55
+ <div class="app-container blur-background">
56
+ <!-- Sidebar -->
57
+ <aside class="sidebar glass">
58
+ <div class="logo-section">
59
+ <div class="legal-tech-logo">
60
+ <i data-lucide="scale" class="gold-icon scales"></i>
61
+ <i data-lucide="pen-tool" class="gold-icon pen"></i>
62
+ </div>
63
+ <h1 class="playfair">Nyaya</h1>
64
+ </div>
65
+ <nav class="nav-menu">
66
+ <button class="nav-item active" data-tool="chat"><i data-lucide="message-square"></i> Legal Chat</button>
67
+ <button class="nav-item" data-tool="search"><i data-lucide="search"></i> Case Search</button>
68
+ <button class="nav-item" data-tool="notice"><i data-lucide="file-text"></i> Draft Notice</button>
69
+ <button class="nav-item" data-tool="rti"><i data-lucide="scroll"></i> RTI Portal</button>
70
+ <button class="nav-item" data-tool="compliance"><i data-lucide="shield-check"></i> Compliance Audit</button>
71
+ <button class="nav-item" data-tool="bridge"><i data-lucide="git-branch"></i> Law Bridge</button>
72
+ <button class="nav-item switch-profile" id="switch-btn"><i data-lucide="user-cog"></i> Switch Profile</button>
73
+ </nav>
74
+ <div class="motto-section">
75
+ <div id="motto-container">
76
+ <p class="motto" id="motto-text">सत्यमेव जयते</p>
77
+ <span class="motto-en" id="motto-lang">HINDI</span>
78
+ </div>
79
+ </div>
80
+ <div class="sidebar-footer">
81
+ <p>⚠️ AI Research Assistant. Always verify legal drafts.</p>
82
+ <div class="footer-icons">
83
+ <i data-lucide="shield-check"></i>
84
+ <i data-lucide="landmark"></i>
85
+ </div>
86
+ </div>
87
+ </aside>
88
+
89
+ <!-- Main Content -->
90
+ <main class="main-content">
91
+ <header class="top-bar glass">
92
+ <div class="status-indicator">
93
+ <span class="dot online"></span>
94
+ <span>Judicial Network Online</span>
95
+ </div>
96
+ <div class="user-profile">
97
+ <i data-lucide="user" class="profile-icon"></i>
98
+ <span id="profile-status">Professional Dashboard</span>
99
+ <div class="info-trigger" id="info-trigger">
100
+ <i data-lucide="info"></i>
101
+ <div class="persona-tooltip glass" id="persona-tooltip">
102
+ Select a profile to see capabilities.
103
+ </div>
104
+ </div>
105
+ </div>
106
+ </header>
107
+
108
+ <div class="chat-wrapper">
109
+ <div id="chat-messages" class="chat-container">
110
+ </div>
111
+
112
+ <div class="input-area glass">
113
+ <input type="file" id="file-upload" style="display: none;" accept=".pdf,.txt">
114
+ <button id="attach-btn" class="icon-btn" title="Attach Document">
115
+ <i data-lucide="paperclip"></i>
116
+ </button>
117
+ <input type="text" id="user-input" placeholder="Enter your legal query here..." autocomplete="off">
118
+ <button id="send-btn" class="gold-btn">
119
+ <i data-lucide="gavel"></i>
120
+ <span>Execute</span>
121
+ </button>
122
+ </div>
123
+ </div>
124
+ </main>
125
+ </div>
126
+
127
+ <script src="script.js"></script>
128
+ <script>
129
+ // Initialize icons
130
+ lucide.createIcons();
131
+ </script>
132
+ </body>
133
+ </html>
frontend/script.js ADDED
@@ -0,0 +1,347 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // API Configuration
2
+ const API_BASE_URL = '/api';
3
+ let userPersona = 'explorer'; // Default
4
+
5
+ const chatMessages = document.getElementById('chat-messages');
6
+ const userInput = document.getElementById('user-input');
7
+ const sendBtn = document.getElementById('send-btn');
8
+ const onboardingOverlay = document.getElementById('onboarding-overlay');
9
+ const appContainer = document.querySelector('.app-container');
10
+ const switchBtn = document.getElementById('switch-btn');
11
+ const profileStatus = document.getElementById('profile-status');
12
+ const attachBtn = document.getElementById('attach-btn');
13
+ const fileUpload = document.getElementById('file-upload');
14
+ const personaTooltip = document.getElementById('persona-tooltip');
15
+ const infoTrigger = document.getElementById('info-trigger');
16
+
17
+ let isRequestInProgress = false;
18
+
19
+ // Persona Capability Data
20
+ const personaCapabilities = {
21
+ lawyer: "<strong>Legal Professional Mode</strong><br>Optimized for deep statutory analysis, procedural advice, and drafting formal legal documents with precise terminology.",
22
+ student: "<strong>Academic Mode</strong><br>Focuses on legal theory, landmark Supreme Court cases, and historical context of Indian laws.",
23
+ citizen: "<strong>Empowerment Mode</strong><br>Provides simple explanations of legal rights, RTI support, and step-by-step guidance for basic legal issues.",
24
+ explorer: "<strong>Orientation Mode</strong><br>General overview of the Indian judicial hierarchy, history, and fundamental legal concepts."
25
+ };
26
+
27
+ function setLockdown(active) {
28
+ isRequestInProgress = active;
29
+ if (active) {
30
+ document.body.classList.add('lockdown-active');
31
+ userInput.placeholder = "Judicial Lockdown: Analysis in progress...";
32
+ sendBtn.disabled = true;
33
+ } else {
34
+ document.body.classList.remove('lockdown-active');
35
+ userInput.placeholder = "Enter your legal query here...";
36
+ sendBtn.disabled = false;
37
+ }
38
+ }
39
+
40
+ // Handle File Upload
41
+ attachBtn.addEventListener('click', () => fileUpload.click());
42
+
43
+ fileUpload.addEventListener('change', async (e) => {
44
+ const file = e.target.files[0];
45
+ if (!file) return;
46
+
47
+ addMessage(`Uploading ${file.name}...`, 'user');
48
+
49
+ const formData = new FormData();
50
+ formData.append('file', file);
51
+
52
+ try {
53
+ const response = await fetch(`${API_BASE_URL}/upload`, {
54
+ method: 'POST',
55
+ body: formData
56
+ });
57
+
58
+ const data = await response.json();
59
+ if (data.text) {
60
+ userInput.value = `Audit this document: \n\n ${data.text.substring(0, 1000)}...`;
61
+ addMessage(`Document ${file.name} processed. I have extracted the text. Click Execute to start the audit.`, 'system');
62
+ }
63
+ } catch (err) {
64
+ addMessage(`Error uploading file: ${err.message}`, 'system');
65
+ }
66
+ });
67
+ document.querySelectorAll('.persona-btn').forEach(btn => {
68
+ btn.addEventListener('click', () => {
69
+ userPersona = btn.getAttribute('data-persona');
70
+ onboardingOverlay.classList.add('hidden');
71
+ appContainer.classList.remove('blur-background');
72
+
73
+ // Update top bar status
74
+ profileStatus.innerText = userPersona.charAt(0).toUpperCase() + userPersona.slice(1) + " Dashboard";
75
+
76
+ // Apply Dynamic Theme
77
+ document.documentElement.setAttribute('data-theme', userPersona);
78
+
79
+ // Update Wisdom Tooltip
80
+ personaTooltip.innerHTML = personaCapabilities[userPersona];
81
+
82
+ addMessage(`Welcome! You are now connected as a **${userPersona.toUpperCase()}**. How can I help you navigate the legal system today?`, 'system');
83
+ });
84
+ });
85
+
86
+ function highlightCitations(text) {
87
+ // Regex to find common Indian legal citations (e.g., Section 302, Article 21, IPC 302)
88
+ const citationRegex = /\b(Section|Article|Act|Clause)\s+\d+[A-Z]?\b|\b(IPC|BNS|CRPC|CPC|DPDPA)\s+\d+[A-Z]?\b/gi;
89
+ return text.replace(citationRegex, (match) => {
90
+ return `<span class="legal-citation" title="Judicial Reference">${match}</span>`;
91
+ });
92
+ }
93
+
94
+ switchBtn.addEventListener('click', () => {
95
+ onboardingOverlay.classList.remove('hidden');
96
+ appContainer.classList.add('blur-background');
97
+ });
98
+
99
+ // Motto Carousel Data
100
+ const mottos = [
101
+ { text: "सत्यमेव जयते", lang: "Hindi" },
102
+ { text: "সত্যমেব জয়তে", lang: "Bengali" },
103
+ { text: "सत्यमेव जयते", lang: "Marathi" },
104
+ { text: "సత్యమేవ జయతే", lang: "Telugu" },
105
+ { text: "சத்யமேவ ஜெயதே", lang: "Tamil" },
106
+ { text: "સત્યમેવ જયતે", lang: "Gujarati" },
107
+ { text: "ستیہ میو جیتے", lang: "Urdu" },
108
+ { text: "ಸತ್ಯಮೇವ ಜಯತೇ", lang: "Kannada" },
109
+ { text: "ସତ୍ୟମେବ ଜୟତେ", lang: "Odia" },
110
+ { text: "സത്യമേവ ജയതേ", lang: "Malayalam" }
111
+ ];
112
+
113
+ let currentMottoIndex = 0;
114
+ const mottoText = document.getElementById('motto-text');
115
+ const mottoLang = document.getElementById('motto-lang');
116
+
117
+ function updateMotto() {
118
+ mottoText.classList.add('fade-out');
119
+ mottoLang.classList.add('fade-out');
120
+
121
+ setTimeout(() => {
122
+ currentMottoIndex = (currentMottoIndex + 1) % mottos.length;
123
+ mottoText.innerText = mottos[currentMottoIndex].text;
124
+ mottoLang.innerText = mottos[currentMottoIndex].lang;
125
+
126
+ mottoText.classList.remove('fade-out');
127
+ mottoLang.classList.remove('fade-out');
128
+ }, 500);
129
+ }
130
+
131
+ setInterval(updateMotto, 4000); // Change every 4 seconds
132
+
133
+ function addMessage(text, sender) {
134
+ const msgDiv = document.createElement('div');
135
+ msgDiv.className = `message ${sender}`; // Explicitly set classes
136
+
137
+ // Highlight Citations
138
+ let highlightedText = highlightCitations(text);
139
+
140
+ // Add Spark Icon for System
141
+ if (sender === 'system') {
142
+ const spark = document.createElement('div');
143
+ spark.className = 'system-spark';
144
+ spark.innerHTML = '✨';
145
+ msgDiv.appendChild(spark);
146
+ }
147
+
148
+ const contentDiv = document.createElement('div');
149
+ contentDiv.className = 'message-content';
150
+ contentDiv.innerHTML = marked.parse(highlightedText);
151
+ msgDiv.appendChild(contentDiv);
152
+
153
+ // Action Button Detection (Proactive Agent Feature)
154
+ if (sender === 'system') {
155
+ const actionArea = document.createElement('div');
156
+ actionArea.classList.add('action-area');
157
+
158
+ if (text.toLowerCase().includes('rti query') || text.toLowerCase().includes('rti act')) {
159
+ const btn = createActionButton('scroll', 'Draft RTI Query', () => {
160
+ userInput.value = "Draft an RTI query for this matter.";
161
+ handleSendMessage();
162
+ });
163
+ actionArea.appendChild(btn);
164
+ }
165
+
166
+ if (text.toLowerCase().includes('legal notice')) {
167
+ const btn = createActionButton('file-text', 'Prepare Legal Notice', () => {
168
+ userInput.value = "Help me prepare a formal legal notice for this.";
169
+ handleSendMessage();
170
+ });
171
+ actionArea.appendChild(btn);
172
+ }
173
+
174
+ // New: Copy Draft Detection
175
+ if (text.includes('LEGAL NOTICE') || text.includes('Subject: Application under RTI') || text.includes('Facts:')) {
176
+ const copyBtn = createActionButton('copy', 'Copy Draft', () => {
177
+ navigator.clipboard.writeText(text);
178
+ alert('Draft copied to clipboard! (Satyameva Jayate)');
179
+ });
180
+ actionArea.appendChild(copyBtn);
181
+
182
+ const docBtn = createActionButton('file-text', 'Download DOC', () => exportToDoc(text));
183
+ actionArea.appendChild(docBtn);
184
+
185
+ const pdfBtn = createActionButton('download', 'Download PDF', () => exportToPdf(text));
186
+ actionArea.appendChild(pdfBtn);
187
+ }
188
+
189
+ if (actionArea.children.length > 0) {
190
+ msgDiv.appendChild(actionArea);
191
+ }
192
+ }
193
+
194
+ const time = new Date().toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
195
+ const timeSpan = document.createElement('span');
196
+ timeSpan.classList.add('message-time');
197
+ timeSpan.innerText = time;
198
+ msgDiv.appendChild(timeSpan);
199
+
200
+ chatMessages.appendChild(msgDiv);
201
+ setTimeout(scrollToBottom, 50); // Small delay for smooth rendering
202
+ lucide.createIcons();
203
+ }
204
+
205
+ function scrollToBottom() {
206
+ chatMessages.scrollTo({
207
+ top: chatMessages.scrollHeight,
208
+ behavior: 'smooth'
209
+ });
210
+ }
211
+
212
+ function exportToDoc(text) {
213
+ const header = "<html xmlns:o='urn:schemas-microsoft-com:office:office' xmlns:w='urn:schemas-microsoft-com:office:word' xmlns='http://www.w3.org/TR/REC-html40'><head><meta charset='utf-8'><title>Legal Draft</title></head><body>";
214
+ const footer = "</body></html>";
215
+ const sourceHTML = header + marked.parse(text) + footer;
216
+
217
+ const source = 'data:application/vnd.ms-word;charset=utf-8,' + encodeURIComponent(sourceHTML);
218
+ const fileDownload = document.createElement("a");
219
+ document.body.appendChild(fileDownload);
220
+ fileDownload.href = source;
221
+ fileDownload.download = 'Nyaya_Legal_Draft.doc';
222
+ fileDownload.click();
223
+ document.body.removeChild(fileDownload);
224
+ }
225
+
226
+ function exportToPdf(text) {
227
+ // Premium Print Mode for PDF
228
+ const printWindow = window.open('', '_blank');
229
+ printWindow.document.write(`
230
+ <html>
231
+ <head>
232
+ <title>Nyaya Legal Draft</title>
233
+ <style>
234
+ body { font-family: 'Times New Roman', serif; padding: 50px; line-height: 1.6; }
235
+ h1, h2 { color: #4a0e0e; border-bottom: 2px solid #c5a059; }
236
+ .watermark { position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%) rotate(-45deg); opacity: 0.1; font-size: 80px; z-index: -1; }
237
+ </style>
238
+ </head>
239
+ <body>
240
+ <div class="watermark">NYAYA AGENT</div>
241
+ ${marked.parse(text)}
242
+ <script>setTimeout(() => { window.print(); window.close(); }, 500);</script>
243
+ </body>
244
+ </html>
245
+ `);
246
+ printWindow.document.close();
247
+ }
248
+
249
+ function createActionButton(icon, label, callback) {
250
+ const btn = document.createElement('button');
251
+ btn.classList.add('action-btn');
252
+ btn.innerHTML = `<i data-lucide="${icon}"></i> <span>${label}</span>`;
253
+ btn.onclick = callback;
254
+ return btn;
255
+ }
256
+
257
+ async function handleSendMessage() {
258
+ if (isRequestInProgress) return;
259
+ const text = userInput.value.trim();
260
+ if (!text) return;
261
+
262
+ setLockdown(true);
263
+
264
+ // Add user message to UI
265
+ addMessage(text, 'user');
266
+ userInput.value = '';
267
+
268
+ // Show animated loading indicator
269
+ const loadingId = 'loading-' + Date.now();
270
+ const loadingDiv = document.createElement('div');
271
+ loadingDiv.id = loadingId;
272
+ loadingDiv.classList.add('message', 'system', 'glass', 'legal-loader');
273
+ loadingDiv.innerHTML = `
274
+ <div class="gavel-animate"><i data-lucide="gavel"></i></div>
275
+ <div class="loader-text">Order in the Court... Analyzing</div>
276
+ `;
277
+ chatMessages.appendChild(loadingDiv);
278
+ lucide.createIcons();
279
+ scrollToBottom();
280
+
281
+ try {
282
+ const response = await fetch(`${API_BASE_URL}/chat`, {
283
+ method: 'POST',
284
+ headers: {
285
+ 'Content-Type': 'application/json'
286
+ },
287
+ body: JSON.stringify({
288
+ message: text,
289
+ persona: userPersona
290
+ })
291
+ });
292
+
293
+ const data = await response.json();
294
+
295
+ // Remove loading indicator
296
+ document.getElementById(loadingId).remove();
297
+
298
+ if (data.response) {
299
+ addMessage(data.response, 'system');
300
+ } else if (data.detail) {
301
+ addMessage(`Error: ${data.detail}`, 'system');
302
+ }
303
+ } catch (error) {
304
+ if (document.getElementById(loadingId)) document.getElementById(loadingId).remove();
305
+ addMessage(`Connection Error: Could not reach the Judicial Network. Ensure the server is running.`, 'system');
306
+ console.error('API Error:', error);
307
+ } finally {
308
+ setLockdown(false);
309
+ }
310
+ }
311
+
312
+ sendBtn.addEventListener('click', handleSendMessage);
313
+
314
+ userInput.addEventListener('keypress', (e) => {
315
+ if (e.key === 'Enter') {
316
+ handleSendMessage();
317
+ }
318
+ });
319
+
320
+ addMessage("Greetings. I am **Nyaya Agent**. I am ready to assist with your legal research, drafting, or compliance queries.", "system");
321
+
322
+ // Sidebar Navigation
323
+ const toolExamples = {
324
+ search: "Search for landmark cases. e.g., 'Find Supreme Court judgments on Right to Privacy (Justice K.S. Puttaswamy case)'",
325
+ notice: "Prepare a formal notice. e.g., 'Help me draft a legal notice for non-payment of rent by a tenant.'",
326
+ rti: "Draft an RTI application. e.g., 'Draft an RTI to find out the status of road repairs in Ward 12.'",
327
+ compliance: "Audit documents for DPDPA 2023. e.g., 'Audit this privacy policy for compliance with the new data protection act.'",
328
+ bridge: "Map old laws to new. e.g., 'What is the new BNS section for IPC 302 (Murder)?'"
329
+ };
330
+
331
+ document.querySelectorAll('.nav-item').forEach(item => {
332
+ item.addEventListener('click', () => {
333
+ if (isRequestInProgress) {
334
+ alert('Judicial Lockdown Active: Please wait for the current analysis to complete.');
335
+ return;
336
+ }
337
+
338
+ document.querySelectorAll('.nav-item').forEach(btn => btn.classList.remove('active'));
339
+ item.classList.add('active');
340
+
341
+ const tool = item.getAttribute('data-tool');
342
+ if (tool !== 'chat') {
343
+ const example = toolExamples[tool];
344
+ addMessage(`Switched to **${tool.toUpperCase()}** module.\n\n**Example:** ${example}`, 'system');
345
+ }
346
+ });
347
+ });
frontend/style.css ADDED
@@ -0,0 +1,805 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ :root {
2
+ --advocate-black: #0d0d0d;
3
+ --sidebar-black: #141414;
4
+ --judicial-gold: #c5a059;
5
+ --gold-glow: rgba(197, 160, 89, 0.2);
6
+ --courtroom-maroon: #4a0e0e;
7
+ --parchment: #f5f5dc;
8
+ --glass: rgba(255, 255, 255, 0.05);
9
+ --glass-border: rgba(255, 255, 255, 0.1);
10
+
11
+ /* Persona Themes */
12
+ --theme-lawyer: #c5a059;
13
+ --theme-student: #4ade80;
14
+ --theme-citizen: #38bdf8;
15
+ --theme-explorer: #a855f7;
16
+
17
+ --accent-color: var(--theme-lawyer);
18
+ }
19
+
20
+ /* Dynamic Theme Application */
21
+ :root[data-theme="lawyer"] { --accent-color: var(--theme-lawyer); --judicial-gold: var(--theme-lawyer); }
22
+ :root[data-theme="student"] { --accent-color: var(--theme-student); --judicial-gold: var(--theme-student); }
23
+ :root[data-theme="citizen"] { --accent-color: var(--theme-citizen); --judicial-gold: var(--theme-citizen); }
24
+ :root[data-theme="explorer"] { --accent-color: var(--theme-explorer); --judicial-gold: var(--theme-explorer); }
25
+
26
+ /* Smart Citation Highlighting */
27
+ .legal-citation {
28
+ color: var(--judicial-gold);
29
+ font-weight: 600;
30
+ text-decoration: underline dotted;
31
+ cursor: help;
32
+ background: rgba(255, 255, 255, 0.05);
33
+ padding: 0 4px;
34
+ border-radius: 4px;
35
+ transition: all 0.3s ease;
36
+ }
37
+
38
+ .legal-citation:hover {
39
+ background: var(--judicial-gold);
40
+ color: var(--advocate-black);
41
+ }
42
+
43
+ * {
44
+ margin: 0;
45
+ padding: 0;
46
+ box-sizing: border-box;
47
+ }
48
+
49
+ body {
50
+ font-family: 'Inter', sans-serif;
51
+ background-color: var(--advocate-black);
52
+ color: var(--parchment);
53
+ height: 100vh;
54
+ overflow: hidden;
55
+ }
56
+
57
+ .app-container {
58
+ display: flex;
59
+ height: 100%;
60
+ }
61
+
62
+ /* Glassmorphism Utility */
63
+ .glass {
64
+ background: var(--glass);
65
+ backdrop-filter: blur(12px);
66
+ -webkit-backdrop-filter: blur(12px);
67
+ border: 1px solid var(--glass-border);
68
+ }
69
+
70
+ /* Sidebar */
71
+ .sidebar {
72
+ width: 280px;
73
+ height: 100%;
74
+ background: var(--sidebar-black);
75
+ padding: 2rem;
76
+ display: flex;
77
+ flex-direction: column;
78
+ border-right: 1px solid var(--glass-border);
79
+ }
80
+
81
+ .logo-section {
82
+ display: flex;
83
+ align-items: center;
84
+ gap: 1.2rem;
85
+ margin-bottom: 3rem;
86
+ }
87
+
88
+ .legal-tech-logo {
89
+ position: relative;
90
+ width: 45px;
91
+ height: 45px;
92
+ }
93
+
94
+ .legal-tech-logo .scales {
95
+ position: absolute;
96
+ top: 0;
97
+ left: 0;
98
+ z-index: 2;
99
+ animation: balance 4s infinite ease-in-out;
100
+ }
101
+
102
+ .legal-tech-logo .pen {
103
+ position: absolute;
104
+ bottom: -5px;
105
+ right: -5px;
106
+ width: 20px;
107
+ height: 20px;
108
+ opacity: 0.8;
109
+ animation: write-glow 3s infinite ease-in-out;
110
+ }
111
+
112
+ @keyframes balance {
113
+ 0%, 100% { transform: rotate(-5deg); }
114
+ 50% { transform: rotate(5deg); }
115
+ }
116
+
117
+ @keyframes write-glow {
118
+ 0%, 100% { filter: drop-shadow(0 0 2px var(--judicial-gold)); opacity: 0.6; }
119
+ 50% { filter: drop-shadow(0 0 10px var(--judicial-gold)); opacity: 1; }
120
+ }
121
+
122
+ .playfair {
123
+ font-family: 'Playfair Display', serif;
124
+ font-size: 1.8rem;
125
+ color: var(--judicial-gold);
126
+ letter-spacing: 1px;
127
+ background: linear-gradient(
128
+ to right,
129
+ var(--judicial-gold) 20%,
130
+ #fff 40%,
131
+ var(--judicial-gold) 60%
132
+ );
133
+ background-size: 200% auto;
134
+ background-clip: text;
135
+ -webkit-background-clip: text;
136
+ -webkit-text-fill-color: transparent;
137
+ animation: shine 5s linear infinite;
138
+ }
139
+
140
+ @keyframes shine {
141
+ to { background-position: 200% center; }
142
+ }
143
+
144
+ .gold-icon {
145
+ color: var(--judicial-gold);
146
+ width: 32px;
147
+ height: 32px;
148
+ filter: drop-shadow(0 0 5px var(--gold-glow));
149
+ }
150
+
151
+ .nav-menu {
152
+ display: flex;
153
+ flex-direction: column;
154
+ gap: 0.5rem;
155
+ flex-grow: 1;
156
+ }
157
+
158
+ .nav-item {
159
+ background: transparent;
160
+ border: none;
161
+ color: rgba(245, 245, 220, 0.6);
162
+ padding: 1rem;
163
+ display: flex;
164
+ align-items: center;
165
+ gap: 1rem;
166
+ cursor: pointer;
167
+ border-radius: 8px;
168
+ transition: all 0.3s ease;
169
+ font-size: 0.95rem;
170
+ }
171
+
172
+ .nav-item i {
173
+ width: 18px;
174
+ }
175
+
176
+ .nav-item:hover, .nav-item.active {
177
+ background: var(--glass);
178
+ color: var(--judicial-gold);
179
+ border-left: 3px solid var(--judicial-gold);
180
+ }
181
+
182
+ .motto-section {
183
+ margin-top: auto;
184
+ text-align: center;
185
+ padding-top: 2rem;
186
+ border-top: 1px solid var(--glass-border);
187
+ }
188
+
189
+ .motto {
190
+ font-family: 'Playfair Display', serif;
191
+ font-size: 1.2rem;
192
+ color: var(--judicial-gold);
193
+ transition: opacity 0.5s ease-in-out;
194
+ }
195
+
196
+ .motto.fade-out {
197
+ opacity: 0;
198
+ }
199
+
200
+ .motto-en {
201
+ font-size: 0.7rem;
202
+ text-transform: uppercase;
203
+ letter-spacing: 2px;
204
+ opacity: 0.5;
205
+ transition: opacity 0.5s ease-in-out;
206
+ }
207
+
208
+ .motto-en.fade-out {
209
+ opacity: 0;
210
+ }
211
+
212
+ /* Main Content */
213
+ .main-content {
214
+ flex-grow: 1;
215
+ display: flex;
216
+ flex-direction: column;
217
+ min-height: 0; /* Ensures child flex containers can scroll */
218
+ background: radial-gradient(circle at top right, #1a0a0a, var(--advocate-black));
219
+ }
220
+
221
+ .top-bar {
222
+ padding: 1rem 2rem;
223
+ display: flex;
224
+ justify-content: space-between;
225
+ align-items: center;
226
+ border-bottom: 1px solid var(--glass-border);
227
+ }
228
+
229
+ .status-indicator {
230
+ display: flex;
231
+ align-items: center;
232
+ gap: 0.8rem;
233
+ font-size: 0.8rem;
234
+ opacity: 0.8;
235
+ }
236
+
237
+ .dot {
238
+ width: 8px;
239
+ height: 8px;
240
+ border-radius: 50%;
241
+ }
242
+
243
+ .dot.online {
244
+ background-color: #4caf50;
245
+ box-shadow: 0 0 10px #4caf50;
246
+ }
247
+
248
+ .chat-wrapper {
249
+ flex-grow: 1;
250
+ display: flex;
251
+ flex-direction: column;
252
+ padding: 2rem;
253
+ max-width: 1000px;
254
+ margin: 0 auto;
255
+ width: 100%;
256
+ min-height: 0; /* Crucial for flex scroll */
257
+ }
258
+
259
+ .chat-container {
260
+ flex-grow: 1;
261
+ overflow-y: auto;
262
+ display: flex;
263
+ flex-direction: column;
264
+ gap: 1.5rem;
265
+ padding-bottom: 2rem;
266
+ padding-right: 1rem; /* Space for scrollbar */
267
+ }
268
+
269
+ .message {
270
+ padding: 1.5rem;
271
+ border-radius: 12px;
272
+ max-width: 85%;
273
+ line-height: 1.7;
274
+ margin-bottom: 2rem;
275
+ position: relative;
276
+ box-shadow: 0 4px 15px rgba(0,0,0,0.2);
277
+ animation: fadeIn 0.4s ease;
278
+ }
279
+
280
+ @keyframes fadeIn {
281
+ from { opacity: 0; transform: translateY(10px); }
282
+ to { opacity: 1; transform: translateY(0); }
283
+ }
284
+
285
+ .message.system {
286
+ align-self: flex-start;
287
+ background: rgba(255, 255, 255, 0.03);
288
+ border-left: 4px solid var(--judicial-gold);
289
+ border-top-left-radius: 0;
290
+ }
291
+
292
+ .message.user {
293
+ align-self: flex-end;
294
+ background: var(--judicial-gold);
295
+ color: var(--advocate-black);
296
+ font-weight: 600;
297
+ border-bottom-right-radius: 0;
298
+ box-shadow: 0 8px 25px var(--gold-glow);
299
+ }
300
+
301
+ .message.user::before {
302
+ content: '⚖️ QUERY';
303
+ position: absolute;
304
+ top: -22px;
305
+ right: 0;
306
+ font-size: 0.65rem;
307
+ letter-spacing: 1px;
308
+ color: var(--judicial-gold);
309
+ opacity: 0.8;
310
+ }
311
+
312
+ .message.system::before {
313
+ content: '🏛️ RESPONSE';
314
+ position: absolute;
315
+ top: -22px;
316
+ left: 0;
317
+ font-size: 0.65rem;
318
+ letter-spacing: 1px;
319
+ color: var(--judicial-gold);
320
+ opacity: 0.8;
321
+ }
322
+
323
+ /* Markdown Styling */
324
+ .message h1, .message h2, .message h3 {
325
+ color: var(--judicial-gold);
326
+ margin: 1.5rem 0 1rem 0;
327
+ font-family: 'Playfair Display', serif;
328
+ border-bottom: 1px solid rgba(197, 160, 89, 0.2);
329
+ padding-bottom: 0.5rem;
330
+ }
331
+
332
+ .message ul, .message ol {
333
+ margin-left: 1.5rem;
334
+ margin-bottom: 1rem;
335
+ }
336
+
337
+ .message p {
338
+ margin-bottom: 0.8rem;
339
+ }
340
+
341
+ /* Action Buttons */
342
+ .action-area {
343
+ display: flex;
344
+ gap: 0.8rem;
345
+ margin-top: 1rem;
346
+ padding-top: 1rem;
347
+ border-top: 1px solid var(--glass-border);
348
+ }
349
+
350
+ .action-btn {
351
+ background: rgba(197, 160, 89, 0.1);
352
+ border: 1px solid var(--judicial-gold);
353
+ color: var(--judicial-gold);
354
+ padding: 0.5rem 1rem;
355
+ border-radius: 6px;
356
+ display: flex;
357
+ align-items: center;
358
+ gap: 0.5rem;
359
+ font-size: 0.85rem;
360
+ cursor: pointer;
361
+ transition: all 0.2s ease;
362
+ }
363
+
364
+ .action-btn:hover {
365
+ background: var(--judicial-gold);
366
+ color: var(--advocate-black);
367
+ }
368
+
369
+ #chat-messages {
370
+ flex: 1;
371
+ overflow-y: auto;
372
+ padding: 20px 20px 100px 20px; /* Large bottom padding for loader space */
373
+ display: flex;
374
+ flex-direction: column;
375
+ gap: 15px;
376
+ scroll-behavior: smooth;
377
+ }
378
+
379
+ .chat-wrapper {
380
+ flex-grow: 1;
381
+ display: flex;
382
+ flex-direction: column;
383
+ overflow: hidden;
384
+ position: relative;
385
+ }
386
+
387
+ .input-area {
388
+ display: flex;
389
+ gap: 1rem;
390
+ padding: 1rem;
391
+ border-radius: 15px;
392
+ margin: 10px 20px 20px 20px;
393
+ align-items: center;
394
+ background: rgba(255, 255, 255, 0.05);
395
+ backdrop-filter: blur(10px);
396
+ border: 1px solid var(--glass-border);
397
+ z-index: 10;
398
+ }
399
+
400
+ .icon-btn {
401
+ background: none;
402
+ border: none;
403
+ color: var(--judicial-gold);
404
+ cursor: pointer;
405
+ opacity: 0.7;
406
+ transition: all 0.2s;
407
+ padding: 0.5rem;
408
+ display: flex;
409
+ align-items: center;
410
+ justify-content: center;
411
+ }
412
+
413
+ .icon-btn:hover {
414
+ opacity: 1;
415
+ transform: scale(1.1);
416
+ }
417
+
418
+ #user-input {
419
+ flex-grow: 1;
420
+ background: transparent;
421
+ border: none;
422
+ color: var(--parchment);
423
+ font-size: 1rem;
424
+ outline: none;
425
+ }
426
+
427
+ .gold-btn {
428
+ background: var(--judicial-gold);
429
+ color: var(--advocate-black);
430
+ border: none;
431
+ padding: 0.8rem 1.5rem;
432
+ border-radius: 8px;
433
+ display: flex;
434
+ align-items: center;
435
+ gap: 0.8rem;
436
+ font-weight: 600;
437
+ cursor: pointer;
438
+ transition: transform 0.2s ease, box-shadow 0.2s ease;
439
+ }
440
+
441
+ .gold-btn:hover {
442
+ transform: translateY(-2px);
443
+ box-shadow: 0 5px 15px var(--gold-glow);
444
+ }
445
+
446
+ /* Legal Loader Animations */
447
+ .legal-loader {
448
+ display: flex;
449
+ flex-direction: column;
450
+ align-items: center;
451
+ gap: 1rem;
452
+ padding: 1rem;
453
+ position: relative;
454
+ }
455
+
456
+ .legal-loader::after {
457
+ content: '';
458
+ position: absolute;
459
+ top: 50%;
460
+ left: 50%;
461
+ width: 20px;
462
+ height: 20px;
463
+ background: var(--judicial-gold);
464
+ border-radius: 50%;
465
+ transform: translate(-50%, -50%);
466
+ animation: ripple 2s infinite;
467
+ z-index: -1;
468
+ opacity: 0;
469
+ }
470
+
471
+ @keyframes ripple {
472
+ 0% { width: 0; height: 0; opacity: 0.5; }
473
+ 100% { width: 200px; height: 200px; opacity: 0; }
474
+ }
475
+
476
+ .gavel-animate {
477
+ font-size: 2.5rem;
478
+ color: var(--judicial-gold);
479
+ animation: strike 1.2s infinite ease-in-out;
480
+ display: inline-block;
481
+ }
482
+
483
+ .loader-text {
484
+ font-size: 0.8rem;
485
+ text-transform: uppercase;
486
+ letter-spacing: 2px;
487
+ color: var(--judicial-gold);
488
+ animation: pulse 1.5s infinite;
489
+ }
490
+
491
+ @keyframes strike {
492
+ 0% { transform: rotate(0deg); }
493
+ 30% { transform: rotate(-45deg); }
494
+ 50% { transform: rotate(10deg); }
495
+ 100% { transform: rotate(0deg); }
496
+ }
497
+
498
+ @keyframes pulse {
499
+ 0%, 100% { opacity: 0.4; }
500
+ 50% { opacity: 1; }
501
+ }
502
+
503
+ /* Weighing the Evidence Animation */
504
+ .lockdown-active .scales {
505
+ animation: weighing 2s infinite ease-in-out;
506
+ }
507
+
508
+ @keyframes weighing {
509
+ 0%, 100% { transform: rotate(-5deg); }
510
+ 50% { transform: rotate(5deg); }
511
+ }
512
+
513
+ /* Onboarding Enhancements */
514
+ .judicial-emblem {
515
+ margin-bottom: 1rem;
516
+ opacity: 0.15;
517
+ transform: scale(3);
518
+ color: var(--judicial-gold);
519
+ }
520
+
521
+ .onboarding-footer {
522
+ margin-top: 2rem;
523
+ padding-top: 1.5rem;
524
+ border-top: 1px solid var(--glass-border);
525
+ font-size: 0.75rem;
526
+ line-height: 1.5;
527
+ opacity: 0.7;
528
+ text-align: justify;
529
+ }
530
+
531
+ .onboarding-footer strong {
532
+ color: var(--judicial-gold);
533
+ }
534
+
535
+ .sidebar-footer {
536
+ padding: 1rem;
537
+ border-top: 1px solid var(--glass-border);
538
+ margin-top: auto;
539
+ font-size: 0.7rem;
540
+ color: var(--judicial-gold);
541
+ opacity: 0.8;
542
+ text-align: center;
543
+ }
544
+
545
+ .footer-icons {
546
+ display: flex;
547
+ justify-content: center;
548
+ gap: 1rem;
549
+ margin-top: 0.5rem;
550
+ }
551
+
552
+ .footer-icons i {
553
+ width: 14px;
554
+ height: 14px;
555
+ }
556
+
557
+ .message {
558
+ padding: 1.2rem 1.8rem;
559
+ border-radius: 20px;
560
+ line-height: 1.8;
561
+ position: relative;
562
+ box-shadow: 0 4px 15px rgba(0,0,0,0.3);
563
+ animation: fadeIn 0.4s ease;
564
+ word-wrap: break-word;
565
+ }
566
+
567
+ .message.user {
568
+ align-self: flex-end;
569
+ background: rgba(197, 160, 89, 0.9); /* Gold Bubble */
570
+ color: #0d0d0d;
571
+ font-weight: 500;
572
+ max-width: 70%;
573
+ border-bottom-right-radius: 4px;
574
+ }
575
+
576
+ .message.system {
577
+ align-self: flex-start;
578
+ background: rgba(255, 255, 255, 0.05); /* Glass Parchment */
579
+ color: var(--parchment);
580
+ max-width: 85%;
581
+ border: 1px solid var(--glass-border);
582
+ border-bottom-left-radius: 4px;
583
+ }
584
+
585
+ .system-spark {
586
+ position: absolute;
587
+ left: -35px;
588
+ top: 5px;
589
+ font-size: 1.2rem;
590
+ opacity: 0.8;
591
+ }
592
+
593
+ .message-content {
594
+ flex: 1;
595
+ }
596
+
597
+ .message-content p {
598
+ margin-bottom: 0.8rem;
599
+ }
600
+
601
+ .message-content p:last-child {
602
+ margin-bottom: 0;
603
+ }
604
+
605
+ /* Onboarding Overlay */
606
+ .onboarding-container {
607
+ position: fixed;
608
+ top: 0;
609
+ left: 0;
610
+ width: 100%;
611
+ height: 100%;
612
+ z-index: 9999;
613
+ display: flex;
614
+ justify-content: center;
615
+ align-items: center;
616
+ background: rgba(10, 10, 10, 0.98);
617
+ backdrop-filter: blur(25px);
618
+ transition: opacity 0.5s ease;
619
+ }
620
+
621
+ .onboarding-container.hidden {
622
+ display: none !important;
623
+ }
624
+
625
+ .onboarding-card {
626
+ background: #141414;
627
+ padding: 3rem;
628
+ border-radius: 24px;
629
+ border: 1px solid var(--judicial-gold);
630
+ text-align: center;
631
+ max-width: 650px;
632
+ width: 90%;
633
+ box-shadow: 0 20px 60px rgba(0,0,0,0.8);
634
+ display: flex;
635
+ flex-direction: column;
636
+ align-items: center;
637
+ position: relative;
638
+ z-index: 10000; /* Higher than container */
639
+ pointer-events: auto !important;
640
+ }
641
+
642
+ .onboarding-sub {
643
+ color: var(--judicial-gold);
644
+ font-size: 1.5rem;
645
+ margin: 1rem 0;
646
+ font-family: 'Playfair Display', serif;
647
+ }
648
+
649
+ .instruction {
650
+ opacity: 0.7;
651
+ margin-bottom: 2rem;
652
+ }
653
+
654
+ .persona-grid {
655
+ display: grid;
656
+ grid-template-columns: 1fr 1fr;
657
+ gap: 1.5rem;
658
+ }
659
+
660
+ .persona-btn {
661
+ background: var(--glass);
662
+ border: 1px solid var(--glass-border);
663
+ color: var(--parchment);
664
+ padding: 1.5rem;
665
+ border-radius: 12px;
666
+ cursor: pointer;
667
+ display: flex;
668
+ flex-direction: column;
669
+ align-items: center;
670
+ gap: 0.8rem;
671
+ transition: all 0.3s ease;
672
+ }
673
+
674
+ .persona-btn i {
675
+ width: 24px;
676
+ height: 24px;
677
+ color: var(--judicial-gold);
678
+ }
679
+
680
+ .persona-btn:hover {
681
+ background: var(--gold-glow);
682
+ border-color: var(--judicial-gold);
683
+ transform: translateY(-5px);
684
+ }
685
+
686
+ .persona-btn small {
687
+ font-size: 0.7rem;
688
+ opacity: 0.6;
689
+ margin-top: 0.3rem;
690
+ }
691
+
692
+ .switch-profile {
693
+ margin-top: 2rem;
694
+ border-top: 1px solid var(--glass-border) !important;
695
+ border-radius: 0 !important;
696
+ }
697
+
698
+ .blur-background {
699
+ filter: blur(10px);
700
+ }
701
+
702
+ /* Custom Scrollbar */
703
+ ::-webkit-scrollbar {
704
+ width: 6px;
705
+ }
706
+
707
+ ::-webkit-scrollbar-track {
708
+ background: transparent;
709
+ }
710
+
711
+ ::-webkit-scrollbar-thumb {
712
+ background: var(--glass-border);
713
+ border-radius: 10px;
714
+ }
715
+
716
+ ::-webkit-scrollbar-thumb:hover {
717
+ background: var(--judicial-gold);
718
+ }
719
+
720
+ /* Persona Info Icon & Tooltip */
721
+ .info-trigger {
722
+ margin-left: 10px;
723
+ cursor: pointer;
724
+ position: relative;
725
+ display: flex;
726
+ align-items: center;
727
+ color: var(--judicial-gold);
728
+ opacity: 0.7;
729
+ transition: opacity 0.3s ease;
730
+ }
731
+
732
+ .info-trigger:hover {
733
+ opacity: 1;
734
+ }
735
+
736
+ .persona-tooltip {
737
+ position: absolute;
738
+ top: 40px;
739
+ right: 0;
740
+ width: 250px;
741
+ padding: 15px;
742
+ border-radius: 12px;
743
+ font-size: 0.85rem;
744
+ line-height: 1.4;
745
+ color: var(--parchment);
746
+ opacity: 0;
747
+ visibility: hidden;
748
+ transform: translateY(-10px);
749
+ transition: all 0.3s ease;
750
+ z-index: 1000;
751
+ border: 1px solid rgba(197, 160, 89, 0.2);
752
+ box-shadow: 0 10px 30px rgba(0,0,0,0.5);
753
+ background: rgba(13, 13, 13, 0.95);
754
+ backdrop-filter: blur(20px);
755
+ }
756
+
757
+ .info-trigger:hover .persona-tooltip {
758
+ opacity: 1;
759
+ visibility: visible;
760
+ transform: translateY(0);
761
+ }
762
+
763
+ .persona-tooltip strong {
764
+ color: var(--judicial-gold);
765
+ display: block;
766
+ margin-bottom: 5px;
767
+ font-family: 'Playfair Display', serif;
768
+ }
769
+
770
+ /* Judicial Lockdown State */
771
+ .lockdown-active {
772
+ pointer-events: none;
773
+ cursor: not-allowed !important;
774
+ }
775
+
776
+ .lockdown-active aside,
777
+ .lockdown-active .top-bar,
778
+ .lockdown-active .input-area {
779
+ opacity: 0.6;
780
+ filter: grayscale(0.5);
781
+ transition: all 0.3s ease;
782
+ }
783
+
784
+ .lockdown-active .input-area {
785
+ border-color: rgba(255, 0, 0, 0.2);
786
+ }
787
+
788
+ .lockdown-active #user-input::placeholder {
789
+ color: rgba(255, 255, 255, 0.2);
790
+ }
791
+
792
+ .message-time {
793
+ position: absolute;
794
+ bottom: 5px;
795
+ right: 12px;
796
+ font-size: 0.6rem;
797
+ opacity: 0.5;
798
+ font-family: 'Inter', sans-serif;
799
+ font-weight: 400;
800
+ }
801
+
802
+ .message.user .message-time {
803
+ color: var(--advocate-black);
804
+ opacity: 0.7;
805
+ }
full_models_list.txt ADDED
Binary file (3.63 kB). View file
 
list_models.py ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ from google import genai
3
+ from dotenv import load_dotenv
4
+
5
+ load_dotenv(override=True)
6
+
7
+ def list_available_models():
8
+ client = genai.Client(api_key=os.getenv("GEMINI_API_KEY"))
9
+ print("--- Available Models ---")
10
+ try:
11
+ for model in client.models.list():
12
+ print(f"- {model.name}")
13
+ except Exception as e:
14
+ print(f"Error: {e}")
15
+
16
+ if __name__ == "__main__":
17
+ list_available_models()
nyaya_project_brief.md ADDED
@@ -0,0 +1,64 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # 🏛️ Nyaya Agent: Technical & Functional Overview
2
+
3
+ **Nyaya Agent** is a premium, AI-powered Judicial Assistant designed to navigate the complexities of the Indian Legal System. It leverages state-of-the-art Generative AI to provide persona-aware legal research, statutory mapping, and compliance auditing.
4
+
5
+ ---
6
+
7
+ ## 🚀 Tech Stack
8
+ | Component | Technology |
9
+ | :--- | :--- |
10
+ | **AI Engine** | Google Gemini 2.0 Flash / Flash Lite |
11
+ | **Backend** | FastAPI (Python 3.11) |
12
+ | **Database** | ChromaDB (Vector Database for RAG) |
13
+ | **Frontend** | Vanilla HTML5, CSS3 (Glassmorphism), Lucide Icons |
14
+ | **Deployment** | Docker / Podman (Containerized) |
15
+ | **Hosting** | Hugging Face Spaces (Cloud) |
16
+
17
+ ---
18
+
19
+ ## 🏛️ Core Features
20
+
21
+ ### ⚖️ BNS-IPC Law Bridge
22
+ A specialized tool designed for the 2023 criminal law transition.
23
+ - **Function**: Instantly maps old **Indian Penal Code (IPC)** sections to the new **Bharatiya Nyaya Sanhita (BNS)**.
24
+ - **Value**: Provides lawyers with immediate statutory references and highlights key changes in definitions and punishments.
25
+
26
+ ### 🛡️ DPDPA Compliance Audit
27
+ Automated auditing for the **Digital Personal Data Protection Act (DPDPA), 2023**.
28
+ - **Function**: Analyzes privacy policies (PDF/Text) to identify legal gaps and compliance risks.
29
+ - **Value**: Simplifies regulatory adherence for businesses and legal consultants.
30
+
31
+ ### 🔍 Judicial Network (Live Search)
32
+ Integrated with the **Indian Kanoon API**.
33
+ - **Function**: Real-time retrieval of landmark judgments, statutes, and case laws.
34
+ - **Value**: Provides evidence-based legal research directly from official judicial records.
35
+
36
+ ---
37
+
38
+ ## 👤 User Personas
39
+ The system dynamically adapts its language, technical depth, and output format based on the selected profile:
40
+
41
+ 1. **Lawyer**: Focuses on procedural details, specific sections, and judicial precedents.
42
+ 2. **Student**: Emphasizes legal theory, landmark cases, and academic analysis.
43
+ 3. **Citizen**: Provides simple, jargon-free explanations of fundamental legal rights.
44
+ 4. **Explorer**: Offers a general overview and historical context of the Indian legal system.
45
+
46
+ ---
47
+
48
+ ## ⚙️ System Workflow
49
+ 1. **Input**: User interacts with the **Glassmorphism UI** or uploads a document.
50
+ 2. **Routing**: The **FastAPI Backend** processes the request and identifies the active **Persona**.
51
+ 3. **Reasoning**: The **Gemini AI Engine** determines if it needs to call specialized **Tools** (Kanoon Search, BNS Bridge, etc.).
52
+ 4. **Synthesis**: The agent combines statutory data with its generative capabilities to provide a persona-tailored response.
53
+ 5. **Output**: Results are displayed in the interactive chat with support for one-click **Copy-to-Clipboard** and **Drafting**.
54
+
55
+ ---
56
+
57
+ ## 🔐 Security & Deployment
58
+ - **Containerization**: The entire ecosystem is packaged as a Docker image for consistent performance across environments.
59
+ - **Secrets Management**: API Keys are never hardcoded; they are managed via **Space Secrets** (Hugging Face) or `.env` files (Local).
60
+ - **Sub-Path Namespacing**: The application is architected to be cloud-ready and easily deployable to platforms like Hugging Face.
61
+
62
+ ---
63
+ **Satyameva Jayate**
64
+ *Truth Alone Triumphs*
requirements.txt ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ google-genai
2
+ python-dotenv
3
+ fastapi
4
+ uvicorn
5
+ pydantic-settings
6
+ python-multipart
7
+ pypdf
8
+ chromadb
9
+ requests
10
+ markdown
server.py ADDED
@@ -0,0 +1,95 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import FastAPI, HTTPException, File, UploadFile
2
+ from pydantic import BaseModel
3
+ from fastapi.middleware.cors import CORSMiddleware
4
+ from fastapi.staticfiles import StaticFiles
5
+ import io
6
+ import os
7
+ import pypdf
8
+ import traceback
9
+ from core.agent import NyayaAgent
10
+ from tools.search_tool import search_indian_kanoon, get_act_details, search_legal_documents
11
+ from tools.legal_tools import draft_rti_query, draft_legal_notice, analyze_case_summary
12
+ from tools.compliance import audit_privacy_policy
13
+ from tools.law_bridge import ipc_to_bns_lookup
14
+ from google.genai import types
15
+
16
+ # Initialize Agent and App
17
+ agent = NyayaAgent()
18
+ app = FastAPI(title="Nyaya Agent")
19
+
20
+ # CORS
21
+ app.add_middleware(
22
+ CORSMiddleware,
23
+ allow_origins=["*"],
24
+ allow_credentials=True,
25
+ allow_methods=["*"],
26
+ allow_headers=["*"],
27
+ )
28
+
29
+ class ChatRequest(BaseModel):
30
+ message: str
31
+ persona: str = "explorer"
32
+
33
+ # API ROUTES MUST COME BEFORE STATIC MOUNT
34
+ @app.post("/api/chat")
35
+ async def chat(request: ChatRequest):
36
+ try:
37
+ custom_instruction = f"{agent.system_instruction}\n\nCURRENT USER PERSONA: {request.persona.upper()}. "
38
+ if request.persona == "lawyer":
39
+ custom_instruction += "Provide highly technical legal analysis with specific sections and procedural details."
40
+ elif request.persona == "student":
41
+ custom_instruction += "Provide academic analysis, citing landmark cases and legal theory."
42
+ else:
43
+ custom_instruction += "Use simple language, avoid jargon, and explain basic legal concepts clearly."
44
+
45
+ tools = [
46
+ search_indian_kanoon,
47
+ get_act_details,
48
+ search_legal_documents,
49
+ draft_rti_query,
50
+ draft_legal_notice,
51
+ analyze_case_summary,
52
+ audit_privacy_policy,
53
+ ipc_to_bns_lookup
54
+ ]
55
+
56
+ config = types.GenerateContentConfig(
57
+ system_instruction=custom_instruction,
58
+ tools=tools,
59
+ temperature=0.2,
60
+ )
61
+
62
+ response_text = agent.generate_response(request.message, config=config)
63
+ return {"response": response_text}
64
+ except Exception as e:
65
+ print(f"ERROR IN CHAT: {str(e)}", flush=True)
66
+ traceback.print_exc()
67
+ raise HTTPException(status_code=500, detail=str(e))
68
+
69
+ @app.post("/api/upload")
70
+ async def upload_file(file: UploadFile = File(...)):
71
+ try:
72
+ content = await file.read()
73
+ text = ""
74
+ if file.filename.endswith(".pdf"):
75
+ reader = pypdf.PdfReader(io.BytesIO(content))
76
+ for page in reader.pages:
77
+ text += page.extract_text() + "\n"
78
+ else:
79
+ text = content.decode("utf-8")
80
+ return {"filename": file.filename, "text": text}
81
+ except Exception as e:
82
+ raise HTTPException(status_code=500, detail=f"Error processing file: {str(e)}")
83
+
84
+ @app.get("/api/status")
85
+ async def status():
86
+ return {"status": "Satyameva Jayate - Online"}
87
+
88
+ # MOUNT STATIC FILES LAST
89
+ app.mount("/", StaticFiles(directory="frontend", html=True), name="frontend")
90
+
91
+ if __name__ == "__main__":
92
+ import uvicorn
93
+ # Hugging Face uses 7860
94
+ port = int(os.getenv("PORT", 7860))
95
+ uvicorn.run(app, host="0.0.0.0", port=port)
session_snapshot.md ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # 🏛️ Nyaya Agent: Session Snapshot
2
+
3
+ **Date**: May 12, 2026
4
+ **Status**: Successfully Deployed & Verified 🚀
5
+
6
+ ---
7
+
8
+ ## ✅ Completed Milestones
9
+ 1. **AI Engine**: Configured to use `gemini-flash-lite-latest` for maximum free-tier stability and high quota.
10
+ 2. **Architecture**: FastAPI backend with a Root-Level routing system optimized for Hugging Face Spaces.
11
+ 3. **UI/UX**: Full Glassmorphism judicial dashboard with persona-adaptive interactions.
12
+ 4. **Legal Tools**:
13
+ - **BNS-IPC Bridge** (Criminal Law mapping)
14
+ - **DPDPA 2023 Audit** (Privacy Policy analysis)
15
+ - **Indian Kanoon Search** (Case law retrieval)
16
+ 5. **Cloud Deployment**: 100% functional Docker deployment on Hugging Face Spaces.
17
+
18
+ ---
19
+
20
+ ## 🔑 Active Configuration
21
+ - **App URL**: `http://localhost:8000` (Local) | `huggingface.co/spaces/SeriousSam07/nyaya-agent` (Cloud)
22
+ - **Container Port**: `7860` (Internal) -> `8000` (External)
23
+ - **Base Path**: Root (`/`)
24
+ - **API Endpoint**: `/api`
25
+
26
+ ---
27
+
28
+ ## 🛠️ Next Steps / Ideas for Future Sessions
29
+ 1. **Legal History Sidebar**: Implement `localStorage` to save and display previous chat sessions.
30
+ 2. **Judicial News Ticker**: Add a live RSS feed for the latest Supreme Court and High Court judgments.
31
+ 3. **Advanced PDF Parsing**: Improve table extraction for complex legal documents.
32
+ 4. **Audio Interface**: Add "Speech-to-Text" for lawyers to dictate notes directly.
33
+
34
+ ---
35
+ **Current State**: All systems operational.
36
+ **Satyameva Jayate.**
test_drive.py ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import requests
2
+ import json
3
+ import os
4
+ from dotenv import load_dotenv
5
+
6
+ load_dotenv()
7
+
8
+ # Updated for root-level deployment
9
+ BASE_URL = "http://localhost:8000/api"
10
+
11
+ def test_endpoint(path, payload, method="POST"):
12
+ print(f"Testing {path}...")
13
+ try:
14
+ if method == "POST":
15
+ response = requests.post(f"{BASE_URL}{path}", json=payload)
16
+ else:
17
+ response = requests.get(f"{BASE_URL}{path}")
18
+
19
+ print(f"Status: {response.status_code}")
20
+ # Only print first 500 chars of response to keep logs clean
21
+ resp_json = response.json()
22
+ resp_str = json.dumps(resp_json, indent=2)
23
+ print(f"Response: {resp_str[:500]}..." if len(resp_str) > 500 else f"Response: {resp_str}")
24
+ print("-" * 30)
25
+ return response.status_code == 200
26
+ except Exception as e:
27
+ print(f"Error: {e}")
28
+ return False
29
+
30
+ if __name__ == "__main__":
31
+ print("=== NYAYA AGENT FINAL ACCEPTANCE TEST ===\n")
32
+
33
+ # 1. Test Status
34
+ test_endpoint("/status", {}, method="GET")
35
+
36
+ # 2. Test Lawyer Persona + BNS Bridge
37
+ test_endpoint("/chat", {
38
+ "message": "What is the new BNS section for IPC 302?",
39
+ "persona": "lawyer"
40
+ })
41
+
42
+ # 3. Test Citizen Persona + General Advice
43
+ test_endpoint("/chat", {
44
+ "message": "How do I file an RTI for my property records?",
45
+ "persona": "citizen"
46
+ })
47
+
48
+ # 4. Test Compliance Audit Tool
49
+ test_endpoint("/chat", {
50
+ "message": "Audit this: We collect your email for marketing. You can contact us at privacy@example.com.",
51
+ "persona": "lawyer"
52
+ })
53
+
54
+ print("\nTests complete. If all statuses are 200, the Judicial Hub is ready for the team!")
test_kanoon.py ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ from dotenv import load_dotenv
3
+ from tools.search_tool import search_indian_kanoon
4
+
5
+ load_dotenv(override=True)
6
+
7
+ def run_test():
8
+ print("--- Indian Kanoon API Connection Test ---")
9
+ query = "Constitution"
10
+ result = search_indian_kanoon(query)
11
+ print(f"Query: {query}")
12
+ print(f"Result:\n{result}")
13
+ print("-" * 40)
14
+
15
+ if __name__ == "__main__":
16
+ run_test()
test_quota.py ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ from google import genai
3
+ from dotenv import load_dotenv
4
+
5
+ load_dotenv()
6
+ client = genai.Client(api_key=os.getenv("GEMINI_API_KEY"))
7
+
8
+ models_to_test = ['gemini-flash-latest', 'gemini-pro-latest', 'gemini-1.5-flash-8b', 'gemini-1.5-flash']
9
+
10
+ for model in models_to_test:
11
+ print(f"Testing model: {model}...")
12
+ try:
13
+ response = client.models.generate_content(
14
+ model=model,
15
+ contents="Say hi"
16
+ )
17
+ print(f"SUCCESS: {model} works! Response: {response.text}")
18
+ except Exception as e:
19
+ print(f"FAILED: {model} - Error: {e}")
tools/compliance.py ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ def audit_privacy_policy(policy_text: str):
2
+ """
3
+ Analyzes a Privacy Policy against the Digital Personal Data Protection Act (DPDPA) 2023.
4
+
5
+ Args:
6
+ policy_text: The full text of the privacy policy to audit.
7
+ """
8
+ # This tool will be called by the agent to perform a structured audit.
9
+ # The agent will use its internal knowledge of DPDPA 2023 to identify gaps.
10
+ return (
11
+ "DPDPA 2023 AUDIT REPORT\n"
12
+ "-----------------------\n"
13
+ "1. NOTICE (Section 5): Analyzing if purpose and data types are specified...\n"
14
+ "2. CONSENT (Section 6): Checking for 'Clear and Affirmative' consent language...\n"
15
+ "3. GRIEVANCE REDRESSAL (Section 12): Searching for Grievance Officer contact details...\n\n"
16
+ "Please provide the policy text, and I will highlight the specific compliance gaps."
17
+ )
tools/ingest.py ADDED
@@ -0,0 +1,66 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import chromadb
3
+ from chromadb.utils import embedding_functions
4
+ from pypdf import PdfReader
5
+ from dotenv import load_dotenv
6
+
7
+ load_dotenv(override=True)
8
+
9
+ # Configuration
10
+ CHROMA_PATH = "data/chroma_db"
11
+ COLLECTION_NAME = "nyaya_legal_docs"
12
+
13
+ # Initialize ChromaDB
14
+ client = chromadb.PersistentClient(path=CHROMA_PATH)
15
+
16
+ # Use Gemini embeddings via a custom wrapper or OpenAI-compatible one if available
17
+ # For simplicity in this workshop, we'll use a default sentence-transformer if available,
18
+ # or a simple placeholder.
19
+ # Better yet: Use Chroma's built-in default for now.
20
+ embedding_func = embedding_functions.DefaultEmbeddingFunction()
21
+
22
+ collection = client.get_or_create_collection(
23
+ name=COLLECTION_NAME,
24
+ embedding_function=embedding_func
25
+ )
26
+
27
+ def ingest_pdf(file_path):
28
+ """Reads a PDF, chunks it, and adds it to the vector database."""
29
+ print(f"Ingesting: {file_path}")
30
+ reader = PdfReader(file_path)
31
+
32
+ doc_id = os.path.basename(file_path)
33
+ chunks = []
34
+ metadata = []
35
+ ids = []
36
+
37
+ for i, page in enumerate(reader.pages):
38
+ text = page.extract_text()
39
+ if text.strip():
40
+ # Basic chunking by page for now
41
+ chunks.append(text)
42
+ metadata.append({"source": doc_id, "page": i + 1})
43
+ ids.append(f"{doc_id}_page_{i+1}")
44
+
45
+ if chunks:
46
+ collection.add(
47
+ documents=chunks,
48
+ metadatas=metadata,
49
+ ids=ids
50
+ )
51
+ print(f"Successfully added {len(chunks)} pages from {doc_id}")
52
+
53
+ def search_docs(query, n_results=3):
54
+ """Searches the collection for relevant snippets."""
55
+ results = collection.query(
56
+ query_texts=[query],
57
+ n_results=n_results
58
+ )
59
+ return results
60
+
61
+ if __name__ == "__main__":
62
+ # Test with any PDFs in the data folder
63
+ data_dir = "data"
64
+ for file in os.listdir(data_dir):
65
+ if file.endswith(".pdf"):
66
+ ingest_pdf(os.path.join(data_dir, file))
tools/law_bridge.py ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ def ipc_to_bns_lookup(ipc_section: str):
2
+ """
3
+ Maps an Indian Penal Code (IPC) section to the corresponding Bharatiya Nyaya Sanhita (BNS) 2023 section.
4
+
5
+ Args:
6
+ ipc_section: The IPC section number (e.g., '302', '420').
7
+ """
8
+ # Key Mappings (Sample for MVP)
9
+ mappings = {
10
+ "302": {"bns": "101", "name": "Punishment for Murder", "change": "Punishment remains life/death; restructuring of clauses for clarity."},
11
+ "420": {"bns": "318", "name": "Cheating and dishonestly inducing delivery of property", "change": "Merged with other cheating sections; broader definition of 'property'."},
12
+ "498A": {"bns": "85/86", "name": "Cruelty by husband or relatives", "change": "Split into two sections; Section 85 defines cruelty, Section 86 defines punishment."},
13
+ "376": {"bns": "64-70", "name": "Punishment for Rape", "change": "Extensively expanded; separate sections for aggravated cases and gang rape."},
14
+ "124A": {"bns": "152", "name": "Sedition (now 'Acts endangering sovereignty')", "change": "The word 'Sedition' is removed; focuses on acts against the state/sovereignty."}
15
+ }
16
+
17
+ clean_section = ipc_section.upper().replace("IPC", "").strip()
18
+
19
+ if clean_section in mappings:
20
+ m = mappings[clean_section]
21
+ return (
22
+ f"--- BNS-IPC CROSS-REFERENCE ---\n"
23
+ f"Old Section: IPC {clean_section} ({m['name']})\n"
24
+ f"New Section: BNS {m['bns']}\n"
25
+ f"Key Change: {m['change']}\n"
26
+ f"--------------------------------"
27
+ )
28
+ else:
29
+ return f"Section IPC {clean_section} not found in the immediate lookup table. Please consult the full BNS Schedule or ask me to search for the specific offense name."
tools/legal_tools.py ADDED
@@ -0,0 +1,52 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ def draft_rti_query(subject: str, department: str = "Relevant Public Authority"):
2
+ """
3
+ Drafts a formal RTI (Right to Information) query for a given subject.
4
+ """
5
+ template = (
6
+ f"Subject: Application under RTI Act, 2005 - Regarding {subject}\n\n"
7
+ f"To,\nThe Public Information Officer,\n{department}\n\n"
8
+ f"Sir/Madam,\n"
9
+ f"I request you to provide the following information under the RTI Act, 2005:\n"
10
+ f"1. Detailed records/notifications regarding {subject}.\n"
11
+ f"2. Any internal circulars or guidelines issued concerning this matter.\n"
12
+ f"3. Time period of the requested data: [Specify Period].\n\n"
13
+ f"I am a citizen of India. I have attached the prescribed fee of Rs. 10/-\n\n"
14
+ f"Regards,\n[Your Name]"
15
+ )
16
+ return template
17
+
18
+ def draft_legal_notice(sender: str, receiver: str, grievance: str, relief: str):
19
+ """
20
+ Prepares a formal legal notice for a specific grievance.
21
+
22
+ Args:
23
+ sender: Name and address of the sender.
24
+ receiver: Name and address of the receiver.
25
+ grievance: Detailed description of the legal grievance/dispute.
26
+ relief: The action or compensation demanded from the receiver.
27
+ """
28
+ notice = (
29
+ f"LEGAL NOTICE\n\n"
30
+ f"From: {sender}\n"
31
+ f"To: {receiver}\n\n"
32
+ f"Under instructions from my client {sender}, I hereby serve you with this legal notice:\n\n"
33
+ f"1. THE GRIEVANCE: {grievance}\n"
34
+ f"2. LEGAL VIOLATION: This act is a violation of relevant Indian laws.\n"
35
+ f"3. THE RELIEF: You are hereby called upon to {relief} within 15 days of receipt of this notice.\n\n"
36
+ f"Failing which, my client shall be constrained to initiate civil/criminal proceedings against you.\n\n"
37
+ f"Regards,\n[Advocate Name]"
38
+ )
39
+ return notice
40
+
41
+ def analyze_case_summary(case_text: str):
42
+ """
43
+ Analyzes a legal case and provides a structured summary (Facts, Issues, Ratio).
44
+
45
+ Args:
46
+ case_text: The full text or excerpt of the judgment to analyze.
47
+ """
48
+ return "Case Analysis Placeholder: I will provide Facts, Issues, Arguments, and the Ratio Decidendi here."
49
+
50
+ def suggest_sc_followup():
51
+ """Provides a suggestion to check the latest Supreme Court filings."""
52
+ return "Would you like me to check the latest Supreme Court filings or judgments related to this matter?"
tools/search_tool.py ADDED
@@ -0,0 +1,79 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import chromadb
3
+ from chromadb.utils import embedding_functions
4
+
5
+ # Configuration
6
+ CHROMA_PATH = "data/chroma_db"
7
+ COLLECTION_NAME = "nyaya_legal_docs"
8
+
9
+ def get_vector_collection():
10
+ client = chromadb.PersistentClient(path=CHROMA_PATH)
11
+ embedding_func = embedding_functions.DefaultEmbeddingFunction()
12
+ return client.get_or_create_collection(
13
+ name=COLLECTION_NAME,
14
+ embedding_function=embedding_func
15
+ )
16
+
17
+ def search_legal_documents(query: str):
18
+ """
19
+ Search across the indexed legal documents (Gazettes, Circulars, etc.) using semantic search.
20
+
21
+ Args:
22
+ query: The natural language query to search for in local documents.
23
+ """
24
+ try:
25
+ collection = get_vector_collection()
26
+ results = collection.query(
27
+ query_texts=[query],
28
+ n_results=3
29
+ )
30
+ if results['documents']:
31
+ return "\n\n".join(results['documents'][0])
32
+ return "No relevant local documents found."
33
+ except Exception as e:
34
+ return f"Error searching local documents: {e}"
35
+
36
+ import os
37
+ import requests
38
+
39
+ def search_indian_kanoon(query: str):
40
+ """
41
+ Search for legal cases, acts, and statutes on Indian Kanoon (Online).
42
+ """
43
+ token = os.getenv("INDIANKANOON_API_KEY")
44
+ if not token:
45
+ return f"Search result placeholder for: {query}. (API Token missing in .env. Using internal model knowledge.)"
46
+
47
+ try:
48
+ headers = {
49
+ "Authorization": f"Token {token}",
50
+ "Accept": "application/json"
51
+ }
52
+ params = {"formInput": query, "pagenum": 0}
53
+ # Searching for the query - Indian Kanoon requires POST with params in the URL
54
+ response = requests.post(
55
+ f"https://api.indiankanoon.org/search/",
56
+ headers=headers,
57
+ params=params
58
+ )
59
+ data = response.json()
60
+
61
+ if "docs" in data:
62
+ results = data["docs"][:3]
63
+ summary = "Found these cases on Indian Kanoon:\n"
64
+ for res in results:
65
+ summary += f"- {res['title']} (Source: {res.get('docsource', 'Unknown')}, ID: {res['tid']})\n"
66
+ return summary
67
+ return "No results found on Indian Kanoon."
68
+ except Exception as e:
69
+ return f"Error connecting to Indian Kanoon: {e}"
70
+
71
+ def get_act_details(act_name: str, section: str = None):
72
+ """
73
+ Retrieve details of a specific Indian Act or Section.
74
+
75
+ Args:
76
+ act_name: Name of the Act (e.g., 'IPC', 'DPDPA').
77
+ section: Specific section number (optional).
78
+ """
79
+ return f"Details for {act_name} Section {section if section else 'All'}. (Data retrieval pending)"