|
|
|
|
|
|
|
|
| import streamlit as st
|
| import google.generativeai as genai
|
|
|
| GEMINI_API_KEY = "AIzaSyAsjqUR83MvJWrp32VUGCNxGX1FTtQpjVk"
|
| GEMINI_MODEL = "gemini-2.0-flash"
|
|
|
| st.set_page_config(
|
| page_title="AI Lawyer β Indian Law Assistant",
|
| page_icon="βοΈ",
|
| layout="wide",
|
| initial_sidebar_state="expanded",
|
| )
|
|
|
|
|
|
|
|
|
|
|
|
|
| genai.configure(api_key="AIzaSyAsjqUR83MvJWrp32VUGCNxGX1FTtQpjVk")
|
| _model = genai.GenerativeModel("gemini-2.5-flash-lite")
|
|
|
| SYSTEM_PROMPT = """You are an expert AI lawyer specializing in Indian law.
|
| You have deep knowledge of the Indian Penal Code (IPC), Code of Criminal Procedure (CrPC),
|
| Constitution of India, Civil Procedure Code (CPC), and all major Indian statutes.
|
|
|
| Rules:
|
| - Answer clearly and precisely with relevant section numbers where applicable.
|
| - If a question is outside Indian law, politely redirect.
|
| - Structure long answers with headings when needed.
|
| - Always end with a brief disclaimer: "This is for informational purposes only and not a substitute for professional legal advice."
|
| """
|
|
|
| def ask_llm(chat_history: list) -> str:
|
| """Send the full conversation history to Gemini and return the reply."""
|
| messages = []
|
| for msg in chat_history:
|
| role = "user" if msg["role"] == "user" else "model"
|
| messages.append({"role": role, "parts": [msg["content"]]})
|
|
|
|
|
| full_messages = [
|
| {"role": "user", "parts": [SYSTEM_PROMPT]},
|
| {"role": "model", "parts": ["Understood. I am your AI Lawyer specializing in Indian law. How can I assist you today?"]},
|
| ] + messages
|
|
|
| response = _model.generate_content(full_messages)
|
| return response.text
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| if "chat_history" not in st.session_state:
|
| st.session_state.chat_history = []
|
|
|
|
|
| st.markdown("""
|
| <style>
|
| @import url('https://fonts.googleapis.com/css2?family=Playfair+Display:wght@400;700;900&family=DM+Sans:ital,wght@0,300;0,400;0,500;1,300&display=swap');
|
|
|
| :root {
|
| --gold: #C9A84C;
|
| --gold-lt: #E8C97A;
|
| --dark: #0D0D0D;
|
| --dark2: #141414;
|
| --dark3: #1C1C1C;
|
| --dark4: #222222;
|
| --text: #E8E0D0;
|
| --muted: #8A8070;
|
| --border: rgba(201,168,76,0.18);
|
| }
|
|
|
| html, body, [class*="css"] {
|
| font-family: 'DM Sans', sans-serif;
|
| background-color: var(--dark);
|
| color: var(--text);
|
| }
|
| .stApp { background-color: var(--dark); }
|
| #MainMenu, footer, header { visibility: hidden; }
|
| .block-container { padding: 1.8rem 2.5rem 2rem; max-width: 900px; }
|
|
|
| /* ββ Sidebar ββ */
|
| [data-testid="stSidebar"] {
|
| background: var(--dark2);
|
| border-right: 1px solid var(--border);
|
| }
|
| [data-testid="stSidebar"] .block-container { padding: 1.5rem 1.2rem; }
|
|
|
| /* ββ Hero ββ */
|
| .hero {
|
| background: linear-gradient(135deg, #0D0D0D 0%, #1A1205 55%, #0D0D0D 100%);
|
| border: 1px solid var(--border);
|
| border-radius: 16px;
|
| padding: 2rem 2.6rem 1.8rem;
|
| margin-bottom: 1.8rem;
|
| position: relative;
|
| overflow: hidden;
|
| }
|
| .hero::before {
|
| content: "\u2696";
|
| position: absolute; right: -8px; top: -18px;
|
| font-size: 13rem; opacity: 0.04; line-height: 1; pointer-events: none;
|
| }
|
| .hero h1 {
|
| font-family: 'Playfair Display', serif;
|
| font-size: 2.4rem; font-weight: 900;
|
| background: linear-gradient(90deg, var(--gold), var(--gold-lt), var(--gold));
|
| -webkit-background-clip: text; -webkit-text-fill-color: transparent;
|
| margin: 0 0 0.3rem; line-height: 1.1;
|
| }
|
| .hero .sub { color: var(--muted); font-size: 0.9rem; font-weight: 300; letter-spacing: 0.03em; margin: 0; }
|
| .hero .pwr { margin-top: 0.7rem; font-size: 0.68rem; letter-spacing: 0.08em; color: rgba(201,168,76,0.4); font-style: italic; }
|
|
|
| /* ββ Divider ββ */
|
| .gold-divider { border: none; border-top: 1px solid var(--border); margin: 1.3rem 0; }
|
|
|
| /* ββ Section label ββ */
|
| .section-label {
|
| font-size: 0.67rem; letter-spacing: 0.2em;
|
| text-transform: uppercase; color: var(--gold);
|
| font-weight: 500; margin-bottom: 0.5rem;
|
| }
|
|
|
| /* ββ Chat window ββ */
|
| .chat-window {
|
| background: var(--dark2);
|
| border: 1px solid var(--border);
|
| border-radius: 14px;
|
| padding: 1.4rem 1.6rem;
|
| margin-bottom: 1.2rem;
|
| max-height: 520px;
|
| overflow-y: auto;
|
| }
|
| .chat-window::-webkit-scrollbar { width: 5px; }
|
| .chat-window::-webkit-scrollbar-track { background: transparent; }
|
| .chat-window::-webkit-scrollbar-thumb { background: var(--border); border-radius: 99px; }
|
|
|
| /* ββ Bubbles ββ */
|
| .user-bubble {
|
| display: flex; justify-content: flex-end; margin: 0.7rem 0;
|
| }
|
| .user-bubble .bub {
|
| background: linear-gradient(135deg, #A8832A, var(--gold));
|
| color: #0D0D0D;
|
| border-radius: 18px 18px 4px 18px;
|
| padding: 0.75rem 1.1rem;
|
| max-width: 78%;
|
| font-size: 0.92rem;
|
| line-height: 1.6;
|
| font-weight: 500;
|
| }
|
|
|
| .ai-bubble {
|
| display: flex; justify-content: flex-start;
|
| align-items: flex-start; gap: 0.7rem;
|
| margin: 0.7rem 0;
|
| }
|
| .ai-bubble .avatar {
|
| width: 32px; height: 32px; min-width: 32px;
|
| background: linear-gradient(135deg, #1A1205, #2A1F08);
|
| border: 1px solid var(--border);
|
| border-radius: 50%;
|
| display: flex; align-items: center; justify-content: center;
|
| font-size: 0.95rem;
|
| }
|
| .ai-bubble .bub {
|
| background: var(--dark3);
|
| border: 1px solid var(--border);
|
| border-radius: 4px 18px 18px 18px;
|
| padding: 0.75rem 1.1rem;
|
| max-width: 78%;
|
| font-size: 0.92rem;
|
| line-height: 1.75;
|
| color: var(--text);
|
| }
|
|
|
| /* ββ Typing indicator ββ */
|
| .typing { display: flex; gap: 4px; padding: 0.4rem 0; align-items: center; }
|
| .typing span {
|
| width: 7px; height: 7px; background: var(--gold);
|
| border-radius: 50%; animation: bounce 1.2s infinite;
|
| }
|
| .typing span:nth-child(2) { animation-delay: 0.2s; }
|
| .typing span:nth-child(3) { animation-delay: 0.4s; }
|
| @keyframes bounce { 0%,80%,100%{transform:scale(0.7);opacity:0.4} 40%{transform:scale(1);opacity:1} }
|
|
|
| /* ββ Empty state ββ */
|
| .empty-chat {
|
| text-align: center; padding: 2.5rem 1rem;
|
| color: var(--muted); font-size: 0.88rem; line-height: 1.8;
|
| }
|
| .empty-chat .big { font-size: 2.8rem; margin-bottom: 0.6rem; }
|
| .empty-chat .title {
|
| font-family: 'Playfair Display', serif;
|
| color: rgba(201,168,76,0.6); font-size: 1.05rem; margin-bottom: 0.4rem;
|
| }
|
|
|
| /* ββ Suggestions ββ */
|
| .sug-btn-wrap { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-bottom: 1.2rem; }
|
|
|
| /* ββ Inputs ββ */
|
| .stTextInput > div > div > input {
|
| background: var(--dark3) !important; border: 1px solid var(--border) !important;
|
| border-radius: 12px !important; color: var(--text) !important;
|
| font-family: 'DM Sans', sans-serif !important; font-size: 0.95rem !important;
|
| padding: 0.65rem 1rem !important;
|
| }
|
| .stTextInput > div > div > input:focus {
|
| border-color: var(--gold) !important;
|
| box-shadow: 0 0 0 2px rgba(201,168,76,0.14) !important;
|
| }
|
|
|
| /* ββ Buttons ββ */
|
| .stButton > button {
|
| background: linear-gradient(135deg, var(--gold), #A8832A) !important;
|
| color: #0D0D0D !important; border: none !important;
|
| border-radius: 10px !important; font-family: 'DM Sans', sans-serif !important;
|
| font-weight: 600 !important; font-size: 0.86rem !important;
|
| padding: 0.48rem 1.4rem !important; letter-spacing: 0.02em !important;
|
| transition: all 0.2s !important;
|
| }
|
| .stButton > button:hover {
|
| transform: translateY(-1px) !important;
|
| box-shadow: 0 5px 18px rgba(201,168,76,0.28) !important;
|
| }
|
|
|
| /* ββ Sidebar elements ββ */
|
| .sidebar-heading {
|
| font-family: 'Playfair Display', serif;
|
| font-size: 1.15rem; color: var(--gold); margin-bottom: 0.15rem;
|
| }
|
| .sb-credits {
|
| margin-top: 2rem; padding-top: 1rem;
|
| border-top: 1px solid rgba(201,168,76,0.12);
|
| font-size: 0.68rem; color: rgba(138,128,112,0.6);
|
| line-height: 1.75; text-align: center;
|
| }
|
| .sb-credits .sb-name {
|
| color: rgba(201,168,76,0.75);
|
| font-family: 'Playfair Display', serif;
|
| font-size: 0.82rem;
|
| }
|
|
|
| /* ββ Footer ββ */
|
| .footer {
|
| margin-top: 2.5rem; padding: 1.2rem 0 0.4rem;
|
| border-top: 1px solid var(--border); text-align: center;
|
| }
|
| .footer .name {
|
| font-family: 'Playfair Display', serif;
|
| font-size: 0.95rem; color: var(--gold); letter-spacing: 0.04em;
|
| }
|
| .footer .org { font-size: 0.74rem; color: var(--muted); margin-top: 0.2rem; letter-spacing: 0.06em; }
|
| .footer .copy { font-size: 0.62rem; color: rgba(138,128,112,0.4); margin-top: 0.5rem; letter-spacing: 0.1em; text-transform: uppercase; }
|
| </style>
|
| """, unsafe_allow_html=True)
|
|
|
|
|
|
|
| with st.sidebar:
|
| st.markdown('<p class="sidebar-heading">βοΈ AI Lawyer</p>', unsafe_allow_html=True)
|
| st.markdown('<p style="color:#8A8070;font-size:0.76rem;margin-top:-6px;">Indian Law Assistant</p>', unsafe_allow_html=True)
|
| st.markdown('<hr class="gold-divider">', unsafe_allow_html=True)
|
|
|
| st.markdown('<p class="section-label">About</p>', unsafe_allow_html=True)
|
| st.markdown("""
|
| <div style="background:#1C1C1C;border:1px solid rgba(201,168,76,0.15);border-radius:10px;padding:1rem 1.1rem;font-size:0.82rem;color:#8A8070;line-height:1.7;">
|
| Ask any question related to <span style="color:#C9A84C;">Indian law</span> β IPC, CrPC, Constitution, CPC, and more.<br><br>
|
| The AI will provide precise answers with relevant <span style="color:#C9A84C;">section references</span>.
|
| </div>
|
| """, unsafe_allow_html=True)
|
|
|
| st.markdown('<hr class="gold-divider">', unsafe_allow_html=True)
|
| st.markdown('<p class="section-label">Topics Covered</p>', unsafe_allow_html=True)
|
|
|
| topics = ["βοΈ Indian Penal Code", "π Constitution of India", "π CrPC", "π Civil Procedure Code", "ποΈ Contract Act", "π¨βπ©βπ§ Family Law", "ποΈ Property Law", "πΌ Labour Law"]
|
| for t in topics:
|
| st.markdown(f'<div style="font-size:0.8rem;color:#8A8070;padding:3px 0;">{t}</div>', unsafe_allow_html=True)
|
|
|
| st.markdown('<hr class="gold-divider">', unsafe_allow_html=True)
|
|
|
| if st.session_state.chat_history:
|
| msg_count = len([m for m in st.session_state.chat_history if m["role"] == "user"])
|
| st.markdown(f'<div style="font-size:0.75rem;color:#8A8070;">π¬ <span style="color:#C9A84C;">{msg_count}</span> question{"s" if msg_count!=1 else ""} asked</div>', unsafe_allow_html=True)
|
| st.markdown("")
|
| if st.button("π Clear Chat", use_container_width=True):
|
| st.session_state.chat_history = []
|
| st.rerun()
|
|
|
| st.markdown("""
|
| <div class="sb-credits">
|
| Designed & Developed by<br>
|
| <span class="sb-name">Yedeedya Injeti</span><br>
|
| Innomatics Research Labs
|
| </div>
|
| """, unsafe_allow_html=True)
|
|
|
|
|
|
|
| st.markdown("""
|
| <div class="hero">
|
| <h1>AI Lawyer</h1>
|
| <p class="sub">Your intelligent legal assistant for Indian law • IPC • CrPC • Constitution & more</p>
|
| <p class="pwr">Powered by RAG + LLM</p>
|
| </div>
|
| """, unsafe_allow_html=True)
|
|
|
|
|
|
|
| suggestions = [
|
| "Punishment for murder under IPC?",
|
| "What is Article 21 of the Constitution?",
|
| "Define culpable homicide.",
|
| "What are bailable offences?",
|
| "Right to self-defence in India?",
|
| "What is the limitation period for filing a civil suit?",
|
| ]
|
|
|
| if not st.session_state.chat_history:
|
| st.markdown('<p class="section-label">Suggested Questions</p>', unsafe_allow_html=True)
|
| col1, col2, col3 = st.columns(3)
|
| chosen = None
|
| for i, sug in enumerate(suggestions):
|
| col = [col1, col2, col3][i % 3]
|
| with col:
|
| if st.button(sug, key=f"sug_{i}", use_container_width=True):
|
| chosen = sug
|
| st.markdown("")
|
|
|
|
|
|
|
| if not st.session_state.chat_history:
|
| st.markdown("""
|
| <div class="chat-window">
|
| <div class="empty-chat">
|
| <div class="big">βοΈ</div>
|
| <div class="title">How can I assist you today?</div>
|
| Ask me anything about Indian law β I'll provide accurate answers<br>with relevant section references and case principles.
|
| </div>
|
| </div>
|
| """, unsafe_allow_html=True)
|
| else:
|
| bubbles_html = '<div class="chat-window">'
|
| for msg in st.session_state.chat_history:
|
| if msg["role"] == "user":
|
| bubbles_html += f"""
|
| <div class="user-bubble">
|
| <div class="bub">{msg["content"]}</div>
|
| </div>"""
|
| else:
|
|
|
| content = msg["content"].replace("\n", "<br>")
|
| bubbles_html += f"""
|
| <div class="ai-bubble">
|
| <div class="avatar">βοΈ</div>
|
| <div class="bub">{content}</div>
|
| </div>"""
|
| bubbles_html += "</div>"
|
| st.markdown(bubbles_html, unsafe_allow_html=True)
|
|
|
|
|
|
|
| col_inp, col_send = st.columns([6, 1])
|
| with col_inp:
|
| question = st.text_input(
|
| "input", label_visibility="collapsed",
|
| placeholder="Ask your legal questionβ¦",
|
| key="chat_input",
|
| )
|
| with col_send:
|
| send_btn = st.button("Send βοΈ", use_container_width=True)
|
|
|
|
|
|
|
| final_q = None
|
| if "chosen" in dir() and chosen:
|
| final_q = chosen
|
| elif send_btn and question.strip():
|
| final_q = question.strip()
|
|
|
| if final_q:
|
| st.session_state.chat_history.append({"role": "user", "content": final_q})
|
|
|
| with st.spinner(""):
|
| answer = ask_llm(st.session_state.chat_history)
|
|
|
| st.session_state.chat_history.append({"role": "assistant", "content": answer})
|
| st.rerun()
|
|
|
|
|
|
|
| st.markdown("""
|
| <div class="footer">
|
| <div class="name">✦ Designed & Developed by Yedeedya Injeti ✦</div>
|
| <div class="org">Innomatics Research Labs</div>
|
| <div class="copy">© 2026 · AI Lawyer · Indian Law Assistant</div>
|
| </div>
|
| """, unsafe_allow_html=True) |