File size: 5,976 Bytes
1d9bd9b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
import streamlit as st
import sys
import os

# Ensure the app can find the local modules
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
if BASE_DIR not in sys.path:
    sys.path.insert(0, BASE_DIR)

from unified_legal_rag import ask

st.set_page_config(
    page_title="LegalAIapex",
    page_icon="βš–οΈ",
    layout="wide"
)

st.title("βš–οΈ LegalAIapex: Unified Statute + Judgment RAG")
st.markdown("""
Welcome to the Unified Legal RAG system. This system dynamically routes your query to **Statutes** (IPC, BNS, CrPC, BNSS, IEA, BSA) and **Supreme Court Judgments**. It features a dual-layer verification system to ensure zero hallucinations.
""")

with st.sidebar:
    st.header("βš™οΈ Settings")
    intent_mode = st.selectbox(
        "Response Format",
        options=[
            "βš–οΈ General Legal Research (Default)",
            "✨ Auto-Detect Format (AI decides)",
            "πŸ“– Analyze My Story (Legal Advice)",
            "πŸ“„ Brief Case/Statute Summary",
            "πŸ“š In-Depth Case Study",
            "πŸ”„ Compare Laws/Cases"
        ],
        index=0,
        help="Choose the structure of the answer. By default, it provides a clean Citation Table."
    )

INTENT_MAP = {
    "βš–οΈ General Legal Research (Default)": "LEGAL_RESEARCH",
    "✨ Auto-Detect Format (AI decides)": "AUTO",
    "πŸ“– Analyze My Story (Legal Advice)": "STORY_EVALUATION",
    "πŸ“„ Brief Case/Statute Summary": "CASE_SUMMARY",
    "πŸ“š In-Depth Case Study": "COMPREHENSIVE_CASE_STUDY",
    "πŸ”„ Compare Laws/Cases": "CASE_COMPARISON"
}
force_intent = INTENT_MAP[intent_mode]

# Initialize chat history
if "messages" not in st.session_state:
    st.session_state.messages = []

# Display chat messages from history on app rerun
for message in st.session_state.messages:
    if message["role"] != "system":
        with st.chat_message(message["role"]):
            st.markdown(message["content"])

# React to user input
if prompt := st.chat_input("Ask a legal question... (e.g. 'What is the law on murder under BNS 103?')"):
    # Display user message in chat message container
    st.chat_message("user").markdown(prompt)

    with st.chat_message("assistant"):
        status_text = st.empty()
        status_text.text("Retrieving legal evidence and generating response...")

        with st.spinner("Searching the legal database..."):
            try:
                # The prompt is added to history after, so we pass history up to this point
                result = ask(prompt, st.session_state.messages, force_intent=force_intent)

                # Clear status text
                status_text.empty()

                # Display the main answer (which uses the markdown table format you requested)
                st.markdown(result.get("answer", "No answer generated."))

                # Add an expander for the "behind-the-scenes" metadata
                with st.expander("πŸ” Retrieval & Verification Details", expanded=True):
                    # Route, Intent & Speed
                    st.caption(
                        f"**Intent:** {result.get('intent', 'LEGAL_RESEARCH')} | **Route Taken:** {result.get('route')} | **Speed:** {result.get('elapsed_seconds')}s")

                    st.divider()

                    # Verification Block
                    v = result.get("verification", {})
                    if v:
                        grounded = v.get("grounded", None)
                        if grounded:
                            st.success("βœ… **FULLY GROUNDED:** All citations perfectly match retrieved evidence.")
                        else:
                            st.warning(
                                "⚠️ **HALLUCINATED CITATIONS DETECTED:** The LLM cited sections/cases not found anywhere in the local database.")

                        if v.get("unverified_sections"):
                            st.write(f"πŸ›‘ **Hallucinated Sections (NOT in DB):** {', '.join(v['unverified_sections'])}")
                        if v.get("retrieval_miss_sections"):
                            st.info(
                                f"πŸ”„ **Retrieval Miss (in DB, not retrieved this query):** {', '.join(v['retrieval_miss_sections'])} β€” These sections exist in the database but were not surfaced by the search engine for this query. The LLM cited them from its training memory.")
                        if v.get("citations_confirmed_via_live_lookup"):
                            st.info(
                                f"🟒 **Confirmed via Bharat-Courts (Live):** {', '.join(v['citations_confirmed_via_live_lookup'])}")
                        if v.get("citations_likely_fabricated"):
                            st.error(f"❌ **Likely Fabricated:** {', '.join(v['citations_likely_fabricated'])}")
                        if v.get("citations_could_not_verify"):
                            st.write(f"❓ **Could not verify:** {', '.join(v['citations_could_not_verify'])}")

                    st.divider()

                    # Evidence Block
                    st.write("**Top Evidence Used for Context:**")
                    evidence_list = result.get("evidence", [])
                    if evidence_list:
                        for ev in evidence_list:
                            type_icon = "πŸ“œ" if ev['type'] == 'statute' else "πŸ›οΈ"
                            st.write(f"{type_icon} `[{ev['type']}]` **Score:** {ev['score']:+.3f} β€” {ev['label']}")
                    else:
                        st.write("No evidence retrieved.")

            except Exception as e:
                status_text.empty()
                st.error(f"An error occurred: {str(e)}")
                result = {"answer": "Error generating response."}

    # Add user message and assistant message to chat history
    st.session_state.messages.append({"role": "user", "content": prompt})
    st.session_state.messages.append({"role": "assistant", "content": result.get("answer", "")})