deven367/llama.cpp-conversation-viewer
1
1import json2from datetime import datetime3 4import streamlit as st5 6# Set page config7st.set_page_config(page_title="Conversation Viewer", layout="wide")8 9@st.cache_data10def load_conversations(uploaded_file):11 """Load conversations from uploaded JSON file"""12 return json.load(uploaded_file)13 14def format_timestamp(timestamp):15 """Convert timestamp to readable format"""16 try:17 if timestamp > 1e12: # milliseconds18 timestamp = timestamp / 100019 return datetime.fromtimestamp(timestamp).strftime('%Y-%m-%d %H:%M:%S')20 except Exception:21 return "N/A"22 23def search_in_conversation(conv, search_term):24 """Check if search term exists in conversation"""25 if not search_term:26 return True27 28 search_term = search_term.lower()29 30 # Search in conversation name31 if search_term in conv['conv']['name'].lower():32 return True33 34 # Search in messages35 for msg in conv['messages']:36 if 'content' in msg and search_term in msg['content'].lower():37 return True38 39 return False40 41def display_message(msg):42 """Display a single message"""43 if msg['role'] == 'user':44 with st.chat_message("user"):45 st.markdown(msg['content'])46 elif msg['role'] == 'assistant':47 with st.chat_message("assistant"):48 # Remove <think> tags if present49 content = msg['content']50 51 # Handle <think> tags if present52 if '<think>' in content and '</think>' in content:53 start = content.find('<think>')54 end = content.find('</think>') + len('</think>')55 56 # Extract thinking content and response content57 thinking_content = content[start + len('<think>'):content.find('</think>')]58 response_content = content[end:].strip()59 60 # Display thinking content in a collapsed expander61 with st.expander("๐ง Internal Thinking", expanded=False):62 st.code(thinking_content.strip(), language="text", wrap_lines=True)63 64 # Display the actual response65 if response_content:66 st.markdown(response_content)67 else:68 # No thinking tags, display content normally69 st.markdown(content)70 71def main():72 st.title("๐ฌ Conversation Viewer")73 st.write("XSRF:", st.get_option("server.enableXsrfProtection"))74 75 # File uploader76 json_file = st.file_uploader("Upload JSON file", type="json")77 78 if json_file is None:79 st.info("๐ Please upload a JSON file containing your conversations to get started.")80 return81 82 try:83 conversations = load_conversations(json_file)84 85 # Sidebar for search and filtering86 with st.sidebar:87 st.header("Search & Filter")88 search_term = st.text_input("๐ Search conversations", "")89 90 st.divider()91 92 # Filter conversations93 filtered_convs = [94 conv for conv in conversations95 if search_in_conversation(conv, search_term)96 ]97 98 st.write(f"**{len(filtered_convs)}** conversations found")99 100 # Sort options101 sort_by = st.selectbox(102 "Sort by",103 ["Most Recent", "Oldest First", "Alphabetical"]104 )105 106 if sort_by == "Most Recent":107 filtered_convs.sort(key=lambda x: x['conv'].get('lastModified', 0), reverse=True)108 elif sort_by == "Oldest First":109 filtered_convs.sort(key=lambda x: x['conv'].get('lastModified', 0))110 else:111 filtered_convs.sort(key=lambda x: x['conv']['name'])112 113 st.divider()114 115 # Conversation list116 st.subheader("Conversations")117 selected_conv_id = st.radio(118 "Select a conversation",119 options=[conv['conv']['id'] for conv in filtered_convs],120 format_func=lambda x: next(121 (conv['conv']['name'][:50] + "..." if len(conv['conv']['name']) > 50122 else conv['conv']['name'])123 for conv in filtered_convs if conv['conv']['id'] == x124 ),125 label_visibility="collapsed"126 )127 128 # Main content area129 if filtered_convs:130 # Find selected conversation131 selected_conv = next(132 (conv for conv in filtered_convs if conv['conv']['id'] == selected_conv_id),133 filtered_convs[0]134 )135 136 # Display conversation details137 # have a border around this box138 st.write(selected_conv['conv']['name'])139 140 col1, col2, col3 = st.columns(3)141 with col1:142 st.metric("Messages", len(selected_conv['messages']) - 1) # Exclude root143 with col2:144 st.metric("Last Modified", format_timestamp(selected_conv['conv']['lastModified']))145 with col3:146 st.metric("Conv ID", selected_conv['conv']['id'][:8] + "...")147 148 st.divider()149 150 # Display messages151 messages = [msg for msg in selected_conv['messages'] if msg['role'] != 'root']152 153 for msg in messages:154 if msg['role'] in ['user', 'assistant']:155 display_message(msg)156 else:157 st.info("No conversations found matching your search.")158 159 except json.JSONDecodeError:160 st.error("โ Invalid JSON file format. Please upload a valid JSON file.")161 except Exception as e:162 st.error(f"โ Error loading conversations: {str(e)}")163 164if __name__ == "__main__":165 main()166 167 