import streamlit as st
import PyPDF2
import os
import torch
import torch.nn as nn
import numpy as np
from transformers import AutoModel, AutoTokenizer, pipeline, AutoModelForSeq2SeqLM
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain_community.embeddings import HuggingFaceEmbeddings
from langchain_community.vectorstores import FAISS
from langchain_google_genai import ChatGoogleGenerativeAI
# ---------------------------------------------------------
# 1. Custom AI Architecture for IPC Prediction
# ---------------------------------------------------------
class LegalExpertModel(nn.Module):
def __init__(self, model_name, num_labels):
super().__init__()
self.bert = AutoModel.from_pretrained(model_name)
self.dropout = nn.Dropout(0.3)
self.classifier = nn.Linear(768, num_labels)
def forward(self, input_ids, attention_mask, **kwargs):
outputs = self.bert(input_ids=input_ids, attention_mask=attention_mask, **kwargs)
pooled_output = outputs.last_hidden_state[:, 0, :]
pooled_output = self.dropout(pooled_output)
logits = self.classifier(pooled_output)
return {"logits": logits}
class IPCClassifier:
def __init__(self, model_dir="./ipc_section"):
self.device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
# Load the Answer Key (The Laws)
self.classes = np.load(f"{model_dir}/ipc_classes.npy", allow_pickle=True)
num_labels = len(self.classes)
# Load the Optimized Math Thresholds
self.thresholds = np.load(f"{model_dir}/optimal_thresholds.npy")
# Load Tokenizer & Model Weights
self.tokenizer = AutoTokenizer.from_pretrained(model_dir)
self.model = LegalExpertModel("nlpaueb/legal-bert-base-uncased", num_labels)
self.model.load_state_dict(torch.load(f"{model_dir}/custom_model_weights.bin", map_location=self.device))
self.model.to(self.device)
self.model.eval()
def predict(self, text_scenario):
encodings = self.tokenizer(text_scenario, truncation=True, padding='max_length', max_length=512, return_tensors="pt")
input_ids = encodings['input_ids'].to(self.device)
attention_mask = encodings['attention_mask'].to(self.device)
with torch.no_grad():
outputs = self.model(input_ids=input_ids, attention_mask=attention_mask)
logits = outputs["logits"].squeeze()
probabilities = torch.sigmoid(logits).cpu().numpy()
predicted_laws = []
if probabilities.ndim == 0:
probabilities = np.array([probabilities])
for i, prob in enumerate(probabilities):
if prob > self.thresholds[i]:
predicted_laws.append({
"ipc_section": self.classes[i],
"confidence": round(float(prob * 100), 2)
})
if not predicted_laws:
return [{"ipc_section": "No crime detected or insufficient details", "confidence": 0.0}]
return sorted(predicted_laws, key=lambda x: x['confidence'], reverse=True)
# ---------------------------------------------------------
# 2. Setup Page & CSS
# ---------------------------------------------------------
st.set_page_config(page_title="Indian Legal Assistant", page_icon="⚖️", layout="wide", initial_sidebar_state="expanded")
st.markdown("""
""", unsafe_allow_html=True)
# ---------------------------------------------------------
# 3. Model Loaders (Global Memory)
# ---------------------------------------------------------
@st.cache_resource
def load_text_classifier():
try: return pipeline("text-classification", model="./legal_brain")
except Exception: return None
@st.cache_resource
def load_ipc_classifier():
try: return IPCClassifier(model_dir="./ipc_section")
except Exception: return None
@st.cache_resource
def load_summarizer():
try:
# FINAL FIX: Direct Engine Loading (No more pipeline crashes!)
tokenizer = AutoTokenizer.from_pretrained("facebook/bart-large-cnn")
model = AutoModelForSeq2SeqLM.from_pretrained("facebook/bart-large-cnn")
return {"tokenizer": tokenizer, "model": model}
except Exception as e:
print(f"Summarizer Error: {e}")
return None
legal_classifier = load_text_classifier()
ipc_engine = load_ipc_classifier()
summarizer_engine = load_summarizer()
# ---------------------------------------------------------
# 4. Sidebar (File Upload & API)
# ---------------------------------------------------------
with st.sidebar:
st.markdown("
Paste long legal paragraphs here to get a concise summary.
", unsafe_allow_html=True) summ_input = st.text_area("Legal Text to Summarize:", height=200, placeholder="Paste lengthy legal arguments or facts here...") if st.button("Generate Summary", type="primary", key="summ_btn"): if summ_input and summarizer_engine: with st.spinner("Generating Summary... (This may take 10-15 seconds)"): try: tokenizer = summarizer_engine["tokenizer"] model = summarizer_engine["model"] # Convert Text to Tokens inputs = tokenizer(summ_input, return_tensors="pt", max_length=1024, truncation=True) # Generate Summary summary_ids = model.generate( inputs["input_ids"], max_length=150, min_length=40, length_penalty=1.0, num_beams=4, early_stopping=True ) # Convert Tokens back to English Text final_summary = tokenizer.decode(summary_ids[0], skip_special_tokens=True) st.markdown("#### ✨ Final Summary:") st.success(final_summary) except Exception as e: st.error(f"Summarization failed. Error: {e}") elif not summarizer_engine: st.error("Summarizer model not loaded properly. Check the 'legal_summarizer' folder.") else: st.warning("Please paste some text first.")