adarsh-maurya commited on
Commit
89c1309
·
verified ·
1 Parent(s): f8f4bda

Upload 9 files

Browse files
.gitignore ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Python
2
+ .env
3
+ *.pyc
4
+ __pycache__/
5
+ *.so
6
+ .Python
7
+ build/
8
+ develop-eggs/
9
+ dist/
10
+ downloads/
11
+ eggs/
12
+ .eggs/
13
+ lib/
14
+ lib64/
15
+ parts/
16
+ sdist/
17
+ var/
18
+ wheels/
19
+ *.egg-info/
20
+ .installed.cfg
21
+ *.egg
22
+
23
+ # Environments
24
+ .env
25
+ .venv
26
+ env/
27
+ venv/
28
+ ENV/
29
+ env.bak/
30
+ venv.bak/
31
+
32
+ # Streamlit
33
+ .streamlit/
34
+
35
+ # Firebase
36
+ *.json
37
+ serviceAccountKey.json
38
+
39
+ # IDE
40
+ .vscode/
41
+ .idea/
42
+ *.swp
43
+ *.swo
44
+
45
+ # Temp files
46
+ *.tmp
47
+ *.temp
48
+
49
+ # Logs
50
+ *.log
Ingest.py ADDED
@@ -0,0 +1,61 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import ray
2
+ import logging
3
+ from langchain_community.document_loaders import DirectoryLoader
4
+ from langchain_community.embeddings import HuggingFaceEmbeddings
5
+ from langchain.text_splitter import RecursiveCharacterTextSplitter
6
+ from langchain_community.vectorstores import FAISS
7
+ from faiss import IndexFlatL2 # Assuming using L2 distance for simplicity
8
+
9
+ # Initialize Ray
10
+ ray.init()
11
+
12
+ # Set up basic configuration for logging
13
+ logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
14
+
15
+ # Load documents with logging
16
+ logging.info("Loading documents...")
17
+ loader = DirectoryLoader('data', glob="./*.txt") #ipc_law.txt file get loaded
18
+ documents = loader.load()
19
+
20
+ # Extract text from documents and split into manageable texts with logging
21
+ logging.info("Extracting and splitting texts from documents...")
22
+ text_splitter = RecursiveCharacterTextSplitter(chunk_size=1024, chunk_overlap=200)
23
+ texts = []
24
+ for document in documents:
25
+ if hasattr(document, 'get_text'):
26
+ text_content = document.get_text() # Adjust according to actual method
27
+ else:
28
+ text_content = "" # Default to empty string if no text method is available
29
+
30
+ texts.extend(text_splitter.split_text(text_content))
31
+
32
+ # Define embedding function
33
+ def embedding_function(text):
34
+ embeddings_model = HuggingFaceEmbeddings(model_name="law-ai/InLegalBERT")
35
+ return embeddings_model.embed_query(text)
36
+
37
+ # Create FAISS index for embeddings
38
+ index = IndexFlatL2(768) # Dimension of embeddings, adjust as needed
39
+
40
+ # Assuming docstore as a simple dictionary to store document texts
41
+ docstore = {i: text for i, text in enumerate(texts)}
42
+ index_to_docstore_id = {i: i for i in range(len(texts))}
43
+
44
+ # Initialize FAISS
45
+ faiss_db = FAISS(embedding_function, index, docstore, index_to_docstore_id)
46
+
47
+ # Process and store embeddings
48
+ logging.info("Storing embeddings in FAISS...")
49
+ for i, text in enumerate(texts):
50
+ embedding = embedding_function(text)
51
+ faiss_db.add_documents([embedding])
52
+
53
+ # Exporting the vector embeddings database with logging
54
+ logging.info("Exporting the vector embeddings database...")
55
+ faiss_db.save_local("ipc_embed_db")
56
+
57
+ # Log a message to indicate the completion of the process
58
+ logging.info("Process completed successfully.")
59
+
60
+ # Shutdown Ray after the process
61
+ ray.shutdown()
README.md CHANGED
@@ -1,13 +1,95 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  ---
2
- title: ApnaLawyer V1
3
- emoji: 🏢
4
- colorFrom: gray
5
- colorTo: gray
6
- sdk: streamlit
7
- sdk_version: 1.44.1
8
- app_file: app.py
9
- pinned: false
10
- license: mit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11
  ---
12
 
13
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
1
+ # ApnaLaw: AI IPC Legal advice Assistant 📘
2
+
3
+ ApnaLaw is a sophisticated legal advisory chatbot focused on providing detailed and contextually accurate responses about the Indian Penal Code. It utilizes a powerful combination of machine learning technologies to efficiently process and retrieve legal information.
4
+
5
+ ---
6
+
7
+ ## Features 🌟
8
+
9
+ - **Document Ingestion**: Automated processing of text documents to store legal information in a FAISS vector database.
10
+ - **Real-Time Interaction**: Real-time legal advice through a conversational interface built with Streamlit.
11
+ - **Legal Prompt Templating**: Structured prompt format ensuring clarity, detail, and legal accuracy in responses.
12
+ <br>
13
+
14
+ ---
15
+
16
+ <h4><strong>🚀Blast off to discovery! Our project is waiting for you <a href= "https://huggingface.co/spaces/adarsh-maurya/ApnaLawyer">ApnaLaw</a>. Explore it today and elevate your understanding!🌟</strong><h4>
17
+ <br>
18
+
19
+ ---
20
+
21
+ ## Components 🛠️
22
+
23
+ ### Ingestion Script (`Ingest.py`)
24
+
25
+ | Functionality | Description |
26
+ |----------------------|-------------|
27
+ | **Document Loading** | Loads text documents from a specified directory. |
28
+ | **Text Splitting** | Splits documents into manageable chunks for processing. |
29
+ | **Embedding Generation** | Utilizes `HuggingFace's InLegalBERT` to generate text embeddings. |
30
+ | **FAISS Database** | Indexes embeddings for fast and efficient retrieval. |
31
+
32
+ ### Web Application (`app.py`)
33
+
34
+ | Feature | Description |
35
+ |-----------------------|-------------|
36
+ | **Streamlit Interface** | Provides a web interface for user interaction. |
37
+ | **Chat Functionality** | Manages conversational flow and stores chat history. |
38
+ | **Legal Information Retrieval** | Leverages FAISS index to fetch pertinent legal information based on queries.
39
+
40
  ---
41
+
42
+ ## Setup 📦
43
+
44
+ ### Prerequisites
45
+
46
+ - Python 3.8 or later
47
+ - ray
48
+ - langchain
49
+ - streamlit
50
+ - faiss
51
+
52
+ ### Installation
53
+
54
+ 1. **Clone the repository:**
55
+ ```bash
56
+ git clone https://github.com/your-repo/ApnaLaw.git
57
+ cd ApnaLaw
58
+ ```
59
+ 2. **Install dependencies:**
60
+ ```bash
61
+ pip install -r requirements.txt
62
+ ```
63
+ 3. **Set up the Together AI API Key:**
64
+ Obtain an API key from <a href="https://api.together.xyz/">Together AI</a>.&nbsp;
65
+ Sign up with Together AI today and get $25 worth of free credit! 🎉 Whether you choose to use it for a short-term project or opt for a long-term commitment, Together AI offers cost-effective solutions compared to the OpenAI API. 🚀&nbsp;<br><br>
66
+ **> To set this API key as an environment variable on any OS, you can use the following approach:**
67
+ - On macOS and Linux:
68
+ ```bash
69
+ echo "export TOGETHER_API_KEY='Your-API-Key-Here'" >> ~/.bash_profile
70
+ source ~/.bash_profile
71
+ ```
72
+ - On Windows (using Command Prompt):
73
+ ```cmd
74
+ setx TOGETHER_API_KEY "Your-API-Key-Here"
75
+ ```
76
+ - On Windows (using PowerShell):
77
+ ```powershell
78
+ [Environment]::SetEnvironmentVariable("TOGETHER_API_KEY", "Your-API-Key-Here", "User")
79
+ ```
80
+ This key is crucial for the chatbot to access language model functionalities provided by Together AI.
81
+
82
+ ## Running the Application
83
+ 1. **Run the ingestion script to prepare the data:**
84
+ ```bash
85
+ python ingest.py
86
+ ```
87
+ 2. Launch the Streamlit application:
88
+ ```bash
89
+ streamlit run app.py
90
+ ```
91
  ---
92
 
93
+ ## Usage 🔍
94
+
95
+ Navigate to the local URL provided by Streamlit to interact with the ApnaLaw chatbot. Enter your legal queries and receive precise information derived from the indexed legal documents. Utilize the chat interface to engage in a legal discussion and get accurate advice.<br>
apna-lawyer-firebase-adminsdk-fbsvc-4171a65364.json ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "type": "service_account",
3
+ "project_id": "apna-lawyer",
4
+ "private_key_id": "4171a65364e11ca6ede460482c459105e6b13429",
5
+ "private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDimw6wj4ek0ENk\n/zyfFToTO6PRILg+RwUfq5sT9wyR4UenX/qIJn5MqJBhNzv04IAmHDxIbLJj00gC\n8OPlSQ2cYxDCYreAqUuKXur/MiLrfR7W6bqZKuhipNoVz4UNpFQLrxc5cYAS4FER\nvJnsqngRi7thd+6LdYhnHYrdCnWTJigPjw3wKgWj+ATTAJ0QfqMhzHMswmxZpisX\nrlNbDmwJOhtgKCwjSGHZ4/Hk78oBVSVzkBXMYpykbgAf8QDQQy9yBf0uIbVkOPXk\nCRqsM9w4nHuimjPDJglKR8pKc+DDf9NVfgvRczoZKiu6jDJ6nmffSKbpN2xaooP2\nAeTsHqslAgMBAAECggEARXYUTajhgnLYhcf7VCRUlfqtH3ixIV3xwyB+O+N5tenh\nZfv0tvFdu6/b+gDNXyXGAmibTfQLxq/IHiarJOh8xJhVVdCewVCjuDmaPTmoHJlQ\n773blgHiFALGWvMurNzXanF0ZAZXpPGfyBkQ8cvbXD2B5cG2nIcdlcYnf9Qp8D2p\nHgFM2OIZ8dmpmc+CpIVntC/qsNYKHKps2cm4xOi0FhC2S/g2M332aNiJd29lh0TF\nFkACRg5ls5K2SJt2wXAzSXIlcEHCoUTpQpg1+0Y3bbKT4qZRKIsox0HaOfDy1+Ww\neDt4km6ym7GjI++GODoitHJ9l3RZVYPuM5mR/nAeDQKBgQD+cj1t0V+2OZ2VlHqo\nv/azmysyXMNNsvbl8t4npkGekugthtwW0mGBODpHHRoQlnGI/xbdaRVX6dI7ktUh\noYqGQRjysau68Boe7isc2c7F6ClDaLEIW+wEfH0yEuBHPXlmqRo+DOiRi0KWnGCm\ng9fCkJIq2+F+x8vA09sOpVxLAwKBgQDj/UvHNuAxUP/F5IDTZfOtZLZLPVmmE+0R\nh99KN+jjjJxR3/5inuBAkMDKzgrnCvQsQ0U70+ffiOrHLBjvrG85jThXsVFHcry/\ncU4wV8N+Rm8Ljt4mJ57txXzKZx6bNSY9ZZN93lfmv9Rn7D8EOcALqrrKk7Oh1EW4\nwOxc/FMEtwKBgQDxMQMv1ReAGa9Z+ewniAfnir/wtmPfhDRsFsMlHID5OtJhTYPV\nEkmg/tanUFvDu4gVz5AyAwlbU2aYWAA2J/Wye4SVkXty8WQhS6yMZZ6OlRqALn4Z\nqWDZg9P9Ik182jX47XTVutC+Hh7Zu5QWY8WjRf14KQPgdK2ctHXitTb+VwKBgGJB\nQ2szhyM52UEb3Tk98uqDQNzkL8KXS9AGUoDV35RRgPz4H9W4ysSInc3JRoGUAu8g\nfrHt/Twk8amso4KHOdf/uIxyaqj0FcwbtKq46BN/n1PH2o1u/dtTBRjloBcbrMNB\nB3NzY0aa3Zt8ARx9FvrwNVggl4Xiybl5y2O3ir+5AoGBAIHuvfs/t6F0/S1SQgVf\nTpN/y88/klytRvaYJhvp2FFQ2p5z1WZQBDlqiueJLnQ5xcvMDsxhX+KufDR0u0nm\nEwujQBx/4qTzyy1Df8qcW6nEL+E/ftQKI5sZxdyR5PGmQL9tddpORweuuOA1H3UN\ncxNKyn5YfYHTxabURRGA+1et\n-----END PRIVATE KEY-----\n",
6
+ "client_email": "[email protected]",
7
+ "client_id": "109468658206929239872",
8
+ "auth_uri": "https://accounts.google.com/o/oauth2/auth",
9
+ "token_uri": "https://oauth2.googleapis.com/token",
10
+ "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
11
+ "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/firebase-adminsdk-fbsvc%40apna-lawyer.iam.gserviceaccount.com",
12
+ "universe_domain": "googleapis.com"
13
+ }
app.py ADDED
@@ -0,0 +1,896 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import time
2
+ import os
3
+ import streamlit as st
4
+ from langchain_community.vectorstores import FAISS
5
+ from langchain_community.embeddings import HuggingFaceEmbeddings
6
+ from langchain.prompts import PromptTemplate
7
+ from langchain.memory import ConversationBufferWindowMemory
8
+ from langchain.chains import ConversationalRetrievalChain
9
+ from langchain_together import Together
10
+ from footer import footer
11
+ from firebase_config import firebaseConfig
12
+ import pyrebase
13
+ # Import firebase_admin and credentials
14
+ import firebase_admin
15
+ from firebase_admin import credentials, initialize_app, db as firebase_db
16
+
17
+ # Add at the top of your file
18
+ import streamlit.components.v1 as components
19
+ import hashlib
20
+ import urllib.parse
21
+ from deep_translator import GoogleTranslator
22
+ from langdetect import detect
23
+
24
+ from transformers import pipeline
25
+ import soundfile as sf
26
+ import numpy as np
27
+ from io import BytesIO
28
+ import tempfile
29
+ # # Speech Recognition Imports (add these at top of file)
30
+ # import tempfile
31
+ import openai
32
+ from dotenv import load_dotenv
33
+ load_dotenv()
34
+ openai.api_key = os.getenv('OPENAI_API_KEY')
35
+
36
+ # Function to translate text
37
+ def translate_text(text, target_language):
38
+ try:
39
+ # Use GoogleTranslator from deep-translator
40
+ translated_text = GoogleTranslator(source='auto', target=target_language).translate(text)
41
+ return translated_text
42
+ except Exception as e:
43
+ return f"⚠ Translation failed: {str(e)}"
44
+
45
+ # Initialize the translator
46
+ #translator = Translator()
47
+
48
+ # Initialize Firebase (you would call this at the start of your app)
49
+ def initialize_firebase():
50
+ try:
51
+ if not firebase_admin._apps:
52
+ cred = credentials.Certificate("apna-lawyer-firebase-adminsdk-fbsvc-4171a65364.json")
53
+ firebase_app = initialize_app(cred, {
54
+ 'databaseURL': firebaseConfig['databaseURL']
55
+ })
56
+ except Exception as e:
57
+ st.error(f"Firebase initialization error: {str(e)}")
58
+
59
+ # ----------------- Firebase Init -------------------
60
+ firebase = pyrebase.initialize_app(firebaseConfig)
61
+ auth = firebase.auth()
62
+ initialize_firebase()
63
+
64
+ # ----------------- Streamlit Config -------------------
65
+ st.set_page_config(page_title="ApnaLawyer", layout="centered")
66
+
67
+ col1, col2, col3 = st.columns([1, 30, 1])
68
+ with col2:
69
+ st.image("images/banner.jpg", use_container_width=True)
70
+
71
+ st.markdown("""
72
+ <style>
73
+ #MainMenu {visibility: hidden;}
74
+ footer {visibility: hidden;}
75
+ </style>
76
+ """, unsafe_allow_html=True)
77
+
78
+ # ----------------- Login/Signup Interface -------------------
79
+ import json
80
+ import requests
81
+ from streamlit.components.v1 import html
82
+
83
+ # Custom CSS for the enhanced UI
84
+ def inject_custom_css():
85
+ st.markdown("""
86
+ <style>
87
+ /* Main container styles */
88
+ .stApp {
89
+ background: radial-gradient(circle at top left, #0f0f0f, #050505);
90
+ color: white;
91
+ }
92
+
93
+ /* Sidebar styles */
94
+ [data-testid="stSidebar"] {
95
+ background: rgba(255, 255, 255, 0.05) !important;
96
+ border: 1px solid rgba(255, 255, 255, 0.1) !important;
97
+ backdrop-filter: blur(12px) !important;
98
+ box-shadow: 0 0 30px rgba(0, 255, 255, 0.2) !important;
99
+ border-radius: 20px !important;
100
+ padding: 30px !important;
101
+ margin: 20px !important;
102
+ animation: fadeIn 1s ease !important;
103
+ }
104
+
105
+ @keyframes fadeIn {
106
+ from { opacity: 0; transform: translateY(20px); }
107
+ to { opacity: 1; transform: translateY(0); }
108
+ }
109
+
110
+ /* Input field styles */
111
+ .stTextInput>div>div>input, .stPassword>div>div>input {
112
+ background: rgba(255, 255, 255, 0.1) !important;
113
+ color: white !important;
114
+ border: 1px solid transparent !important;
115
+ border-radius: 10px !important;
116
+ padding: 12px 20px !important;
117
+ transition: all 0.3s ease !important;
118
+ }
119
+
120
+ .stTextInput>div>div>input:focus, .stPassword>div>div>input:focus {
121
+ border-color: #00ffff !important;
122
+ background: rgba(255, 255, 255, 0.15) !important;
123
+ box-shadow: 0 0 10px rgba(0, 255, 255, 0.2) !important;
124
+ outline: none !important;
125
+ }
126
+
127
+ /* Button styles */
128
+ .stButton>button {
129
+ width: 100% !important;
130
+ padding: 12px 20px !important;
131
+ border-radius: 10px !important;
132
+ background: linear-gradient(45deg, #00ffff, #007fff) !important;
133
+ color: black !important;
134
+ font-weight: 600 !important;
135
+ border: none !important;
136
+ transition: all 0.3s ease !important;
137
+ box-shadow: 0 4px 15px rgba(0, 255, 255, 0.3) !important;
138
+ }
139
+
140
+ .stButton>button:hover {
141
+ transform: translateY(-2px) !important;
142
+ box-shadow: 0 6px 20px rgba(0, 255, 255, 0.4) !important;
143
+ }
144
+
145
+ /* Radio button styles */
146
+ .stRadio>div {
147
+ flex-direction: column !important;
148
+ gap: 10px !important;
149
+ }
150
+
151
+ .stRadio>div>label {
152
+ color: white !important;
153
+ font-weight: 500 !important;
154
+ padding: 8px 12px !important;
155
+ border-radius: 8px !important;
156
+ background: rgba(255, 255, 255, 0.05) !important;
157
+ transition: all 0.3s ease !important;
158
+ }
159
+
160
+ .stRadio>div>label:hover {
161
+ background: rgba(255, 255, 255, 0.1) !important;
162
+ }
163
+
164
+ .stRadio>div>label[data-baseweb="radio"]>div:first-child {
165
+ border-color: #00ffff !important;
166
+ }
167
+
168
+ /* Link styles */
169
+ a {
170
+ color: #00ffff !important;
171
+ text-decoration: none !important;
172
+ transition: all 0.3s ease !important;
173
+ }
174
+
175
+ a:hover {
176
+ text-shadow: 0 0 10px rgba(0, 255, 255, 0.5) !important;
177
+ }
178
+
179
+ /* Error message styles */
180
+ .stAlert {
181
+ border-radius: 10px !important;
182
+ background: rgba(255, 0, 0, 0.1) !important;
183
+ border: 1px solid rgba(255, 0, 0, 0.2) !important;
184
+ }
185
+
186
+ /* Success message styles */
187
+ .stSuccess {
188
+ border-radius: 10px !important;
189
+ background: rgba(0, 255, 0, 0.1) !important;
190
+ border: 1px solid rgba(0, 255, 0, 0.2) !important;
191
+ }
192
+ /* Audio recording animation */
193
+ @keyframes pulse {
194
+ 0% { transform: scale(1); }
195
+ 50% { transform: scale(1.1); }
196
+ 100% { transform: scale(1); }
197
+ }
198
+ .recording-active {
199
+ animation: pulse 1.5s infinite;
200
+ color: #ff4b4b !important;
201
+ }
202
+ </style>
203
+ """, unsafe_allow_html=True)
204
+
205
+ def store_user_data(user_id, name, email):
206
+ try:
207
+ ref = firebase_db.reference(f'users/{user_id}')
208
+ ref.set({
209
+ 'name': name,
210
+ 'email': email,
211
+ 'created_at': time.time()
212
+ })
213
+ return True
214
+ except Exception as e:
215
+ st.error(f"Error storing user data: {str(e)}")
216
+ return False
217
+
218
+ # Add these Firebase functions right after your existing Firebase functions
219
+ def save_chat_to_history(user_id, chat_title, messages):
220
+ try:
221
+ ref = firebase_db.reference(f'users/{user_id}/chats')
222
+ new_chat_ref = ref.push()
223
+ new_chat_ref.set({
224
+ 'title': chat_title,
225
+ 'messages': messages,
226
+ 'timestamp': time.time(),
227
+ 'last_updated': time.time()
228
+ })
229
+ return new_chat_ref.key
230
+ except Exception as e:
231
+ st.error(f"Error saving chat history: {str(e)}")
232
+ return None
233
+
234
+ def update_chat_history(user_id, chat_id, messages):
235
+ try:
236
+ ref = firebase_db.reference(f'users/{user_id}/chats/{chat_id}')
237
+ ref.update({
238
+ 'messages': messages,
239
+ 'last_updated': time.time()
240
+ })
241
+ return True
242
+ except Exception as e:
243
+ st.error(f"Error updating chat history: {str(e)}")
244
+ return False
245
+
246
+ def get_chat_history(user_id):
247
+ try:
248
+ ref = firebase_db.reference(f'users/{user_id}/chats')
249
+ chats = ref.get()
250
+ if chats:
251
+ return sorted(
252
+ [(chat_id, chat_data) for chat_id, chat_data in chats.items()],
253
+ key=lambda x: x[1]['last_updated'],
254
+ reverse=True
255
+ )
256
+ return []
257
+ except Exception as e:
258
+ st.error(f"Error fetching chat history: {str(e)}")
259
+ return []
260
+
261
+ def delete_chat_history(user_id, chat_id):
262
+ try:
263
+ ref = firebase_db.reference(f'users/{user_id}/chats/{chat_id}')
264
+ ref.delete()
265
+ return True
266
+ except Exception as e:
267
+ st.error(f"Error deleting chat history: {str(e)}")
268
+ return False
269
+
270
+ def generate_chat_title(messages):
271
+ for message in messages:
272
+ if message['role'] == 'user':
273
+ user_message = message['content']
274
+ return user_message[:30] + "..." if len(user_message) > 30 else user_message
275
+ return "New Chat"
276
+
277
+ def get_user_name(user_id):
278
+ try:
279
+ ref = firebase_db.reference(f'users/{user_id}')
280
+ user_data = ref.get()
281
+ return user_data.get('name', 'User') if user_data else 'User'
282
+ except Exception as e:
283
+ st.error(f"Error fetching user data: {str(e)}")
284
+ return 'User'
285
+
286
+ # Use the pyrebase auth object for login/signup
287
+ def login_signup_ui():
288
+ inject_custom_css()
289
+
290
+ st.sidebar.markdown("""
291
+ <div style="text-align: center; margin-bottom: 30px;">
292
+ <h1 style="color: #00ffff; font-size: 28px; margin-bottom: 5px;">🔐 ApnaLawyer</h1>
293
+ <p style="color: rgba(255,255,255,0.7); font-size: 14px;">Secure Legal Assistance Portal</p>
294
+ </div>
295
+ """, unsafe_allow_html=True)
296
+
297
+ choice = st.sidebar.radio("Select Option", ["Login", "Signup", "Forgot Password"], label_visibility="collapsed")
298
+
299
+ if choice == "Signup":
300
+ st.sidebar.markdown("### Create New Account")
301
+ name = st.sidebar.text_input("Full Name", key="signup_name")
302
+ email = st.sidebar.text_input("Email Address", key="signup_email")
303
+ password = st.sidebar.text_input("Password", type="password", key="signup_password")
304
+ confirm_password = st.sidebar.text_input("Confirm Password", type="password", key="signup_confirm")
305
+
306
+ if st.sidebar.button("Create Account", key="signup_button"):
307
+ if not name:
308
+ st.sidebar.error("Please enter your full name!")
309
+ elif not email:
310
+ st.sidebar.error("Email address is required!")
311
+ elif not password or not confirm_password:
312
+ st.sidebar.error("Password fields cannot be empty!")
313
+ elif password != confirm_password:
314
+ st.sidebar.error("Passwords do not match!")
315
+ else:
316
+ try:
317
+ user = auth.create_user_with_email_and_password(email, password)
318
+ if store_user_data(user['localId'], name, email):
319
+ auth.send_email_verification(user['idToken'])
320
+ st.sidebar.success("✅ Account created! Please verify your email before logging in.")
321
+ except Exception as e:
322
+ error_str = str(e)
323
+ if "EMAIL_EXISTS" in error_str:
324
+ st.sidebar.warning("⚠ Email already exists. Please try a different email address.")
325
+ elif "WEAK_PASSWORD" in error_str:
326
+ st.sidebar.warning("⚠ Password should be at least 6 characters long.")
327
+ else:
328
+ st.sidebar.error(f"Error: {error_str}")
329
+
330
+ elif choice == "Login":
331
+ st.sidebar.markdown("### Welcome Back")
332
+ email = st.sidebar.text_input("Email Address", key="login_email")
333
+ password = st.sidebar.text_input("Password", type="password", key="login_password")
334
+
335
+ if st.sidebar.button("Login", key="login_button"):
336
+ if not email:
337
+ st.sidebar.error("✋ Please enter your email address")
338
+ elif not password:
339
+ st.sidebar.error("✋ Please enter your password")
340
+ else:
341
+ try:
342
+ user = auth.sign_in_with_email_and_password(email, password)
343
+ user_info = auth.get_account_info(user['idToken'])
344
+ email_verified = user_info['users'][0]['emailVerified']
345
+
346
+ if email_verified:
347
+ user_name = get_user_name(user['localId'])
348
+ st.session_state.logged_in = True
349
+ st.session_state.user_email = email
350
+ st.session_state.user_token = user['idToken']
351
+ st.session_state.user_name = user_name
352
+ st.sidebar.success(f"🎉 Welcome back, {user_name}!")
353
+ st.rerun()
354
+ else:
355
+ st.sidebar.warning("📧 Email not verified. Please check your inbox.")
356
+ if st.sidebar.button("🔁 Resend Verification Email", key="resend_verification"):
357
+ auth.send_email_verification(user['idToken'])
358
+ st.sidebar.info("📬 Verification email sent again!")
359
+ except Exception as e:
360
+ error_str = str(e)
361
+ if "EMAIL_NOT_FOUND" in error_str or "no user record" in error_str.lower():
362
+ st.sidebar.error("📭 Account not found")
363
+ st.sidebar.warning("Don't have an account? Please sign up.")
364
+ elif "INVALID_PASSWORD" in error_str or "INVALID_LOGIN_CREDENTIALS" in error_str:
365
+ st.sidebar.error("🔐 Incorrect password")
366
+ else:
367
+ st.sidebar.error("⚠ Login error. Please try again.")
368
+
369
+ elif choice == "Forgot Password":
370
+ st.sidebar.markdown("### Reset Your Password")
371
+ email = st.sidebar.text_input("Enter your email address", key="reset_email")
372
+
373
+ if st.sidebar.button("Send Reset Link", key="reset_button"):
374
+ if not email:
375
+ st.sidebar.error("Please enter your email address!")
376
+ else:
377
+ try:
378
+ auth.send_password_reset_email(email)
379
+ st.sidebar.success("📬 Password reset link sent to your email.")
380
+ except Exception as e:
381
+ error_str = str(e)
382
+ if "EMAIL_NOT_FOUND" in error_str:
383
+ st.sidebar.error("❌ No account found with this email address")
384
+ st.sidebar.warning("⚠ Don't have an account? Please sign up.")
385
+ else:
386
+ st.sidebar.error(f"Error: {error_str}")
387
+
388
+ # In your login_signup_ui() function, replace the Google login section with:
389
+ st.sidebar.markdown("---")
390
+ st.sidebar.markdown("### Or continue with")
391
+
392
+ if st.sidebar.button("Continue with Google", key="google_login"):
393
+ try:
394
+ # Generate a unique state token
395
+ state_token = hashlib.sha256(str(time.time()).encode()).hexdigest()
396
+
397
+ # Get Firebase config values
398
+ client_id = "546645596018-nvtkegm7mi8e83upfv771tv6t58c7snn.apps.googleusercontent.com" # Use actual OAuth client ID
399
+ firebase_auth_domain = firebaseConfig["authDomain"]
400
+ redirect_uri = f"https://{firebase_auth_domain}/auth/handler"
401
+
402
+ # Build the Google OAuth URL
403
+ auth_url = (
404
+ f"https://accounts.google.com/o/oauth2/v2/auth?"
405
+ f"response_type=code&"
406
+ f"client_id={client_id}&"
407
+ f"redirect_uri={urllib.parse.quote(redirect_uri)}&"
408
+ f"scope=email%20profile%20openid&"
409
+ f"state={state_token}"
410
+ )
411
+
412
+ # Store state token in session
413
+ st.session_state.oauth_state = state_token
414
+
415
+ # Open OAuth flow in new tab
416
+ components.html(
417
+ f"""
418
+ <script>
419
+ window.open('{auth_url}', '_blank').focus();
420
+ </script>
421
+ """,
422
+ height=0
423
+ )
424
+
425
+ st.sidebar.info("Google login window should open. Please allow popups if it doesn't appear.")
426
+
427
+ except Exception as e:
428
+ st.sidebar.error(f"Failed to start Google login: {str(e)}")
429
+
430
+ def check_google_callback():
431
+ try:
432
+ if 'code' in st.query_params and 'state' in st.query_params:
433
+ # Verify state token matches
434
+ if st.query_params['state'] != st.session_state.get('oauth_state'):
435
+ st.error("Security verification failed. Please try logging in again.")
436
+ return
437
+
438
+ auth_code = st.query_params['code']
439
+
440
+ # Initialize the Google Auth Provider
441
+ provider = firebase.auth.GoogleAuthProvider()
442
+
443
+ # Sign in with the auth code
444
+ credential = provider.credential(
445
+ None, # No ID token needed for code flow
446
+ auth_code
447
+ )
448
+
449
+ # Sign in with credential
450
+ user = auth.sign_in_with_credential(credential)
451
+
452
+ # Store user in session
453
+ st.session_state.logged_in = True
454
+ st.session_state.user_email = user['email']
455
+ st.session_state.user_name = user.get('displayName', 'Google User')
456
+ st.session_state.user_token = user['idToken']
457
+
458
+ # Store user data if new
459
+ if not user_exists(user['localId']):
460
+ store_user_data(
461
+ user['localId'],
462
+ st.session_state.user_name,
463
+ user['email']
464
+ )
465
+
466
+ # Clear the OAuth code from URL
467
+ st.query_params.clear()
468
+ st.rerun()
469
+
470
+ except Exception as e:
471
+ st.error(f"Google login failed: {str(e)}")
472
+
473
+ # Initialize speech-to-text model (cached to avoid reloading)
474
+ @st.cache_resource
475
+ def load_speech_to_text_model():
476
+ return pipeline("automatic-speech-recognition", model="openai/whisper-base")
477
+
478
+ # Function to translate text
479
+ def translate_text(text, target_language):
480
+ try:
481
+ translated_text = GoogleTranslator(source='auto', target=target_language).translate(text)
482
+ return translated_text
483
+ except Exception as e:
484
+ return f"⚠ Translation failed: {str(e)}"
485
+
486
+ def transcribe_audio(audio_bytes):
487
+ """Transcribe audio using Whisper API"""
488
+ try:
489
+ # Create temp file
490
+ with tempfile.NamedTemporaryFile(suffix=".wav", delete=False) as tmpfile:
491
+ tmpfile.write(audio_bytes)
492
+ tmp_path = tmpfile.name
493
+
494
+ # Transcribe with Whisper
495
+ with open(tmp_path, "rb") as audio_file:
496
+ transcript = openai.audio.transcriptions.create(
497
+ model="whisper-1",
498
+ file=audio_file,
499
+ language=st.session_state.get('language', 'en')
500
+ )
501
+
502
+ # Clean up temp file
503
+ try:
504
+ os.remove(tmp_path)
505
+ except:
506
+ pass # Don't fail if temp file deletion fails
507
+
508
+ return transcript['text']
509
+
510
+ except Exception as e:
511
+ st.error(f"Error transcribing audio: {str(e)}")
512
+ return None
513
+
514
+ # def transcribe_audio(audio_bytes):
515
+ # """Transcribe audio using Whisper API without PyDub"""
516
+ # try:
517
+ # # Create temp file
518
+ # with tempfile.NamedTemporaryFile(suffix=".wav", delete=False) as tmpfile:
519
+ # tmpfile.write(audio_bytes)
520
+ # tmp_path = tmpfile.name
521
+
522
+ # # Transcribe with Whisper
523
+ # with open(tmp_path, "rb") as audio_file:
524
+ # transcript = openai.Audio.transcribe(
525
+ # model="whisper-1",
526
+ # file=audio_file,
527
+ # language=st.session_state.get('language', 'en')
528
+ # )
529
+
530
+ # os.remove(tmp_path)
531
+ # return transcript['text']
532
+
533
+ # except Exception as e:
534
+ # st.error(f"Error transcribing audio: {str(e)}")
535
+ # return None
536
+
537
+ # Add this function with your other utility functions
538
+ def check_rate_limit():
539
+ """Simple rate limiting for audio transcription"""
540
+ if 'last_transcription_time' not in st.session_state:
541
+ st.session_state.last_transcription_time = time.time()
542
+ return True
543
+
544
+ current_time = time.time()
545
+ time_since_last = current_time - st.session_state.last_transcription_time
546
+
547
+ if time_since_last < 10: # 10 second cooldown between transcriptions
548
+ return False
549
+
550
+ st.session_state.last_transcription_time = current_time
551
+ return True
552
+
553
+
554
+ def chatbot_ui():
555
+ # Initialize language state
556
+ if "language" not in st.session_state:
557
+ st.session_state.language = "en" # Default language is English
558
+
559
+ # Initialize with personalized welcome message if first time
560
+ if "messages" not in st.session_state:
561
+ st.session_state.messages = [{
562
+ "role": "assistant",
563
+ "content": f"🎉✨ Welcome {st.session_state.user_name}! ✨🎉\n\nI'm ApnaLawyer, your AI legal assistant. "
564
+ "I can help explain Indian laws in simple terms. What would you like to know?"
565
+ }]
566
+
567
+ if "memory" not in st.session_state:
568
+ st.session_state.memory = ConversationBufferWindowMemory(k=2, memory_key="chat_history", return_messages=True)
569
+
570
+ # Get user ID
571
+ if "user_id" not in st.session_state:
572
+ try:
573
+ user_info = auth.get_account_info(st.session_state.user_token)
574
+ st.session_state.user_id = user_info['users'][0]['localId']
575
+ st.session_state.chat_history = get_chat_history(st.session_state.user_id)
576
+ except Exception as e:
577
+ st.error(f"Error getting user info: {str(e)}")
578
+
579
+ @st.cache_resource
580
+ def load_embeddings():
581
+ return HuggingFaceEmbeddings(model_name="law-ai/InLegalBERT")
582
+
583
+ embeddings = load_embeddings()
584
+ db = FAISS.load_local("ipc_embed_db", embeddings, allow_dangerous_deserialization=True)
585
+ db_retriever = db.as_retriever(search_type="similarity", search_kwargs={"k": 3})
586
+
587
+ # Audio recording section - modified to remove duplicate input
588
+ audio_file = st.audio_input("", key="audio_recorder")
589
+ audio_bytes = audio_file.getvalue() if audio_file else None
590
+
591
+
592
+ # Process audio if recorded
593
+ if audio_bytes:
594
+ if not os.getenv('OPENAI_API_KEY'):
595
+ st.error("Voice input disabled - OpenAI API key not configured")
596
+ elif not check_rate_limit():
597
+ st.warning("Please wait a moment before sending another voice message")
598
+ else:
599
+ with st.spinner("Transcribing your voice..."):
600
+ try:
601
+ transcribed_text = transcribe_audio(audio_bytes)
602
+ if transcribed_text:
603
+ # Auto-inject the transcription
604
+ st.session_state.audio_transcription = transcribed_text
605
+ st.rerun()
606
+ except Exception as e:
607
+ st.error(f"Transcription failed: {str(e)}")
608
+
609
+ # Single input handling for both text and voice
610
+ # prompt = st.chat_input("Type or speak your message...")
611
+ # if 'audio_transcription' in st.session_state:
612
+ # prompt = st.session_state.audio_transcription
613
+ # del st.session_state.audio_transcription
614
+
615
+
616
+ prompt_template = """
617
+ <s>[INST]
618
+ You are ApnaLawyer.bot, a friendly legal assistant specializing in Indian law. You provide clear, accurate information about the Indian Penal Code (IPC) and related laws.
619
+
620
+ Key principles:
621
+ - Be concise but thorough
622
+ - Use simple language anyone can understand
623
+ - Always clarify when something is outside your expertise
624
+ - Structure responses logically but conversationally
625
+
626
+ CONTEXT: {context}
627
+ CHAT HISTORY: {chat_history}
628
+ QUESTION: {question}
629
+
630
+ Provide a helpful response that:
631
+ 1. Directly answers the question
632
+ 2. Cites relevant laws/sections when possible
633
+ 3. Notes important exceptions
634
+ 4. Suggests next steps if needed
635
+ </s>[INST]
636
+ """
637
+
638
+ prompt = PromptTemplate(template=prompt_template, input_variables=['context', 'question', 'chat_history'])
639
+
640
+ api_key = os.getenv('TOGETHER_API_KEY')
641
+ if not api_key:
642
+ st.error("API key for Together is missing. Please set the TOGETHER_API_KEY environment variable.")
643
+
644
+ llm = Together(model="mistralai/Mixtral-8x22B-Instruct-v0.1", temperature=0.5, max_tokens=1024, together_api_key=api_key)
645
+
646
+ qa = ConversationalRetrievalChain.from_llm(llm=llm, memory=st.session_state.memory, retriever=db_retriever,
647
+ combine_docs_chain_kwargs={'prompt': prompt})
648
+
649
+ # Voice input functionality
650
+ def handle_voice_input():
651
+ st.session_state.recording = True
652
+ audio_file = audio_recorder()
653
+ if audio_file:
654
+ try:
655
+ # Extract bytes from UploadedFile
656
+ audio_bytes = audio_file.getvalue() # Correctly extract bytes from UploadedFile
657
+
658
+ # Convert bytes to numpy array
659
+ audio_array, sample_rate = sf.read(BytesIO(audio_bytes))
660
+ audio_dict = {"raw": audio_array, "sampling_rate": sample_rate}
661
+
662
+ # Load model if not already loaded
663
+ if "speech_to_text" not in st.session_state:
664
+ st.session_state.speech_to_text = load_speech_to_text_model()
665
+
666
+ # Convert speech to text
667
+ text = st.session_state.speech_to_text(audio_dict)["text"]
668
+
669
+ if text.strip():
670
+ # Process the transcribed text as user input
671
+ process_user_input(text)
672
+
673
+ except Exception as e:
674
+ st.error(f"Error processing audio: {str(e)}")
675
+ st.session_state.recording = False
676
+
677
+ def extract_answer(full_response):
678
+ try:
679
+ answer_start = full_response.find("Response:")
680
+ if answer_start != -1:
681
+ answer_start += len("Response:")
682
+ return full_response[answer_start:].strip()
683
+ return full_response.strip()
684
+ except Exception as e:
685
+ return f"Error extracting answer: {str(e)}"
686
+
687
+ def create_new_chat():
688
+ st.session_state.messages = [{
689
+ "role": "assistant",
690
+ "content": f"🆕 New chat started {st.session_state.user_name}! What legal question can I help you with?"
691
+ }]
692
+ st.session_state.memory.clear()
693
+ st.session_state.current_chat_id = None
694
+ st.rerun()
695
+
696
+ def load_chat(chat_id):
697
+ try:
698
+ ref = firebase_db.reference(f'users/{st.session_state.user_id}/chats/{chat_id}')
699
+ chat_data = ref.get()
700
+ if chat_data:
701
+ st.session_state.messages = chat_data['messages']
702
+ st.session_state.current_chat_id = chat_id
703
+ st.session_state.memory.clear()
704
+ st.rerun()
705
+ except Exception as e:
706
+ st.error(f"Error loading chat: {str(e)}")
707
+
708
+ def delete_chat(chat_id):
709
+ if delete_chat_history(st.session_state.user_id, chat_id):
710
+ if st.session_state.current_chat_id == chat_id:
711
+ create_new_chat()
712
+ st.session_state.chat_history = get_chat_history(st.session_state.user_id)
713
+ st.rerun()
714
+
715
+ # Static translations dictionary
716
+ static_translations = {
717
+ "language_switched": {
718
+ "en": "Language switched to",
719
+ "hi": "भाषा बदल दी गई है",
720
+ "fr": "Langue changée en",
721
+ "es": "Idioma cambiado a",
722
+ "de": "Sprache gewechselt zu",
723
+ "zh-cn": "语言切换为",
724
+ "ar": "تم تغيير اللغة إلى",
725
+ "ru": "Язык переключен на",
726
+ "ja": "言語が変更されました",
727
+ "ko": "언어가 변경되었습니다",
728
+ "it": "Lingua cambiata in",
729
+ "pt": "Idioma alterado para",
730
+ "bn": "ভাষা পরিবর্তন করা হয়েছে",
731
+ "ta": "மொழி மாற்றப்பட்டது",
732
+ "te": "భాష మార్చబడింది",
733
+ "ml": "ഭാഷ മാറ്റി",
734
+ "kn": "ಭಾಷೆಯನ್ನು ಬದಲಿಸಲಾಗಿದೆ",
735
+ "mr": "भाषा बदलली गेली आहे",
736
+ "gu": "ભાષા બદલાઈ ગઈ છે",
737
+ "pa": "ਭਾਸ਼ਾ ਬਦਲ ਦਿੱਤੀ ਗਈ ਹੈ",
738
+ "or": "ଭାଷା ପରିବର୍ତ୍ତନ କରାଯାଇଛି",
739
+ "as": "ভাষা পৰিবৰ্তন কৰা হৈছে",
740
+ "ne": "भाषा परिवर्तन गरिएको छ",
741
+ "ur": "زبان تبدیل کر دی گئی ہے",
742
+ "sd": "ٻولي تبديل ڪئي وئي آهي",
743
+ "sa": "भाषा परिवर्तिता अस्ति",
744
+ "kok": "भाषा बदलली",
745
+ "mni": "লানগুয়েজ চেঞ্জ করা হইছে",
746
+ "doi": "भाषा बदल दी गई है",
747
+ "sat": "ᱵᱟᱹᱡᱟ ᱯᱟᱹᱨᱤᱵᱟᱹᱨᱛᱤᱱ ᱠᱟᱹᱨᱟᱹᱜ ᱠᱟᱹᱨᱟᱹᱜ",
748
+ "brx": "भाषा बदल दी गई है",
749
+ "mai": "भाषा बदलल ग��ल अछि"
750
+ }
751
+ }
752
+
753
+
754
+ supported_languages = [
755
+ "en", # English
756
+ "as", # Assamese
757
+ "bn", # Bengali
758
+ "brx", # Bodo
759
+ "doi", # Dogri
760
+ "gu", # Gujarati
761
+ "hi", # Hindi
762
+ "kn", # Kannada
763
+ "ks", # Kashmiri
764
+ "kok", # Konkani
765
+ "mai", # Maithili
766
+ "ml", # Malayalam
767
+ "mni", # Manipuri
768
+ "mr", # Marathi
769
+ "ne", # Nepali
770
+ "or", # Odia
771
+ "pa", # Punjabi
772
+ "sa", # Sanskrit
773
+ "sat", # Santali
774
+ "sd", # Sindhi
775
+ "ta", # Tamil
776
+ "te", # Telugu
777
+ "ur" # Urdu
778
+ ]
779
+
780
+ # Display chat messages
781
+ for message in st.session_state.messages:
782
+ with st.chat_message(message["role"]):
783
+ st.write(message["content"])
784
+
785
+ # Handle user input
786
+ if prompt := st.chat_input("Say something..."):
787
+ with st.chat_message("user"):
788
+ st.markdown(f"You: {prompt}")
789
+
790
+ # Detect user language
791
+ user_language = detect(prompt)
792
+ if user_language in static_translations["language_switched"]:
793
+ st.session_state.language = user_language
794
+
795
+ # Check for language change command
796
+ if prompt.startswith("/language"):
797
+ lang_code = prompt.split(" ")[1].strip()
798
+ if lang_code not in supported_languages:
799
+ st.session_state.messages.append({
800
+ "role": "assistant",
801
+ "content": f"⚠ Unsupported language code: {lang_code}. Supported languages are: {', '.join(supported_languages)}."
802
+ })
803
+ st.experimental_rerun()
804
+ st.session_state.language = lang_code
805
+ st.session_state.messages.append({
806
+ "role": "assistant",
807
+ "content": f"{static_translations['language_switched'].get(lang_code, 'Language switched to')} {lang_code.upper()}."
808
+ })
809
+ st.experimental_rerun()
810
+
811
+ # Process user input
812
+ st.session_state.messages.append({"role": "user", "content": prompt})
813
+
814
+ with st.chat_message("assistant"):
815
+ with st.spinner("Thinking 💡..."):
816
+ result = qa.invoke(input=prompt)
817
+ answer = extract_answer(result["answer"])
818
+
819
+ # Translate the chatbot's response if necessary
820
+ if st.session_state.language != "en":
821
+ answer = translate_text(answer, st.session_state.language)
822
+
823
+ message_placeholder = st.empty()
824
+ full_response = "⚠ Gentle reminder: We generally ensure precise information, but do double-check. \n\n\n"
825
+ for chunk in answer:
826
+ full_response += chunk
827
+ time.sleep(0.02)
828
+ message_placeholder.markdown(full_response + " |", unsafe_allow_html=True)
829
+ message_placeholder.markdown(full_response)
830
+
831
+ st.session_state.messages.append({"role": "assistant", "content": answer})
832
+
833
+ # Save or update chat
834
+ if len(st.session_state.messages) > 2: # Only save if there's actual conversation
835
+ chat_title = generate_chat_title(st.session_state.messages)
836
+ if hasattr(st.session_state, 'current_chat_id') and st.session_state.current_chat_id:
837
+ update_chat_history(st.session_state.user_id, st.session_state.current_chat_id, st.session_state.messages)
838
+ else:
839
+ chat_id = save_chat_to_history(st.session_state.user_id, chat_title, st.session_state.messages)
840
+ st.session_state.current_chat_id = chat_id
841
+ # Refresh chat history
842
+ st.session_state.chat_history = get_chat_history(st.session_state.user_id)
843
+
844
+ # Sidebar UI
845
+ with st.sidebar:
846
+ st.markdown(f"""
847
+ <div style="margin-bottom: 20px;">
848
+ <h3 style="color: #00ffff; margin-bottom: 5px;">👤 {st.session_state.user_name}</h3>
849
+ <p style="color: rgba(255,255,255,0.7); font-size: 12px; margin-top: 0;">{st.session_state.user_email}</p>
850
+ </div>
851
+ """, unsafe_allow_html=True)
852
+
853
+ if st.button("➕ New Chat", use_container_width=True):
854
+ create_new_chat()
855
+
856
+ st.markdown("---")
857
+ st.markdown("### Chat History")
858
+
859
+ if hasattr(st.session_state, 'chat_history') and st.session_state.chat_history:
860
+ for chat_id, chat_data in st.session_state.chat_history:
861
+ timestamp = time.strftime('%d %b %Y, %I:%M %p', time.localtime(chat_data['last_updated']))
862
+
863
+ col1, col2 = st.columns([0.8, 0.2])
864
+ with col1:
865
+ if st.button(
866
+ f"{chat_data['title']}",
867
+ key=f"chat_{chat_id}",
868
+ help=f"Last updated: {timestamp}",
869
+ use_container_width=True
870
+ ):
871
+ load_chat(chat_id)
872
+ with col2:
873
+ if st.button("🗑", key=f"delete_{chat_id}"):
874
+ delete_chat(chat_id)
875
+ else:
876
+ st.markdown("<p style='color: rgba(255,255,255,0.5);'>No chat history yet</p>", unsafe_allow_html=True)
877
+
878
+ st.markdown("---")
879
+
880
+ if st.button("🚪 Logout", use_container_width=True):
881
+ st.session_state.logged_in = False
882
+ st.session_state.user_email = None
883
+ st.session_state.user_name = None
884
+ st.session_state.user_id = None
885
+ st.rerun()
886
+
887
+ footer()
888
+
889
+ # ----------------- Main App -------------------
890
+ if "logged_in" not in st.session_state:
891
+ st.session_state.logged_in = False
892
+
893
+ if not st.session_state.logged_in:
894
+ login_signup_ui()
895
+ else:
896
+ chatbot_ui()
firebase_config.py ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import pyrebase
2
+
3
+ firebaseConfig = {
4
+ "apiKey": "AIzaSyAiWuuPRnw4JfNhYE6OQDlQsNJ1AxMzXFo",
5
+ "authDomain": "apna-lawyer.firebaseapp.com",
6
+ "projectId": "apna-lawyer",
7
+ "storageBucket": "apna-lawyer.firebasestorage.app",
8
+ "messagingSenderId": "19684757095",
9
+ "appId": "1:19684757095:web:ab63c06848201e29ba8ec2",
10
+ "databaseURL": "https://apna-lawyer-default-rtdb.firebaseio.com/", # Not needed unless using Realtime DB
11
+ }
12
+
13
+ firebase = pyrebase.initialize_app(firebaseConfig)
14
+ auth = firebase.auth()
footer.py ADDED
@@ -0,0 +1,68 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ from htbuilder import HtmlElement, div, a, p, img, styles
3
+ from htbuilder.units import percent, px
4
+
5
+
6
+ def image(src_as_string, **style):
7
+ return img(src=src_as_string, style=styles(**style))
8
+
9
+
10
+ def link(link, text, **style):
11
+ return a(_href=link, _target="_blank", style=styles(**style))(text)
12
+
13
+
14
+ def layout(*args):
15
+
16
+ style = """
17
+ <style>
18
+ # MainMenu {visibility: hidden;}
19
+ footer {visibility: hidden;}
20
+ .stApp { bottom: 40px; }
21
+ .st-emotion-cache-139wi93 {
22
+ width: 100%;
23
+ padding: 1rem 1rem 15px;
24
+ max-width: 46rem;
25
+ }
26
+ </style>
27
+ """
28
+
29
+ style_div = styles(
30
+ position="fixed",
31
+ left=0,
32
+ bottom=0,
33
+ margin=px(0, 0, 0, 0),
34
+ width=percent(100),
35
+ color="white",
36
+ text_align="center",
37
+ height="auto",
38
+ opacity=1
39
+ )
40
+
41
+ body = p()
42
+ foot = div(
43
+ style=style_div
44
+ )(
45
+ body
46
+ )
47
+
48
+ st.markdown(style, unsafe_allow_html=True)
49
+
50
+ for arg in args:
51
+ if isinstance(arg, str):
52
+ body(arg)
53
+
54
+ elif isinstance(arg, HtmlElement):
55
+ body(arg)
56
+
57
+ st.markdown(str(foot), unsafe_allow_html=True)
58
+
59
+
60
+ def footer():
61
+ myargs = [
62
+ "Made with ❤️ by Adarsh, Anand, Anurag and Aditya",
63
+ ]
64
+ layout(*myargs)
65
+
66
+
67
+ if __name__ == "__main__":
68
+ footer()
key.env ADDED
@@ -0,0 +1 @@
 
 
1
+ OPENAI_API_KEY=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
requirements.txt ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ langchain==0.1.15
2
+ pypdf
3
+ transformers==4.39.3
4
+ sentence-transformers
5
+ accelerate
6
+ faiss-cpu
7
+ streamlit==1.33.0
8
+ langchain-fireworks
9
+ einops
10
+ langchain-together
11
+ ray==2.10.0
12
+ unstructured
13
+ htbuilder
14
+ pyrebase
15
+ pycryptodome
16
+ firebase-admin
17
+ openai # OpenAI Python client for Whisper
18
+ requests # For making API calls
19
+ sounddevice
20
+ numpy
21
+ wave
22
+ python-dotenv