Alex Amari commited on
Commit
0c58f4d
·
1 Parent(s): ac16d83

Restyle app to match OHA branding

Browse files
__pycache__/app.cpython-312-pytest-7.4.4.pyc CHANGED
Binary files a/__pycache__/app.cpython-312-pytest-7.4.4.pyc and b/__pycache__/app.cpython-312-pytest-7.4.4.pyc differ
 
app.py CHANGED
@@ -631,79 +631,246 @@ def stream_chat_response(message, chat_history, eligibility_data):
631
  # === CUSTOM CSS ===
632
 
633
  custom_css = """
634
- /* CT.gov inspired styling */
 
 
635
  .gradio-container {
636
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif !important;
637
- max-width: 1200px !important;
638
- margin: auto !important;
 
 
 
 
639
  }
640
 
641
- /* CT Blue header */
642
- h1 {
643
- color: #0d6efd !important;
644
- font-weight: 600 !important;
645
- border-bottom: 3px solid #0d6efd;
646
- padding-bottom: 1rem;
 
 
 
 
 
647
  }
648
 
649
- /* Buttons - CT Blue */
650
- .gr-button-primary {
651
- background: #0d6efd !important;
 
 
 
 
 
 
 
 
 
 
652
  border: none !important;
653
- color: white !important;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
654
  }
655
 
656
- .gr-button-primary:hover {
657
- background: #0a58ca !important;
 
 
 
 
 
 
658
  }
659
 
660
- .gr-button-secondary {
661
- background: #6c757d !important;
 
 
662
  border: none !important;
663
- color: white !important;
 
 
 
 
 
 
 
 
 
 
 
 
 
664
  }
665
 
666
- /* Form inputs */
667
- .gr-box, .gr-input, .gr-dropdown {
668
- border: 1px solid #ced4da !important;
669
- border-radius: 0.375rem !important;
670
  }
671
 
672
- /* Card-like sections */
673
- .gr-group {
674
- background: #f8f9fa !important;
675
- padding: 1.5rem !important;
676
- border-radius: 0.5rem !important;
677
- border: 1px solid #dee2e6 !important;
 
 
678
  }
679
 
680
- /* Labels */
681
  label {
682
  color: #212529 !important;
683
  font-weight: 500 !important;
684
- margin-bottom: 0.5rem !important;
 
685
  }
686
 
687
- /* Results cards */
688
- .markdown-text h2 {
689
- color: #0d6efd !important;
690
- border-bottom: 2px solid #e9ecef;
691
- padding-bottom: 0.5rem;
 
 
 
 
 
 
 
 
 
692
  }
693
 
694
- .markdown-text h3 {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
695
  color: #495057 !important;
696
- font-size: 1.1rem;
 
 
 
 
 
 
697
  }
698
 
699
- /* Source links section */
700
- .markdown-text a {
701
- color: #0d6efd !important;
702
- text-decoration: none;
 
 
 
 
 
 
 
 
 
 
703
  }
704
 
705
- .markdown-text a:hover {
706
- text-decoration: underline;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
707
  }
708
  """
709
 
@@ -712,7 +879,21 @@ label {
712
  def create_interface():
713
  """Build and return the Gradio Blocks interface with all steps and event wiring."""
714
  with gr.Blocks(
715
- theme=gr.themes.Default(primary_hue="blue", neutral_hue="slate"),
 
 
 
 
 
 
 
 
 
 
 
 
 
 
716
  css=custom_css
717
  ) as demo:
718
 
@@ -722,13 +903,31 @@ def create_interface():
722
  chat_history_state = gr.State([]) # List of {"role":..., "content":...} dicts
723
  chat_count_state = gr.State(0) # Message counter for rate limiting
724
 
725
- # Header with Beta tag
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
726
  with gr.Row():
727
- with gr.Column(scale=4):
728
- gr.Markdown("# 🏥 Connecticut Hospital Financial Assistance <span style='background-color: #ffc107; color: #664d03; padding: 4px 12px; border-radius: 4px; font-size: 0.75em; font-weight: bold; margin-left: 0.5rem;'>BETA</span>")
729
- with gr.Column(scale=1):
730
  lang_toggle = gr.Radio(
731
- choices=["English", "Español"],
732
  value="English",
733
  label="Language",
734
  container=False
@@ -739,13 +938,15 @@ def create_interface():
739
  with step1:
740
  gr.Markdown("### How would you like to start?")
741
  with gr.Row():
742
- help_btn = gr.Button("🔍 Search: Help me find a hospital", variant="primary", size="lg")
743
- know_btn = gr.Button("🏥 Select: I know my hospital", variant="secondary", size="lg")
744
 
745
  gr.HTML(
 
746
  '<iframe src="https://www.google.com/maps/d/u/0/embed?mid=1UVO9r7ZS26kZr8Q62dY0147v3Milu_s&ll=41.508444988744984%2C-72.7719992&z=9" '
747
- 'width="100%" height="480" style="border:0; border-radius: 8px; margin-top: 1rem;" '
748
  'allowfullscreen="" loading="lazy" title="Map: Connecticut Hospital Locations"></iframe>'
 
749
  )
750
 
751
  # Step 2a: Find hospital by ZIP
@@ -758,7 +959,7 @@ def create_interface():
758
  nearby_cards = gr.Markdown()
759
  hospital_radio = gr.Radio(label="Select a hospital", choices=[], visible=False)
760
  continue_btn_a = gr.Button("Continue", variant="primary", visible=False)
761
- back_btn_a = gr.Button("Back", size="sm")
762
 
763
  # Step 2b: Select known hospital
764
  step2b = gr.Group(visible=False)
@@ -769,7 +970,7 @@ def create_interface():
769
  label="Hospital"
770
  )
771
  continue_btn_b = gr.Button("Continue", variant="primary")
772
- back_btn_b = gr.Button("Back", size="sm")
773
 
774
  # Step 3: Eligibility form
775
  step3 = gr.Group(visible=False)
@@ -782,32 +983,32 @@ def create_interface():
782
  insurance_radio = gr.Radio(choices=["Yes", "No"], label="Do you have health insurance?", value="No")
783
 
784
  check_btn = gr.Button("Check Eligibility", variant="primary", size="lg")
785
- back_btn_c = gr.Button("Back", size="sm")
786
 
787
  # Step 4: Results (with streaming) + follow-up chat
788
  step4 = gr.Group(visible=False)
789
  with step4:
790
  results_output = gr.Markdown()
791
  with gr.Row():
792
- restart_btn = gr.Button("🔄 Restart: Check Another Hospital", variant="secondary")
793
- download_btn = gr.Button("📥 Download: Save Results", variant="secondary")
794
  download_file = gr.File(visible=False, label="Download")
795
 
796
  # --- Follow-up chat section ---
797
  gr.Markdown("---")
798
- gr.Markdown("### 💬 Follow-Up Questions")
799
- gr.Markdown("Ask questions about your eligibility, the application process, required documents, or appeal rights.")
800
 
801
  chatbot = gr.Chatbot(
802
- label="Chat",
803
  height=350,
804
  )
805
 
806
- # Suggested prompt buttons
807
- with gr.Row():
808
  prompt_btn_1 = gr.Button("What documents do I need to apply?", size="sm")
809
  prompt_btn_2 = gr.Button("Can I appeal if I'm denied?", size="sm")
810
- with gr.Row():
811
  prompt_btn_3 = gr.Button("Does this cover emergency visits?", size="sm")
812
  prompt_btn_4 = gr.Button("How do I contact the financial assistance office?", size="sm")
813
 
 
631
  # === CUSTOM CSS ===
632
 
633
  custom_css = """
634
+ /* ===== CT.GOV / OHA Official Branding ===== */
635
+
636
+ /* --- Global --- */
637
  .gradio-container {
638
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif !important;
639
+ max-width: 1100px !important;
640
+ margin: 0 auto !important;
641
+ background: #FFFFFF !important;
642
+ color: #212529 !important;
643
+ font-size: 16px !important;
644
+ line-height: 1.6 !important;
645
  }
646
 
647
+ /* --- CT.GOV Top Bar --- */
648
+ .ct-gov-bar {
649
+ background: #00264D;
650
+ color: #FFFFFF;
651
+ font-size: 0.8rem;
652
+ padding: 6px 24px;
653
+ letter-spacing: 0.03em;
654
+ margin: -16px -16px 0 -16px;
655
+ }
656
+ .ct-gov-bar span {
657
+ opacity: 0.85;
658
  }
659
 
660
+ /* --- Blue Header Band --- */
661
+ .oha-header {
662
+ background: #003DA5;
663
+ color: #FFFFFF;
664
+ padding: 1.25rem 24px;
665
+ margin: 0 -16px 1.5rem -16px;
666
+ }
667
+ .oha-header h1 {
668
+ color: #FFFFFF !important;
669
+ font-size: 1.75rem !important;
670
+ font-weight: 300 !important;
671
+ margin: 0 !important;
672
+ padding: 0 !important;
673
  border: none !important;
674
+ line-height: 1.3;
675
+ }
676
+ .oha-header .oha-subtitle {
677
+ color: rgba(255,255,255,0.85);
678
+ font-size: 0.95rem;
679
+ margin-top: 0.25rem;
680
+ font-weight: 400;
681
+ }
682
+ .oha-header .oha-beta {
683
+ display: inline-block;
684
+ background: rgba(255,255,255,0.2);
685
+ color: #FFFFFF;
686
+ padding: 2px 10px;
687
+ border-radius: 3px;
688
+ font-size: 0.7rem;
689
+ font-weight: 600;
690
+ letter-spacing: 0.08em;
691
+ margin-left: 0.75rem;
692
+ vertical-align: middle;
693
+ }
694
+
695
+ /* --- Language Toggle --- */
696
+ .lang-toggle {
697
+ text-align: right;
698
+ padding-top: 2px;
699
+ }
700
+ .lang-toggle .gr-radio-group, .lang-toggle label {
701
+ color: #FFFFFF !important;
702
  }
703
 
704
+ /* --- Section Cards / Groups --- */
705
+ .gr-group {
706
+ background: #FFFFFF !important;
707
+ padding: 1.5rem !important;
708
+ border-radius: 6px !important;
709
+ border: 1px solid #E0E0E0 !important;
710
+ box-shadow: 0 1px 3px rgba(0,0,0,0.06) !important;
711
+ margin-bottom: 1rem !important;
712
  }
713
 
714
+ /* --- Headings --- */
715
+ h1 {
716
+ color: #003DA5 !important;
717
+ font-weight: 300 !important;
718
  border: none !important;
719
+ padding: 0 !important;
720
+ }
721
+ h2 {
722
+ color: #003DA5 !important;
723
+ font-weight: 500 !important;
724
+ font-size: 1.35rem !important;
725
+ border-bottom: 2px solid #E0E0E0;
726
+ padding-bottom: 0.5rem;
727
+ margin-bottom: 1rem;
728
+ }
729
+ h3 {
730
+ color: #212529 !important;
731
+ font-weight: 500 !important;
732
+ font-size: 1.05rem !important;
733
  }
734
 
735
+ /* --- Body Text --- */
736
+ p, span, div {
737
+ color: #212529;
 
738
  }
739
 
740
+ /* --- Links --- */
741
+ a {
742
+ color: #003DA5 !important;
743
+ text-decoration: none;
744
+ }
745
+ a:hover {
746
+ text-decoration: underline;
747
+ color: #00264D !important;
748
  }
749
 
750
+ /* --- Labels --- */
751
  label {
752
  color: #212529 !important;
753
  font-weight: 500 !important;
754
+ font-size: 0.95rem !important;
755
+ margin-bottom: 0.4rem !important;
756
  }
757
 
758
+ /* --- Form Inputs --- */
759
+ input[type="text"], input[type="number"], textarea, select,
760
+ .gr-box, .gr-input, .gr-dropdown {
761
+ border: 1px solid #CED4DA !important;
762
+ border-radius: 4px !important;
763
+ padding: 0.5rem 0.75rem !important;
764
+ font-size: 1rem !important;
765
+ color: #212529 !important;
766
+ background: #FFFFFF !important;
767
+ }
768
+ input:focus, textarea:focus, select:focus {
769
+ border-color: #003DA5 !important;
770
+ box-shadow: 0 0 0 2px rgba(0,61,165,0.15) !important;
771
+ outline: none !important;
772
  }
773
 
774
+ /* --- Primary Buttons --- */
775
+ .gr-button-primary, button.primary {
776
+ background: #003DA5 !important;
777
+ color: #FFFFFF !important;
778
+ border: none !important;
779
+ border-radius: 5px !important;
780
+ font-weight: 500 !important;
781
+ font-size: 0.95rem !important;
782
+ padding: 0.6rem 1.5rem !important;
783
+ transition: background 0.15s ease !important;
784
+ }
785
+ .gr-button-primary:hover, button.primary:hover {
786
+ background: #002D7A !important;
787
+ }
788
+
789
+ /* --- Secondary Buttons --- */
790
+ .gr-button-secondary, button.secondary {
791
+ background: #FFFFFF !important;
792
+ color: #003DA5 !important;
793
+ border: 1.5px solid #003DA5 !important;
794
+ border-radius: 5px !important;
795
+ font-weight: 500 !important;
796
+ font-size: 0.95rem !important;
797
+ padding: 0.6rem 1.5rem !important;
798
+ transition: all 0.15s ease !important;
799
+ }
800
+ .gr-button-secondary:hover, button.secondary:hover {
801
+ background: #F0F4FA !important;
802
+ border-color: #002D7A !important;
803
+ }
804
+
805
+ /* --- Small / Back Buttons --- */
806
+ button.sm {
807
+ font-size: 0.85rem !important;
808
+ padding: 0.35rem 0.9rem !important;
809
  color: #495057 !important;
810
+ background: transparent !important;
811
+ border: 1px solid #CED4DA !important;
812
+ border-radius: 4px !important;
813
+ }
814
+ button.sm:hover {
815
+ background: #F5F5F5 !important;
816
+ color: #212529 !important;
817
  }
818
 
819
+ /* --- Suggested Prompt Pill Buttons --- */
820
+ .prompt-pill button {
821
+ background: #FFFFFF !important;
822
+ color: #003DA5 !important;
823
+ border: 1.5px solid #003DA5 !important;
824
+ border-radius: 20px !important;
825
+ font-size: 0.85rem !important;
826
+ font-weight: 400 !important;
827
+ padding: 0.4rem 1rem !important;
828
+ transition: all 0.15s ease !important;
829
+ }
830
+ .prompt-pill button:hover {
831
+ background: #003DA5 !important;
832
+ color: #FFFFFF !important;
833
  }
834
 
835
+ /* --- Results / Disclaimer --- */
836
+ blockquote {
837
+ background: #FFF8E1 !important;
838
+ border-left: 4px solid #FFC107 !important;
839
+ padding: 0.75rem 1rem !important;
840
+ border-radius: 4px !important;
841
+ font-size: 0.9rem !important;
842
+ color: #495057 !important;
843
+ margin: 0 0 1rem 0 !important;
844
+ }
845
+
846
+ /* --- Status Badge --- */
847
+ .markdown-text h3 {
848
+ font-size: 1.05rem !important;
849
+ }
850
+
851
+ /* --- Chatbot --- */
852
+ .chatbot {
853
+ border: 1px solid #E0E0E0 !important;
854
+ border-radius: 6px !important;
855
+ }
856
+
857
+ /* --- Map iframe --- */
858
+ .map-embed iframe {
859
+ border-radius: 6px;
860
+ border: 1px solid #E0E0E0;
861
+ }
862
+
863
+ /* --- Horizontal rules in markdown --- */
864
+ hr {
865
+ border: none !important;
866
+ border-top: 1px solid #E0E0E0 !important;
867
+ margin: 1rem 0 !important;
868
+ }
869
+
870
+ /* --- File download --- */
871
+ .gr-file {
872
+ border: 1px solid #E0E0E0 !important;
873
+ border-radius: 4px !important;
874
  }
875
  """
876
 
 
879
  def create_interface():
880
  """Build and return the Gradio Blocks interface with all steps and event wiring."""
881
  with gr.Blocks(
882
+ theme=gr.themes.Default(
883
+ primary_hue=gr.themes.Color(
884
+ c50="#F0F4FA", c100="#D6E2F5", c200="#AECAEF",
885
+ c300="#7BAEE6", c400="#4A8FDB", c500="#003DA5",
886
+ c600="#003490", c700="#002D7A", c800="#00264D",
887
+ c900="#001B3A", c950="#001028",
888
+ ),
889
+ neutral_hue=gr.themes.Color(
890
+ c50="#F5F5F5", c100="#E0E0E0", c200="#CED4DA",
891
+ c300="#ADB5BD", c400="#6C757D", c500="#495057",
892
+ c600="#343A40", c700="#212529", c800="#1A1E21",
893
+ c900="#111315", c950="#0A0C0D",
894
+ ),
895
+ font=["-apple-system", "BlinkMacSystemFont", "Segoe UI", "Roboto", "Helvetica Neue", "Arial", "sans-serif"],
896
+ ),
897
  css=custom_css
898
  ) as demo:
899
 
 
903
  chat_history_state = gr.State([]) # List of {"role":..., "content":...} dicts
904
  chat_count_state = gr.State(0) # Message counter for rate limiting
905
 
906
+ # CT.GOV top bar (decorative)
907
+ gr.HTML(
908
+ '<div class="ct-gov-bar">'
909
+ '<span><strong>CT.GOV</strong> &nbsp;|&nbsp; State of Connecticut</span>'
910
+ '</div>'
911
+ )
912
+
913
+ # OHA blue header band with language toggle
914
+ gr.HTML(
915
+ '<div class="oha-header">'
916
+ '<div style="display:flex; justify-content:space-between; align-items:center;">'
917
+ '<div>'
918
+ '<h1>Office of the Healthcare Advocate<span class="oha-beta">BETA</span></h1>'
919
+ '<div class="oha-subtitle">Hospital Financial Assistance Eligibility Screener</div>'
920
+ '</div>'
921
+ '</div>'
922
+ '</div>'
923
+ )
924
+
925
  with gr.Row():
926
+ with gr.Column():
927
+ pass
928
+ with gr.Column(scale=0, min_width=160):
929
  lang_toggle = gr.Radio(
930
+ choices=["English", "Espa\u00f1ol"],
931
  value="English",
932
  label="Language",
933
  container=False
 
938
  with step1:
939
  gr.Markdown("### How would you like to start?")
940
  with gr.Row():
941
+ help_btn = gr.Button("Find a Hospital by ZIP Code", variant="primary", size="lg")
942
+ know_btn = gr.Button("I Know My Hospital", variant="secondary", size="lg")
943
 
944
  gr.HTML(
945
+ '<div class="map-embed" style="margin-top:1rem;">'
946
  '<iframe src="https://www.google.com/maps/d/u/0/embed?mid=1UVO9r7ZS26kZr8Q62dY0147v3Milu_s&ll=41.508444988744984%2C-72.7719992&z=9" '
947
+ 'width="100%" height="480" style="border:0; border-radius: 6px;" '
948
  'allowfullscreen="" loading="lazy" title="Map: Connecticut Hospital Locations"></iframe>'
949
+ '</div>'
950
  )
951
 
952
  # Step 2a: Find hospital by ZIP
 
959
  nearby_cards = gr.Markdown()
960
  hospital_radio = gr.Radio(label="Select a hospital", choices=[], visible=False)
961
  continue_btn_a = gr.Button("Continue", variant="primary", visible=False)
962
+ back_btn_a = gr.Button("Back", size="sm")
963
 
964
  # Step 2b: Select known hospital
965
  step2b = gr.Group(visible=False)
 
970
  label="Hospital"
971
  )
972
  continue_btn_b = gr.Button("Continue", variant="primary")
973
+ back_btn_b = gr.Button("Back", size="sm")
974
 
975
  # Step 3: Eligibility form
976
  step3 = gr.Group(visible=False)
 
983
  insurance_radio = gr.Radio(choices=["Yes", "No"], label="Do you have health insurance?", value="No")
984
 
985
  check_btn = gr.Button("Check Eligibility", variant="primary", size="lg")
986
+ back_btn_c = gr.Button("Back", size="sm")
987
 
988
  # Step 4: Results (with streaming) + follow-up chat
989
  step4 = gr.Group(visible=False)
990
  with step4:
991
  results_output = gr.Markdown()
992
  with gr.Row():
993
+ restart_btn = gr.Button("Check Another Hospital", variant="secondary")
994
+ download_btn = gr.Button("Download Results", variant="secondary")
995
  download_file = gr.File(visible=False, label="Download")
996
 
997
  # --- Follow-up chat section ---
998
  gr.Markdown("---")
999
+ gr.Markdown("### Follow-Up Questions")
1000
+ gr.Markdown("Have additional questions? Ask about eligibility, the application process, required documents, or appeal rights.")
1001
 
1002
  chatbot = gr.Chatbot(
1003
+ label="Conversation",
1004
  height=350,
1005
  )
1006
 
1007
+ # Suggested prompt buttons (pill-shaped via CSS)
1008
+ with gr.Row(elem_classes="prompt-pill"):
1009
  prompt_btn_1 = gr.Button("What documents do I need to apply?", size="sm")
1010
  prompt_btn_2 = gr.Button("Can I appeal if I'm denied?", size="sm")
1011
+ with gr.Row(elem_classes="prompt-pill"):
1012
  prompt_btn_3 = gr.Button("Does this cover emergency visits?", size="sm")
1013
  prompt_btn_4 = gr.Button("How do I contact the financial assistance office?", size="sm")
1014