Nischal Subedi commited on
Commit
728d3ad
·
1 Parent(s): 80f99f6
Files changed (1) hide show
  1. app.py +310 -382
app.py CHANGED
@@ -263,7 +263,7 @@ Answer:"""
263
  return answer
264
  else:
265
  # Wrap successful response in a div with an animation class
266
- formatted_response_content = f"<div class='response-header'><span class='response-icon'>📜</span>Response for {state}</div><hr class='divider'>{answer}"
267
  return f"<div class='animated-output-content'>{formatted_response_content}</div>"
268
 
269
  try:
@@ -279,7 +279,6 @@ Answer:"""
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
284
  example_queries_base = [
285
  ["What are the rules for security deposit returns?", "California"],
@@ -300,658 +299,587 @@ Answer:"""
300
  else: # Fallback if states list is problematic (e.g., empty or error)
301
  example_queries.append(["What basic rights do tenants have?", "California"])
302
 
303
-
304
- # Custom CSS for better UI design, clear boundaries, and text alignment for HuggingFace
305
  custom_css = """
306
- /* Import legible fonts from Google Fonts */
307
- @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=Poppins:wght@600;700;800&display=swap');
308
 
309
- /* Root variables for consistent theming - adjusted for an inviting orange palette */
310
  :root {
311
- --primary-color: #FF8C00; /* Darker Orange for buttons/accents */
312
- --primary-hover: #E07B00; /* Slightly darker orange for hover */
313
- --background-primary: #FFF8F0; /* Very light cream/off-white for main cards, inputs, output area */
314
- --background-secondary: #FDEBD9; /* Slightly darker cream for overall app background, table headers, placeholder */
315
- --text-primary: #4A3C32; /* Dark warm brown/charcoal for main text */
316
- --text-secondary: #8C7B6F; /* Muted warm gray/brown for secondary text */
317
- --border-color: #DDC6AF; /* Light, desaturated orange-brown for borders */
318
- --border-focus: #FF8C00; /* Focus color matches primary */
319
- --shadow-sm: 0 1px 3px rgba(0,0,0,0.08);
320
- --shadow-md: 0 4px 10px rgba(0,0,0,0.1);
321
- --shadow-lg: 0 10px 20px rgba(0,0,0,0.15);
322
- --error-bg: #FFF0E0; /* Light orange-pink for errors */
323
- --error-border: #FFD2B2; /* Medium orange-pink for error borders */
324
- --error-text: #E05C00; /* Darker, strong orange-red for error text */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
325
  }
326
-
327
- /* Dark mode variables - for consistency if a dark mode toggle were present */
328
- body.dark {
329
- --primary-color: #FFA500; /* Bright orange for dark mode */
330
- --primary-hover: #CC8400;
331
- --background-primary: #2C2C2C; /* Dark charcoal */
332
- --background-secondary: #1F1F1F; /* Even darker charcoal */
333
- --text-primary: #F0F0F0;
334
- --text-secondary: #B0B0B0;
335
- --border-color: #555555;
336
- --border-focus: #FFA500;
337
- --error-bg: #400000;
338
- --error-border: #800000;
339
- --error-text: #FF6666;
340
- }
341
-
342
- /* Ensure the very outer body background is also set, overriding any Gradio defaults */
343
  body, html {
344
  background-color: var(--background-secondary) !important;
 
345
  }
346
 
347
- /* Base container improvements */
348
  .gradio-container {
349
- max-width: 900px !important; /* Slightly smaller for focused content */
350
- margin: 0 auto !important; /* Center the whole app */
351
- padding: 1.5rem !important;
352
- font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif !important;
353
- background-color: var(--background-secondary) !important; /* Overall background of the container */
354
- box-shadow: none !important; /* Remove default gradio container shadow */
355
- }
356
- /* Ensure all main content sections have primary background */
357
- .main-dashboard-container > * {
358
- background-color: var(--background-primary) !important;
359
  }
360
 
361
- /* Header styling - centered and prominent */
362
  .app-header-wrapper {
363
- background: linear-gradient(135deg, var(--background-primary) 0%, var(--background-secondary) 100%) !important;
364
- border: 2px solid var(--border-color) !important;
365
  border-radius: 16px !important;
366
- padding: 2.5rem 1.5rem !important; /* More vertical padding */
367
- margin-bottom: 1.5rem !important;
368
- box-shadow: var(--shadow-md) !important;
369
- position: relative; /* For potential pseudo-element effects */
370
- overflow: hidden; /* For any overflow animations */
371
- /* text-align: center applied here for general content within wrapper */
372
- text-align: center !important;
373
  }
374
 
375
- .app-header-wrapper::before { /* Subtle background pattern for dynamism */
376
  content: '';
377
  position: absolute;
378
  top: 0;
379
  left: 0;
380
  width: 100%;
381
  height: 100%;
382
- background: radial-gradient(circle at top left, rgba(255,140,0,0.05) 0%, transparent 40%),
383
- radial-gradient(circle at bottom right, rgba(255,140,0,0.05) 0%, transparent 40%);
384
  z-index: 0;
385
- opacity: 0.8;
386
  pointer-events: none;
387
  }
388
 
389
  .app-header-logo {
390
- font-size: 4.5rem !important; /* Larger icon */
391
- margin-bottom: 0.75rem !important;
392
- display: block !important; /* Make it a block to center it within text-align */
393
- color: var(--primary-color) !important; /* Theme color */
394
  position: relative;
395
- z-index: 1; /* Bring icon to front of pseudo-element */
396
- /* Animation for dynamism */
397
- animation: float-icon 3s ease-in-out infinite alternate;
398
- }
399
- /* Keyframes for floating icon */
400
- @keyframes float-icon {
401
- 0% { transform: translateY(0px); }
402
- 50% { transform: translateY(-5px); }
403
- 100% { transform: translateY(0px); }
404
  }
405
 
406
  .app-header-title {
407
- font-family: 'Poppins', sans-serif !important;
408
- font-size: 3rem !important; /* Even larger title */
409
- font-weight: 800 !important; /* Bolder */
410
  color: var(--text-primary) !important;
411
- margin: 0 0 0.75rem 0 !important;
412
- line-height: 1.1 !important;
413
- letter-spacing: -0.03em !important; /* Tighter spacing */
414
  position: relative;
415
  z-index: 1;
416
- display: inline-block; /* Essential for text-align: center on parent to work for this block */
417
- max-width: 100%; /* Prevent overflow on smaller screens */
418
  }
 
419
  .app-header-tagline {
420
- font-size: 1.25rem !important; /* Slightly larger tagline */
421
  color: var(--text-secondary) !important;
422
  font-weight: 400 !important;
423
  margin: 0 !important;
424
- max-width: 700px; /* Constrain tagline width */
425
- display: inline-block; /* Essential for text-align: center on parent to work for this block */
426
  position: relative;
427
  z-index: 1;
428
  }
429
 
430
- /* Main container with consistent spacing */
431
  .main-dashboard-container {
432
  display: flex !important;
433
  flex-direction: column !important;
434
- gap: 1.25rem !important; /* Consistent spacing between cards */
435
  }
436
- /* Card sections with clear boundaries and subtle dynamic effects */
437
  .dashboard-card-section {
438
- background-color: var(--background-primary) !important; /* Explicitly set background */
439
- border: 2px solid var(--border-color) !important; /* Distinct border */
440
  border-radius: 12px !important;
441
- padding: 1.75rem !important; /* Consistent padding */
442
- box-shadow: var(--shadow-sm) !important; /* Subtle shadow */
443
- transition: all 0.3s ease-out !important; /* Smoother transition */
444
- cursor: default; /* Indicate not directly clickable (unless examples) */
445
  }
 
446
  .dashboard-card-section:hover {
447
  box-shadow: var(--shadow-md) !important;
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 */
465
  color: var(--text-primary) !important;
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 */
478
- .dashboard-card-section p {
479
- line-height: 1.7 !important;
480
- color: var(--text-primary) !important;
481
- font-size: 1rem !important;
482
- text-align: left !important; /* Ensure content text is left-aligned */
483
- }
484
- .dashboard-card-section strong {
485
- color: var(--primary-color) !important; /* Highlight strong text with primary color */
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;
497
- padding: 0.85rem 1rem !important; /* Slightly more padding */
498
- font-size: 0.98rem !important;
499
  font-family: 'Inter', sans-serif !important;
500
- color: var(--text-primary) !important; /* Text color inside inputs */
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 */
589
- text-align: left !important; /* Ensure info text is left aligned */
590
- }
591
- /* Input row layout improvements */
592
- .input-row {
593
- display: flex !important;
594
- gap: 1.25rem !important; /* Consistent gap between query and state */
595
  margin-bottom: 0.5rem !important;
596
- }
597
- .input-field {
598
- flex: 1 !important;
599
  }
600
 
601
- /* Button styling improvements with active state for dynamism */
602
  .button-row {
603
  display: flex !important;
604
- gap: 1rem !important;
605
- justify-content: flex-end !important; /* Align buttons to the right */
606
- margin-top: 1.5rem !important; /* More space above buttons */
607
  }
 
608
  .gradio-button {
609
- padding: 0.85rem 1.8rem !important; /* More padding for bigger buttons */
610
- border-radius: 9px !important; /* Slightly more rounded */
611
- font-weight: 600 !important; /* Bolder text */
612
- font-size: 1rem !important;
613
- transition: all 0.2s ease-out !important; /* Smooth transition for hover/active */
614
  cursor: pointer !important;
615
- border: 2px solid transparent !important;
616
- text-align: center !important; /* Ensure button text is centered */
617
  }
 
618
  .gr-button-primary {
619
- background-color: var(--primary-color) !important; /* Explicitly set background */
620
  color: white !important;
621
  box-shadow: var(--shadow-sm) !important;
622
  }
 
623
  .gr-button-primary:hover {
624
- background-color: var(--primary-hover) !important; /* Explicitly set background */
625
  box-shadow: var(--shadow-md) !important;
626
- transform: translateY(-2px) !important; /* Subtle lift effect on hover */
627
- }
628
- .gr-button-primary:active { /* Press down effect on click */
629
- transform: translateY(1px) !important;
630
- box-shadow: none !important;
631
  }
 
632
  .gr-button-secondary {
633
- background-color: transparent !important; /* Explicitly set background */
634
- color: var(--text-primary) !important;
635
  border-color: var(--border-color) !important;
636
  }
 
637
  .gr-button-secondary:hover {
638
- background-color: var(--background-secondary) !important; /* Explicitly set background */
639
  border-color: var(--primary-color) !important;
640
- transform: translateY(-2px) !important;
641
- }
642
- .gr-button-secondary:active { /* Press down effect on click */
643
- transform: translateY(1px) !important;
644
- box-shadow: none !important;
645
  }
646
 
647
- /* Output styling with clear boundaries and dynamic fade-in */
648
  .output-content-wrapper {
649
- background-color: var(--background-primary) !important; /* Explicitly set background */
650
- border: 2px solid var(--border-color) !important; /* Clear border */
651
  border-radius: 8px !important;
652
  padding: 1.5rem !important;
653
- min-height: 150px !important; /* More space for output */
654
  color: var(--text-primary) !important;
655
- /* Ensure the inner animated content fits well */
656
  display: flex;
657
  flex-direction: column;
658
- justify-content: center; /* Center content vertically if small */
659
- align-items: center; /* Center content horizontally if small */
660
  }
661
- /* The div holding the actual response content, enabling fade-in animation */
662
  .animated-output-content {
663
  opacity: 0;
664
- animation: fadeInAndSlideUp 0.7s ease-out forwards; /* More pronounced animation */
665
- width: 100%; /* Take full width of parent */
666
- /* Preserve formatting within the animated content */
667
  white-space: pre-wrap;
668
  overflow-wrap: break-word;
669
  word-break: break-word;
670
- text-align: left !important; /* Ensure text is left-aligned within this div */
671
  }
672
- @keyframes fadeInAndSlideUp {
673
- from { opacity: 0; transform: translateY(15px); }
674
- to { opacity: 1; transform: translateY(0); }
 
 
 
 
 
 
 
675
  }
676
 
677
  .response-header {
678
- font-size: 1.3rem !important;
679
  font-weight: 700 !important;
680
- color: var(--primary-color) !important; /* Matches primary color */
681
- margin-bottom: 0.75rem !important;
682
  display: flex !important;
683
  align-items: center !important;
684
- gap: 0.6rem !important;
685
- text-align: left !important; /* Ensure header itself is not affected by parent centering */
686
- width: 100%; /* Take full width */
687
- justify-content: flex-start; /* Align content to the start */
688
  }
 
689
  .response-icon {
690
- font-size: 1.5rem !important;
691
  color: var(--primary-color) !important;
692
  }
 
693
  .divider {
694
  border: none !important;
695
- border-top: 1px dashed var(--border-color) !important; /* Dashed divider for visual separation */
696
  margin: 1rem 0 !important;
697
  }
698
- /* Error message styling */
 
699
  .error-message {
700
- background-color: var(--error-bg) !important; /* Explicitly set background */
701
- border: 2px solid var(--error-border) !important;
702
  color: var(--error-text) !important;
703
- padding: 1.25rem !important;
704
  border-radius: 8px !important;
705
  display: flex !important;
706
  align-items: flex-start !important;
707
- gap: 0.8rem !important;
708
  font-size: 0.95rem !important;
709
  font-weight: 500 !important;
710
- line-height: 1.6 !important;
711
- text-align: left !important; /* Ensure error message text is left aligned */
712
- width: 100%; /* Take full width of parent */
713
- box-sizing: border-box; /* Include padding/border in width */
714
  }
 
715
  .error-message a {
716
  color: var(--error-text) !important;
717
  text-decoration: underline !important;
718
  }
 
719
  .error-icon {
720
- font-size: 1.4rem !important;
721
  line-height: 1 !important;
722
  margin-top: 0.1rem !important;
723
  }
724
- .error-details {
725
- font-size: 0.85rem !important;
726
- color: var(--error-text) !important;
727
- margin-top: 0.5rem !important;
728
- opacity: 0.8;
729
- }
730
- /* Placeholder styling for empty output */
731
  .placeholder {
732
- background-color: var(--background-secondary) !important; /* Explicitly set background */
733
- border: 2px dashed var(--border-color) !important;
734
  border-radius: 8px !important;
735
- padding: 2.5rem 1.5rem !important;
736
- text-align: center !important; /* Ensure placeholder text is centered */
737
- color: var(--text-secondary) !important;
738
  font-style: italic !important;
739
- font-size: 1.1rem !important;
740
- width: 100%; /* Ensure it takes full width of parent */
741
- box-sizing: border-box; /* Include padding/border in width */
742
  }
743
 
744
- /* Examples table styling with dynamic hover */
745
  .examples-section .gr-samples-table {
746
- border: 2px solid var(--border-color) !important;
747
  border-radius: 8px !important;
748
  overflow: hidden !important;
749
  margin-top: 1rem !important;
 
750
  }
 
751
  .examples-section .gr-samples-table th,
752
  .examples-section .gr-samples-table td {
753
- padding: 0.9rem !important;
754
  border: none !important;
755
  font-size: 0.95rem !important;
756
- text-align: left !important; /* Ensure example text is left-aligned */
757
  }
 
758
  .examples-section .gr-samples-table th {
759
- background-color: var(--background-secondary) !important; /* Explicitly set background */
760
- font-weight: 700 !important;
761
  color: var(--text-primary) !important;
762
  }
 
763
  .examples-section .gr-samples-table td {
764
- background-color: var(--background-primary) !important; /* Explicitly set background */
765
  color: var(--text-primary) !important;
766
- border-top: 1px solid var(--border-color) !important;
767
  cursor: pointer !important;
768
- transition: background 0.2s ease, transform 0.1s ease !important; /* Smooth transitions */
769
  }
 
770
  .examples-section .gr-samples-table tr:hover td {
771
- background-color: var(--background-secondary) !important; /* Explicitly set background */
772
- transform: translateX(5px); /* Subtle slide on hover */
773
  }
774
- /* Hide Gradio default elements for examples for cleaner look */
775
- .gr-examples .gr-label,
776
- .gr-examples .label-wrap,
777
- .gr-examples .gr-accordion-header {
778
- display: none !important;
779
- }
780
-
781
- /* Footer styling - centered text */
782
  .app-footer-wrapper {
783
- background-color: var(--background-secondary) !important; /* Explicitly set background */
784
- border: 2px solid var(--border-color) !important;
785
  border-radius: 12px !important;
786
- padding: 1.75rem !important;
787
- margin-top: 1.5rem !important;
788
- margin-bottom: 1.5rem !important; /* Ensures space at the very bottom before the container padding */
789
- text-align: center !important; /* Centered footer text */
790
  }
791
- .app-footer p {
792
- margin: 0.6rem 0 !important;
793
- font-size: 0.95rem !important;
 
794
  color: var(--text-secondary) !important;
795
  line-height: 1.6 !important;
796
  }
797
- .app-footer a {
 
798
  color: var(--primary-color) !important;
799
  text-decoration: none !important;
800
  font-weight: 600 !important;
801
  }
802
- .app-footer a:hover {
 
803
  text-decoration: underline !important;
804
  }
805
 
806
- /* Responsive design for smaller screens */
807
  @media (max-width: 768px) {
808
  .gradio-container {
809
  padding: 1rem !important;
810
  }
 
811
  .app-header-title {
812
- font-size: 2.2rem !important;
813
  }
 
814
  .app-header-tagline {
815
  font-size: 1rem !important;
816
  }
817
- .section-title {
818
- font-size: 1.4rem !important;
 
819
  }
 
820
  .input-row {
821
- flex-direction: column !important; /* Stack inputs vertically */
822
  }
 
823
  .button-row {
824
- flex-direction: column !important; /* Stack buttons vertically */
825
  }
 
826
  .gradio-button {
827
- width: 100% !important; /* Full width buttons */
828
- }
829
- .dashboard-card-section {
830
- padding: 1.25rem !important;
831
- }
832
- .output-content-wrapper {
833
- min-height: 120px !important;
834
- }
835
- .placeholder {
836
- padding: 1.5rem 1rem !important;
837
- font-size: 1rem !important;
838
  }
839
  }
840
  """
841
 
842
- # Using gr.Blocks with custom CSS only to ensure no undesired colors are inherited from a theme.
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.
867
 
868
- **Disclaimer:** This tool is for informational purposes only and does not constitute legal advice. For specific legal guidance, always consult a licensed attorney in your jurisdiction.
869
  """
870
  )
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
879
- placeholder="Enter your OpenAI API key (e.g., sk-...)",
880
- info="Required to process your query. Get one from OpenAI: platform.openai.com/api-keys",
881
- lines=1,
882
- elem_classes=["input-field-group"] # Custom class for input styling
883
  )
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(
892
- label="Your Question",
893
- placeholder="E.g., What are the rules for security deposit returns in my state?",
894
  lines=4,
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"])
907
- submit_button = gr.Button("Submit Query", variant="primary", elem_classes=["gr-button-primary"])
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
916
  )
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,
925
  inputs=[query_input, state_input],
926
  examples_per_page=5,
927
- label="" # Hide default Gradio label for examples to use our custom title
928
  )
929
  else:
930
- gr.Markdown("<div class='placeholder'>Sample questions could not be loaded. Please ensure the vector database is populated.</div>")
931
 
932
- # Footer Section - contains disclaimer and developer info
933
  with gr.Group(elem_classes="app-footer-wrapper"):
934
  gr.Markdown(
935
  """
936
- This tool is for informational purposes only and does not constitute legal advice. For legal guidance, always consult with a licensed attorney in your jurisdiction.
937
- Developed by **Nischal Subedi**. Connect on [LinkedIn](https://www.linkedin.com/in/nischal1/) or explore insights at [Substack](https://datascientistinsights.substack.com/).
 
938
  """
939
  )
940
 
941
- # Event Listeners for buttons
942
  submit_button.click(
943
  fn=query_interface_wrapper,
944
  inputs=[api_key_input, query_input, state_input],
945
  outputs=output,
946
- api_name="submit_query" # Useful for debugging / external calls
947
  )
948
 
949
  clear_button.click(
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=[],
957
  outputs=[api_key_input, query_input, state_input, output]
 
263
  return answer
264
  else:
265
  # Wrap successful response in a div with an animation class
266
+ formatted_response_content = f"<div class='response-header'><span class='response-icon'>📋</span>Legal Analysis for {state}</div><hr class='divider'>{answer}"
267
  return f"<div class='animated-output-content'>{formatted_response_content}</div>"
268
 
269
  try:
 
279
  radio_choices = ["Error: Critical failure loading states"]
280
  initial_value_radio = radio_choices[0]
281
 
 
282
  # Define example queries, filtering based on available states
283
  example_queries_base = [
284
  ["What are the rules for security deposit returns?", "California"],
 
299
  else: # Fallback if states list is problematic (e.g., empty or error)
300
  example_queries.append(["What basic rights do tenants have?", "California"])
301
 
302
+ # Professional custom CSS with refined design
 
303
  custom_css = """
304
+ /* Import professional fonts */
305
+ @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=Playfair+Display:wght@600;700&display=swap');
306
 
307
+ /* Professional color palette with refined oranges and neutrals */
308
  :root {
309
+ --primary-color: #D97706; /* Refined amber-orange */
310
+ --primary-hover: #B45309; /* Deeper amber for hover */
311
+ --primary-light: #FEF3C7; /* Very light amber for backgrounds */
312
+ --secondary-color: #6B7280; /* Professional gray */
313
+ --accent-color: #0F172A; /* Deep slate for text */
314
+
315
+ --background-primary: #FFFFFF; /* Pure white for cards */
316
+ --background-secondary: #F8FAFC; /* Very light gray for page background */
317
+ --background-tertiary: #F1F5F9; /* Slightly darker for subtle contrast */
318
+
319
+ --text-primary: #0F172A; /* Deep slate for primary text */
320
+ --text-secondary: #475569; /* Medium slate for secondary text */
321
+ --text-muted: #64748B; /* Lighter slate for muted text */
322
+
323
+ --border-color: #E2E8F0; /* Light gray for borders */
324
+ --border-focus: #D97706; /* Primary color for focus states */
325
+ --border-subtle: #F1F5F9; /* Very subtle border */
326
+
327
+ --shadow-xs: 0 1px 2px 0 rgba(0,0,0,0.05);
328
+ --shadow-sm: 0 1px 3px 0 rgba(0,0,0,0.1), 0 1px 2px -1px rgba(0,0,0,0.1);
329
+ --shadow-md: 0 4px 6px -1px rgba(0,0,0,0.1), 0 2px 4px -2px rgba(0,0,0,0.1);
330
+ --shadow-lg: 0 10px 15px -3px rgba(0,0,0,0.1), 0 4px 6px -4px rgba(0,0,0,0.1);
331
+ --shadow-xl: 0 20px 25px -5px rgba(0,0,0,0.1), 0 8px 10px -6px rgba(0,0,0,0.1);
332
+
333
+ --error-bg: #FEF2F2; /* Light red background */
334
+ --error-border: #FECACA; /* Light red border */
335
+ --error-text: #DC2626; /* Strong red text */
336
+
337
+ --success-bg: #F0FDF4; /* Light green background */
338
+ --success-border: #BBF7D0; /* Light green border */
339
+ --success-text: #16A34A; /* Strong green text */
340
  }
341
+
342
+ /* Base styling */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
343
  body, html {
344
  background-color: var(--background-secondary) !important;
345
+ font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif !important;
346
  }
347
 
348
+ /* Main container with professional spacing */
349
  .gradio-container {
350
+ max-width: 1000px !important;
351
+ margin: 0 auto !important;
352
+ padding: 2rem !important;
353
+ background-color: var(--background-secondary) !important;
 
 
 
 
 
 
354
  }
355
 
356
+ /* Professional header with subtle elegance */
357
  .app-header-wrapper {
358
+ background: linear-gradient(135deg, var(--background-primary) 0%, var(--primary-light) 100%) !important;
359
+ border: 1px solid var(--border-color) !important;
360
  border-radius: 16px !important;
361
+ padding: 3rem 2rem !important;
362
+ margin-bottom: 2rem !important;
363
+ box-shadow: var(--shadow-sm) !important;
364
+ position: relative !important;
365
+ text-align: center !important;
366
+ overflow: hidden !important;
 
367
  }
368
 
369
+ .app-header-wrapper::before {
370
  content: '';
371
  position: absolute;
372
  top: 0;
373
  left: 0;
374
  width: 100%;
375
  height: 100%;
376
+ background: radial-gradient(circle at 30% 20%, rgba(217, 119, 6, 0.03) 0%, transparent 50%),
377
+ radial-gradient(circle at 70% 80%, rgba(217, 119, 6, 0.03) 0%, transparent 50%);
378
  z-index: 0;
 
379
  pointer-events: none;
380
  }
381
 
382
  .app-header-logo {
383
+ font-size: 3.5rem !important;
384
+ margin-bottom: 1rem !important;
385
+ display: block !important;
386
+ color: var(--primary-color) !important;
387
  position: relative;
388
+ z-index: 1;
389
+ filter: drop-shadow(0 2px 4px rgba(217, 119, 6, 0.1));
 
 
 
 
 
 
 
390
  }
391
 
392
  .app-header-title {
393
+ font-family: 'Playfair Display', serif !important;
394
+ font-size: 2.75rem !important;
395
+ font-weight: 700 !important;
396
  color: var(--text-primary) !important;
397
+ margin: 0 0 1rem 0 !important;
398
+ line-height: 1.2 !important;
399
+ letter-spacing: -0.02em !important;
400
  position: relative;
401
  z-index: 1;
 
 
402
  }
403
+
404
  .app-header-tagline {
405
+ font-size: 1.125rem !important;
406
  color: var(--text-secondary) !important;
407
  font-weight: 400 !important;
408
  margin: 0 !important;
409
+ max-width: 600px;
410
+ margin: 0 auto !important;
411
  position: relative;
412
  z-index: 1;
413
  }
414
 
415
+ /* Professional card sections */
416
  .main-dashboard-container {
417
  display: flex !important;
418
  flex-direction: column !important;
419
+ gap: 1.5rem !important;
420
  }
421
+
422
  .dashboard-card-section {
423
+ background-color: var(--background-primary) !important;
424
+ border: 1px solid var(--border-color) !important;
425
  border-radius: 12px !important;
426
+ padding: 2rem !important;
427
+ box-shadow: var(--shadow-sm) !important;
428
+ transition: all 0.2s ease !important;
 
429
  }
430
+
431
  .dashboard-card-section:hover {
432
  box-shadow: var(--shadow-md) !important;
433
+ transform: translateY(-1px) !important;
 
 
 
 
 
 
 
 
 
434
  }
435
 
436
+ /* Professional typography for section titles */
437
+ .section-title {
438
+ font-family: 'Playfair Display', serif !important;
439
+ font-size: 1.5rem !important;
440
+ font-weight: 700 !important;
441
  color: var(--text-primary) !important;
442
+ margin: 0 0 1.5rem 0 !important;
443
  padding-bottom: 0.75rem !important;
444
+ border-bottom: 2px solid var(--primary-light) !important;
445
+ text-align: center !important;
446
+ position: relative !important;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
447
  }
448
 
449
+ .section-title::after {
450
+ content: '';
451
+ position: absolute;
452
+ bottom: -2px;
453
+ left: 50%;
454
+ transform: translateX(-50%);
455
+ width: 60px;
456
+ height: 2px;
457
+ background-color: var(--primary-color);
458
+ border-radius: 1px;
459
  }
460
+
461
+ /* Professional input styling */
462
  .gradio-textbox textarea,
463
  .gradio-textbox input {
464
+ background-color: var(--background-primary) !important;
465
+ border: 1px solid var(--border-color) !important;
466
  border-radius: 8px !important;
467
+ padding: 0.875rem 1rem !important;
468
+ font-size: 0.95rem !important;
469
  font-family: 'Inter', sans-serif !important;
470
+ color: var(--text-primary) !important;
471
+ transition: all 0.2s ease !important;
472
+ box-shadow: var(--shadow-xs) !important;
473
  }
474
+
475
  .gradio-textbox textarea:focus,
476
  .gradio-textbox input:focus {
477
  outline: none !important;
478
+ border-color: var(--border-focus) !important;
479
+ box-shadow: 0 0 0 3px rgba(217, 119, 6, 0.1) !important;
480
  }
481
 
482
+ /* Professional radio button styling */
483
  .gradio-radio {
484
+ padding: 0 !important;
485
+ margin-top: 0.5rem !important;
 
486
  }
487
 
488
+ .gradio-radio .gr-radio-input {
489
  display: none !important;
490
  }
491
 
492
  .gradio-radio label {
493
+ display: flex !important;
494
+ justify-content: center !important;
 
495
  align-items: center !important;
496
  padding: 0.75rem 1rem !important;
497
+ border: 1px solid var(--border-color) !important;
498
  border-radius: 8px !important;
499
+ background-color: var(--background-primary) !important;
500
  color: var(--text-primary) !important;
501
  font-weight: 500 !important;
502
  cursor: pointer !important;
503
+ transition: all 0.2s ease !important;
504
+ box-shadow: var(--shadow-xs) !important;
505
+ margin: 0.25rem 0 !important;
506
+ width: 100% !important;
507
+ box-sizing: border-box !important;
 
 
 
 
 
 
 
508
  }
509
 
 
510
  .gradio-radio label:hover {
511
+ background-color: var(--background-tertiary) !important;
512
+ border-color: var(--primary-color) !important;
513
+ box-shadow: var(--shadow-sm) !important;
514
+ transform: translateY(-1px) !important;
515
  }
516
 
517
+ .gradio-radio label.selected {
518
+ background-color: var(--primary-color) !important;
519
+ color: white !important;
 
520
  border-color: var(--primary-hover) !important;
521
  box-shadow: var(--shadow-md) !important;
 
 
 
 
 
 
 
 
522
  }
523
 
524
+ .gradio-radio label.selected span {
525
+ color: white !important;
526
+ }
527
 
528
+ /* Professional label styling */
529
  .gradio-textbox label,
530
+ .gradio-radio .gr-form-label {
531
+ font-weight: 600 !important;
532
  color: var(--text-primary) !important;
533
+ font-size: 0.95rem !important;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
534
  margin-bottom: 0.5rem !important;
535
+ display: block !important;
 
 
536
  }
537
 
538
+ /* Professional button styling */
539
  .button-row {
540
  display: flex !important;
541
+ gap: 0.75rem !important;
542
+ justify-content: flex-end !important;
543
+ margin-top: 1.5rem !important;
544
  }
545
+
546
  .gradio-button {
547
+ padding: 0.75rem 2rem !important;
548
+ border-radius: 8px !important;
549
+ font-weight: 600 !important;
550
+ font-size: 0.95rem !important;
551
+ transition: all 0.2s ease !important;
552
  cursor: pointer !important;
553
+ border: 1px solid transparent !important;
554
+ text-align: center !important;
555
  }
556
+
557
  .gr-button-primary {
558
+ background-color: var(--primary-color) !important;
559
  color: white !important;
560
  box-shadow: var(--shadow-sm) !important;
561
  }
562
+
563
  .gr-button-primary:hover {
564
+ background-color: var(--primary-hover) !important;
565
  box-shadow: var(--shadow-md) !important;
566
+ transform: translateY(-1px) !important;
 
 
 
 
567
  }
568
+
569
  .gr-button-secondary {
570
+ background-color: transparent !important;
571
+ color: var(--text-secondary) !important;
572
  border-color: var(--border-color) !important;
573
  }
574
+
575
  .gr-button-secondary:hover {
576
+ background-color: var(--background-tertiary) !important;
577
  border-color: var(--primary-color) !important;
578
+ color: var(--text-primary) !important;
579
+ transform: translateY(-1px) !important;
 
 
 
580
  }
581
 
582
+ /* Professional output styling */
583
  .output-content-wrapper {
584
+ background-color: var(--background-primary) !important;
585
+ border: 1px solid var(--border-color) !important;
586
  border-radius: 8px !important;
587
  padding: 1.5rem !important;
588
+ min-height: 120px !important;
589
  color: var(--text-primary) !important;
 
590
  display: flex;
591
  flex-direction: column;
592
+ justify-content: center;
593
+ align-items: center;
594
  }
595
+
596
  .animated-output-content {
597
  opacity: 0;
598
+ animation: fadeInUp 0.5s ease-out forwards;
599
+ width: 100%;
 
600
  white-space: pre-wrap;
601
  overflow-wrap: break-word;
602
  word-break: break-word;
603
+ text-align: left !important;
604
  }
605
+
606
+ @keyframes fadeInUp {
607
+ from {
608
+ opacity: 0;
609
+ transform: translateY(10px);
610
+ }
611
+ to {
612
+ opacity: 1;
613
+ transform: translateY(0);
614
+ }
615
  }
616
 
617
  .response-header {
618
+ font-size: 1.25rem !important;
619
  font-weight: 700 !important;
620
+ color: var(--primary-color) !important;
621
+ margin-bottom: 1rem !important;
622
  display: flex !important;
623
  align-items: center !important;
624
+ gap: 0.5rem !important;
625
+ text-align: left !important;
626
+ width: 100%;
627
+ justify-content: flex-start;
628
  }
629
+
630
  .response-icon {
631
+ font-size: 1.25rem !important;
632
  color: var(--primary-color) !important;
633
  }
634
+
635
  .divider {
636
  border: none !important;
637
+ border-top: 1px solid var(--border-color) !important;
638
  margin: 1rem 0 !important;
639
  }
640
+
641
+ /* Professional error styling */
642
  .error-message {
643
+ background-color: var(--error-bg) !important;
644
+ border: 1px solid var(--error-border) !important;
645
  color: var(--error-text) !important;
646
+ padding: 1rem !important;
647
  border-radius: 8px !important;
648
  display: flex !important;
649
  align-items: flex-start !important;
650
+ gap: 0.75rem !important;
651
  font-size: 0.95rem !important;
652
  font-weight: 500 !important;
653
+ line-height: 1.5 !important;
654
+ text-align: left !important;
655
+ width: 100%;
656
+ box-sizing: border-box;
657
  }
658
+
659
  .error-message a {
660
  color: var(--error-text) !important;
661
  text-decoration: underline !important;
662
  }
663
+
664
  .error-icon {
665
+ font-size: 1.25rem !important;
666
  line-height: 1 !important;
667
  margin-top: 0.1rem !important;
668
  }
669
+
670
+ /* Professional placeholder styling */
 
 
 
 
 
671
  .placeholder {
672
+ background-color: var(--background-tertiary) !important;
673
+ border: 1px dashed var(--border-color) !important;
674
  border-radius: 8px !important;
675
+ padding: 2rem 1.5rem !important;
676
+ text-align: center !important;
677
+ color: var(--text-muted) !important;
678
  font-style: italic !important;
679
+ font-size: 1rem !important;
680
+ width: 100%;
681
+ box-sizing: border-box;
682
  }
683
 
684
+ /* Professional examples table */
685
  .examples-section .gr-samples-table {
686
+ border: 1px solid var(--border-color) !important;
687
  border-radius: 8px !important;
688
  overflow: hidden !important;
689
  margin-top: 1rem !important;
690
+ box-shadow: var(--shadow-xs) !important;
691
  }
692
+
693
  .examples-section .gr-samples-table th,
694
  .examples-section .gr-samples-table td {
695
+ padding: 0.875rem !important;
696
  border: none !important;
697
  font-size: 0.95rem !important;
698
+ text-align: left !important;
699
  }
700
+
701
  .examples-section .gr-samples-table th {
702
+ background-color: var(--background-tertiary) !important;
703
+ font-weight: 600 !important;
704
  color: var(--text-primary) !important;
705
  }
706
+
707
  .examples-section .gr-samples-table td {
708
+ background-color: var(--background-primary) !important;
709
  color: var(--text-primary) !important;
710
+ border-top: 1px solid var(--border-subtle) !important;
711
  cursor: pointer !important;
712
+ transition: background-color 0.2s ease !important;
713
  }
714
+
715
  .examples-section .gr-samples-table tr:hover td {
716
+ background-color: var(--background-tertiary) !important;
 
717
  }
718
+
719
+ /* Professional footer */
 
 
 
 
 
 
720
  .app-footer-wrapper {
721
+ background-color: var(--background-primary) !important;
722
+ border: 1px solid var(--border-color) !important;
723
  border-radius: 12px !important;
724
+ padding: 1.5rem !important;
725
+ margin-top: 2rem !important;
726
+ text-align: center !important;
727
+ box-shadow: var(--shadow-xs) !important;
728
  }
729
+
730
+ .app-footer-wrapper p {
731
+ margin: 0.5rem 0 !important;
732
+ font-size: 0.9rem !important;
733
  color: var(--text-secondary) !important;
734
  line-height: 1.6 !important;
735
  }
736
+
737
+ .app-footer-wrapper a {
738
  color: var(--primary-color) !important;
739
  text-decoration: none !important;
740
  font-weight: 600 !important;
741
  }
742
+
743
+ .app-footer-wrapper a:hover {
744
  text-decoration: underline !important;
745
  }
746
 
747
+ /* Responsive design */
748
  @media (max-width: 768px) {
749
  .gradio-container {
750
  padding: 1rem !important;
751
  }
752
+
753
  .app-header-title {
754
+ font-size: 2rem !important;
755
  }
756
+
757
  .app-header-tagline {
758
  font-size: 1rem !important;
759
  }
760
+
761
+ .dashboard-card-section {
762
+ padding: 1.5rem !important;
763
  }
764
+
765
  .input-row {
766
+ flex-direction: column !important;
767
  }
768
+
769
  .button-row {
770
+ flex-direction: column !important;
771
  }
772
+
773
  .gradio-button {
774
+ width: 100% !important;
 
 
 
 
 
 
 
 
 
 
775
  }
776
  }
777
  """
778
 
779
+ # Using gr.Blocks with custom CSS
780
  with gr.Blocks(css=custom_css, title="Landlord-Tenant Rights Assistant") as demo:
781
+ # Professional Header
782
  with gr.Group(elem_classes="app-header-wrapper"):
 
 
783
  gr.Markdown(
784
  """
785
  <span class='app-header-logo'>⚖️</span>
786
  <h1 class='app-header-title'>Landlord-Tenant Rights Assistant</h1>
787
+ <p class='app-header-tagline'>Professional Legal Research & Analysis Platform</p>
788
  """,
789
  elem_classes="full-width-center"
790
  )
791
 
792
+ # Main Dashboard
793
  with gr.Column(elem_classes="main-dashboard-container"):
794
 
795
+ # Welcome Section
796
  with gr.Group(elem_classes="dashboard-card-section"):
797
+ gr.Markdown("<h3 class='section-title'>Welcome & Legal Disclaimer</h3>")
 
798
  gr.Markdown(
799
  """
800
+ This professional legal research platform provides comprehensive, state-specific analysis of landlord-tenant laws. Our system delivers detailed responses grounded in legal authority and precedent.
801
 
802
+ **Important Legal Disclaimer:** This platform provides informational content only and does not constitute legal advice. For specific legal matters, always consult with a qualified attorney licensed in your jurisdiction.
803
  """
804
  )
805
 
806
+ # API Configuration
807
  with gr.Group(elem_classes="dashboard-card-section"):
808
+ gr.Markdown("<h3 class='section-title'>API Configuration</h3>")
 
809
  api_key_input = gr.Textbox(
810
+ label="OpenAI API Key",
811
+ type="password",
812
+ placeholder="Enter your OpenAI API key (sk-...)",
813
+ info="Required for query processing. Obtain from: platform.openai.com/api-keys",
814
+ lines=1
 
815
  )
816
 
817
+ # Query Interface
818
  with gr.Group(elem_classes="dashboard-card-section"):
819
+ gr.Markdown("<h3 class='section-title'>Legal Query Interface</h3>")
820
+ with gr.Row(elem_classes="input-row"):
821
+ with gr.Column(elem_classes="input-field", scale=3):
 
822
  query_input = gr.Textbox(
823
+ label="Legal Question",
824
+ placeholder="Enter your landlord-tenant law question here...",
825
  lines=4,
826
+ max_lines=8
 
827
  )
828
+ with gr.Column(elem_classes="input-field", scale=1):
829
  state_input = gr.Radio(
830
+ label="Jurisdiction",
831
  choices=radio_choices,
832
+ value=initial_value_radio
 
833
  )
834
+ with gr.Row(elem_classes="button-row"):
835
+ clear_button = gr.Button("Clear Form", variant="secondary")
836
+ submit_button = gr.Button("Analyze Query", variant="primary")
837
 
838
+ # Results Display
839
  with gr.Group(elem_classes="dashboard-card-section"):
840
+ gr.Markdown("<h3 class='section-title'>Legal Analysis Results</h3>")
841
+ output = gr.HTML(
842
+ value="<div class='placeholder'>Your comprehensive legal analysis will appear here after submitting your query.</div>",
843
+ elem_classes="output-content-wrapper"
 
844
  )
845
 
846
+ # Example Queries
847
  with gr.Group(elem_classes="dashboard-card-section examples-section"):
848
+ gr.Markdown("<h3 class='section-title'>Sample Legal Queries</h3>")
 
849
  if example_queries:
850
  gr.Examples(
851
  examples=example_queries,
852
  inputs=[query_input, state_input],
853
  examples_per_page=5,
854
+ label=""
855
  )
856
  else:
857
+ gr.Markdown("<div class='placeholder'>Sample queries are currently unavailable. Please ensure the legal database is properly configured.</div>")
858
 
859
+ # Professional Footer
860
  with gr.Group(elem_classes="app-footer-wrapper"):
861
  gr.Markdown(
862
  """
863
+ **Legal Notice:** This platform is designed for informational and research purposes only. It does not establish an attorney-client relationship and should not be relied upon as a substitute for professional legal counsel.
864
+
865
+ **Platform Development:** Created by **Nischal Subedi** • [LinkedIn](https://www.linkedin.com/in/nischal1/) • [Professional Insights](https://datascientistinsights.substack.com/)
866
  """
867
  )
868
 
869
+ # Event Handlers
870
  submit_button.click(
871
  fn=query_interface_wrapper,
872
  inputs=[api_key_input, query_input, state_input],
873
  outputs=output,
874
+ api_name="submit_query"
875
  )
876
 
877
  clear_button.click(
878
  fn=lambda: (
879
+ "",
880
+ "",
881
+ initial_value_radio,
882
+ "<div class='placeholder'>Form cleared successfully. Ready for your next legal query.</div>"
883
  ),
884
  inputs=[],
885
  outputs=[api_key_input, query_input, state_input, output]