Nischal Subedi commited on
Commit
5017cba
·
1 Parent(s): 2b34827
Files changed (1) hide show
  1. app.py +391 -169
app.py CHANGED
@@ -248,6 +248,7 @@ Answer:"""
248
 
249
  def gradio_interface(self):
250
  def query_interface_wrapper(api_key: str, query: str, state: str) -> str:
 
251
  if not api_key or not api_key.strip() or not api_key.startswith("sk-"):
252
  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>"
253
  if not state or state is None:
@@ -255,9 +256,11 @@ Answer:"""
255
  if not query or not query.strip():
256
  return "<div class='error-message'><span class='error-icon'>⚠️</span>Please enter your question in the text box.</div>"
257
 
 
258
  result = self.process_query(query=query, state=state, openai_api_key=api_key)
259
  answer = result.get("answer", "<div class='error-message'><span class='error-icon'>⚠️</span>An unexpected error occurred.</div>")
260
 
 
261
  if "<div class='error-message'>" in answer:
262
  return answer
263
  else:
@@ -273,6 +276,7 @@ Answer:"""
273
  print(f"DEBUG: Error loading states for selection: {e}")
274
  radio_choices = ["Error: Critical failure loading states"]
275
  initial_value_radio = None
 
276
  example_queries_base = [
277
  ["What are the rules for security deposit returns?", "California"],
278
  ["Can a landlord enter my apartment without notice?", "New York"],
@@ -290,320 +294,532 @@ Answer:"""
290
  example_queries.append(["What basic rights do tenants have?", "California"])
291
 
292
  custom_css = """
293
- /* Import modern fonts */
294
- @import url('https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;700&family=Open+Sans:wght@600;700;800&display=swap');
295
 
296
- /* Define custom properties for light and dark themes */
297
  :root {
298
- --background-primary: #F7F7F7;
299
- --background-secondary: #EDF2F7;
300
- --text-primary: #1A1A1A;
301
- --text-secondary: #4A5568;
302
- --accent-primary: #38A169;
303
- --border-color: #CBD5E0;
304
- --shadow-sm: 0 2px 4px rgba(0,0,0,0.05);
305
- --shadow-md: 0 4px 12px rgba(0,0,0,0.1);
306
- --error-bg: #FEF2F2;
307
- --error-text: #E53E3E;
308
- }
309
-
310
- @media (prefers-color-scheme: dark) {
311
- :root {
312
- --background-primary: #2D3748;
313
- --background-secondary: #4A5568;
314
- --text-primary: #FFFFFF;
315
- --text-secondary: #A0AEC0;
316
- --border-color: #718096;
317
- --error-bg: #63171B;
318
- }
319
- }
320
-
321
- /* Base styles */
322
- html, body, .gradio-container {
323
- background-color: var(--background-primary) !important;
324
  color: var(--text-primary) !important;
325
- font-family: 'Roboto', sans-serif !important;
326
- margin: 0 !important;
327
- padding: 0 !important;
328
  }
329
-
330
  .gradio-container {
331
- max-width: 1000px !important;
332
- margin: 2rem auto !important;
333
- padding: 2rem !important;
334
- border-radius: 12px !important;
335
- box-shadow: var(--shadow-md) !important;
 
 
 
 
 
336
  }
337
-
338
- /* Header Section */
339
  .app-header-wrapper {
340
- background: linear-gradient(135deg, var(--background-secondary), var(--background-primary)) !important;
341
- border: 1px solid var(--border-color) !important;
342
- border-radius: 12px !important;
343
- padding: 2rem !important;
344
- margin-bottom: 2rem !important;
345
- text-align: center !important;
346
- box-shadow: var(--shadow-sm) !important;
347
  position: relative;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
348
  }
349
-
350
  .app-header-logo {
351
- font-size: 5rem !important;
352
- color: var(--accent-primary) !important;
353
- margin-bottom: 1rem !important;
354
- animation: pulse 2s infinite ease-in-out;
 
 
 
355
  }
356
-
357
- @keyframes pulse {
358
- 0% { transform: scale(1); }
359
- 50% { transform: scale(1.1); }
360
- 100% { transform: scale(1); }
361
  }
362
-
363
  .app-header-title {
364
- font-family: 'Open Sans', sans-serif !important;
365
- font-size: 2.5rem !important;
366
- font-weight: 700 !important;
367
  color: var(--text-primary) !important;
368
- margin: 0 !important;
369
- line-height: 1.2 !important;
370
- text-shadow: 1px 1px 3px rgba(0,0,0,0.1) !important;
 
 
 
 
371
  }
372
-
373
  .app-header-tagline {
374
- font-size: 1.1rem !important;
375
  color: var(--text-secondary) !important;
376
- margin-top: 0.5rem !important;
377
  font-weight: 400 !important;
 
 
 
 
 
378
  }
379
-
380
- /* Main Dashboard Layout */
381
  .main-dashboard-container {
382
  display: flex !important;
383
  flex-direction: column !important;
384
- gap: 1.5rem !important;
385
  }
386
-
387
  .dashboard-card-section {
388
  background-color: var(--background-primary) !important;
389
- border: 1px solid var(--border-color) !important;
390
- border-radius: 10px !important;
391
  padding: 0 !important;
392
  box-shadow: var(--shadow-sm) !important;
393
- transition: transform 0.2s ease, box-shadow 0.2s ease !important;
 
 
394
  }
395
-
396
  .dashboard-card-section:hover {
397
- transform: translateY(-3px) !important;
398
  box-shadow: var(--shadow-md) !important;
 
 
 
 
 
 
 
 
 
399
  }
400
-
401
  .section-title-gradient-bar {
402
  background-color: var(--background-secondary) !important;
403
- padding: 1rem !important;
404
  border-top-left-radius: 10px !important;
405
  border-top-right-radius: 10px !important;
 
406
  text-align: center !important;
 
 
 
407
  }
408
-
409
  .section-title {
410
- font-family: 'Open Sans', sans-serif !important;
411
- font-size: 1.6rem !important;
412
- font-weight: 600 !important;
413
  color: var(--text-primary) !important;
414
  margin: 0 !important;
415
- border-bottom: 2px solid var(--accent-primary) !important;
 
 
416
  display: inline-block !important;
 
 
417
  }
418
-
419
  .dashboard-card-content-area {
420
- padding: 1.5rem !important;
421
  background-color: var(--background-primary) !important;
 
 
422
  color: var(--text-primary) !important;
423
  }
424
-
425
- /* Input and Form Elements */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
426
  .gradio-textbox textarea,
427
- .gradio-textbox input {
 
 
428
  background-color: var(--background-primary) !important;
429
  color: var(--text-primary) !important;
430
- border: 1px solid var(--border-color) !important;
 
 
 
 
 
 
431
  border-radius: 8px !important;
432
- padding: 0.75rem !important;
433
- font-size: 1rem !important;
434
- box-shadow: var(--shadow-sm) !important;
 
435
  transition: border-color 0.2s ease, box-shadow 0.2s ease !important;
 
 
 
 
436
  }
437
-
438
  .gradio-textbox textarea:focus,
439
  .gradio-textbox input:focus {
440
- border-color: var(--accent-primary) !important;
441
- box-shadow: 0 0 0 3px rgba(56, 161, 105, 0.2) !important;
442
  outline: none !important;
 
 
 
 
 
 
 
 
 
443
  }
444
-
445
  .gradio-radio label {
446
- background-color: var(--background-primary) !important;
447
- color: var(--text-primary) !important;
448
- border: 1px solid var(--border-color) !important;
 
 
449
  border-radius: 8px !important;
450
- padding: 0.75rem !important;
451
- margin: 0.25rem 0 !important;
452
  cursor: pointer !important;
453
- transition: all 0.2s ease !important;
 
 
 
 
 
 
 
 
 
454
  }
455
-
456
  .gradio-radio label:hover {
457
- border-color: var(--accent-primary) !important;
458
  background-color: var(--background-secondary) !important;
 
 
 
459
  }
460
-
461
  .gradio-radio input[type="radio"]:checked + label {
462
- background-color: var(--accent-primary) !important;
463
- color: white !important;
464
- border-color: var(--accent-primary) !important;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
465
  }
466
-
467
  .gradio-button {
468
- padding: 0.75rem 1.5rem !important;
469
- border-radius: 8px !important;
470
  font-weight: 600 !important;
471
  font-size: 1rem !important;
472
- transition: all 0.2s ease !important;
 
 
 
 
473
  }
474
-
475
  .gr-button-primary {
476
- background-color: var(--accent-primary) !important;
477
  color: white !important;
478
- border: none !important;
479
  }
480
-
481
  .gr-button-primary:hover {
482
- background-color: #2F855A !important; /* Darker green */
 
483
  transform: translateY(-2px) !important;
484
  }
485
-
 
 
 
486
  .gr-button-secondary {
487
  background-color: transparent !important;
488
  color: var(--text-primary) !important;
489
- border: 1px solid var(--border-color) !important;
490
  }
491
-
492
  .gr-button-secondary:hover {
493
  background-color: var(--background-secondary) !important;
494
- border-color: var(--accent-primary) !important;
 
 
 
 
 
495
  }
496
-
497
- /* Output and Error Messages */
498
  .output-content-wrapper {
499
  background-color: var(--background-primary) !important;
500
- border: 1px solid var(--border-color) !important;
501
  border-radius: 8px !important;
502
  padding: 1.5rem !important;
503
  min-height: 150px !important;
504
  color: var(--text-primary) !important;
 
 
 
 
505
  }
506
-
507
  .animated-output-content {
508
- animation: fadeIn 0.5s ease-out forwards;
 
 
 
 
 
 
509
  color: var(--text-primary) !important;
510
  }
511
-
512
- @keyframes fadeIn {
513
- from { opacity: 0; }
514
- to { opacity: 1; }
515
  }
516
-
517
  .response-header {
518
  font-size: 1.3rem !important;
519
- font-weight: 600 !important;
520
- color: var(--accent-primary) !important;
521
  margin-bottom: 0.75rem !important;
522
  display: flex !important;
523
  align-items: center !important;
524
- gap: 0.5rem !important;
 
 
 
525
  }
526
-
527
  .response-icon {
528
  font-size: 1.5rem !important;
 
529
  }
530
-
531
  .divider {
532
  border: none !important;
533
  border-top: 1px dashed var(--border-color) !important;
534
  margin: 1rem 0 !important;
535
  }
536
-
537
  .error-message {
538
  background-color: var(--error-bg) !important;
 
539
  color: var(--error-text) !important;
540
- padding: 1rem !important;
541
  border-radius: 8px !important;
542
  display: flex !important;
543
- align-items: center !important;
544
- gap: 0.5rem !important;
 
 
 
 
 
 
 
 
 
 
545
  }
546
-
547
  .error-icon {
548
- font-size: 1.2rem !important;
 
 
 
 
 
 
 
 
549
  }
550
-
551
  .placeholder {
 
 
 
 
 
552
  color: var(--text-secondary) !important;
553
  font-style: italic !important;
554
- text-align: center !important;
555
- padding: 2rem !important;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
556
  }
557
-
558
- /* Footer */
559
  .app-footer-wrapper {
560
- background: linear-gradient(135deg, var(--background-primary), var(--background-secondary)) !important;
561
- border: 1px solid var(--border-color) !important;
562
  border-radius: 12px !important;
563
- padding: 1.5rem !important;
564
- margin-top: 2rem !important;
 
565
  text-align: center !important;
 
566
  }
567
-
568
  .app-footer p {
 
 
 
569
  color: var(--text-secondary) !important;
570
- font-size: 0.9rem !important;
 
 
 
 
 
 
 
571
  }
572
-
573
  .app-footer a {
574
- color: var(--accent-primary) !important;
575
  text-decoration: underline !important;
 
576
  }
577
-
578
  .app-footer a:hover {
579
  text-decoration: none !important;
580
  }
581
-
582
- /* Responsive Design */
583
  @media (max-width: 768px) {
584
  .gradio-container {
585
  padding: 1rem !important;
586
- margin: 1rem !important;
587
  }
588
  .app-header-title {
589
- font-size: 2rem !important;
 
 
 
590
  }
591
  .section-title {
592
- font-size: 1.3rem !important;
 
 
 
 
 
 
593
  }
594
  .gradio-button {
595
  width: 100% !important;
596
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
597
  }
598
  """
599
 
600
- custom_theme = gr.themes.Soft(
601
- primary_hue="green",
602
- secondary_hue="gray",
603
- neutral_hue="stone"
604
- )
605
-
606
- with gr.Blocks(css=custom_css, theme=custom_theme, title="Landlord-Tenant Rights Assistant") as demo:
607
  with gr.Group(elem_classes="app-header-wrapper"):
608
  gr.Markdown(
609
  """
@@ -615,6 +831,7 @@ Answer:"""
615
  )
616
 
617
  with gr.Column(elem_classes="main-dashboard-container"):
 
618
  with gr.Group(elem_classes="dashboard-card-section"):
619
  gr.Markdown("<h3 class='section-title'>How This Assistant Works</h3>", elem_classes="full-width-center section-title-gradient-bar")
620
  with gr.Column(elem_classes="dashboard-card-content-area"):
@@ -624,6 +841,7 @@ Answer:"""
624
  """
625
  )
626
 
 
627
  with gr.Group(elem_classes="dashboard-card-section"):
628
  gr.Markdown("<h3 class='section-title'>OpenAI API Key</h3>", elem_classes="full-width-center section-title-gradient-bar")
629
  with gr.Column(elem_classes="dashboard-card-content-area"):
@@ -639,6 +857,7 @@ Answer:"""
639
  elem_classes="gr-prose"
640
  )
641
 
 
642
  with gr.Group(elem_classes="dashboard-card-section"):
643
  gr.Markdown("<h3 class='section-title'>Ask Your Question</h3>", elem_classes="full-width-center section-title-gradient-bar")
644
  with gr.Column(elem_classes="dashboard-card-content-area"):
@@ -663,6 +882,7 @@ Answer:"""
663
  clear_button = gr.Button("Clear", variant="secondary", elem_classes=["gr-button-secondary"])
664
  submit_button = gr.Button("Submit Query", variant="primary", elem_classes=["gr-button-primary"])
665
 
 
666
  with gr.Group(elem_classes="dashboard-card-section"):
667
  gr.Markdown("<h3 class='section-title'>Legal Assistant's Response</h3>", elem_classes="full-width-center section-title-gradient-bar")
668
  with gr.Column(elem_classes="dashboard-card-content-area"):
@@ -671,6 +891,7 @@ Answer:"""
671
  elem_classes="output-content-wrapper"
672
  )
673
 
 
674
  with gr.Group(elem_classes="dashboard-card-section examples-section"):
675
  gr.Markdown("<h3 class='section-title'>Example Questions</h3>", elem_classes="full-width-center section-title-gradient-bar")
676
  with gr.Column(elem_classes="dashboard-card-content-area"):
@@ -684,13 +905,14 @@ Answer:"""
684
  else:
685
  gr.Markdown("<div class='placeholder'>Sample questions could not be loaded. Please ensure the vector database is populated.</div>")
686
 
 
687
  with gr.Group(elem_classes="app-footer-wrapper"):
688
  gr.Markdown(
689
  f"""
690
  <style>
691
  .custom-link {{
692
  font-weight: bold !important;
693
- color: var(--accent-primary) !important;
694
  text-decoration: underline;
695
  }}
696
  </style>
 
248
 
249
  def gradio_interface(self):
250
  def query_interface_wrapper(api_key: str, query: str, state: str) -> str:
251
+ # Basic client-side validation for immediate feedback (redundant but good UX)
252
  if not api_key or not api_key.strip() or not api_key.startswith("sk-"):
253
  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>"
254
  if not state or state is None:
 
256
  if not query or not query.strip():
257
  return "<div class='error-message'><span class='error-icon'>⚠️</span>Please enter your question in the text box.</div>"
258
 
259
+ # Call the core processing logic
260
  result = self.process_query(query=query, state=state, openai_api_key=api_key)
261
  answer = result.get("answer", "<div class='error-message'><span class='error-icon'>⚠️</span>An unexpected error occurred.</div>")
262
 
263
+ # Check if the answer already contains an error message
264
  if "<div class='error-message'>" in answer:
265
  return answer
266
  else:
 
276
  print(f"DEBUG: Error loading states for selection: {e}")
277
  radio_choices = ["Error: Critical failure loading states"]
278
  initial_value_radio = None
279
+
280
  example_queries_base = [
281
  ["What are the rules for security deposit returns?", "California"],
282
  ["Can a landlord enter my apartment without notice?", "New York"],
 
294
  example_queries.append(["What basic rights do tenants have?", "California"])
295
 
296
  custom_css = """
297
+ /* Import legible fonts from Google Fonts */
298
+ @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=Poppins:wght@600;700;800&display=swap');
299
 
300
+ /* Root variables for consistent light theme */
301
  :root {
302
+ --primary-color: #FF8C00;
303
+ --primary-hover: #E07B00;
304
+ --background-primary: hsl(30, 100%, 99.9%);
305
+ --background-secondary: hsl(30, 100%, 96%);
306
+ --text-primary: #4A3C32;
307
+ --text-secondary: #8C7B6F;
308
+ --border-color: hsl(30, 70%, 85%);
309
+ --border-focus: #FF8C00;
310
+ --shadow-sm: 0 1px 3px rgba(0,0,0,0.08);
311
+ --shadow-md: 0 4px 10px rgba(0,0,0,0.1);
312
+ --shadow-lg: 0 10px 20px rgba(0,0,0,0.15);
313
+ --error-bg: #FFF0E0;
314
+ --error-border: #FFD2B2;
315
+ --error-text: #E05C00;
316
+ }
317
+
318
+ body, html {
319
+ background-color: var(--background-secondary) !important;
 
 
 
 
 
 
 
 
320
  color: var(--text-primary) !important;
321
+ transition: none !important; /* Disable transitions to prevent theme switching */
 
 
322
  }
 
323
  .gradio-container {
324
+ max-width: 900px !important;
325
+ margin: 0 auto !important;
326
+ padding: 1.5rem !important;
327
+ font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif !important;
328
+ background-color: var(--background-secondary) !important;
329
+ box-shadow: none !important;
330
+ color: var(--text-primary) !important;
331
+ }
332
+ .main-dashboard-container > * {
333
+ background-color: var(--background-primary) !important;
334
  }
 
 
335
  .app-header-wrapper {
336
+ background: linear-gradient(145deg, var(--background-primary) 0%, var(--background-secondary) 100%) !important;
337
+ border: 2px solid var(--border-color) !important;
338
+ border-radius: 16px !important;
339
+ padding: 2.5rem 1.5rem !important;
340
+ margin-bottom: 1.5rem !important;
341
+ box-shadow: var(--shadow-md) !important;
 
342
  position: relative;
343
+ overflow: hidden;
344
+ text-align: center !important;
345
+ color: var(--text-primary) !important;
346
+ }
347
+ .app-header-wrapper::before {
348
+ content: '';
349
+ position: absolute;
350
+ top: 0;
351
+ left: 0;
352
+ width: 100%;
353
+ height: 100%;
354
+ background: radial-gradient(circle at top left, rgba(255,140,0,0.3) 0%, transparent 60%), radial-gradient(circle at bottom right, rgba(255,140,0,0.3) 0%, transparent 60%);
355
+ z-index: 0;
356
+ opacity: 0.8;
357
+ pointer-events: none;
358
  }
 
359
  .app-header-logo {
360
+ font-size: 8.5rem !important;
361
+ margin-bottom: 0.75rem !important;
362
+ display: block !important;
363
+ color: var(--primary-color) !important;
364
+ position: relative;
365
+ z-index: 1;
366
+ animation: float-icon 3s ease-in-out infinite alternate;
367
  }
368
+ @keyframes float-icon {
369
+ 0% { transform: translateY(0px); }
370
+ 50% { transform: translateY(-5px); }
371
+ 100% { transform: translateY(0px); }
 
372
  }
 
373
  .app-header-title {
374
+ font-family: 'Poppins', sans-serif !important;
375
+ font-size: 3rem !important;
376
+ font-weight: 800 !important;
377
  color: var(--text-primary) !important;
378
+ margin: 0 0 0.75rem 0 !important;
379
+ line-height: 1.1 !important;
380
+ letter-spacing: -0.03em !important;
381
+ position: relative;
382
+ z-index: 1;
383
+ display: inline-block;
384
+ max-width: 100%;
385
  }
 
386
  .app-header-tagline {
387
+ font-size: 1.25rem !important;
388
  color: var(--text-secondary) !important;
 
389
  font-weight: 400 !important;
390
+ margin: 0 !important;
391
+ max-width: 700px;
392
+ display: inline-block;
393
+ position: relative;
394
+ z-index: 1;
395
  }
 
 
396
  .main-dashboard-container {
397
  display: flex !important;
398
  flex-direction: column !important;
399
+ gap: 1.25rem !important;
400
  }
 
401
  .dashboard-card-section {
402
  background-color: var(--background-primary) !important;
403
+ border: 2px solid var(--border-color) !important;
404
+ border-radius: 12px !important;
405
  padding: 0 !important;
406
  box-shadow: var(--shadow-sm) !important;
407
+ transition: all 0.3s ease-out !important;
408
+ cursor: default;
409
+ color: var(--text-primary) !important;
410
  }
 
411
  .dashboard-card-section:hover {
 
412
  box-shadow: var(--shadow-md) !important;
413
+ transform: translateY(-3px) !important;
414
+ }
415
+ .full-width-center {
416
+ display: flex !important;
417
+ justify-content: center !important;
418
+ align-items: center !important;
419
+ width: 100% !important;
420
+ flex-direction: column !important;
421
+ background-color: transparent !important;
422
  }
 
423
  .section-title-gradient-bar {
424
  background-color: var(--background-secondary) !important;
425
+ padding: 1.25rem 1.75rem !important;
426
  border-top-left-radius: 10px !important;
427
  border-top-right-radius: 10px !important;
428
+ margin-bottom: 0 !important;
429
  text-align: center !important;
430
+ box-sizing: border-box;
431
+ width: 100%;
432
+ color: var(--text-primary) !important;
433
  }
 
434
  .section-title {
435
+ font-family: 'Poppins', sans-serif !important;
436
+ font-size: 1.7rem !important;
437
+ font-weight: 700 !important;
438
  color: var(--text-primary) !important;
439
  margin: 0 !important;
440
+ padding-bottom: 0 !important;
441
+ border-bottom: Gtk-2px solid var(--border-color) !important;
442
+ line-height: 1.1 !important;
443
  display: inline-block !important;
444
+ text-align: center !important;
445
+ letter-spacing: -0.01em !important;
446
  }
 
447
  .dashboard-card-content-area {
448
+ padding: 0 1.75rem 1.75rem 1.75rem !important;
449
  background-color: var(--background-primary) !important;
450
+ box-sizing: border-box;
451
+ width: 100%;
452
  color: var(--text-primary) !important;
453
  }
454
+ .dashboard-card-section p {
455
+ line-height: 1.7 !important;
456
+ color: var(--text-primary) !important;
457
+ font-size: 1rem !important;
458
+ text-align: left !important;
459
+ background-color: transparent !important;
460
+ margin: 0 !important;
461
+ padding: 0 !important;
462
+ white-space: normal !important;
463
+ }
464
+ .dashboard-card-section strong, .dashboard-card-section b {
465
+ font-weight: 700 !important;
466
+ color: var(--primary-color) !important;
467
+ }
468
+ .gr-block, .gr-box, .gr-prose, .gr-form, .gr-panel,
469
+ .gr-columns, .gr-column,
470
+ .gradio-html, .gradio-markdown, .gradio-textbox, .gradio-radio, .gradio-button {
471
+ background-color: transparent !important;
472
+ color: var(--text-primary) !important;
473
+ white-space: normal !important;
474
+ overflow-wrap: break-word;
475
+ word-break: break-word;
476
+ }
477
  .gradio-textbox textarea,
478
+ .gradio-textbox input,
479
+ .gradio-radio label,
480
+ .placeholder {
481
  background-color: var(--background-primary) !important;
482
  color: var(--text-primary) !important;
483
+ }
484
+ .gradio-textbox {
485
+ margin-bottom: 0.5rem !important;
486
+ }
487
+ .gradio-textbox textarea,
488
+ .gradio-textbox input {
489
+ border: 2px solid var(--border-color) !important;
490
  border-radius: 8px !important;
491
+ padding: 0.85rem 1rem !important;
492
+ font-size: 0.98rem !important;
493
+ font-family: 'Inter', sans-serif !important;
494
+ color: var(--text-primary) !important;
495
  transition: border-color 0.2s ease, box-shadow 0.2s ease !important;
496
+ box-shadow: var(--shadow-sm) !important;
497
+ }
498
+ .gradio-textbox .scroll-hide {
499
+ background-color: var(--background-primary) !important;
500
  }
 
501
  .gradio-textbox textarea:focus,
502
  .gradio-textbox input:focus {
 
 
503
  outline: none !important;
504
+ border-color: var(--border-focus) !important;
505
+ box-shadow: 0 0 0 4px rgba(255, 140, 0, 0.2) !important;
506
+ }
507
+ .gradio-radio {
508
+ padding: 0 !important;
509
+ margin-top: 1rem !important;
510
+ }
511
+ .gradio-radio input[type="radio"] {
512
+ display: none !important;
513
  }
 
514
  .gradio-radio label {
515
+ display: flex !important;
516
+ justify-content: center !important;
517
+ align-items: center !important;
518
+ padding: 0.75rem 1rem !important;
519
+ border: 2px solid var(--border-color) !important;
520
  border-radius: 8px !important;
521
+ color: var(--text-primary) !important;
522
+ font-weight: 500 !important;
523
  cursor: pointer !important;
524
+ transition: all 0.2s ease-out !important;
525
+ box-shadow: var(--shadow-sm) !important;
526
+ margin: 0.2rem 0 !important;
527
+ width: 100% !important;
528
+ box-sizing: border-box !important;
529
+ }
530
+ .gradio-radio label span.text-lg {
531
+ font-weight: 600 !important;
532
+ color: var(--text-primary) !important;
533
+ font-size: 0.98rem !important;
534
  }
 
535
  .gradio-radio label:hover {
 
536
  background-color: var(--background-secondary) !important;
537
+ border-color: var(--primary-color) !important;
538
+ box-shadow: var(--shadow-md) !important;
539
+ transform: translateY(-2px) !important;
540
  }
 
541
  .gradio-radio input[type="radio"]:checked + label {
542
+ background-color: var(--primary-color) !important;
543
+ color: var(--text-primary) !important;
544
+ border-color: var(--primary-hover) !important;
545
+ box-shadow: var(--shadow-md) !important;
546
+ transform: translateY(-1px) !important;
547
+ }
548
+ .gradio-radio input[type="radio"]:checked + label span.text-lg {
549
+ color: var(--text-primary) !important;
550
+ }
551
+ .gradio-radio .gr-form {
552
+ padding: 0 !important;
553
+ }
554
+ .gradio-textbox label,
555
+ .gradio-radio > label {
556
+ font-weight: 600 !important;
557
+ color: var(--text-primary) !important;
558
+ font-size: 1rem !important;
559
+ margin-bottom: 0.6rem !important;
560
+ display: block !important;
561
+ text-align: left !important;
562
+ }
563
+ .gr-prose {
564
+ font-size: 0.9rem !important;
565
+ color: var(--text-secondary) !important;
566
+ margin-top: 0.4rem !important;
567
+ text-align: left !important;
568
+ background-color: transparent !important;
569
+ }
570
+ .input-column {
571
+ display: flex !important;
572
+ flex-direction: column !important;
573
+ gap: 1.25rem !important;
574
+ margin-bottom: 0.5rem !important;
575
+ }
576
+ .input-field {
577
+ flex: none !important;
578
+ width: 100% !important;
579
+ }
580
+ .button-row {
581
+ display: flex !important;
582
+ gap: 1rem !important;
583
+ justify-content: flex-end !important;
584
+ margin-top: 1.5rem !important;
585
  }
 
586
  .gradio-button {
587
+ padding: 0.85rem 1.8rem !important;
588
+ border-radius: 9px !important;
589
  font-weight: 600 !important;
590
  font-size: 1rem !important;
591
+ transition: all 0.2s ease-out !important;
592
+ cursor: pointer !important;
593
+ border: 2px solid transparent !important;
594
+ text-align: center !important;
595
+ color: var(--text-primary) !important;
596
  }
 
597
  .gr-button-primary {
598
+ background-color: var(--primary-color) !important;
599
  color: white !important;
600
+ box-shadow: var(--shadow-sm) !important;
601
  }
 
602
  .gr-button-primary:hover {
603
+ background-color: var(--primary-hover) !important;
604
+ box-shadow: var(--shadow-md) !important;
605
  transform: translateY(-2px) !important;
606
  }
607
+ .gr-button-primary:active {
608
+ transform: translateY(1px) !important;
609
+ box-shadow: none !important;
610
+ }
611
  .gr-button-secondary {
612
  background-color: transparent !important;
613
  color: var(--text-primary) !important;
614
+ border-color: var(--border-color) !important;
615
  }
 
616
  .gr-button-secondary:hover {
617
  background-color: var(--background-secondary) !important;
618
+ border-color: var(--primary-color) !important;
619
+ transform: translateY(-2px) !important;
620
+ }
621
+ .gr-button-secondary:active {
622
+ transform: translateY(1px) !important;
623
+ box-shadow: none !important;
624
  }
 
 
625
  .output-content-wrapper {
626
  background-color: var(--background-primary) !important;
627
+ border: 2px solid var(--border-color) !important;
628
  border-radius: 8px !important;
629
  padding: 1.5rem !important;
630
  min-height: 150px !important;
631
  color: var(--text-primary) !important;
632
+ display: flex;
633
+ flex-direction: column;
634
+ justify-content: center;
635
+ align-items: center;
636
  }
 
637
  .animated-output-content {
638
+ opacity: 0;
639
+ animation: fadeInAndSlideUp 0.7s ease-out forwards;
640
+ width: 100%;
641
+ white-space: pre-wrap;
642
+ overflow-wrap: break-word;
643
+ word-break: break-word;
644
+ text-align: left !important;
645
  color: var(--text-primary) !important;
646
  }
647
+ @keyframes fadeInAndSlideUp {
648
+ from { opacity: 0; transform: translateY(15px); }
649
+ to { opacity: 1; transform: translateY(0); }
 
650
  }
 
651
  .response-header {
652
  font-size: 1.3rem !important;
653
+ font-weight: 700 !important;
654
+ color: var(--primary-color) !important;
655
  margin-bottom: 0.75rem !important;
656
  display: flex !important;
657
  align-items: center !important;
658
+ gap: 0.6rem !important;
659
+ text-align: left !important;
660
+ width: 100%;
661
+ justify-content: flex-start;
662
  }
 
663
  .response-icon {
664
  font-size: 1.5rem !important;
665
+ color: var(--primary-color) !important;
666
  }
 
667
  .divider {
668
  border: none !important;
669
  border-top: 1px dashed var(--border-color) !important;
670
  margin: 1rem 0 !important;
671
  }
 
672
  .error-message {
673
  background-color: var(--error-bg) !important;
674
+ border: 2px solid var(--error-border) !important;
675
  color: var(--error-text) !important;
676
+ padding: 1.25rem !important;
677
  border-radius: 8px !important;
678
  display: flex !important;
679
+ align-items: flex-start !important;
680
+ gap: 0.8rem !important;
681
+ font-size: 0.95rem !important;
682
+ font-weight: 500 !important;
683
+ line-height: 1.6 !important;
684
+ text-align: left !important;
685
+ width: 100%;
686
+ box-sizing: border-box;
687
+ }
688
+ .error-message a {
689
+ color: var(--error-text) !important;
690
+ text-decoration: underline !important;
691
  }
 
692
  .error-icon {
693
+ font-size: 1.4rem !important;
694
+ line-height: 1 !important;
695
+ margin-top: 0.1rem !important;
696
+ }
697
+ .error-details {
698
+ font-size: 0.85rem !important;
699
+ color: var(--error-text) !important;
700
+ margin-top: 0.5rem !important;
701
+ opacity: 0.8;
702
  }
 
703
  .placeholder {
704
+ background-color: var(--background-primary) !important;
705
+ border: 2px dashed var(--border-color) !important;
706
+ border-radius: 8px !important;
707
+ padding: 2.5rem 1.5rem !important;
708
+ text-align: center !important;
709
  color: var(--text-secondary) !important;
710
  font-style: italic !important;
711
+ font-size: 1.1rem !important;
712
+ width: 100%;
713
+ box-sizing: border-box;
714
+ }
715
+ .examples-section .gr-samples-table {
716
+ border: 2px solid var(--border-color) !important;
717
+ border-radius: 8px !important;
718
+ overflow: hidden !important;
719
+ margin-top: 1rem !important;
720
+ }
721
+ .examples-section .gr-samples-table th,
722
+ .examples-section .gr-samples-table td {
723
+ padding: 0.9rem !important;
724
+ border: none !important;
725
+ font-size: 0.95rem !important;
726
+ text-align: left !important;
727
+ color: var(--text-primary) !important;
728
+ }
729
+ .examples-section .gr-samples-table th {
730
+ background-color: var(--background-secondary) !important;
731
+ font-weight: 700 !important;
732
+ color: var(--text-primary) !important;
733
+ }
734
+ .examples-section .gr-samples-table td {
735
+ background-color: var(--background-primary) !important;
736
+ color: var(--text-primary) !important;
737
+ border-top: 1px solid var(--border-color) !important;
738
+ cursor: pointer !important;
739
+ transition: background 0.2s ease, transform 0.1s ease !important;
740
+ }
741
+ .examples-section .gr-samples-table tr:hover td {
742
+ background-color: var(--background-secondary) !important;
743
+ transform: translateX(5px);
744
+ }
745
+ .gr-examples .gr-label,
746
+ .gr-examples .label-wrap,
747
+ .gr-examples .gr-accordion-header {
748
+ display: none !important;
749
  }
 
 
750
  .app-footer-wrapper {
751
+ background: linear-gradient(145deg, var(--background-primary) 0%, var(--background-secondary) 100%) !important;
752
+ border: 2px solid var(--border-color) !important;
753
  border-radius: 12px !important;
754
+ padding: 1.75rem !important;
755
+ margin-top: 1.5rem !important;
756
+ margin-bottom: 1.5rem !important;
757
  text-align: center !important;
758
+ color: var(--text-primary) !important;
759
  }
 
760
  .app-footer p {
761
+ margin: 0 !important;
762
+ max-width: 90% !important;
763
+ font-size: 0.95rem !important;
764
  color: var(--text-secondary) !important;
765
+ line-height: 1.6 !important;
766
+ background-color: transparent !important;
767
+ text-align: center !important;
768
+ white-space: normal !important;
769
+ }
770
+ .app-footer strong, .app-footer b {
771
+ font-weight: 700 !important;
772
+ color: var(--primary-color) !important;
773
  }
 
774
  .app-footer a {
775
+ color: var(--primary-color) !important;
776
  text-decoration: underline !important;
777
+ font-weight: 600 !important;
778
  }
 
779
  .app-footer a:hover {
780
  text-decoration: none !important;
781
  }
 
 
782
  @media (max-width: 768px) {
783
  .gradio-container {
784
  padding: 1rem !important;
 
785
  }
786
  .app-header-title {
787
+ font-size: 2.2rem !important;
788
+ }
789
+ .app-header-tagline {
790
+ font-size: 1rem !important;
791
  }
792
  .section-title {
793
+ font-size: 1.4rem !important;
794
+ }
795
+ .input-column {
796
+ flex-direction: column !important;
797
+ }
798
+ .button-row {
799
+ flex-direction: column !important;
800
  }
801
  .gradio-button {
802
  width: 100% !important;
803
  }
804
+ .dashboard-card-section {
805
+ }
806
+ .section-title-gradient-bar {
807
+ padding: 0.1rem 1rem !important;
808
+ }
809
+ .dashboard-card-content-area {
810
+ padding: 0 1rem 1rem 1rem !important;
811
+ }
812
+ .output-content-wrapper {
813
+ min-height: 120px !important;
814
+ }
815
+ .placeholder {
816
+ padding: 1.5rem 1rem !important;
817
+ font-size: 1rem !important;
818
+ }
819
  }
820
  """
821
 
822
+ with gr.Blocks(css=custom_css, title="Landlord-Tenant Rights Assistant") as demo:
 
 
 
 
 
 
823
  with gr.Group(elem_classes="app-header-wrapper"):
824
  gr.Markdown(
825
  """
 
831
  )
832
 
833
  with gr.Column(elem_classes="main-dashboard-container"):
834
+ # How This Assistant Works Box
835
  with gr.Group(elem_classes="dashboard-card-section"):
836
  gr.Markdown("<h3 class='section-title'>How This Assistant Works</h3>", elem_classes="full-width-center section-title-gradient-bar")
837
  with gr.Column(elem_classes="dashboard-card-content-area"):
 
841
  """
842
  )
843
 
844
+ # OpenAI API Key Input Card
845
  with gr.Group(elem_classes="dashboard-card-section"):
846
  gr.Markdown("<h3 class='section-title'>OpenAI API Key</h3>", elem_classes="full-width-center section-title-gradient-bar")
847
  with gr.Column(elem_classes="dashboard-card-content-area"):
 
857
  elem_classes="gr-prose"
858
  )
859
 
860
+ # Query Input and State Selection Card
861
  with gr.Group(elem_classes="dashboard-card-section"):
862
  gr.Markdown("<h3 class='section-title'>Ask Your Question</h3>", elem_classes="full-width-center section-title-gradient-bar")
863
  with gr.Column(elem_classes="dashboard-card-content-area"):
 
882
  clear_button = gr.Button("Clear", variant="secondary", elem_classes=["gr-button-secondary"])
883
  submit_button = gr.Button("Submit Query", variant="primary", elem_classes=["gr-button-primary"])
884
 
885
+ # Output Display Card
886
  with gr.Group(elem_classes="dashboard-card-section"):
887
  gr.Markdown("<h3 class='section-title'>Legal Assistant's Response</h3>", elem_classes="full-width-center section-title-gradient-bar")
888
  with gr.Column(elem_classes="dashboard-card-content-area"):
 
891
  elem_classes="output-content-wrapper"
892
  )
893
 
894
+ # Example Questions Section
895
  with gr.Group(elem_classes="dashboard-card-section examples-section"):
896
  gr.Markdown("<h3 class='section-title'>Example Questions</h3>", elem_classes="full-width-center section-title-gradient-bar")
897
  with gr.Column(elem_classes="dashboard-card-content-area"):
 
905
  else:
906
  gr.Markdown("<div class='placeholder'>Sample questions could not be loaded. Please ensure the vector database is populated.</div>")
907
 
908
+ # Footer Section
909
  with gr.Group(elem_classes="app-footer-wrapper"):
910
  gr.Markdown(
911
  f"""
912
  <style>
913
  .custom-link {{
914
  font-weight: bold !important;
915
+ color: orange !important;
916
  text-decoration: underline;
917
  }}
918
  </style>