Nischal Subedi commited on
Commit
56f099b
·
1 Parent(s): d55a911

Another UI change

Browse files
Files changed (1) hide show
  1. app.py +111 -264
app.py CHANGED
@@ -240,13 +240,14 @@ Answer:"""
240
  # --- GRADIO INTERFACE ---
241
  def gradio_interface(self):
242
  def query_interface_wrapper(api_key: str, query: str, state: str) -> str:
243
- logging.info(f"Gradio interface received query: '{query[:50]}...', state: '{state}'")
244
  if not api_key or not api_key.strip() or not api_key.startswith("sk-"):
245
  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'>Get one here</a>.</div>"
246
  if not state or state == "Select a state..." or "Error" in state:
247
  return "<div class='error-message'><span class='error-icon'>⚠️</span>Please select a valid state from the dropdown.</div>"
248
  if not query or not query.strip():
249
  return "<div class='error-message'><span class='error-icon'>⚠️</span>Please enter your question in the text box.</div>"
 
250
  result = self.process_query(query=query, state=state, openai_api_key=api_key)
251
  answer = result.get("answer", "<div class='error-message'><span class='error-icon'>⚠️</span>An unexpected error occurred.</div>")
252
  if not "<div class='error-message'>" in answer:
@@ -259,7 +260,7 @@ Answer:"""
259
  available_states_list = self.get_states()
260
  dropdown_choices = ["Select a state..."] + (available_states_list if available_states_list and "Error" not in available_states_list[0] else ["Error: States unavailable"])
261
  initial_value = dropdown_choices[0]
262
- except Exception:
263
  dropdown_choices = ["Error: Critical failure loading states"]
264
  initial_value = dropdown_choices[0]
265
 
@@ -269,301 +270,148 @@ Answer:"""
269
  ["My landlord hasn't made necessary repairs. What can I do?", "Texas"],
270
  ]
271
  example_queries = []
272
- if available_states_list and "Error" not in available_states_list[0] and len(available_states_list) > 0: # Check length too
273
  loaded_states_set = set(available_states_list)
274
  example_queries = [ex for ex in example_queries_base if ex[1] in loaded_states_set]
275
- if not example_queries: # If base examples don't match loaded states, add a generic one
276
  example_queries.append(["What basic rights do tenants have?", available_states_list[0]])
277
- elif not example_queries: # Fallback if states list is empty or errored
278
  example_queries.append(["What basic rights do tenants have?", "California"])
279
 
280
 
281
- # --- REFINED "Clarity & Counsel" Theme ---
282
  custom_css = """
283
  @import url('https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap');
284
 
285
  :root {
286
  --font-family-main: 'Poppins', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
287
-
288
- /* Clarity & Counsel - Light Theme */
289
- --app-bg-light: #F9FAFB;
290
- --surface-bg-light: #FFFFFF;
291
- --text-primary-light: #1A202C; /* Tailwind gray-900 - darker for more contrast */
292
- --text-secondary-light: #718096; /* Tailwind gray-600 */
293
- --accent-primary-light: #00796B; /* Teal 700 */
294
- --accent-primary-hover-light: #00695C; /* Teal 800 */
295
- --interactive-text-light: #00796B;
296
- --interactive-text-hover-light: #005F52; /* Darker hover for links */
297
- --border-light: #E2E8F0; /* Tailwind gray-300 */
298
- --button-secondary-bg-light: #F1F5F9; /* Tailwind slate-100 */
299
- --button-secondary-text-light: #334155; /* Tailwind slate-700 */
300
- --button-secondary-hover-bg-light: #E2E8F0; /* Tailwind slate-200 */
301
- --shadow-light: 0 4px 12px rgba(0,0,0,0.05); /* Single softer, more diffused shadow */
302
- --focus-ring-light: rgba(0, 121, 107, 0.2);
303
  --error-bg-light: #FFF1F2; --error-text-light: #C81E1E; --error-border-light: #FFD0D0;
304
  --success-bg-light: #EFFCF6; --success-text-light: #15803D; --success-border-light: #B3EED1;
305
-
306
- /* Clarity & Counsel - Dark Theme */
307
- --app-bg-dark: #0F172A; /* Tailwind slate-900 - deeper dark */
308
- --surface-bg-dark: #1E293B; /* Tailwind slate-800 */
309
- --text-primary-dark: #F1F5F9; /* Tailwind slate-100 */
310
- --text-secondary-dark: #94A3B8; /* Tailwind slate-400 */
311
- --accent-primary-dark: #2DD4BF; /* Teal 400 */
312
- --accent-primary-hover-dark: #14B8A6; /* Teal 500 */
313
- --interactive-text-dark: #5EEAD4; /* Brighter teal for links */
314
- --interactive-text-hover-dark: #99F6E4; /* Even brighter */
315
- --border-dark: #334155; /* Tailwind slate-700 */
316
- --button-secondary-bg-dark: #334155;
317
- --button-secondary-text-dark: #CBD5E1; /* Tailwind slate-300 */
318
- --button-secondary-hover-bg-dark: #475569; /* Tailwind slate-600 */
319
- --shadow-dark: 0 4px 12px rgba(0,0,0,0.2);
320
- --focus-ring-dark: rgba(45, 212, 191, 0.25);
321
  --error-bg-dark: #451515; --error-text-dark: #FFD0D0; --error-border-dark: #9E2D2D;
322
  --success-bg-dark: #073D24; --success-text-dark: #B3EED1; --success-border-dark: #16653D;
323
 
324
- --radius-sm: 4px; --radius-md: 8px; --radius-lg: 12px; /* More pronounced radius */
325
- --transition: 0.15s ease-in-out;
326
  }
327
 
328
- body, .gradio-container {
329
- font-family: var(--font-family-main) !important; background: var(--app-bg-light) !important;
330
- color: var(--text-primary-light) !important; margin: 0; padding: 0; min-height: 100vh;
331
- font-size: 16px; line-height: 1.7;
332
- }
333
  * { box-sizing: border-box; }
334
- @media (prefers-color-scheme: dark) {
335
- body, .gradio-container { background: var(--app-bg-dark) !important; color: var(--text-primary-dark) !important; }
336
- }
337
 
338
- .gradio-container > .flex.flex-col {
339
- max-width: 800px; margin: 0 auto !important; padding: 3rem 1.5rem !important; gap: 3rem !important; /* Increased gap */
340
- }
341
 
342
- .content-surface {
343
- background: var(--surface-bg-light) !important; border-radius: var(--radius-lg) !important;
344
- padding: 2.75rem !important; /* More padding */
345
- box-shadow: var(--shadow-light) !important; border: 1px solid var(--border-light) !important;
346
- }
347
- @media (prefers-color-scheme: dark) {
348
- .content-surface {
349
- background: var(--surface-bg-dark) !important; box-shadow: var(--shadow-dark) !important;
350
- border: 1px solid var(--border-dark) !important;
351
- }
352
- }
353
 
354
- .app-header {
355
- background: var(--accent-primary-light) !important; color: #FFFFFF !important;
356
- padding: 3.5rem 2rem !important; /* More padding */
357
- text-align: center; margin-bottom: 3rem; /* Increased space */
358
- border-bottom-left-radius: var(--radius-lg); border-bottom-right-radius: var(--radius-lg);
359
- box-shadow: 0 6px 15px rgba(0, 121, 107, 0.15); /* Shadow using accent color */
360
- border-bottom: 4px solid var(--accent-primary-hover-light);
361
- }
362
- .app-header-logo { font-size: 3.25rem; margin-bottom: 0.85rem; display: block; }
363
- .app-header-title { font-size: 2.4rem; font-weight: 600; margin: 0 0 0.6rem 0; }
364
- .app-header-tagline { font-size: 1.15rem; font-weight: 300; opacity: 0.95; }
365
  @media (prefers-color-scheme: dark) {
366
- .app-header {
367
- background: var(--accent-primary-dark) !important; color: var(--app-bg-dark) !important; /* Dark text on bright teal */
368
- box-shadow: 0 6px 15px rgba(45, 212, 191, 0.2);
369
- border-bottom: 4px solid var(--accent-primary-hover-dark);
370
- }
371
  }
372
 
373
- .section-title, .input-form-card h3, .examples-card .gr-examples-header {
374
- font-size: 1.6rem !important; font-weight: 600 !important; color: var(--text-primary-light) !important;
375
- margin: 0 auto 2.25rem auto !important; padding-bottom: 1rem !important;
376
- border-bottom: 1px solid var(--border-light) !important; text-align: center !important; max-width: 100%;
377
- }
378
- @media (prefers-color-scheme: dark) {
379
- .section-title, .input-form-card h3, .examples-card .gr-examples-header {
380
- color: var(--text-primary-dark) !important; border-bottom-color: var(--border-dark) !important;
381
- }
382
- }
383
 
384
- .content-surface p { font-size: 1.05rem; line-height: 1.75; color: var(--text-secondary-light); margin-bottom: 1.1rem; }
385
  .content-surface a { color: var(--interactive-text-light); text-decoration: none; font-weight: 500; }
386
  .content-surface a:hover { color: var(--interactive-text-hover-light); text-decoration: underline; }
387
  .content-surface strong { font-weight: 600; color: var(--text-primary-light); }
388
- @media (prefers-color-scheme: dark) {
389
- .content-surface p { color: var(--text-secondary-dark); }
390
- .content-surface a { color: var(--interactive-text-dark); }
391
- .content-surface a:hover { color: var(--interactive-text-hover-dark); }
392
- .content-surface strong { color: var(--text-primary-dark); }
393
- }
394
 
395
  .input-field-group { margin-bottom: 2rem; }
396
- .input-row { display: flex; gap: 2rem; flex-wrap: wrap; margin-bottom: 2rem; }
397
- .input-field { flex: 1; min-width: 240px; }
398
 
399
- .gradio-input-label {
400
- font-size: 0.95rem !important; font-weight: 500 !important; color: var(--text-primary-light) !important;
401
- margin-bottom: 0.6rem !important; display: block !important;
402
- }
403
- .gradio-input-info { font-size: 0.85rem !important; color: var(--text-secondary-light) !important; margin-top: 0.4rem; }
404
- @media (prefers-color-scheme: dark) {
405
- .gradio-input-label { color: var(--text-primary-dark) !important; }
406
- .gradio-input-info { color: var(--text-secondary-dark) !important; }
407
- }
408
 
409
- .gradio-textbox textarea, .gradio-dropdown select, .gradio-textbox input[type=password] {
410
- border: 1px solid var(--border-light) !important; border-radius: var(--radius-md) !important;
411
- padding: 0.9rem 1.1rem !important; font-size: 1rem !important;
412
- background: var(--surface-bg-light) !important; color: var(--text-primary-light) !important;
413
- width: 100% !important; box-shadow: none !important;
414
- }
415
- .gradio-textbox textarea { min-height: 125px; }
416
- .gradio-textbox textarea::placeholder, .gradio-textbox input[type=password]::placeholder { color: #A0AEC0 !important; } /* Tailwind gray-400 for placeholder */
417
- .gradio-textbox textarea:focus, .gradio-dropdown select:focus, .gradio-textbox input[type=password]:focus {
418
- border-color: var(--accent-primary-light) !important;
419
- box-shadow: 0 0 0 3px var(--focus-ring-light) !important; outline: none !important;
420
- }
421
- @media (prefers-color-scheme: dark) {
422
- .gradio-textbox textarea, .gradio-dropdown select, .gradio-textbox input[type=password] {
423
- border: 1px solid var(--border-dark) !important; background: var(--surface-bg-dark) !important;
424
- color: var(--text-primary-dark) !important;
425
- }
426
- .gradio-textbox textarea::placeholder, .gradio-textbox input[type=password]::placeholder { color: #718096 !important; } /* Tailwind gray-600 dark placeholder */
427
- .gradio-textbox textarea:focus, .gradio-dropdown select:focus, .gradio-textbox input[type=password]:focus {
428
- border-color: var(--accent-primary-dark) !important; box-shadow: 0 0 0 3px var(--focus-ring-dark) !important;
429
- }
430
- }
431
- .gradio-dropdown select {
432
- appearance: none; -webkit-appearance: none; -moz-appearance: none;
433
- background-image: url('data:image/svg+xml;charset=US-ASCII,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2020%2020%22%20fill%3D%22%236B7280%22%3E%3Cpath%20fill-rule%3D%22evenodd%22%20d%3D%22M5.293%207.293a1%201%200%20011.414%200L10%2010.586l3.293-3.293a1%201%200%20111.414%201.414l-4%204a1%201%200%2001-1.414%200l-4-4a1%201%200%20010-1.414z%22%20clip-rule%3D%22evenodd%22%2F%3E%3C%2Fsvg%3E');
434
- background-repeat: no-repeat; background-position: right 1.1rem center; background-size: 1em; padding-right: 3.2rem !important;
435
- }
436
- @media (prefers-color-scheme: dark) {
437
- .gradio-dropdown select {
438
- background-image: url('data:image/svg+xml;charset=US-ASCII,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2020%2020%22%20fill%3D%22%239CA3AF%22%3E%3Cpath%20fill-rule%3D%22evenodd%22%20d%3D%22M5.293%207.293a1%201%200%20011.414%200L10%2010.586l3.293-3.293a1%201%200%20111.414%201.414l-4%204a1%201%200%2001-1.414%200l-4-4a1%201%200%20010-1.414z%22%20clip-rule%3D%22evenodd%22%2F%3E%3C%2Fsvg%3E');
439
- }
440
- }
441
 
442
  .button-row { display: flex; gap: 1.25rem; margin-top: 2.25rem; flex-wrap: wrap; justify-content: flex-end; }
443
- .gradio-button {
444
- border-radius: var(--radius-md) !important; padding: 0.85rem 2rem !important; /* Generous padding */
445
- font-size: 1rem !important; font-weight: 500 !important; border: 1px solid transparent !important;
446
- box-shadow: var(--shadow-light) !important;
447
- }
448
- .gradio-button:hover:not(:disabled) { transform: translateY(-2px); box-shadow: 0 5px 10px rgba(0,0,0,0.07) !important; }
449
  .gradio-button:active:not(:disabled) { transform: translateY(-1px); }
450
- .gradio-button:disabled {
451
- background: #E5E7EB !important; color: #9CA3AF !important; box-shadow: none !important; border-color: #D1D5DB !important;
452
- }
453
- .gr-button-primary {
454
- background: var(--accent-primary-light) !important; color: #FFFFFF !important; border-color: var(--accent-primary-light) !important;
455
- }
456
  .gr-button-primary:hover:not(:disabled) { background: var(--accent-primary-hover-light) !important; border-color: var(--accent-primary-hover-light) !important;}
457
- .gr-button-secondary {
458
- background: var(--button-secondary-bg-light) !important; color: var(--button-secondary-text-light) !important;
459
- border-color: var(--border-light) !important;
460
- }
461
  .gr-button-secondary:hover:not(:disabled) { background: var(--button-secondary-hover-bg-light) !important; border-color: #CBD5E0 !important; }
462
- @media (prefers-color-scheme: dark) {
463
- .gradio-button { box-shadow: var(--shadow-dark) !important; }
464
- .gradio-button:hover:not(:disabled) { box-shadow: 0 5px 10px rgba(0,0,0,0.25) !important; }
465
- .gradio-button:disabled { background: #334155 !important; color: #6B7280 !important; border-color: #475569 !important;}
466
- .gr-button-primary {
467
- background: var(--accent-primary-dark) !important; color: var(--app-bg-dark) !important; /* Dark text on bright teal */
468
- border-color: var(--accent-primary-dark) !important;
469
- }
470
- .gr-button-primary:hover:not(:disabled) { background: var(--accent-primary-hover-dark) !important; border-color: var(--accent-primary-hover-dark) !important; }
471
- .gr-button-secondary {
472
- background: var(--button-secondary-bg-dark) !important; color: var(--button-secondary-text-dark) !important;
473
- border-color: var(--border-dark) !important;
474
- }
475
- .gr-button-secondary:hover:not(:disabled) { background: var(--button-secondary-hover-bg-dark) !important; border-color: #475569 !important; }
476
- }
477
 
478
- .output-card .response-header { font-size: 1.35rem; font-weight: 600; color: var(--text-primary-light); margin: 0 0 1rem 0; display: flex; align-items: center; gap: 0.65rem; }
479
- .output-card .response-icon { font-size: 1.5rem; color: var(--text-secondary-light); }
480
  .output-card .divider { border: none; border-top: 1px solid var(--border-light); margin: 1.5rem 0; }
481
- .output-card .output-content-wrapper { font-size: 1.05rem; line-height: 1.8; color: var(--text-primary-light); }
482
- @media (prefers-color-scheme: dark) {
483
- .output-card .response-header { color: var(--text-primary-dark); }
484
- .output-card .response-icon { color: var(--text-secondary-dark); }
485
- .output-card .divider { border-top: 1px solid var(--border-dark); }
486
- .output-card .output-content-wrapper { color: var(--text-primary-dark); }
487
- }
488
-
489
- .output-card .error-message, .output-card .success-message {
490
- padding: 1.1rem 1.35rem; margin-top: 1.25rem; font-size: 1rem;
491
- }
492
- .output-card .error-message .error-icon { font-size: 1.25rem; }
493
- .output-card .error-details { font-size: 0.9rem; }
494
- .output-card .placeholder { padding: 3.5rem 1.75rem; font-size: 1.15rem; }
495
-
496
- .examples-card .gr-examples-table {
497
- border-radius: var(--radius-lg) !important; border: 1px solid var(--border-light) !important;
498
- }
499
- .examples-card .gr-examples-table th, .examples-card .gr-examples-table td {
500
- padding: 1rem 1.2rem !important; font-size: 1rem !important;
501
- }
502
- .examples-card .gr-examples-table th { background: #F9FAFB !important; } /* Slightly off-white header */
503
- @media (prefers-color-scheme: dark) {
504
- .examples-card .gr-examples-table { border: 1px solid var(--border-dark) !important;}
505
- .examples-card .gr-examples-table th { background: #111827 !important; }
506
- }
507
-
508
- .app-footer {
509
- border-top: 1px solid var(--border-light) !important; padding: 3rem 1.5rem !important;
510
- margin-top: 3rem !important; text-align: center !important;
511
- font-size: 0.95rem !important; color: var(--text-secondary-light);
512
- }
513
- .app-footer p { color: var(--text-secondary-light) !important; margin-bottom: 0.6rem; } /* Explicit color for p */
514
- .app-footer a { color: var(--interactive-text-light) !important; } /* Explicit color for a */
515
- .app-footer a:hover { color: var(--interactive-text-hover-light) !important; }
516
- @media (prefers-color-scheme: dark) {
517
- .app-footer { border-top: 1px solid var(--border-dark) !important; color: var(--text-secondary-dark); }
518
- .app-footer p { color: var(--text-secondary-dark) !important; }
519
- .app-footer a { color: var(--interactive-text-dark) !important; }
520
- .app-footer a:hover { color: var(--interactive-text-hover-dark) !important; }
521
- }
522
 
523
  :focus-visible { outline: 2px solid var(--accent-primary-light) !important; outline-offset: 2px; box-shadow: 0 0 0 3px var(--focus-ring-light) !important; }
524
- @media (prefers-color-scheme: dark) {
525
- :focus-visible { outline-color: var(--accent-primary-dark) !important; box-shadow: 0 0 0 3px var(--focus-ring-dark) !important; }
526
- }
527
  .gradio-button span:focus { outline: none !important; }
528
 
529
- @media (max-width: 768px) {
530
- body { font-size: 15px; }
531
- .gradio-container > .flex.flex-col { padding: 2rem 1rem !important; gap: 2.5rem !important; }
532
- .content-surface { padding: 2.25rem !important; }
533
- .app-header { padding: 3rem 1.25rem !important; }
534
- .app-header-logo { font-size: 2.8rem; } .app-header-title { font-size: 2rem; } .app-header-tagline { font-size: 1.05rem; }
535
- .input-row { flex-direction: column; gap: 1.75rem; } .input-field { min-width: 100%; }
536
- .button-row { justify-content: stretch; } .gradio-button { width: 100%; }
537
- .section-title, .input-form-card h3, .examples-card .gr-examples-header { font-size: 1.4rem !important; }
538
- }
539
- @media (max-width: 480px) {
540
- .gradio-container > .flex.flex-col { padding: 1.75rem 0.75rem !important; gap: 2rem !important; }
541
- .content-surface { padding: 1.75rem !important; border-radius: var(--radius-md) !important; }
542
- .app-header { padding: 2.5rem 1rem !important; border-bottom-left-radius: var(--radius-md); border-bottom-right-radius: var(--radius-md); }
543
- .app-header-logo { font-size: 2.4rem; } .app-header-title { font-size: 1.8rem; } .app-header-tagline { font-size: 1rem; }
544
- .section-title, .input-form-card h3, .examples-card .gr-examples-header { font-size: 1.3rem !important; margin-bottom: 1.75rem !important; padding-bottom: 0.85rem !important; }
545
- .gradio-textbox textarea, .gradio-dropdown select, .gradio-textbox input[type=password] { font-size: 0.95rem !important; padding: 0.85rem 1rem !important; }
546
- .gradio-button { padding: 0.85rem 1.5rem !important; font-size: 1rem !important; }
547
- }
548
 
549
- .gradio-container > .flex { gap: 3rem !important; }
550
  .gradio-markdown > *:first-child { margin-top: 0; } .gradio-markdown > *:last-child { margin-bottom: 0; }
551
  .gradio-dropdown, .gradio-textbox { border: none !important; padding: 0 !important; background: transparent !important; }
552
  """
553
 
554
  with gr.Blocks(theme=None, css=custom_css, title="Landlord-Tenant Rights Assistant") as demo:
555
- with gr.Row():
556
- with gr.Column(scale=12):
557
- gr.Markdown(
558
- """
559
- <div class="app-header">
560
- <span class="app-header-logo">⚖️</span>
561
- <h1 class="app-header-title">Landlord-Tenant Rights Assistant</h1>
562
- <p class="app-header-tagline">Empowering You with State-Specific Legal Insights</p>
563
- </div>
564
- """
565
- )
 
566
 
 
567
  with gr.Group(elem_classes="content-surface"):
568
  gr.Markdown("<h3 class='section-title'>Know Your Rights</h3>")
569
  gr.Markdown(
@@ -582,12 +430,12 @@ Answer:"""
582
  info="Required to process your query. Securely used per request, not stored.", lines=1
583
  )
584
  with gr.Row(elem_classes="input-row"):
585
- with gr.Column(elem_classes="input-field", min_width="58%"): # Adjusted min-width
586
  query_input = gr.Textbox(
587
  label="Your Question", placeholder="E.g., What are the rules for security deposit returns in my state?",
588
- lines=5, max_lines=10 # Slightly taller
589
  )
590
- with gr.Column(elem_classes="input-field", min_width="38%"): # Adjusted min-width
591
  state_input = gr.Dropdown(
592
  label="Select State", choices=dropdown_choices, value=initial_value,
593
  allow_custom_value=False
@@ -596,7 +444,7 @@ Answer:"""
596
  clear_button = gr.Button("Clear", variant="secondary", elem_classes=["gr-button-secondary"])
597
  submit_button = gr.Button("Submit Query", variant="primary", elem_classes=["gr-button-primary"])
598
 
599
- with gr.Group(elem_classes="content-surface output-card"): # Added output-card for specific styling if needed
600
  output = gr.Markdown(
601
  value="<div class='placeholder'>Your answer will appear here after submitting your query.</div>",
602
  elem_classes="output-content-wrapper"
@@ -612,19 +460,18 @@ Answer:"""
612
  with gr.Group(elem_classes="content-surface"):
613
  gr.Markdown("<div class='placeholder'>Sample questions could not be loaded.</div>")
614
 
615
- with gr.Row():
616
- with gr.Column(scale=12):
617
- gr.Markdown(
618
- """
619
- <div class="app-footer">
620
- <p>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.</p>
621
- <p>Developed by <span style="color:#2AE7D6; font-weight:bold;">Nischal Subedi</span>.
622
- Connect on <a href="https://www.linkedin.com/in/nischal1/" target='_blank' style="color:#2AE7D6; text-decoration:underline;">LinkedIn</a>
623
- or explore insights at <a href="https://datascientistinsights.substack.com/" target='_blank' style="color:#2AE7D6; text-decoration:underline;">Substack</a>.</p>
624
- </div>
625
- """
626
- )
627
-
628
 
629
  submit_button.click(
630
  fn=query_interface_wrapper, inputs=[api_key_input, query_input, state_input], outputs=output, api_name="submit_query"
@@ -633,7 +480,7 @@ Answer:"""
633
  fn=lambda: ("", "", initial_value, "<div class='placeholder'>Inputs cleared. Ready for your next question.</div>"),
634
  inputs=[], outputs=[api_key_input, query_input, state_input, output]
635
  )
636
- logging.info("Refined Clarity & Counsel theme Gradio interface created.")
637
  return demo
638
 
639
  # --- Main Execution Block (remains the same) ---
 
240
  # --- GRADIO INTERFACE ---
241
  def gradio_interface(self):
242
  def query_interface_wrapper(api_key: str, query: str, state: str) -> str:
243
+ # ... (validation logic remains the same)
244
  if not api_key or not api_key.strip() or not api_key.startswith("sk-"):
245
  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'>Get one here</a>.</div>"
246
  if not state or state == "Select a state..." or "Error" in state:
247
  return "<div class='error-message'><span class='error-icon'>⚠️</span>Please select a valid state from the dropdown.</div>"
248
  if not query or not query.strip():
249
  return "<div class='error-message'><span class='error-icon'>⚠️</span>Please enter your question in the text box.</div>"
250
+
251
  result = self.process_query(query=query, state=state, openai_api_key=api_key)
252
  answer = result.get("answer", "<div class='error-message'><span class='error-icon'>⚠️</span>An unexpected error occurred.</div>")
253
  if not "<div class='error-message'>" in answer:
 
260
  available_states_list = self.get_states()
261
  dropdown_choices = ["Select a state..."] + (available_states_list if available_states_list and "Error" not in available_states_list[0] else ["Error: States unavailable"])
262
  initial_value = dropdown_choices[0]
263
+ except Exception: # Catch-all for safety
264
  dropdown_choices = ["Error: Critical failure loading states"]
265
  initial_value = dropdown_choices[0]
266
 
 
270
  ["My landlord hasn't made necessary repairs. What can I do?", "Texas"],
271
  ]
272
  example_queries = []
273
+ if available_states_list and "Error" not in available_states_list[0] and len(available_states_list) > 0:
274
  loaded_states_set = set(available_states_list)
275
  example_queries = [ex for ex in example_queries_base if ex[1] in loaded_states_set]
276
+ if not example_queries and available_states_list[0] != "Error: States unavailable": # Ensure first state is not error
277
  example_queries.append(["What basic rights do tenants have?", available_states_list[0]])
278
+ elif not example_queries : # Fallback if states list is problematic
279
  example_queries.append(["What basic rights do tenants have?", "California"])
280
 
281
 
282
+ # --- FINAL REFINED "Clarity & Counsel" Theme ---
283
  custom_css = """
284
  @import url('https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap');
285
 
286
  :root {
287
  --font-family-main: 'Poppins', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
288
+ /* Light Theme */
289
+ --app-bg-light: #F9FAFB; --surface-bg-light: #FFFFFF; --text-primary-light: #1A202C;
290
+ --text-secondary-light: #718096; --accent-primary-light: #00796B; --accent-primary-hover-light: #00695C;
291
+ --interactive-text-light: #00796B; --interactive-text-hover-light: #005F52; --border-light: #E2E8F0;
292
+ --button-secondary-bg-light: #F1F5F9; --button-secondary-text-light: #334155; --button-secondary-hover-bg-light: #E2E8F0;
293
+ --shadow-light: 0 5px 15px rgba(0,0,0,0.05); --focus-ring-light: rgba(0, 121, 107, 0.25);
 
 
 
 
 
 
 
 
 
 
294
  --error-bg-light: #FFF1F2; --error-text-light: #C81E1E; --error-border-light: #FFD0D0;
295
  --success-bg-light: #EFFCF6; --success-text-light: #15803D; --success-border-light: #B3EED1;
296
+ /* Dark Theme */
297
+ --app-bg-dark: #0F172A; --surface-bg-dark: #1E293B; --text-primary-dark: #F1F5F9;
298
+ --text-secondary-dark: #94A3B8; --accent-primary-dark: #2DD4BF; --accent-primary-hover-dark: #14B8A6;
299
+ --interactive-text-dark: #5EEAD4; --interactive-text-hover-dark: #99F6E4; --border-dark: #334155;
300
+ --button-secondary-bg-dark: #334155; --button-secondary-text-dark: #CBD5E1; --button-secondary-hover-bg-dark: #475569;
301
+ --shadow-dark: 0 5px 15px rgba(0,0,0,0.2); --focus-ring-dark: rgba(45, 212, 191, 0.3);
 
 
 
 
 
 
 
 
 
 
302
  --error-bg-dark: #451515; --error-text-dark: #FFD0D0; --error-border-dark: #9E2D2D;
303
  --success-bg-dark: #073D24; --success-text-dark: #B3EED1; --success-border-dark: #16653D;
304
 
305
+ --radius-md: 8px; --radius-lg: 12px; --transition: 0.2s ease-in-out;
 
306
  }
307
 
308
+ body, .gradio-container { font-family: var(--font-family-main) !important; background: var(--app-bg-light) !important; color: var(--text-primary-light) !important; margin: 0; padding: 0; min-height: 100vh; font-size: 16px; line-height: 1.7; }
 
 
 
 
309
  * { box-sizing: border-box; }
310
+ @media (prefers-color-scheme: dark) { body, .gradio-container { background: var(--app-bg-dark) !important; color: var(--text-primary-dark) !important; } }
 
 
311
 
312
+ .gradio-container > .flex.flex-col { max-width: 820px; margin: 0 auto !important; padding: 0 1.5rem 3rem 1.5rem !important; gap: 0 !important; /* Remove gap, manage spacing with element margins */ }
 
 
313
 
314
+ .content-surface { background: var(--surface-bg-light) !important; border-radius: var(--radius-lg) !important; padding: 3rem !important; box-shadow: var(--shadow-light) !important; border: 1px solid var(--border-light) !important; margin-bottom: 3rem; }
315
+ .content-surface:last-child { margin-bottom: 0; } /* No bottom margin for the last surface */
316
+ @media (prefers-color-scheme: dark) { .content-surface { background: var(--surface-bg-dark) !important; box-shadow: var(--shadow-dark) !important; border: 1px solid var(--border-dark) !important; } }
 
 
 
 
 
 
 
 
317
 
318
+ .app-header-wrapper { background: var(--accent-primary-light) !important; margin-bottom: 3rem; border-bottom-left-radius: var(--radius-lg); border-bottom-right-radius: var(--radius-lg); box-shadow: var(--shadow-light); }
319
+ .app-header { color: #FFFFFF !important; padding: 3.5rem 2rem !important; text-align: center !important; display: flex; flex-direction: column; align-items: center; }
320
+ .app-header-logo { font-size: 3rem; margin-bottom: 0.75rem; display: block; text-align: center !important; }
321
+ .app-header-title { font-size: 2.25rem; font-weight: 600; margin: 0 0 0.5rem 0; text-align: center !important; }
322
+ .app-header-tagline { font-size: 1.1rem; font-weight: 300; opacity: 0.95; text-align: center !important; }
 
 
 
 
 
 
323
  @media (prefers-color-scheme: dark) {
324
+ .app-header-wrapper { background: var(--accent-primary-dark) !important; box-shadow: var(--shadow-dark); }
325
+ .app-header { color: var(--app-bg-dark) !important; }
 
 
 
326
  }
327
 
328
+ .section-title, .input-form-card h3, .examples-card .gr-examples-header { font-size: 1.5rem !important; font-weight: 600 !important; color: var(--text-primary-light) !important; margin: 0 auto 2rem auto !important; padding-bottom: 1rem !important; border-bottom: 1px solid var(--border-light) !important; text-align: center !important; width: 100%; }
329
+ @media (prefers-color-scheme: dark) { .section-title, .input-form-card h3, .examples-card .gr-examples-header { color: var(--text-primary-dark) !important; border-bottom-color: var(--border-dark) !important; } }
 
 
 
 
 
 
 
 
330
 
331
+ .content-surface p { font-size: 1rem; line-height: 1.75; color: var(--text-secondary-light); margin-bottom: 1rem; }
332
  .content-surface a { color: var(--interactive-text-light); text-decoration: none; font-weight: 500; }
333
  .content-surface a:hover { color: var(--interactive-text-hover-light); text-decoration: underline; }
334
  .content-surface strong { font-weight: 600; color: var(--text-primary-light); }
335
+ @media (prefers-color-scheme: dark) { .content-surface p { color: var(--text-secondary-dark); } .content-surface a { color: var(--interactive-text-dark); } .content-surface a:hover { color: var(--interactive-text-hover-dark); } .content-surface strong { color: var(--text-primary-dark); } }
 
 
 
 
 
336
 
337
  .input-field-group { margin-bottom: 2rem; }
338
+ .input-row { display: flex; gap: 1.75rem; flex-wrap: wrap; margin-bottom: 2rem; }
339
+ .input-field { flex: 1; min-width: 250px; }
340
 
341
+ .gradio-input-label { font-size: 0.9rem !important; font-weight: 500 !important; color: var(--text-primary-light) !important; margin-bottom: 0.5rem !important; display: block !important; }
342
+ .gradio-input-info { font-size: 0.8rem !important; color: var(--text-secondary-light) !important; margin-top: 0.35rem; }
343
+ @media (prefers-color-scheme: dark) { .gradio-input-label { color: var(--text-primary-dark) !important; } .gradio-input-info { color: var(--text-secondary-dark) !important; } }
 
 
 
 
 
 
344
 
345
+ .gradio-textbox textarea, .gradio-dropdown select, .gradio-textbox input[type=password] { border: 1px solid var(--border-light) !important; border-radius: var(--radius-md) !important; padding: 0.9rem 1.05rem !important; font-size: 1rem !important; background: var(--surface-bg-light) !important; color: var(--text-primary-light) !important; width: 100% !important; box-shadow: none !important; transition: border-color var(--transition), box-shadow var(--transition); }
346
+ .gradio-textbox textarea { min-height: 120px; }
347
+ .gradio-textbox textarea::placeholder, .gradio-textbox input[type=password]::placeholder { color: #A0AEC0 !important; }
348
+ .gradio-textbox textarea:focus, .gradio-dropdown select:focus, .gradio-textbox input[type=password]:focus { border-color: var(--accent-primary-light) !important; box-shadow: 0 0 0 3px var(--focus-ring-light) !important; outline: none !important; }
349
+ @media (prefers-color-scheme: dark) { .gradio-textbox textarea, .gradio-dropdown select, .gradio-textbox input[type=password] { border: 1px solid var(--border-dark) !important; background: var(--surface-bg-dark) !important; color: var(--text-primary-dark) !important; } .gradio-textbox textarea::placeholder, .gradio-textbox input[type=password]::placeholder { color: #718096 !important; } .gradio-textbox textarea:focus, .gradio-dropdown select:focus, .gradio-textbox input[type=password]:focus { border-color: var(--accent-primary-dark) !important; box-shadow: 0 0 0 3px var(--focus-ring-dark) !important; } }
350
+ .gradio-dropdown select { appearance: none; -webkit-appearance: none; -moz-appearance: none; background-image: url('data:image/svg+xml;charset=US-ASCII,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2020%2020%22%20fill%3D%22%236B7280%22%3E%3Cpath%20fill-rule%3D%22evenodd%22%20d%3D%22M5.293%207.293a1%201%200%20011.414%200L10%2010.586l3.293-3.293a1%201%200%20111.414%201.414l-4%204a1%201%200%2001-1.414%200l-4-4a1%201%200%20010-1.414z%22%20clip-rule%3D%22evenodd%22%2F%3E%3C%2Fsvg%3E'); background-repeat: no-repeat; background-position: right 1rem center; background-size: 1em; padding-right: 3rem !important; }
351
+ @media (prefers-color-scheme: dark) { .gradio-dropdown select { background-image: url('data:image/svg+xml;charset=US-ASCII,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2020%2020%22%20fill%3D%22%239CA3AF%22%3E%3Cpath%20fill-rule%3D%22evenodd%22%20d%3D%22M5.293%207.293a1%201%200%20011.414%200L10%2010.586l3.293-3.293a1%201%200%20111.414%201.414l-4%204a1%201%200%2001-1.414%200l-4-4a1%201%200%20010-1.414z%22%20clip-rule%3D%22evenodd%22%2F%3E%3C%2Fsvg%3E'); } }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
352
 
353
  .button-row { display: flex; gap: 1.25rem; margin-top: 2.25rem; flex-wrap: wrap; justify-content: flex-end; }
354
+ .gradio-button { border-radius: var(--radius-md) !important; padding: 0.8rem 1.85rem !important; font-size: 1rem !important; font-weight: 500 !important; border: 1px solid transparent !important; box-shadow: var(--shadow-light) !important; }
355
+ .gradio-button:hover:not(:disabled) { transform: translateY(-2px); box-shadow: 0 6px 12px rgba(0,0,0,0.07) !important; }
 
 
 
 
356
  .gradio-button:active:not(:disabled) { transform: translateY(-1px); }
357
+ .gradio-button:disabled { background: #E5E7EB !important; color: #9CA3AF !important; box-shadow: none !important; border-color: #D1D5DB !important; }
358
+ .gr-button-primary { background: var(--accent-primary-light) !important; color: #FFFFFF !important; border-color: var(--accent-primary-light) !important; }
 
 
 
 
359
  .gr-button-primary:hover:not(:disabled) { background: var(--accent-primary-hover-light) !important; border-color: var(--accent-primary-hover-light) !important;}
360
+ .gr-button-secondary { background: var(--button-secondary-bg-light) !important; color: var(--button-secondary-text-light) !important; border-color: var(--border-light) !important; }
 
 
 
361
  .gr-button-secondary:hover:not(:disabled) { background: var(--button-secondary-hover-bg-light) !important; border-color: #CBD5E0 !important; }
362
+ @media (prefers-color-scheme: dark) { .gradio-button { box-shadow: var(--shadow-dark) !important; } .gradio-button:hover:not(:disabled) { box-shadow: 0 6px 12px rgba(0,0,0,0.25) !important; } .gradio-button:disabled { background: #334155 !important; color: #6B7280 !important; border-color: #475569 !important;} .gr-button-primary { background: var(--accent-primary-dark) !important; color: var(--app-bg-dark) !important; border-color: var(--accent-primary-dark) !important; } .gr-button-primary:hover:not(:disabled) { background: var(--accent-primary-hover-dark) !important; border-color: var(--accent-primary-hover-dark) !important; } .gr-button-secondary { background: var(--button-secondary-bg-dark) !important; color: var(--button-secondary-text-dark) !important; border-color: var(--border-dark) !important; } .gr-button-secondary:hover:not(:disabled) { background: var(--button-secondary-hover-bg-dark) !important; border-color: #475569 !important; } }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
363
 
364
+ .output-card .response-header { font-size: 1.3rem; font-weight: 600; color: var(--text-primary-light); margin: 0 0 1rem 0; display: flex; align-items: center; gap: 0.6rem; }
365
+ .output-card .response-icon { font-size: 1.4rem; color: var(--text-secondary-light); }
366
  .output-card .divider { border: none; border-top: 1px solid var(--border-light); margin: 1.5rem 0; }
367
+ .output-card .output-content-wrapper { font-size: 1rem; line-height: 1.75; color: var(--text-primary-light); }
368
+ .output-card .output-content-wrapper p { margin-bottom: 1rem; } .output-card .output-content-wrapper ul, .output-card .output-content-wrapper ol { margin-left: 1.5rem; margin-bottom: 1rem; padding-left: 1rem; } .output-card .output-content-wrapper li { margin-bottom: 0.5rem; }
369
+ @media (prefers-color-scheme: dark) { .output-card .response-header { color: var(--text-primary-dark); } .output-card .response-icon { color: var(--text-secondary-dark); } .output-card .divider { border-top: 1px solid var(--border-dark); } .output-card .output-content-wrapper { color: var(--text-primary-dark); } }
370
+
371
+ .output-card .error-message, .output-card .success-message { padding: 1rem 1.25rem; margin-top: 1.25rem; font-size: 0.95rem; border-radius: var(--radius-md);}
372
+ .output-card .error-message .error-icon { font-size: 1.2rem; } .output-card .error-details { font-size: 0.85rem; }
373
+ .output-card .placeholder { padding: 3rem 1.5rem; font-size: 1.1rem; border-radius: var(--radius-lg); border: 2px dashed var(--border-light); }
374
+ @media (prefers-color-scheme: dark) { .output-card .placeholder { border-color: var(--border-dark); } }
375
+
376
+ .examples-card .gr-examples-table { border-radius: var(--radius-lg) !important; border: 1px solid var(--border-light) !important; }
377
+ .examples-card .gr-examples-table th, .examples-card .gr-examples-table td { padding: 0.9rem 1.1rem !important; font-size: 0.95rem !important; }
378
+ .examples-card .gr-examples-table th { background: #F9FAFB !important; }
379
+ @media (prefers-color-scheme: dark) { .examples-card .gr-examples-table { border: 1px solid var(--border-dark) !important;} .examples-card .gr-examples-table th { background: #0F172A !important; } }
380
+
381
+ .app-footer-wrapper { border-top: 1px solid var(--border-light) !important; margin-top: 3rem; }
382
+ .app-footer { padding: 3rem 1.5rem !important; text-align: center !important; display: flex; flex-direction: column; align-items: center; }
383
+ .app-footer p { font-size: 0.9rem !important; color: var(--text-secondary-light) !important; margin-bottom: 0.75rem; text-align: center !important; max-width: 600px; /* Constrain footer text width */ }
384
+ .app-footer a { color: var(--interactive-text-light) !important; font-weight: 500; }
385
+ .app-footer a:hover { color: var(--interactive-text-hover-light) !important; text-decoration: underline; }
386
+ @media (prefers-color-scheme: dark) { .app-footer-wrapper { border-top-color: var(--border-dark) !important; } .app-footer p { color: var(--text-secondary-dark) !important; } .app-footer a { color: var(--interactive-text-dark) !important; } .app-footer a:hover { color: var(--interactive-text-hover-dark) !important; } }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
387
 
388
  :focus-visible { outline: 2px solid var(--accent-primary-light) !important; outline-offset: 2px; box-shadow: 0 0 0 3px var(--focus-ring-light) !important; }
389
+ @media (prefers-color-scheme: dark) { :focus-visible { outline-color: var(--accent-primary-dark) !important; box-shadow: 0 0 0 3px var(--focus-ring-dark) !important; } }
 
 
390
  .gradio-button span:focus { outline: none !important; }
391
 
392
+ @media (max-width: 768px) { body { font-size: 15px; } .gradio-container > .flex.flex-col { padding: 0 1rem 2.5rem 1rem !important; } .content-surface { padding: 2.25rem !important; margin-bottom: 2.5rem; } .app-header-wrapper { margin-bottom: 2.5rem; } .app-header { padding: 2.75rem 1.25rem !important; } .app-header-logo { font-size: 2.6rem; } .app-header-title { font-size: 2rem; } .app-header-tagline { font-size: 1.05rem; } .input-row { flex-direction: column; gap: 1.5rem; } .input-field { min-width: 100%; } .button-row { justify-content: stretch; } .gradio-button { width: 100%; } .section-title, .input-form-card h3, .examples-card .gr-examples-header { font-size: 1.35rem !important; } .app-footer-wrapper { margin-top: 2.5rem; } .app-footer { padding: 2.5rem 1rem !important; } }
393
+ @media (max-width: 480px) { .gradio-container > .flex.flex-col { padding: 0 0.75rem 2rem 0.75rem !important; } .content-surface { padding: 1.75rem !important; margin-bottom: 2rem; border-radius: var(--radius-md) !important; } .app-header-wrapper { margin-bottom: 2rem; border-bottom-left-radius: var(--radius-md); border-bottom-right-radius: var(--radius-md); } .app-header { padding: 2.25rem 1rem !important; } .app-header-logo { font-size: 2.2rem; } .app-header-title { font-size: 1.7rem; } .app-header-tagline { font-size: 0.95rem; } .section-title, .input-form-card h3, .examples-card .gr-examples-header { font-size: 1.25rem !important; margin-bottom: 1.75rem !important; padding-bottom: 0.85rem !important; } .gradio-textbox textarea, .gradio-dropdown select, .gradio-textbox input[type=password] { font-size: 0.95rem !important; padding: 0.85rem 1rem !important; } .gradio-button { padding: 0.85rem 1.5rem !important; font-size: 0.95rem !important; } .examples-card .gr-examples-table th, .examples-card .gr-examples-table td { padding: 0.75rem 0.9rem !important; font-size: 0.9rem !important; } .app-footer-wrapper { margin-top: 2rem; } .app-footer { padding: 2rem 0.75rem !important; } }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
394
 
395
+ .gradio-container > .flex { gap: 0 !important; } /* Main gap removed, managed by surface margins */
396
  .gradio-markdown > *:first-child { margin-top: 0; } .gradio-markdown > *:last-child { margin-bottom: 0; }
397
  .gradio-dropdown, .gradio-textbox { border: none !important; padding: 0 !important; background: transparent !important; }
398
  """
399
 
400
  with gr.Blocks(theme=None, css=custom_css, title="Landlord-Tenant Rights Assistant") as demo:
401
+ # --- Header Section ---
402
+ # We'll wrap the Markdown in a gr.Group to apply wrapper styles if needed
403
+ with gr.Group(elem_classes="app-header-wrapper"):
404
+ gr.Markdown(
405
+ """
406
+ <div class="app-header">
407
+ <span class="app-header-logo">⚖️</span>
408
+ <h1 class="app-header-title">Landlord-Tenant Rights Assistant</h1>
409
+ <p class="app-header-tagline">Empowering You with State-Specific Legal Insights</p>
410
+ </div>
411
+ """
412
+ )
413
 
414
+ # --- Main Content Sections ---
415
  with gr.Group(elem_classes="content-surface"):
416
  gr.Markdown("<h3 class='section-title'>Know Your Rights</h3>")
417
  gr.Markdown(
 
430
  info="Required to process your query. Securely used per request, not stored.", lines=1
431
  )
432
  with gr.Row(elem_classes="input-row"):
433
+ with gr.Column(elem_classes="input-field", min_width="58%"):
434
  query_input = gr.Textbox(
435
  label="Your Question", placeholder="E.g., What are the rules for security deposit returns in my state?",
436
+ lines=5, max_lines=10
437
  )
438
+ with gr.Column(elem_classes="input-field", min_width="38%"):
439
  state_input = gr.Dropdown(
440
  label="Select State", choices=dropdown_choices, value=initial_value,
441
  allow_custom_value=False
 
444
  clear_button = gr.Button("Clear", variant="secondary", elem_classes=["gr-button-secondary"])
445
  submit_button = gr.Button("Submit Query", variant="primary", elem_classes=["gr-button-primary"])
446
 
447
+ with gr.Group(elem_classes="content-surface output-card"):
448
  output = gr.Markdown(
449
  value="<div class='placeholder'>Your answer will appear here after submitting your query.</div>",
450
  elem_classes="output-content-wrapper"
 
460
  with gr.Group(elem_classes="content-surface"):
461
  gr.Markdown("<div class='placeholder'>Sample questions could not be loaded.</div>")
462
 
463
+ # --- Footer Section ---
464
+ with gr.Group(elem_classes="app-footer-wrapper"):
465
+ gr.Markdown(
466
+ """
467
+ <div class="app-footer">
468
+ <p>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.</p>
469
+ <p>Developed by <strong>Nischal Subedi</strong>.
470
+ Connect on <a href="https://www.linkedin.com/in/nischal1/" target='_blank'>LinkedIn</a>
471
+ or explore insights at <a href="https://datascientistinsights.substack.com/" target='_blank'>Substack</a>.</p>
472
+ </div>
473
+ """
474
+ )
 
475
 
476
  submit_button.click(
477
  fn=query_interface_wrapper, inputs=[api_key_input, query_input, state_input], outputs=output, api_name="submit_query"
 
480
  fn=lambda: ("", "", initial_value, "<div class='placeholder'>Inputs cleared. Ready for your next question.</div>"),
481
  inputs=[], outputs=[api_key_input, query_input, state_input, output]
482
  )
483
+ logging.info("Final refined Clarity & Counsel theme Gradio interface created.")
484
  return demo
485
 
486
  # --- Main Execution Block (remains the same) ---