File size: 15,312 Bytes
d9feb53
 
 
 
 
 
 
93220ad
 
d9feb53
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
93220ad
 
 
d9feb53
 
93220ad
d9feb53
93220ad
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
d9feb53
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
93220ad
d9feb53
 
 
 
 
 
 
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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
"""
UI components and helper functions for the Defensor application.
"""

import gradio as gr
import time
import traceback
import uuid
import re

def create_fallback_ui(custom_css):
    """Create a fallback UI for when data loading fails."""
    with gr.Blocks(
        theme=gr.themes.Base(),
        css=custom_css,
        title="Defensor Legal Assistant - Data Error"
    ) as demo:
        # Create a header with app-header class for better styling
        with gr.Column(elem_classes="app-header"):
            gr.HTML("""
            <div class="logo-container">
                <div class="logo">
                    <span class="logo-icon">⚖️</span>
                    <span class="logo-text">Defensor</span>
                </div>
            </div>
            """)
            gr.Markdown("# Agentic Defensor - Data Loading Error")
        
        with gr.Column(elem_classes="main-container"):
            gr.Markdown("""
            ### There was an error loading the required data files.
            
            This application requires specific dataset files to function properly. 
            The system tried to download them from Hugging Face Hub but encountered errors.
            
            Please check the application logs for more details on what went wrong.
            
            Common issues:
            1. Dataset repository might not be accessible or might not contain the expected files
            2. Network connectivity issues when downloading datasets
            3. Missing or invalid Hugging Face token for accessing private datasets
            """)
            
            with gr.Row():
                input_text = gr.Textbox(label="You can enter text here, but functionality is limited")
                output_text = gr.Textbox(label="System response")
                
            submit_btn = gr.Button("Submit (Limited functionality)")
            
            def dummy_response(text):
                return "The system is in fallback mode due to data loading errors. Please check application logs."
                
            submit_btn.click(dummy_response, inputs=[input_text], outputs=[output_text])
        
    return demo

def create_interface(custom_css, process_query_function):
    """Create the main Gradio interface."""
    
    with gr.Blocks(
        title="Defensor Legal Assistant",
        theme=gr.themes.Base(),
        css=custom_css
    ) as demo:
        # Create a header with app-header class for better styling
        with gr.Column(elem_classes="app-header"):
            gr.HTML("""
            <div class="logo-container">
                <div class="logo">
                    <span class="logo-icon">⚖️</span>
                    <span class="logo-text">Defensor</span>
                </div>
            </div>
            """)
            gr.Markdown("# Defensor Legal Assistant")
            gr.Markdown("Ask questions about legal defense strategies and get comprehensive answers based on legitimate sources.")
        
        # Main application container
        with gr.Column(elem_classes="main-container"):
            # Add status indicator with styles - in its own container
            with gr.Row(elem_classes="status-container"):
                status_indicator = gr.HTML(
                    value="<div class='status-ready'>Ready to assist</div>",
                    label=None
                )
            
            # Enhanced container for the input area
            with gr.Column(elem_classes="input-container"):
                query_input = gr.Textbox(
                    label="Your Legal Question",
                    placeholder="Enter your legal question here (e.g., 'What are the key elements of self-defense?')",
                    lines=3
                )
                gr.Markdown("<div class='hint-text'>Ask detailed questions for better results. Be specific about the legal concepts you're interested in.</div>")
            
            # Create a dedicated container for the progress area
            with gr.Column(elem_classes="progress-container"):
                # Progress indicator with animation and better styling
                progress = gr.Progress()
                
                # Add a visual progress label
                progress_label = gr.HTML(
                    "<div class='progress-label'>Waiting for your question...</div>", 
                    visible=True
                )
            
            # Better button container with centered buttons
            with gr.Row(elem_classes="button-container"):
                submit_btn = gr.Button(
                    "Submit Question", 
                    variant="primary", 
                    interactive=True
                )
                clear_btn = gr.Button(
                    "Clear", 
                    variant="secondary"
                )
            
            # Settings in collapsible section
            with gr.Accordion("Settings & Options", open=False):
                with gr.Row():
                    top_k = gr.Slider(
                        minimum=5, 
                        maximum=50, 
                        value=20, 
                        step=5, 
                        label="Number of Documents to Consider"
                    )
                    debug = gr.Checkbox(label="Show Agent Reasoning Process", value=True)
            
            # Display area for the response with enhanced formatting
            with gr.Column(elem_classes="output-container"):
                output = gr.HTML(label="Response", value="")
        
        # About section at the bottom
        with gr.Accordion("About Defensor Legal Assistant", open=False):
            gr.Markdown("""
            ## About Defensor Legal Assistant
            
            Defensor is a specialized legal assistant powered by advanced AI technology and a comprehensive legal knowledge base. It provides insights and information about legal defense strategies based on authoritative sources.
            
            ### How It Works
            
            1. **Query Analysis**: The system analyzes your legal question to understand its context and intent
            2. **Knowledge Retrieval**: It searches through a database of legal documents to find relevant information
            3. **Context Organization**: The system organizes the retrieved information into a coherent context
            4. **Response Generation**: A comprehensive answer is generated based on the collected information
            
            ### Tips for Best Results
            
            - Be specific in your questions
            - Include relevant legal terms or concepts
            - For complex topics, consider breaking down into multiple targeted questions
            - Use the "Show Agent Reasoning" option to see how the system arrived at its answer
            
            ### Limitations
            
            This assistant provides legal information, not legal advice. Always consult with a qualified attorney for advice on specific legal matters.
            """)

        # Define status update helper functions
        def set_ready_status():
            return "<div class='status-ready'>Ready to assist</div>", "<div class='progress-label'>Waiting for your question...</div>"
        
        def set_processing_status():
            return "<div class='status-processing'>Processing your question...</div>", gr.update(interactive=False), "<div class='progress-label'>Processing legal query...</div>"
        
        def set_completed_status():
            return "<div class='status-complete'>Response complete</div>", gr.update(interactive=True), "<div class='progress-label'>Response complete</div>"
        
        def clear_inputs():
            return "", "<div class='status-ready'>Ready to assist</div>", gr.update(interactive=True), "", "<div class='progress-label'>Waiting for your question...</div>"
        
        # Set up event handlers with improved button state management
        submit_btn.click(
            fn=set_processing_status,
            outputs=[status_indicator, submit_btn, progress_label],
            queue=False
        ).then(
            fn=process_query_function,
            inputs=[query_input, top_k, debug],
            outputs=[output, progress_label],
            api_name="query"
        ).then(
            fn=set_completed_status,
            outputs=[status_indicator, submit_btn, progress_label],
            queue=False
        )
        
        clear_btn.click(
            fn=clear_inputs,
            outputs=[query_input, status_indicator, submit_btn, output, progress_label],
            queue=False
        )
        
        return demo
        
def format_progress_stages(stage, is_error=False):
    """Helper to format the progress stages HTML."""
    if stage == 1:
        return """<div class='progress-stages-container'>
            <div class='progress-stage active'>► Analyzing query</div>
            <div class='progress-stage'>Searching documents</div>
            <div class='progress-stage'>Organizing information</div>
            <div class='progress-stage'>Formulating response</div>
        </div>"""
    elif stage == 2:
        return """<div class='progress-stages-container'>
            <div class='progress-stage complete'>✓ Analyzing query</div>
            <div class='progress-stage active'>► Searching documents</div>
            <div class='progress-stage'>Organizing information</div>
            <div class='progress-stage'>Formulating response</div>
        </div>"""
    elif stage == 3:
        return """<div class='progress-stages-container'>
            <div class='progress-stage complete'>✓ Analyzing query</div>
            <div class='progress-stage complete'>✓ Searching documents</div>
            <div class='progress-stage active'>► Organizing information</div>
            <div class='progress-stage'>Formulating response</div>
        </div>"""
    elif stage == 4:
        return """<div class='progress-stages-container'>
            <div class='progress-stage complete'>✓ Analyzing query</div>
            <div class='progress-stage complete'>✓ Searching documents</div>
            <div class='progress-stage complete'>✓ Organizing information</div>
            <div class='progress-stage active'>► Formulating response</div>
        </div>"""
    elif stage == 5:  # Complete
        return """<div class='progress-stages-container'>
            <div class='progress-stage complete'>✓ Analyzing query</div>
            <div class='progress-stage complete'>✓ Searching documents</div>
            <div class='progress-stage complete'>✓ Organizing information</div>
            <div class='progress-stage complete'>✓ Response ready</div>
        </div>"""
    elif is_error:  # Error state
        return """<div class='progress-stages-container'>
            <div class='progress-stage complete'>✓ Analyzing query</div>
            <div class='progress-stage complete'>✓ Searching documents</div>
            <div class='progress-stage error'>✗ Error</div>
            <div class='progress-stage'>Formulating response</div>
        </div>"""
    
    # Default fallback
    return ""

def format_answer_html(answer, sources=None, reasoning_steps=None, debug=False):
    """Format the answer into well-structured HTML with improved Markdown rendering."""
    
    # Process Markdown more comprehensively
    answer_html = ""
    
    # Process paragraphs and add proper formatting
    for paragraph in answer.split("\n\n"):
        if not paragraph.strip():
            continue
            
        # Process headers
        if paragraph.startswith("# "):
            heading = paragraph[2:].strip()
            answer_html += f"<h2>{heading}</h2>"
        elif paragraph.startswith("## "):
            heading = paragraph[3:].strip()
            answer_html += f"<h3>{heading}</h3>"
        elif paragraph.startswith("### "):
            heading = paragraph[4:].strip()
            answer_html += f"<h4>{heading}</h4>"
        # Process lists
        elif re.match(r'^\d+\.\s', paragraph):
            # Ordered list
            items = paragraph.split("\n")
            answer_html += "<ol>"
            for item in items:
                if re.match(r'^\d+\.\s', item):
                    item_content = re.sub(r'^\d+\.\s', '', item)
                    answer_html += f"<li>{item_content}</li>"
            answer_html += "</ol>"
        elif re.match(r'^[*-]\s', paragraph):
            # Unordered list
            items = paragraph.split("\n")
            answer_html += "<ul>"
            for item in items:
                if re.match(r'^[*-]\s', item):
                    item_content = re.sub(r'^[*-]\s', '', item)
                    answer_html += f"<li>{item_content}</li>"
            answer_html += "</ul>"
        # Process code blocks
        elif paragraph.startswith("```") and paragraph.endswith("```"):
            code = paragraph[3:-3].strip()
            language = ""
            if "\n" in code:
                first_line = code.split("\n")[0].strip()
                if first_line and not first_line.startswith("```"):
                    language = first_line
                    code = "\n".join(code.split("\n")[1:])
            
            answer_html += f'<pre class="code-block"><code class="language-{language}">{code}</code></pre>'
        # Process blockquotes
        elif paragraph.startswith(">"):
            content = paragraph.replace("\n>", "\n").replace(">", "")
            answer_html += f'<blockquote>{content}</blockquote>'
        # Standard paragraph
        else:
            # Process inline code
            paragraph = re.sub(r'`([^`]+)`', r'<code>\1</code>', paragraph)
            # Process bold text
            paragraph = re.sub(r'\*\*([^*]+)\*\*', r'<strong>\1</strong>', paragraph)
            # Process italic text
            paragraph = re.sub(r'\*([^*]+)\*', r'<em>\1</em>', paragraph)
            
            answer_html += f"<p>{paragraph}</p>"
    
    # Add sources if available
    if sources:
        sources_html = "<div class='sources-section'>"
        sources_html += "<h3>Sources</h3><ul>"
        for source in sources:
            if source and source != "Source information unavailable":
                sources_html += f"<li class='source-item'>{source}</li>"
        sources_html += "</ul></div>"
        answer_html += sources_html
    
    # Add debugging information if available with nice formatting
    if debug and reasoning_steps:
        reasoning_html = "<h3>Agent Reasoning Process</h3>"
        for step in reasoning_steps:
            step_stage = step['stage']
            step_reasoning = step['reasoning'].replace('\n', '<br>')
            reasoning_html += f"""
            <div class='reasoning-step'>
                <div class='reasoning-stage'>{step_stage}</div>
                <div>{step_reasoning}</div>
            </div>
            """
        answer_html += reasoning_html
    
    # Return the final formatted HTML without any copy functionality
    return f"""
    <div class="response-wrapper">
        <div class="answer-container">
            {answer_html}
        </div>
    </div>
    """