AnirudhEsthuri-MV commited on
Commit
8bccf3c
Β·
unverified Β·
1 Parent(s): eff42b4

Update to purple theme - sync changes from test-playground

Browse files
Files changed (2) hide show
  1. app.py +252 -16
  2. styles.css +46 -1
app.py CHANGED
@@ -7,7 +7,7 @@ from urllib.parse import urlencode
7
  import requests
8
  import streamlit as st
9
 
10
- from gateway_client import delete_profile, ingest_and_rewrite
11
  from llm import chat, set_model
12
  from model_config import MODEL_CHOICES, MODEL_TO_PROVIDER, MODEL_DISPLAY_NAMES
13
 
@@ -116,13 +116,15 @@ def delete_session(session_name: str) -> bool:
116
 
117
 
118
  def rewrite_message(
119
- msg: str, persona_name: str, show_rationale: bool
120
  ) -> str:
121
- if persona_name.lower() == "control":
 
122
  rewritten_msg = msg
123
  if show_rationale:
124
  rewritten_msg += " At the beginning of your response, please say the following in ITALIC: 'Persona Rationale: No personalization applied.'. Begin your answer on the next line."
125
  return rewritten_msg
 
126
  try:
127
  rewritten_msg = ingest_and_rewrite(
128
  user_id=persona_name, query=msg
@@ -165,7 +167,7 @@ HEADER_STYLE = """
165
  border-radius: 0;
166
  }
167
  .memmachine-header-links .powered-by {
168
- color: #0a6cff;
169
  font-weight: 700;
170
  font-size: 16px;
171
  margin-right: 6px;
@@ -449,7 +451,7 @@ with st.sidebar:
449
  key="hf_token_input",
450
  type="password",
451
  placeholder="hf_xxxxxxxxxxxxxxxxxxxxx",
452
- help="Get your token from: https://huggingface.co/settings/tokens"
453
  )
454
 
455
  if st.button("Authenticate", use_container_width=True, type="primary"):
@@ -459,7 +461,20 @@ with st.sidebar:
459
  if is_valid and username:
460
  st.session_state.hf_authenticated_user = username
461
  st.session_state.hf_token = token_input.strip() # Store for future use
462
- st.success(f"βœ… Authenticated as **{username}**")
 
 
 
 
 
 
 
 
 
 
 
 
 
463
  st.rerun()
464
  else:
465
  error_display = error_msg if error_msg else "Invalid token. Please check your Hugging Face access token."
@@ -471,7 +486,20 @@ with st.sidebar:
471
  else:
472
  # User is authenticated - lock to their username
473
  persona_name = st.session_state.hf_authenticated_user
474
- st.success(f"πŸ” Authenticated as: **{persona_name}**")
 
 
 
 
 
 
 
 
 
 
 
 
 
475
  st.caption("Your memories are secured to your account only.")
476
  if st.button("πŸ”“ Sign Out", use_container_width=True):
477
  del st.session_state.hf_authenticated_user
@@ -495,7 +523,48 @@ with st.sidebar:
495
  custom_persona.strip() if custom_persona.strip() else selected_persona
496
  )
497
 
498
- compare_personas = st.checkbox("Compare without MemMachine")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
499
  show_rationale = st.checkbox("Show Persona Rationale")
500
 
501
  st.divider()
@@ -560,12 +629,117 @@ def typewriter_effect(text: str, speed: float = 0.02):
560
  yield " " + word
561
  time.sleep(speed)
562
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
563
  msg = st.chat_input("Type your message…")
564
  if msg:
565
  st.session_state.history.append({"role": "user", "content": msg})
566
- if compare_personas:
 
 
567
  all_answers = {}
568
- rewritten_msg = rewrite_message(msg, persona_name, show_rationale)
569
  msgs = clean_history(st.session_state.history, persona_name)
570
  msgs = append_user_turn(msgs, rewritten_msg)
571
  try:
@@ -575,7 +749,7 @@ if msg:
575
  st.error(f"❌ {str(e)}")
576
  st.stop()
577
 
578
- rewritten_msg_control = rewrite_message(msg, "Control", show_rationale)
579
  msgs_control = clean_history(st.session_state.history, "Control")
580
  msgs_control = append_user_turn(msgs_control, rewritten_msg_control)
581
  try:
@@ -589,12 +763,13 @@ if msg:
589
  {"role": "assistant_all", "axis": "role", "content": all_answers, "is_new": True}
590
  )
591
  else:
592
- rewritten_msg = rewrite_message(msg, persona_name, show_rationale)
 
593
  msgs = clean_history(st.session_state.history, persona_name)
594
  msgs = append_user_turn(msgs, rewritten_msg)
595
  try:
596
  txt, lat, tok, tps = chat(
597
- msgs, "Arnold" if persona_name == "Control" else persona_name
598
  )
599
  st.session_state.history.append(
600
  {"role": "assistant", "persona": persona_name, "content": txt, "is_new": True}
@@ -605,6 +780,23 @@ if msg:
605
  st.rerun()
606
 
607
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
608
  # ──��───────────────────────────────────────────────────────────
609
  # Chat history display
610
  # ──────────────────────────────────────────────────────────────
@@ -624,11 +816,42 @@ for turn in st.session_state.history:
624
  content_items = list(turn["content"].items())
625
  is_new = turn.get("is_new", False)
626
  if len(content_items) >= 2:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
627
  cols = st.columns([1, 0.03, 1])
628
  persona_label, persona_response = content_items[0]
629
  control_label, control_response = content_items[1]
630
  with cols[0]:
631
- st.markdown(f"**{persona_label}**")
 
 
 
 
 
 
 
 
 
 
 
 
 
632
  if is_new:
633
  st.write_stream(typewriter_effect(persona_response))
634
  else:
@@ -641,7 +864,20 @@ for turn in st.session_state.history:
641
  '<div class="vertical-divider"></div>', unsafe_allow_html=True
642
  )
643
  with cols[2]:
644
- st.markdown(f"**{control_label}**")
 
 
 
 
 
 
 
 
 
 
 
 
 
645
  if is_new:
646
  st.write_stream(typewriter_effect(control_response))
647
  else:
@@ -660,4 +896,4 @@ for turn in st.session_state.history:
660
  )
661
  # Mark as no longer new
662
  if is_new:
663
- turn["is_new"] = False
 
7
  import requests
8
  import streamlit as st
9
 
10
+ from gateway_client import delete_profile, ingest_and_rewrite, get_memories, ingest_memories
11
  from llm import chat, set_model
12
  from model_config import MODEL_CHOICES, MODEL_TO_PROVIDER, MODEL_DISPLAY_NAMES
13
 
 
116
 
117
 
118
  def rewrite_message(
119
+ msg: str, persona_name: str, show_rationale: bool, use_memory: bool = True
120
  ) -> str:
121
+ # If memory is disabled or Control persona, don't use memory
122
+ if not use_memory or persona_name.lower() == "control":
123
  rewritten_msg = msg
124
  if show_rationale:
125
  rewritten_msg += " At the beginning of your response, please say the following in ITALIC: 'Persona Rationale: No personalization applied.'. Begin your answer on the next line."
126
  return rewritten_msg
127
+
128
  try:
129
  rewritten_msg = ingest_and_rewrite(
130
  user_id=persona_name, query=msg
 
167
  border-radius: 0;
168
  }
169
  .memmachine-header-links .powered-by {
170
+ color: #667eea;
171
  font-weight: 700;
172
  font-size: 16px;
173
  margin-right: 6px;
 
451
  key="hf_token_input",
452
  type="password",
453
  placeholder="hf_xxxxxxxxxxxxxxxxxxxxx",
454
+ help="❓ Create a Read token: https://huggingface.co/settings/tokens"
455
  )
456
 
457
  if st.button("Authenticate", use_container_width=True, type="primary"):
 
461
  if is_valid and username:
462
  st.session_state.hf_authenticated_user = username
463
  st.session_state.hf_token = token_input.strip() # Store for future use
464
+ # Use custom purple styling instead of green success message
465
+ st.markdown(f"""
466
+ <div style="
467
+ background-color: rgba(102, 126, 234, 0.1);
468
+ border-left: 4px solid #667eea;
469
+ padding: 0.75rem 1rem;
470
+ border-radius: 0.25rem;
471
+ margin-bottom: 0.5rem;
472
+ ">
473
+ <div style="color: #667eea; font-weight: 500;">
474
+ βœ… Authenticated as <strong>{username}</strong>
475
+ </div>
476
+ </div>
477
+ """, unsafe_allow_html=True)
478
  st.rerun()
479
  else:
480
  error_display = error_msg if error_msg else "Invalid token. Please check your Hugging Face access token."
 
486
  else:
487
  # User is authenticated - lock to their username
488
  persona_name = st.session_state.hf_authenticated_user
489
+ # Use custom purple styling instead of green success message
490
+ st.markdown(f"""
491
+ <div style="
492
+ background-color: rgba(102, 126, 234, 0.1);
493
+ border-left: 4px solid #667eea;
494
+ padding: 0.75rem 1rem;
495
+ border-radius: 0.25rem;
496
+ margin-bottom: 0.5rem;
497
+ ">
498
+ <div style="color: #667eea; font-weight: 500;">
499
+ πŸ” Authenticated as: <strong>{persona_name}</strong>
500
+ </div>
501
+ </div>
502
+ """, unsafe_allow_html=True)
503
  st.caption("Your memories are secured to your account only.")
504
  if st.button("πŸ”“ Sign Out", use_container_width=True):
505
  del st.session_state.hf_authenticated_user
 
523
  custom_persona.strip() if custom_persona.strip() else selected_persona
524
  )
525
 
526
+ # Memory toggle - default enabled
527
+ if "memmachine_enabled" not in st.session_state:
528
+ st.session_state.memmachine_enabled = True
529
+ if "compare_personas" not in st.session_state:
530
+ st.session_state.compare_personas = True
531
+
532
+ memmachine_enabled = st.checkbox(
533
+ "Enable MemMachine",
534
+ value=st.session_state.memmachine_enabled,
535
+ help="Enable MemMachine's persistent memory system. When unchecked, the AI will respond without memory (Control Persona mode)."
536
+ )
537
+ st.session_state.memmachine_enabled = memmachine_enabled
538
+
539
+ if memmachine_enabled:
540
+ # Enhanced "Compare with control persona" section with cool styling
541
+ st.markdown("""
542
+ <div style="
543
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
544
+ padding: 1rem;
545
+ border-radius: 0.5rem;
546
+ margin: 0.5rem 0;
547
+ border: 2px solid rgba(255, 255, 255, 0.2);
548
+ box-shadow: 0 4px 15px rgba(102, 126, 234, 0.3);
549
+ ">
550
+ <div style="display: flex; align-items: center; gap: 0.5rem; color: white;">
551
+ <span style="font-size: 1.5rem;">βš–οΈ</span>
552
+ <div>
553
+ <div style="font-weight: 600; font-size: 1rem;">Side-by-Side Comparison with Control Persona</div>
554
+ <div style="font-size: 0.85rem; opacity: 0.9;">Compare MemMachine responses vs Control Persona (no memory)</div>
555
+ </div>
556
+ </div>
557
+ </div>
558
+ """, unsafe_allow_html=True)
559
+
560
+ compare_personas = st.checkbox(
561
+ "πŸ”„ Compare with control persona",
562
+ value=st.session_state.compare_personas,
563
+ help="Enable side-by-side comparison to see how MemMachine's persistent memory enhances responses compared to the control persona (no memory)"
564
+ )
565
+ st.session_state.compare_personas = compare_personas
566
+ else:
567
+ compare_personas = False
568
  show_rationale = st.checkbox("Show Persona Rationale")
569
 
570
  st.divider()
 
629
  yield " " + word
630
  time.sleep(speed)
631
 
632
+ # ──────────────────────────────────────────────────────────────
633
+ # Load Previous Memories Section (Import External Memories)
634
+ # ──────────────────────────────────────────────────────────────
635
+ if "memories_preview" not in st.session_state:
636
+ st.session_state.memories_preview = None
637
+ if "imported_memories_text" not in st.session_state:
638
+ st.session_state.imported_memories_text = ""
639
+
640
+ # Add expandable section for importing memories
641
+ with st.expander("πŸ“‹ Load Previous Memories (Import from ChatGPT, etc.)", expanded=False):
642
+ st.markdown("**Paste your conversation history or memories from external sources (e.g., ChatGPT, other AI chats)**")
643
+
644
+ # Text area for pasting memories
645
+ imported_text = st.text_area(
646
+ "Paste your memories/conversations here",
647
+ value=st.session_state.imported_memories_text,
648
+ height=200,
649
+ placeholder="Example:\nUser: What is machine learning?\nAssistant: Machine learning is...\n\nUser: Can you explain neural networks?\nAssistant: Neural networks are...",
650
+ help="Paste any conversation history, notes, or context you want the AI to remember. These will be ingested into MemMachine's memory system and available for future conversations.",
651
+ key="import_memories_textarea"
652
+ )
653
+
654
+ # File upload option
655
+ uploaded_file = st.file_uploader(
656
+ "Or upload a text file",
657
+ type=['txt', 'md', 'json'],
658
+ help="Upload a text file containing your conversation history or memories"
659
+ )
660
+
661
+ if uploaded_file is not None:
662
+ try:
663
+ # Read file content
664
+ if uploaded_file.type == "application/json":
665
+ import json
666
+ file_content = json.loads(uploaded_file.read().decode("utf-8"))
667
+ imported_text = str(file_content)
668
+ else:
669
+ imported_text = uploaded_file.read().decode("utf-8")
670
+ st.session_state.imported_memories_text = imported_text
671
+ st.success("File loaded successfully!")
672
+ except Exception as e:
673
+ st.error(f"Error reading file: {e}")
674
+
675
+ col1, col2 = st.columns(2)
676
+
677
+ with col1:
678
+ if st.button("πŸ‘οΈ Preview", use_container_width=True, key="preview_memories"):
679
+ if imported_text and imported_text.strip():
680
+ st.session_state.memories_preview = imported_text
681
+ st.session_state.imported_memories_text = imported_text
682
+ st.rerun()
683
+ else:
684
+ st.warning("Please paste or upload some memories first.")
685
+
686
+ with col2:
687
+ if st.button("πŸ’‰ Ingest into MemMachine", use_container_width=True, key="inject_memories_direct"):
688
+ if imported_text and imported_text.strip():
689
+ if persona_name and persona_name != "Control":
690
+ with st.spinner("Ingesting memories into MemMachine..."):
691
+ success = ingest_memories(persona_name, imported_text)
692
+ if success:
693
+ st.session_state.imported_memories_text = imported_text
694
+ st.success("βœ… Memories successfully ingested into MemMachine! They are now part of your memory system.")
695
+ else:
696
+ st.error("❌ Failed to ingest memories. Please try again.")
697
+ else:
698
+ st.warning("Please authenticate or select a persona to ingest memories.")
699
+ st.rerun()
700
+ else:
701
+ st.warning("Please paste or upload some memories first.")
702
+
703
+ # Show preview if memories are loaded
704
+ if st.session_state.memories_preview:
705
+ with st.expander("πŸ“‹ Preview Imported Memories", expanded=True):
706
+ memories = st.session_state.memories_preview
707
+ preview_text = str(memories)[:2000] # Show first 2000 chars
708
+
709
+ if preview_text:
710
+ st.text_area("Memories Preview", preview_text, height=200, disabled=True, key="memories_preview_text")
711
+ st.caption(f"Total length: {len(str(memories))} characters")
712
+
713
+ col1, col2 = st.columns(2)
714
+ with col1:
715
+ if st.button("πŸ’‰ Ingest into MemMachine", use_container_width=True, key="inject_memories_from_preview"):
716
+ if persona_name and persona_name != "Control":
717
+ with st.spinner("Ingesting memories into MemMachine..."):
718
+ success = ingest_memories(persona_name, str(st.session_state.memories_preview))
719
+ if success:
720
+ st.success("βœ… Memories successfully ingested into MemMachine! They are now part of your memory system.")
721
+ else:
722
+ st.error("❌ Failed to ingest memories. Please try again.")
723
+ else:
724
+ st.warning("Please authenticate or select a persona to ingest memories.")
725
+ st.rerun()
726
+ with col2:
727
+ if st.button("πŸ—‘οΈ Clear", use_container_width=True, key="clear_memories_preview"):
728
+ st.session_state.memories_preview = None
729
+ st.session_state.imported_memories_text = ""
730
+ st.rerun()
731
+ else:
732
+ st.info("No memories to preview.")
733
+ st.session_state.memories_preview = None
734
+
735
  msg = st.chat_input("Type your message…")
736
  if msg:
737
  st.session_state.history.append({"role": "user", "content": msg})
738
+ memmachine_enabled = st.session_state.get("memmachine_enabled", True)
739
+
740
+ if compare_personas and memmachine_enabled:
741
  all_answers = {}
742
+ rewritten_msg = rewrite_message(msg, persona_name, show_rationale, use_memory=True)
743
  msgs = clean_history(st.session_state.history, persona_name)
744
  msgs = append_user_turn(msgs, rewritten_msg)
745
  try:
 
749
  st.error(f"❌ {str(e)}")
750
  st.stop()
751
 
752
+ rewritten_msg_control = rewrite_message(msg, "Control", show_rationale, use_memory=False)
753
  msgs_control = clean_history(st.session_state.history, "Control")
754
  msgs_control = append_user_turn(msgs_control, rewritten_msg_control)
755
  try:
 
763
  {"role": "assistant_all", "axis": "role", "content": all_answers, "is_new": True}
764
  )
765
  else:
766
+ # Use memory only if memmachine_enabled is True
767
+ rewritten_msg = rewrite_message(msg, persona_name, show_rationale, use_memory=memmachine_enabled)
768
  msgs = clean_history(st.session_state.history, persona_name)
769
  msgs = append_user_turn(msgs, rewritten_msg)
770
  try:
771
  txt, lat, tok, tps = chat(
772
+ msgs, "Arnold" if persona_name == "Control" or not memmachine_enabled else persona_name
773
  )
774
  st.session_state.history.append(
775
  {"role": "assistant", "persona": persona_name, "content": txt, "is_new": True}
 
780
  st.rerun()
781
 
782
 
783
+ # ──────────────────────────────────────────────────────────────
784
+ # Memory Status Indicator
785
+ # ──────────────────────────────────────────────────────────────
786
+ memmachine_enabled = st.session_state.get("memmachine_enabled", True)
787
+ status_emoji = "🧠" if memmachine_enabled else "βšͺ"
788
+ status_text = "MemMachine Active" if memmachine_enabled else "No Memory Mode"
789
+
790
+ # Add status indicator at the top of chat area
791
+ status_html = f"""
792
+ <div style="display: flex; justify-content: flex-end; margin-bottom: 1rem; padding: 0.5rem 1rem; background: #f0f2f6; border-radius: 0.5rem; border: 1px solid #e0e0e0;">
793
+ <span style="font-size: 0.9rem; color: #666;">
794
+ {status_emoji} <strong>{status_text}</strong>
795
+ </span>
796
+ </div>
797
+ """
798
+ st.markdown(status_html, unsafe_allow_html=True)
799
+
800
  # ──��───────────────────────────────────────────────────────────
801
  # Chat history display
802
  # ──────────────────────────────────────────────────────────────
 
816
  content_items = list(turn["content"].items())
817
  is_new = turn.get("is_new", False)
818
  if len(content_items) >= 2:
819
+ # Enhanced comparison header
820
+ st.markdown("""
821
+ <div style="
822
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
823
+ padding: 0.75rem 1rem;
824
+ border-radius: 0.5rem 0.5rem 0 0;
825
+ margin-bottom: 0.5rem;
826
+ display: flex;
827
+ align-items: center;
828
+ gap: 0.5rem;
829
+ color: white;
830
+ font-weight: 600;
831
+ ">
832
+ <span style="font-size: 1.2rem;">βš–οΈ</span>
833
+ <span>Side-by-Side Comparison</span>
834
+ </div>
835
+ """, unsafe_allow_html=True)
836
+
837
  cols = st.columns([1, 0.03, 1])
838
  persona_label, persona_response = content_items[0]
839
  control_label, control_response = content_items[1]
840
  with cols[0]:
841
+ st.markdown(f"""
842
+ <div style="
843
+ background: linear-gradient(135deg, rgba(102, 126, 234, 0.1) 0%, rgba(118, 75, 162, 0.1) 100%);
844
+ padding: 1rem;
845
+ border-radius: 0.5rem;
846
+ border-left: 4px solid #667eea;
847
+ margin-bottom: 1rem;
848
+ ">
849
+ <div style="display: flex; align-items: center; gap: 0.5rem; margin-bottom: 0.5rem;">
850
+ <span style="font-size: 1.2rem;">🧠</span>
851
+ <strong style="color: #667eea;">{persona_label}</strong>
852
+ </div>
853
+ </div>
854
+ """, unsafe_allow_html=True)
855
  if is_new:
856
  st.write_stream(typewriter_effect(persona_response))
857
  else:
 
864
  '<div class="vertical-divider"></div>', unsafe_allow_html=True
865
  )
866
  with cols[2]:
867
+ st.markdown(f"""
868
+ <div style="
869
+ background: linear-gradient(135deg, rgba(200, 200, 200, 0.1) 0%, rgba(150, 150, 150, 0.1) 100%);
870
+ padding: 1rem;
871
+ border-radius: 0.5rem;
872
+ border-left: 4px solid #888;
873
+ margin-bottom: 1rem;
874
+ ">
875
+ <div style="display: flex; align-items: center; gap: 0.5rem; margin-bottom: 0.5rem;">
876
+ <span style="font-size: 1.2rem;">βšͺ</span>
877
+ <strong style="color: #666;">{control_label}</strong>
878
+ </div>
879
+ </div>
880
+ """, unsafe_allow_html=True)
881
  if is_new:
882
  st.write_stream(typewriter_effect(control_response))
883
  else:
 
896
  )
897
  # Mark as no longer new
898
  if is_new:
899
+ turn["is_new"] = False
styles.css CHANGED
@@ -23,4 +23,49 @@ div[data-testid="column"] {
23
  height: 100%;
24
  border-left: 1px solid #ccc;
25
  margin: 0 0.4rem;
26
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23
  height: 100%;
24
  border-left: 1px solid #ccc;
25
  margin: 0 0.4rem;
26
+ }
27
+
28
+ /* Enhanced comparison section styling */
29
+ .comparison-card {
30
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
31
+ padding: 1rem;
32
+ border-radius: 0.5rem;
33
+ margin: 0.5rem 0;
34
+ border: 2px solid rgba(255, 255, 255, 0.2);
35
+ box-shadow: 0 4px 15px rgba(102, 126, 234, 0.3);
36
+ transition: transform 0.2s ease, box-shadow 0.2s ease;
37
+ }
38
+
39
+ .comparison-card:hover {
40
+ transform: translateY(-2px);
41
+ box-shadow: 0 6px 20px rgba(102, 126, 234, 0.4);
42
+ }
43
+
44
+ /* Comparison columns styling */
45
+ .comparison-column {
46
+ background: rgba(102, 126, 234, 0.05);
47
+ padding: 1rem;
48
+ border-radius: 0.5rem;
49
+ border: 1px solid rgba(102, 126, 234, 0.2);
50
+ }
51
+
52
+ /* Make primary buttons purple */
53
+ button[kind="primary"] {
54
+ background-color: #667eea !important;
55
+ border-color: #667eea !important;
56
+ }
57
+
58
+ button[kind="primary"]:hover {
59
+ background-color: #764ba2 !important;
60
+ border-color: #764ba2 !important;
61
+ }
62
+
63
+ /* Make success messages purple */
64
+ div[data-testid="stSuccess"] {
65
+ background-color: rgba(102, 126, 234, 0.1) !important;
66
+ border-left-color: #667eea !important;
67
+ }
68
+
69
+ div[data-testid="stSuccess"] > div {
70
+ color: #667eea !important;
71
+ }