""" 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("""
""") 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("""
""") 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="
Ready to assist
", 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("
Ask detailed questions for better results. Be specific about the legal concepts you're interested in.
") # 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( "
Waiting for your question...
", 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 "
Ready to assist
", "
Waiting for your question...
" def set_processing_status(): return "
Processing your question...
", gr.update(interactive=False), "
Processing legal query...
" def set_completed_status(): return "
Response complete
", gr.update(interactive=True), "
Response complete
" def clear_inputs(): return "", "
Ready to assist
", gr.update(interactive=True), "", "
Waiting for your question...
" # 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 """
► Analyzing query
Searching documents
Organizing information
Formulating response
""" elif stage == 2: return """
✓ Analyzing query
► Searching documents
Organizing information
Formulating response
""" elif stage == 3: return """
✓ Analyzing query
✓ Searching documents
► Organizing information
Formulating response
""" elif stage == 4: return """
✓ Analyzing query
✓ Searching documents
✓ Organizing information
► Formulating response
""" elif stage == 5: # Complete return """
✓ Analyzing query
✓ Searching documents
✓ Organizing information
✓ Response ready
""" elif is_error: # Error state return """
✓ Analyzing query
✓ Searching documents
✗ Error
Formulating response
""" # 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"

{heading}

" elif paragraph.startswith("## "): heading = paragraph[3:].strip() answer_html += f"

{heading}

" elif paragraph.startswith("### "): heading = paragraph[4:].strip() answer_html += f"

{heading}

" # Process lists elif re.match(r'^\d+\.\s', paragraph): # Ordered list items = paragraph.split("\n") answer_html += "
    " for item in items: if re.match(r'^\d+\.\s', item): item_content = re.sub(r'^\d+\.\s', '', item) answer_html += f"
  1. {item_content}
  2. " answer_html += "
" elif re.match(r'^[*-]\s', paragraph): # Unordered list items = paragraph.split("\n") answer_html += "" # 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'
{code}
' # Process blockquotes elif paragraph.startswith(">"): content = paragraph.replace("\n>", "\n").replace(">", "") answer_html += f'
{content}
' # Standard paragraph else: # Process inline code paragraph = re.sub(r'`([^`]+)`', r'\1', paragraph) # Process bold text paragraph = re.sub(r'\*\*([^*]+)\*\*', r'\1', paragraph) # Process italic text paragraph = re.sub(r'\*([^*]+)\*', r'\1', paragraph) answer_html += f"

{paragraph}

" # Add sources if available if sources: sources_html = "
" sources_html += "

Sources

" answer_html += sources_html # Add debugging information if available with nice formatting if debug and reasoning_steps: reasoning_html = "

Agent Reasoning Process

" for step in reasoning_steps: step_stage = step['stage'] step_reasoning = step['reasoning'].replace('\n', '
') reasoning_html += f"""
{step_stage}
{step_reasoning}
""" answer_html += reasoning_html # Return the final formatted HTML without any copy functionality return f"""
{answer_html}
"""