Nischal Subedi commited on
Commit
720834f
·
1 Parent(s): fd79167
Files changed (1) hide show
  1. app.py +108 -79
app.py CHANGED
@@ -93,7 +93,7 @@ Answer:"""
93
  def process_query_cached(self, query: str, state: str, openai_api_key: str, n_results: int = 5) -> Dict[str, any]:
94
  logging.info(f"Processing query (cache key: '{query}'|'{state}'|key_hidden) with n_results={n_results}")
95
 
96
- if not state or state == "Select a state..." or "Error" in state:
97
  logging.warning("No valid state provided for query.")
98
  return {"answer": "<div class='error-message'>Error: Please select a valid state.</div>", "context_used": "N/A - Invalid Input"}
99
  if not query or not query.strip():
@@ -248,7 +248,7 @@ Answer:"""
248
  # Basic client-side validation for immediate feedback (redundant but good UX)
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 or state is None: # Added check for None
252
  return "<div class='error-message'><span class='error-icon'>⚠️</span>Please select a valid state from the list.</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>"
@@ -352,9 +352,9 @@ Answer:"""
352
  background-color: var(--background-secondary) !important; /* Overall background of the container */
353
  box-shadow: none !important; /* Remove default gradio container shadow */
354
  }
355
- /* Ensure all main content sections have the gradient background */
356
  .main-dashboard-container > * {
357
- background: linear-gradient(145deg, var(--background-primary) 0%, var(--background-secondary) 100%) !important;
358
  }
359
 
360
  /* Header styling - centered and prominent */
@@ -432,10 +432,10 @@ Answer:"""
432
  }
433
  /* Card sections with clear boundaries and subtle dynamic effects */
434
  .dashboard-card-section {
435
- /* Background already set by .main-dashboard-container > * */
436
  border: 2px solid var(--border-color) !important; /* Distinct border */
437
  border-radius: 12px !important;
438
- padding: 1.75rem !important; /* Consistent padding */
439
  box-shadow: var(--shadow-sm) !important; /* Subtle shadow */
440
  transition: all 0.3s ease-out !important; /* Smoother transition */
441
  cursor: default; /* Indicate not directly clickable (unless examples) */
@@ -454,24 +454,36 @@ Answer:"""
454
  flex-direction: column !important; /* Ensure content stacks vertically if needed */
455
  }
456
 
 
 
 
 
 
 
 
 
 
 
 
 
457
  /* Section titles (h3 inside markdown) */
458
  .section-title {
459
  font-family: 'Poppins', sans-serif !important;
460
  font-size: 1.7rem !important; /* Slightly larger */
461
  font-weight: 700 !important; /* Bolder */
462
  color: var(--text-primary) !important;
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: block !important;
467
- text-align: center !important;
468
- width: fit-content !important;
469
- margin-left: auto !important;
470
- margin-right: auto !important;
471
  letter-spacing: -0.01em !important;
 
 
472
  }
473
 
474
- /* Specific styling for all paragraph content within dashboard sections */
 
 
 
 
475
  .dashboard-card-section p {
476
  line-height: 1.7 !important;
477
  color: var(--text-primary) !important;
@@ -484,14 +496,13 @@ Answer:"""
484
  }
485
 
486
  /* Overrides for common Gradio internal elements that might have default backgrounds */
487
- .gr-box, .gr-prose, .gr-form, .gr-panel, .gr-block {
488
- background-color: transparent !important; /* Ensure these are transparent to show parent's gradient */
489
  color: var(--text-primary) !important; /* Ensure text color is consistent */
490
  }
491
 
492
 
493
  /* Improved input styling with clear boundaries and focus */
494
- /* Target the main textbox container to remove any default background */
495
  .gradio-textbox {
496
  background-color: transparent !important; /* Ensure parent container is transparent */
497
  margin-bottom: 0.75rem !important;
@@ -522,7 +533,6 @@ Answer:"""
522
  }
523
 
524
  /* Styling for the radio button group (state selection) */
525
- /* Target the main radio container to remove any default background */
526
  .gradio-radio {
527
  background-color: transparent !important; /* Ensure parent container is transparent */
528
  padding: 0 !important; /* Remove any default padding */
@@ -804,11 +814,14 @@ Answer:"""
804
  text-align: center !important; /* Centered footer text */
805
  }
806
  .app-footer p {
807
- margin: 0.6rem 0 !important;
 
808
  font-size: 0.95rem !important;
809
  color: var(--text-secondary) !important;
810
  line-height: 1.6 !important;
811
  background-color: transparent !important; /* Ensure paragraph in footer does not get unexpected background */
 
 
812
  }
813
  .app-footer a {
814
  color: var(--primary-color) !important;
@@ -843,7 +856,13 @@ Answer:"""
843
  width: 100% !important; /* Full width buttons */
844
  }
845
  .dashboard-card-section {
846
- padding: 1.25rem !important;
 
 
 
 
 
 
847
  }
848
  .output-content-wrapper {
849
  min-height: 120px !important;
@@ -859,8 +878,6 @@ Answer:"""
859
  with gr.Blocks(css=custom_css, title="Landlord-Tenant Rights Assistant") as demo:
860
  # Header Section - uses gr.Group for distinct card-like styling
861
  with gr.Group(elem_classes="app-header-wrapper"):
862
- # Using a single Markdown component for header for easier robust centering
863
- # The 'full-width-center' class applies flexbox centering to the Markdown content
864
  gr.Markdown(
865
  """
866
  <span class='app-header-logo'>⚖️</span>
@@ -873,75 +890,87 @@ Answer:"""
873
  # Main Dashboard Container - acts as a column to stack various sections
874
  with gr.Column(elem_classes="main-dashboard-container"):
875
 
876
- # How It Works Box (formerly Welcome & Disclaimer)
877
  with gr.Group(elem_classes="dashboard-card-section"):
878
- gr.Markdown("<h3 class='section-title'>How This Assistant Works</h3>", elem_classes="full-width-center")
879
- gr.Markdown(
880
- """
881
- This AI-powered assistant helps navigate complex landlord-tenant laws. Simply ask a question about your state's regulations, and it will provide detailed, legally-grounded insights.
882
- """
883
- # Disclaimer text removed from here.
884
- )
 
 
885
 
886
  # OpenAI API Key Input Card
887
  with gr.Group(elem_classes="dashboard-card-section"):
888
- gr.Markdown("<h3 class='section-title'>OpenAI API Key</h3>", elem_classes="full-width-center")
889
- api_key_input = gr.Textbox(
890
- label="API Key",
891
- type="password", # Hides the input for security
892
- placeholder="Enter your OpenAI API key (e.g., sk-...)",
893
- info="Required to process your query. Get one from OpenAI: platform.openai.com/api-keys",
894
- lines=1,
895
- elem_classes=["input-field-group"] # Custom class for input styling
896
- )
 
 
 
897
 
898
  # Query Input and State Selection Card
899
  with gr.Group(elem_classes="dashboard-card-section"):
900
- gr.Markdown("<h3 class='section-title'>Ask Your Question</h3>", elem_classes="full-width-center")
901
-
902
- # Changed from gr.Row to gr.Column for vertical stacking
903
- with gr.Column(elem_classes="input-column"): # New column to stack inputs
904
- with gr.Column(elem_classes="input-field", scale=1): # Query box takes full width, scale=1 for numerical value
905
- query_input = gr.Textbox(
906
- label="Your Question",
907
- placeholder="E.g., What are the rules for security deposit returns in my state?",
908
- lines=8, # Increased default height
909
- max_lines=15, # Increased max height
910
- elem_classes=["input-field-group"]
911
- )
912
- with gr.Column(elem_classes="input-field", scale=1): # State radio buttons take full width below, scale=1 for numerical value
913
- state_input = gr.Radio(
914
- label="Select State",
915
- choices=radio_choices,
916
- value=initial_value_radio, # Set initial value to None
917
- elem_classes=["input-field-group", "gradio-radio-custom"], # Added custom class for specific styling
918
- interactive=True # Ensure it's interactive
919
- )
920
-
921
- with gr.Row(elem_classes="button-row"): # Row for action buttons
922
- clear_button = gr.Button("Clear", variant="secondary", elem_classes=["gr-button-secondary"])
923
- submit_button = gr.Button("Submit Query", variant="primary", elem_classes=["gr-button-primary"])
 
924
 
925
  # Output Display Card - Using gr.HTML for better animation control
926
  with gr.Group(elem_classes="dashboard-card-section"):
927
- gr.Markdown("<h3 class='section-title'>Legal Assistant's Response</h3>", elem_classes="full-width-center")
928
- output = gr.HTML( # Changed to gr.HTML to wrap content with animation class
929
- value="<div class='placeholder'>The answer will appear here after submitting your query.</div>",
930
- elem_classes="output-content-wrapper" # Custom class for output styling
931
- )
 
 
 
932
 
933
  # Example Questions Section
934
  with gr.Group(elem_classes="dashboard-card-section examples-section"):
935
- gr.Markdown("<h3 class='section-title'>Example Questions</h3>", elem_classes="full-width-center")
936
- if example_queries:
937
- gr.Examples(
938
- examples=example_queries,
939
- inputs=[query_input, state_input],
940
- examples_per_page=5,
941
- label="" # Hide default Gradio label for examples to use our custom title
942
- )
943
- else:
944
- gr.Markdown("<div class='placeholder'>Sample questions could not be loaded. Please ensure the vector database is populated.</div>")
 
 
 
945
 
946
  # Footer Section - contains disclaimer and developer info (now including the full disclaimer)
947
  with gr.Group(elem_classes="app-footer-wrapper"):
 
93
  def process_query_cached(self, query: str, state: str, openai_api_key: str, n_results: int = 5) -> Dict[str, any]:
94
  logging.info(f"Processing query (cache key: '{query}'|'{state}'|key_hidden) with n_results={n_results}")
95
 
96
+ if not state or state == "Select a state..." or "Error" in state or state is None: # Added check for None
97
  logging.warning("No valid state provided for query.")
98
  return {"answer": "<div class='error-message'>Error: Please select a valid state.</div>", "context_used": "N/A - Invalid Input"}
99
  if not query or not query.strip():
 
248
  # Basic client-side validation for immediate feedback (redundant but good UX)
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 is None: # Removed "Select a state..." from error check as it's not a choice
252
  return "<div class='error-message'><span class='error-icon'>⚠️</span>Please select a valid state from the list.</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>"
 
352
  background-color: var(--background-secondary) !important; /* Overall background of the container */
353
  box-shadow: none !important; /* Remove default gradio container shadow */
354
  }
355
+ /* All main content sections (cards) will have the primary background, not a gradient */
356
  .main-dashboard-container > * {
357
+ background-color: var(--background-primary) !important;
358
  }
359
 
360
  /* Header styling - centered and prominent */
 
432
  }
433
  /* Card sections with clear boundaries and subtle dynamic effects */
434
  .dashboard-card-section {
435
+ /* Background already set by .main-dashboard-container > * to primary white */
436
  border: 2px solid var(--border-color) !important; /* Distinct border */
437
  border-radius: 12px !important;
438
+ padding: 0 !important; /* Removed padding to allow gradient bar to control it */
439
  box-shadow: var(--shadow-sm) !important; /* Subtle shadow */
440
  transition: all 0.3s ease-out !important; /* Smoother transition */
441
  cursor: default; /* Indicate not directly clickable (unless examples) */
 
454
  flex-direction: column !important; /* Ensure content stacks vertically if needed */
455
  }
456
 
457
+ /* NEW: Class for the gradient title bar within each card */
458
+ .section-title-gradient-bar {
459
+ background: linear-gradient(145deg, var(--background-primary) 0%, var(--background-secondary) 100%) !important;
460
+ padding: 1.25rem 1.75rem !important; /* Inner padding for the title bar */
461
+ border-top-left-radius: 10px !important; /* Match parent's border radius */
462
+ border-top-right-radius: 10px !important;
463
+ margin-bottom: 1.5rem !important; /* Space below the title bar */
464
+ text-align: center !important; /* Ensure content inside this bar is centered */
465
+ box-sizing: border-box; /* Include padding in width */
466
+ width: 100%; /* Ensure it spans full width */
467
+ }
468
+
469
  /* Section titles (h3 inside markdown) */
470
  .section-title {
471
  font-family: 'Poppins', sans-serif !important;
472
  font-size: 1.7rem !important; /* Slightly larger */
473
  font-weight: 700 !important; /* Bolder */
474
  color: var(--text-primary) !important;
475
+ margin: 0 !important; /* No margin on h3 itself as parent handles spacing */
476
+ line-height: 1.1 !important;
 
 
 
 
 
 
477
  letter-spacing: -0.01em !important;
478
+ display: inline-block !important; /* Allow centering within text-align: center of parent */
479
+ text-align: center !important; /* Fallback centering */
480
  }
481
 
482
+ /* General content area padding within dashboard sections (below the title bar) */
483
+ .dashboard-card-content-area {
484
+ padding: 0 1.75rem 1.75rem 1.75rem !important; /* Match overall padding, 0 top because title bar handles it */
485
+ background-color: var(--background-primary) !important; /* Pure white background */
486
+ }
487
  .dashboard-card-section p {
488
  line-height: 1.7 !important;
489
  color: var(--text-primary) !important;
 
496
  }
497
 
498
  /* Overrides for common Gradio internal elements that might have default backgrounds */
499
+ .gr-block, .gr-box, .gr-prose, .gr-form, .gr-panel, .gr-columns, .gr-column {
500
+ background-color: transparent !important; /* Ensure these are transparent to show parent's color */
501
  color: var(--text-primary) !important; /* Ensure text color is consistent */
502
  }
503
 
504
 
505
  /* Improved input styling with clear boundaries and focus */
 
506
  .gradio-textbox {
507
  background-color: transparent !important; /* Ensure parent container is transparent */
508
  margin-bottom: 0.75rem !important;
 
533
  }
534
 
535
  /* Styling for the radio button group (state selection) */
 
536
  .gradio-radio {
537
  background-color: transparent !important; /* Ensure parent container is transparent */
538
  padding: 0 !important; /* Remove any default padding */
 
814
  text-align: center !important; /* Centered footer text */
815
  }
816
  .app-footer p {
817
+ margin: 0.6rem auto !important; /* Auto margins to center block */
818
+ max-width: 90% !important; /* Constrain width for wrapping */
819
  font-size: 0.95rem !important;
820
  color: var(--text-secondary) !important;
821
  line-height: 1.6 !important;
822
  background-color: transparent !important; /* Ensure paragraph in footer does not get unexpected background */
823
+ text-align: center !important; /* Ensure footer text is centered */
824
+ white-space: normal !important; /* Allow text to wrap */
825
  }
826
  .app-footer a {
827
  color: var(--primary-color) !important;
 
856
  width: 100% !important; /* Full width buttons */
857
  }
858
  .dashboard-card-section {
859
+ /* padding handled by section-title-gradient-bar and dashboard-card-content-area */
860
+ }
861
+ .section-title-gradient-bar {
862
+ padding: 0.8rem 1rem !important;
863
+ }
864
+ .dashboard-card-content-area {
865
+ padding: 0 1rem 1rem 1rem !important;
866
  }
867
  .output-content-wrapper {
868
  min-height: 120px !important;
 
878
  with gr.Blocks(css=custom_css, title="Landlord-Tenant Rights Assistant") as demo:
879
  # Header Section - uses gr.Group for distinct card-like styling
880
  with gr.Group(elem_classes="app-header-wrapper"):
 
 
881
  gr.Markdown(
882
  """
883
  <span class='app-header-logo'>⚖️</span>
 
890
  # Main Dashboard Container - acts as a column to stack various sections
891
  with gr.Column(elem_classes="main-dashboard-container"):
892
 
893
+ # How This Assistant Works Box (formerly Welcome & Disclaimer)
894
  with gr.Group(elem_classes="dashboard-card-section"):
895
+ # Title bar with gradient
896
+ gr.Markdown("<h3 class='section-title'>How This Assistant Works</h3>", elem_classes="full-width-center section-title-gradient-bar")
897
+ # Content area with pure primary background
898
+ with gr.Column(elem_classes="dashboard-card-content-area"): # New wrapper for content area
899
+ gr.Markdown(
900
+ """
901
+ This AI-powered assistant helps navigate complex landlord-tenant laws. Simply ask a question about your state's regulations, and it will provide detailed, legally-grounded insights.
902
+ """
903
+ )
904
 
905
  # OpenAI API Key Input Card
906
  with gr.Group(elem_classes="dashboard-card-section"):
907
+ # Title bar with gradient
908
+ gr.Markdown("<h3 class='section-title'>OpenAI API Key</h3>", elem_classes="full-width-center section-title-gradient-bar")
909
+ # Content area with pure primary background
910
+ with gr.Column(elem_classes="dashboard-card-content-area"): # New wrapper for content area
911
+ api_key_input = gr.Textbox(
912
+ label="API Key",
913
+ type="password", # Hides the input for security
914
+ placeholder="Enter your OpenAI API key (e.g., sk-...)",
915
+ info="Required to process your query. Get one from OpenAI: [platform.openai.com/api-keys](https://platform.openai.com/api-keys)", # Made link clickable
916
+ lines=1,
917
+ elem_classes=["input-field-group"] # Custom class for input styling
918
+ )
919
 
920
  # Query Input and State Selection Card
921
  with gr.Group(elem_classes="dashboard-card-section"):
922
+ # Title bar with gradient
923
+ gr.Markdown("<h3 class='section-title'>Ask Your Question</h3>", elem_classes="full-width-center section-title-gradient-bar")
924
+ # Content area with pure primary background
925
+ with gr.Column(elem_classes="dashboard-card-content-area"): # New wrapper for content area
926
+ with gr.Column(elem_classes="input-column"): # Column to stack inputs
927
+ with gr.Column(elem_classes="input-field", scale=1): # Query box takes full width
928
+ query_input = gr.Textbox(
929
+ label="Your Question",
930
+ placeholder="E.g., What are the rules for security deposit returns in my state?",
931
+ lines=8, # Increased default height
932
+ max_lines=15, # Increased max height
933
+ elem_classes=["input-field-group"]
934
+ )
935
+ with gr.Column(elem_classes="input-field", scale=1): # State radio buttons take full width below
936
+ state_input = gr.Radio(
937
+ label="Select State",
938
+ choices=radio_choices,
939
+ value=initial_value_radio, # Set initial value to None
940
+ elem_classes=["input-field-group", "gradio-radio-custom"], # Added custom class for specific styling
941
+ interactive=True # Ensure it's interactive
942
+ )
943
+
944
+ with gr.Row(elem_classes="button-row"): # Row for action buttons
945
+ clear_button = gr.Button("Clear", variant="secondary", elem_classes=["gr-button-secondary"])
946
+ submit_button = gr.Button("Submit Query", variant="primary", elem_classes=["gr-button-primary"])
947
 
948
  # Output Display Card - Using gr.HTML for better animation control
949
  with gr.Group(elem_classes="dashboard-card-section"):
950
+ # Title bar with gradient
951
+ gr.Markdown("<h3 class='section-title'>Legal Assistant's Response</h3>", elem_classes="full-width-center section-title-gradient-bar")
952
+ # Content area with pure primary background
953
+ with gr.Column(elem_classes="dashboard-card-content-area"): # New wrapper for content area
954
+ output = gr.HTML( # Changed to gr.HTML to wrap content with animation class
955
+ value="<div class='placeholder'>The answer will appear here after submitting your query.</div>",
956
+ elem_classes="output-content-wrapper" # Custom class for output styling
957
+ )
958
 
959
  # Example Questions Section
960
  with gr.Group(elem_classes="dashboard-card-section examples-section"):
961
+ # Title bar with gradient
962
+ gr.Markdown("<h3 class='section-title'>Example Questions</h3>", elem_classes="full-width-center section-title-gradient-bar")
963
+ # Content area with pure primary background
964
+ with gr.Column(elem_classes="dashboard-card-content-area"): # New wrapper for content area
965
+ if example_queries:
966
+ gr.Examples(
967
+ examples=example_queries,
968
+ inputs=[query_input, state_input],
969
+ examples_per_page=5,
970
+ label="" # Hide default Gradio label for examples to use our custom title
971
+ )
972
+ else:
973
+ gr.Markdown("<div class='placeholder'>Sample questions could not be loaded. Please ensure the vector database is populated.</div>")
974
 
975
  # Footer Section - contains disclaimer and developer info (now including the full disclaimer)
976
  with gr.Group(elem_classes="app-footer-wrapper"):