# edit_history.py import difflib from datetime import datetime import streamlit as st def init_edit_history(): """Ensure edit history list exists in session_state.""" if "edit_history" not in st.session_state: st.session_state.edit_history = [] def add_edit(old_text: str, new_text: str, source: str | None = None): """ Append an edit event to history. - old_text: text before edit - new_text: text after edit - source: where this edit came from (e.g., "In-place Chat", "System") """ init_edit_history() st.session_state.edit_history.append( { "old": old_text, "new": new_text, "source": source, "ts": datetime.now().strftime("%H:%M:%S"), } ) def _render_diff_html(old: str, new: str) -> str: """ Return HTML for a git-style diff: - removed tokens: red, strikethrough - added tokens: green - unchanged: normal """ # word-level diff diff = difflib.ndiff(old.split(), new.split()) parts: list[str] = [] for token in diff: code = token[:2] # "+ ", "- ", or " " word = token[2:] if code == "+ ": # Added text in green parts.append( f"{word}" ) elif code == "- ": # Removed text in red with strikethrough parts.append( f"{word}" ) else: parts.append(word) return " ".join(parts) def render_edit_history_sidebar(max_items: int = 20): """ Render the edit history inside the sidebar. Call this inside a sidebar container. """ init_edit_history() with st.expander("Edit history", expanded=True): history = st.session_state.edit_history if not history: st.caption("No edits yet. Edits will appear here.") return # Show most recent first for idx, item in enumerate(reversed(history[-max_items:]), start=1): header_html = "
" # Title + meta info meta_bits = [] if "ts" in item: meta_bits.append(item["ts"]) if item.get("source"): meta_bits.append(item["source"]) meta_html = " ยท ".join(meta_bits) header_html += f"Edit {len(history) - idx + 1}" if meta_html: header_html += ( f" " f"{meta_html}" ) header_html += "
" st.markdown(header_html, unsafe_allow_html=True) diff_html = _render_diff_html(item["old"], item["new"]) st.markdown( f"
{diff_html}
", unsafe_allow_html=True, ) st.markdown( "
", unsafe_allow_html=True, )