Spaces:
Running
Running
Update to purple theme - sync changes from test-playground
Browse files- app.py +252 -16
- 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 |
-
|
|
|
|
| 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: #
|
| 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="
|
| 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 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
-
|
|
|
|
|
|
|
| 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 |
-
|
|
|
|
| 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"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
+
}
|