Nischal Subedi commited on
Commit
80f99f6
·
1 Parent(s): f743e73
Files changed (1) hide show
  1. app.py +116 -63
app.py CHANGED
@@ -249,7 +249,7 @@ Answer:"""
249
  if not api_key or not api_key.strip() or not api_key.startswith("sk-"):
250
  return "<div class='error-message'><span class='error-icon'>⚠️</span>Please provide a valid OpenAI API key (starting with 'sk-'). <a href='https://platform.openai.com/api-keys' target='_blank'>OpenAI</a>.</div>"
251
  if not state or state == "Select a state..." or "Error" in state:
252
- return "<div class='error-message'><span class='error-icon'>⚠️</span>Please select a valid state from the dropdown.</div>"
253
  if not query or not query.strip():
254
  return "<div class='error-message'><span class='error-icon'>⚠️</span>Please enter your question in the text box.</div>"
255
 
@@ -269,14 +269,15 @@ Answer:"""
269
  try:
270
  available_states_list = self.get_states()
271
  # DEBUG: Print states to console to verify if data is loaded
272
- print(f"DEBUG: States loaded for dropdown: {available_states_list}")
273
  # Ensure "Select a state..." is always the first option
274
- dropdown_choices = ["Select a state..."] + (available_states_list if available_states_list and "Error" not in available_states_list[0] else ["Error: States unavailable"])
275
- initial_value = dropdown_choices[0] # Set initial value to the prompt
 
276
  except Exception as e: # Catch-all for safety
277
- print(f"DEBUG: Error loading states for dropdown: {e}")
278
- dropdown_choices = ["Error: Critical failure loading states"]
279
- initial_value = dropdown_choices[0]
280
 
281
 
282
  # Define example queries, filtering based on available states
@@ -447,15 +448,17 @@ Answer:"""
447
  transform: translateY(-3px) !important; /* More pronounced lift */
448
  }
449
 
450
- /* NEW: Class to center content within Markdown blocks */
451
- .text-center-markdown {
452
- text-align: center !important;
453
- width: 100% !important; /* Ensure it takes full width to center its content */
454
- display: block !important; /* Make sure it's a block level container */
 
 
455
  }
456
 
457
  /* Section titles (h3 inside markdown) */
458
- .sub-section-title {
459
  font-family: 'Poppins', sans-serif !important;
460
  font-size: 1.7rem !important; /* Slightly larger */
461
  font-weight: 700 !important; /* Bolder */
@@ -463,9 +466,12 @@ Answer:"""
463
  margin: 0 0 1.25rem 0 !important; /* More space below title */
464
  padding-bottom: 0.75rem !important;
465
  border-bottom: 2px solid var(--border-color) !important; /* Underline effect */
466
- display: inline-block !important; /* Allow it to shrink-wrap its content for proper border-bottom width */
 
 
 
 
467
  letter-spacing: -0.01em !important;
468
- /* To center this inline-block, its parent (.text-center-markdown) must have text-align: center */
469
  }
470
 
471
  /* Specific styling for the welcome/disclaimer markdown content */
@@ -480,17 +486,11 @@ Answer:"""
480
  }
481
 
482
  /* Improved input styling with clear boundaries and focus */
483
- .gradio-textbox, .gradio-dropdown {
484
  margin-bottom: 0.75rem !important;
485
  }
486
- /* Directly targeting internal Gradio input elements for specific background/border */
487
  .gradio-textbox textarea,
488
- .gradio-textbox input,
489
- /* Specific targeting for dropdown elements */
490
- .gradio-dropdown > div.primary-wrap > div > input, /* The input field within the dropdown */
491
- .gradio-dropdown > div.primary-wrap, /* The main clickable wrapper of the dropdown */
492
- .gradio-dropdown > div.scroll-hide /* The actual dropdown options list container */
493
- {
494
  background-color: var(--background-primary) !important; /* Explicitly set background to primary cream */
495
  border: 2px solid var(--border-color) !important; /* Clear border */
496
  border-radius: 8px !important;
@@ -501,39 +501,88 @@ Answer:"""
501
  transition: border-color 0.2s ease, box-shadow 0.2s ease !important; /* Smooth transitions */
502
  box-shadow: var(--shadow-sm) !important;
503
  }
504
- /* Focus styles */
505
  .gradio-textbox textarea:focus,
506
- .gradio-textbox input:focus,
507
- .gradio-dropdown > div.primary-wrap > div > input:focus, /* Focus for dropdown input */
508
- .gradio-dropdown > div.primary-wrap.focused { /* Focus for dropdown wrapper */
509
  outline: none !important;
510
  border-color: var(--border-focus) !important; /* Distinct border on focus */
511
  box-shadow: 0 0 0 4px rgba(255, 140, 0, 0.2) !important; /* Broader, softer glow on focus */
512
  }
513
- /* Ensure dropdown arrow is styled correctly */
514
- .gradio-dropdown .primary-wrap .text-lg { /* Targeting the arrow icon itself */
515
- color: var(--text-secondary) !important; /* Use a neutral color for the arrow */
 
 
 
516
  }
517
- /* Handle active/selected state for dropdown options */
518
- .gradio-dropdown .secondary-wrap > div:hover,
519
- .gradio-dropdown .secondary-wrap > div.focused,
520
- .gradio-dropdown .secondary-wrap > div[aria-selected="true"] {
521
- background-color: var(--background-secondary) !important; /* Highlight on hover/focus/selection */
522
- color: var(--primary-color) !important; /* Primary color for selected text */
523
  }
524
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
525
 
526
- /* Label styling for better readability */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
527
  .gradio-textbox label,
528
- .gradio-dropdown label {
529
  font-weight: 600 !important; /* Bolder labels */
530
  color: var(--text-primary) !important;
531
  font-size: 1rem !important;
532
  margin-bottom: 0.6rem !important;
533
  display: block !important;
 
534
  }
535
- /* Info text styling below inputs (typically .gr-prose or .gr-form in Gradio) */
536
- .gr-prose {
537
  font-size: 0.9rem !important;
538
  color: var(--text-secondary) !important;
539
  margin-top: 0.4rem !important; /* More space for info text */
@@ -765,7 +814,7 @@ Answer:"""
765
  .app-header-tagline {
766
  font-size: 1rem !important;
767
  }
768
- .sub-section-title {
769
  font-size: 1.4rem !important;
770
  }
771
  .input-row {
@@ -794,19 +843,24 @@ Answer:"""
794
  with gr.Blocks(css=custom_css, title="Landlord-Tenant Rights Assistant") as demo:
795
  # Header Section - uses gr.Group for distinct card-like styling
796
  with gr.Group(elem_classes="app-header-wrapper"):
797
- # Using separate Markdown components for each part of the header
798
- # with the new 'text-center-markdown' class for robust centering.
799
- gr.Markdown("<span class='app-header-logo'>⚖️</span>", elem_classes="text-center-markdown")
800
- gr.Markdown("<h1 class='app-header-title'>Landlord-Tenant Rights Assistant</h1>", elem_classes="text-center-markdown")
801
- gr.Markdown("<p class='app-header-tagline'>Empowering You with State-Specific Legal Insights</p>", elem_classes="text-center-markdown")
 
 
 
 
 
802
 
803
  # Main Dashboard Container - acts as a column to stack various sections
804
  with gr.Column(elem_classes="main-dashboard-container"):
805
 
806
  # Introduction and Disclaimer Card
807
  with gr.Group(elem_classes="dashboard-card-section"):
808
- # Apply 'text-center-markdown' for section titles
809
- gr.Markdown("<h3 class='sub-section-title'>Welcome & Disclaimer</h3>", elem_classes="text-center-markdown")
810
  gr.Markdown(
811
  """
812
  Navigate landlord-tenant laws with ease. This assistant provides detailed, state-specific answers grounded in legal authority.
@@ -817,8 +871,8 @@ Answer:"""
817
 
818
  # OpenAI API Key Input Card
819
  with gr.Group(elem_classes="dashboard-card-section"):
820
- # Apply 'text-center-markdown' for section titles
821
- gr.Markdown("<h3 class='sub-section-title'>OpenAI API Key</h3>", elem_classes="text-center-markdown")
822
  api_key_input = gr.Textbox(
823
  label="API Key",
824
  type="password", # Hides the input for security
@@ -830,8 +884,8 @@ Answer:"""
830
 
831
  # Query Input and State Selection Card
832
  with gr.Group(elem_classes="dashboard-card-section"):
833
- # Apply 'text-center-markdown' for section titles
834
- gr.Markdown("<h3 class='sub-section-title'>Ask Your Question</h3>", elem_classes="text-center-markdown")
835
  with gr.Row(elem_classes="input-row"): # Row for side-by-side query and state
836
  with gr.Column(elem_classes="input-field", scale=3): # Query text area takes more space
837
  query_input = gr.Textbox(
@@ -841,13 +895,12 @@ Answer:"""
841
  max_lines=8,
842
  elem_classes=["input-field-group"]
843
  )
844
- with gr.Column(elem_classes="input-field", scale=1): # State dropdown takes less space
845
- state_input = gr.Dropdown(
846
  label="Select State",
847
- choices=dropdown_choices,
848
- value=initial_value,
849
- allow_custom_value=False,
850
- elem_classes=["input-field-group"]
851
  )
852
  with gr.Row(elem_classes="button-row"): # Row for action buttons
853
  clear_button = gr.Button("Clear", variant="secondary", elem_classes=["gr-button-secondary"])
@@ -855,8 +908,8 @@ Answer:"""
855
 
856
  # Output Display Card - Using gr.HTML for better animation control
857
  with gr.Group(elem_classes="dashboard-card-section"):
858
- # Apply 'text-center-markdown' for section titles
859
- gr.Markdown("<h3 class='sub-section-title'>Legal Assistant's Response</h3>", elem_classes="text-center-markdown")
860
  output = gr.HTML( # Changed to gr.HTML to wrap content with animation class
861
  value="<div class='placeholder'>The answer will appear here after submitting your query.</div>",
862
  elem_classes="output-content-wrapper" # Custom class for output styling
@@ -864,8 +917,8 @@ Answer:"""
864
 
865
  # Example Questions Section
866
  with gr.Group(elem_classes="dashboard-card-section examples-section"):
867
- # Apply 'text-center-markdown' for section titles
868
- gr.Markdown("<h3 class='sub-section-title'>Example Questions</h3>", elem_classes="text-center-markdown")
869
  if example_queries:
870
  gr.Examples(
871
  examples=example_queries,
@@ -897,7 +950,7 @@ Answer:"""
897
  fn=lambda: (
898
  "", # Clear API key input
899
  "", # Clear query input
900
- initial_value, # Reset state dropdown to default prompt
901
  "<div class='placeholder'>Inputs cleared. Ready for your next question.</div>" # Reset output message
902
  ),
903
  inputs=[],
 
249
  if not api_key or not api_key.strip() or not api_key.startswith("sk-"):
250
  return "<div class='error-message'><span class='error-icon'>⚠️</span>Please provide a valid OpenAI API key (starting with 'sk-'). <a href='https://platform.openai.com/api-keys' target='_blank'>OpenAI</a>.</div>"
251
  if not state or state == "Select a state..." or "Error" in state:
252
+ return "<div class='error-message'><span class='error-icon'>⚠️</span>Please select a valid state from the list.</div>" # Changed dropdown to list
253
  if not query or not query.strip():
254
  return "<div class='error-message'><span class='error-icon'>⚠️</span>Please enter your question in the text box.</div>"
255
 
 
269
  try:
270
  available_states_list = self.get_states()
271
  # DEBUG: Print states to console to verify if data is loaded
272
+ print(f"DEBUG: States loaded for selection: {available_states_list}")
273
  # Ensure "Select a state..." is always the first option
274
+ # For Radio, we might want a distinct initial "no selection" state
275
+ radio_choices = ["Select a state..."] + (available_states_list if available_states_list and "Error" not in available_states_list[0] else ["Error: States unavailable"])
276
+ initial_value_radio = radio_choices[0] # Set initial value to the prompt
277
  except Exception as e: # Catch-all for safety
278
+ print(f"DEBUG: Error loading states for selection: {e}")
279
+ radio_choices = ["Error: Critical failure loading states"]
280
+ initial_value_radio = radio_choices[0]
281
 
282
 
283
  # Define example queries, filtering based on available states
 
448
  transform: translateY(-3px) !important; /* More pronounced lift */
449
  }
450
 
451
+ /* NEW: Class for Markdown blocks to center their content */
452
+ .full-width-center {
453
+ display: flex !important;
454
+ justify-content: center !important;
455
+ align-items: center !important;
456
+ width: 100% !important;
457
+ flex-direction: column !important; /* Ensure content stacks vertically if needed */
458
  }
459
 
460
  /* Section titles (h3 inside markdown) */
461
+ .section-title { /* Renamed from sub-section-title for clarity */
462
  font-family: 'Poppins', sans-serif !important;
463
  font-size: 1.7rem !important; /* Slightly larger */
464
  font-weight: 700 !important; /* Bolder */
 
466
  margin: 0 0 1.25rem 0 !important; /* More space below title */
467
  padding-bottom: 0.75rem !important;
468
  border-bottom: 2px solid var(--border-color) !important; /* Underline effect */
469
+ display: block !important; /* Ensure it's a block-level element for proper width/border */
470
+ text-align: center !important; /* Ensure the text within the h3 is centered */
471
+ width: fit-content !important; /* Make it shrink-wrap its content */
472
+ margin-left: auto !important; /* Auto margins to center block-level element */
473
+ margin-right: auto !important;
474
  letter-spacing: -0.01em !important;
 
475
  }
476
 
477
  /* Specific styling for the welcome/disclaimer markdown content */
 
486
  }
487
 
488
  /* Improved input styling with clear boundaries and focus */
489
+ .gradio-textbox {
490
  margin-bottom: 0.75rem !important;
491
  }
 
492
  .gradio-textbox textarea,
493
+ .gradio-textbox input {
 
 
 
 
 
494
  background-color: var(--background-primary) !important; /* Explicitly set background to primary cream */
495
  border: 2px solid var(--border-color) !important; /* Clear border */
496
  border-radius: 8px !important;
 
501
  transition: border-color 0.2s ease, box-shadow 0.2s ease !important; /* Smooth transitions */
502
  box-shadow: var(--shadow-sm) !important;
503
  }
504
+ /* Focus styles for textboxes */
505
  .gradio-textbox textarea:focus,
506
+ .gradio-textbox input:focus {
 
 
507
  outline: none !important;
508
  border-color: var(--border-focus) !important; /* Distinct border on focus */
509
  box-shadow: 0 0 0 4px rgba(255, 140, 0, 0.2) !important; /* Broader, softer glow on focus */
510
  }
511
+
512
+ /* Styling for the radio button group (state selection) */
513
+ .gradio-radio {
514
+ /* Adjust padding/margins for overall radio group container */
515
+ padding: 0 !important; /* Remove any default padding */
516
+ margin-top: 0.5rem !important; /* Add a little space above */
517
  }
518
+
519
+ .gradio-radio .gr-radio-input { /* Targeting the actual radio button inputs (hidden) */
520
+ display: none !important;
 
 
 
521
  }
522
 
523
+ .gradio-radio label {
524
+ /* Style the clickable area for each radio option */
525
+ display: flex !important; /* Use flexbox for internal alignment */
526
+ justify-content: center !important; /* Center content horizontally */
527
+ align-items: center !important;
528
+ padding: 0.75rem 1rem !important;
529
+ border: 2px solid var(--border-color) !important;
530
+ border-radius: 8px !important;
531
+ background-color: var(--background-primary) !important; /* Matches card background */
532
+ color: var(--text-primary) !important;
533
+ font-weight: 500 !important;
534
+ cursor: pointer !important;
535
+ transition: all 0.2s ease-out !important;
536
+ box-shadow: var(--shadow-sm) !important;
537
+ margin: 0.25rem 0 !important; /* Small vertical margin between options */
538
+ width: 100% !important; /* Ensure options take full width of their column */
539
+ box-sizing: border-box !important; /* Include padding/border in width */
540
+ }
541
 
542
+ /* Style the text/content within the radio label */
543
+ .gradio-radio label span.text-lg { /* Gradio uses text-lg for the label text by default */
544
+ font-weight: 600 !important; /* Make text bold */
545
+ color: var(--text-primary) !important;
546
+ font-size: 0.98rem !important; /* Match input text size */
547
+ }
548
+
549
+ /* Hover effect for radio options */
550
+ .gradio-radio label:hover {
551
+ background-color: var(--background-secondary) !important; /* Slightly darker cream on hover */
552
+ border-color: var(--primary-color) !important; /* Highlight border with primary color */
553
+ box-shadow: var(--shadow-md) !important;
554
+ transform: translateY(-2px) !important;
555
+ }
556
+
557
+ /* Selected state for radio options */
558
+ .gradio-radio label.selected { /* Gradio adds a 'selected' class to the label of the chosen option */
559
+ background-color: var(--primary-color) !important; /* Primary color for selected item */
560
+ color: white !important; /* White text on selected */
561
+ border-color: var(--primary-hover) !important;
562
+ box-shadow: var(--shadow-md) !important;
563
+ transform: translateY(-1px) !important;
564
+ }
565
+ .gradio-radio label.selected span.text-lg {
566
+ color: white !important; /* Ensure text is white when selected */
567
+ }
568
+ /* Gradio's internal wrapper for radio buttons, ensure it doesn't add unwanted padding */
569
+ .gradio-radio .gr-form {
570
+ padding: 0 !important;
571
+ }
572
+
573
+
574
+ /* Label styling for better readability (for Query, State labels) */
575
  .gradio-textbox label,
576
+ .gradio-radio label.gr-form-label { /* Target the main label for the radio group */
577
  font-weight: 600 !important; /* Bolder labels */
578
  color: var(--text-primary) !important;
579
  font-size: 1rem !important;
580
  margin-bottom: 0.6rem !important;
581
  display: block !important;
582
+ text-align: left !important; /* Ensure these labels are left-aligned */
583
  }
584
+ /* Info text styling below inputs (e.g., for API Key) */
585
+ .gr-prose { /* This class is used by Gradio for info text */
586
  font-size: 0.9rem !important;
587
  color: var(--text-secondary) !important;
588
  margin-top: 0.4rem !important; /* More space for info text */
 
814
  .app-header-tagline {
815
  font-size: 1rem !important;
816
  }
817
+ .section-title {
818
  font-size: 1.4rem !important;
819
  }
820
  .input-row {
 
843
  with gr.Blocks(css=custom_css, title="Landlord-Tenant Rights Assistant") as demo:
844
  # Header Section - uses gr.Group for distinct card-like styling
845
  with gr.Group(elem_classes="app-header-wrapper"):
846
+ # Using a single Markdown component for header for easier robust centering
847
+ # The 'full-width-center' class applies flexbox centering to the Markdown content
848
+ gr.Markdown(
849
+ """
850
+ <span class='app-header-logo'>⚖️</span>
851
+ <h1 class='app-header-title'>Landlord-Tenant Rights Assistant</h1>
852
+ <p class='app-header-tagline'>Empowering You with State-Specific Legal Insights</p>
853
+ """,
854
+ elem_classes="full-width-center"
855
+ )
856
 
857
  # Main Dashboard Container - acts as a column to stack various sections
858
  with gr.Column(elem_classes="main-dashboard-container"):
859
 
860
  # Introduction and Disclaimer Card
861
  with gr.Group(elem_classes="dashboard-card-section"):
862
+ # Apply 'full-width-center' for section titles
863
+ gr.Markdown("<h3 class='section-title'>Welcome & Disclaimer</h3>", elem_classes="full-width-center")
864
  gr.Markdown(
865
  """
866
  Navigate landlord-tenant laws with ease. This assistant provides detailed, state-specific answers grounded in legal authority.
 
871
 
872
  # OpenAI API Key Input Card
873
  with gr.Group(elem_classes="dashboard-card-section"):
874
+ # Apply 'full-width-center' for section titles
875
+ gr.Markdown("<h3 class='section-title'>OpenAI API Key</h3>", elem_classes="full-width-center")
876
  api_key_input = gr.Textbox(
877
  label="API Key",
878
  type="password", # Hides the input for security
 
884
 
885
  # Query Input and State Selection Card
886
  with gr.Group(elem_classes="dashboard-card-section"):
887
+ # Apply 'full-width-center' for section titles
888
+ gr.Markdown("<h3 class='section-title'>Ask Your Question</h3>", elem_classes="full-width-center")
889
  with gr.Row(elem_classes="input-row"): # Row for side-by-side query and state
890
  with gr.Column(elem_classes="input-field", scale=3): # Query text area takes more space
891
  query_input = gr.Textbox(
 
895
  max_lines=8,
896
  elem_classes=["input-field-group"]
897
  )
898
+ with gr.Column(elem_classes="input-field", scale=1): # State radio buttons take less space
899
+ state_input = gr.Radio(
900
  label="Select State",
901
+ choices=radio_choices,
902
+ value=initial_value_radio,
903
+ elem_classes=["input-field-group", "gradio-radio-custom"] # Added custom class for specific styling
 
904
  )
905
  with gr.Row(elem_classes="button-row"): # Row for action buttons
906
  clear_button = gr.Button("Clear", variant="secondary", elem_classes=["gr-button-secondary"])
 
908
 
909
  # Output Display Card - Using gr.HTML for better animation control
910
  with gr.Group(elem_classes="dashboard-card-section"):
911
+ # Apply 'full-width-center' for section titles
912
+ gr.Markdown("<h3 class='section-title'>Legal Assistant's Response</h3>", elem_classes="full-width-center")
913
  output = gr.HTML( # Changed to gr.HTML to wrap content with animation class
914
  value="<div class='placeholder'>The answer will appear here after submitting your query.</div>",
915
  elem_classes="output-content-wrapper" # Custom class for output styling
 
917
 
918
  # Example Questions Section
919
  with gr.Group(elem_classes="dashboard-card-section examples-section"):
920
+ # Apply 'full-width-center' for section titles
921
+ gr.Markdown("<h3 class='section-title'>Example Questions</h3>", elem_classes="full-width-center")
922
  if example_queries:
923
  gr.Examples(
924
  examples=example_queries,
 
950
  fn=lambda: (
951
  "", # Clear API key input
952
  "", # Clear query input
953
+ initial_value_radio, # Reset state radio to default prompt
954
  "<div class='placeholder'>Inputs cleared. Ready for your next question.</div>" # Reset output message
955
  ),
956
  inputs=[],