Spaces:
Running
Running
File size: 7,319 Bytes
9a7b741 fec7628 9a7b741 fec7628 9a7b741 fec7628 9a7b741 fec7628 9a7b741 fec7628 9a7b741 86f15b3 9a7b741 78a3087 fec7628 9a7b741 fec7628 9a7b741 fec7628 9a7b741 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 |
# streamlit_app.py
import streamlit as st
import pandas as pd
import numpy as np
from pathlib import Path
import uuid
from cards import (
chat_card,
inplace_chat_card
)
# ---------- Global state init ----------
if "init" not in st.session_state:
st.session_state.init = True
st.session_state.conversations = {} # {chat_id: {"title": str, "messages": [...]}}
st.session_state.current_chat_id = None # which conversation is open
def create_new_conversation():
chat_id = str(uuid.uuid4())
st.session_state.conversations[chat_id] = {
"title": "New chat",
"messages": [],
"editable": False,
"prev_text": "",
"edited_text": "",
"original_user_prompt": "",
"edit_history": []
}
st.session_state.current_chat_id = chat_id
# ensure at least one conversation exists
if not st.session_state.conversations:
create_new_conversation()
# Fix code block font rendering - force monospace
st.markdown("""
<style>
code, pre, pre code {
font-family: 'Space Mono', monospace !important;
font-size: 0.95rem !important;
line-height: 1.4 !important;
font-weight: 400 !important;
}
</style>
""", unsafe_allow_html=True)
pages = [
st.Page(
"inplace_chat.py",
title="In-place Feedback Chat",
icon=":material/edit_document:"
),
st.Page(
"chat.py",
title="Chat",
icon=":material/chat:"
)
]
page = st.navigation(pages)
# ---------- Sidebar: ChatGPT-style history ----------
with st.sidebar:
# new chat button
st.write("This is a simple demo for CSED499 Inplace feedback.")
st.button(
"+ New chat",
use_container_width=True,
on_click=create_new_conversation,
)
st.markdown("---")
st.markdown("### Chat History")
# Add custom CSS for hover effect on chat history items
st.markdown("""
<style>
/* Chat history item buttons */
.stButton > button[kind="secondary"] {
background-color: transparent;
border: none;
color: inherit;
padding: 8px 12px;
text-align: left;
width: 100%;
border-radius: 8px;
transition: background-color 0.2s;
justify-content: flex-start;
}
.stButton > button[kind="secondary"]:hover {
background-color: rgba(128, 128, 128, 0.2);
}
.stButton > button[kind="secondary"]:focus {
box-shadow: none;
}
/* Delete button styling */
.stButton > button[kind="secondary"].delete-btn {
width: auto;
padding: 4px 8px;
color: rgba(128, 128, 128, 0.6);
}
.stButton > button[kind="secondary"].delete-btn:hover {
color: rgba(128, 128, 128, 1);
background-color: rgba(128, 128, 128, 0.15);
}
</style>
""", unsafe_allow_html=True)
# list existing conversations as clickable text
for chat_id, conv in st.session_state.conversations.items():
# truncate title like ChatGPT
label = conv["title"]
if len(label) > 35:
label = label[:35] + "…"
# Create columns for chat item and delete button
col_chat, col_delete = st.columns([0.85, 0.15])
with col_chat:
# highlight current chat with a marker
if chat_id == st.session_state.current_chat_id:
st.markdown(f"**▶ {label}**")
else:
# Make entire text clickable with hover effect
if st.button(label, key=f"chat-{chat_id}", type="secondary", use_container_width=True):
st.session_state.current_chat_id = chat_id
st.rerun()
with col_delete:
# Delete button - only show for non-active chats or show for all
if st.button("✕", key=f"delete-{chat_id}", type="secondary", help="Delete chat"):
# If deleting current chat, switch to another one first
if chat_id == st.session_state.current_chat_id:
remaining = [cid for cid in st.session_state.conversations.keys() if cid != chat_id]
if remaining:
st.session_state.current_chat_id = remaining[0]
else:
st.session_state.current_chat_id = None
# Delete the conversation
del st.session_state.conversations[chat_id]
st.rerun()
# run selected page (after sidebar is defined)
page.run()
# === Edit History Panel ===
st.sidebar.markdown("### Edit History")
if st.session_state.current_chat_id:
current_conv = st.session_state.conversations.get(st.session_state.current_chat_id, {})
edit_history = current_conv.get("edit_history", [])
if edit_history:
st.sidebar.markdown("""
<style>
.diff-container {
font-family: 'Space Mono', monospace;
font-size: 0.85em;
line-height: 1.4;
margin: 8px 0;
padding: 8px;
background-color: rgba(128, 128, 128, 0.05);
border-radius: 4px;
}
.diff-delete {
background-color: rgba(255, 0, 0, 0.15);
color: #d73a49;
text-decoration: line-through;
padding: 2px 4px;
border-radius: 2px;
}
.diff-insert {
background-color: rgba(0, 255, 0, 0.15);
color: #22863a;
padding: 2px 4px;
border-radius: 2px;
}
.diff-equal {
color: inherit;
}
</style>
""", unsafe_allow_html=True)
for idx, edit in enumerate(reversed(edit_history)):
edit_num = len(edit_history) - idx
# Each edit as a collapsible expander
with st.sidebar.expander(f"Edit #{edit_num} at {edit['timestamp']}", expanded=False):
# Build the diff HTML
diff_html = "<div class='diff-container'>"
for chunk in edit.get('diff_chunks', []):
text = chunk['text'].replace('<', '<').replace('>', '>')
if chunk['tag'] == 'delete':
diff_html += f"<span class='diff-delete'>{text}</span>"
elif chunk['tag'] == 'insert':
diff_html += f"<span class='diff-insert'>{text}</span>"
else: # equal
# Truncate long unchanged sections
if len(text) > 100:
text = text[:50] + "..." + text[-50:]
diff_html += f"<span class='diff-equal'>{text}</span>"
diff_html += "</div>"
st.markdown(diff_html, unsafe_allow_html=True)
else:
st.sidebar.write("No edits yet in this conversation.")
else:
st.sidebar.write("No conversation selected.")
# st.markdown("---")
st.sidebar.caption(
"This app uses [Space Grotesk](https://fonts.google.com/specimen/Space+Grotesk) "
"and [Space Mono](https://fonts.google.com/specimen/Space+Mono) fonts."
)
|