Intention/IntentionStudy
0
1import streamlit as st2import pandas as pd3import json4import scrubadub5from vaderSentiment.vaderSentiment import SentimentIntensityAnalyzer6from pymongo.mongo_client import MongoClient7from pymongo.server_api import ServerApi8from datetime import datetime9from uuid import uuid410 11# -----------------------------12# Page Config13# -----------------------------14st.set_page_config(page_title="ChatGPT Log Analyzer", page_icon="๐ค")15 16# -----------------------------17# Sidebar: App Navigation & File Upload18# -----------------------------19st.sidebar.title("โ๏ธ Settings")20 21# Consent22if "consent" not in st.session_state:23 st.session_state.consent = ""24 25with st.sidebar.expander("Consent Form", expanded=True):26 st.radio(27 "**Do you consent to participating in this study?**", 28 ["", "Yes, I consent", "No, I do not consent"], 29 key="consent"30 )31 32# File Upload33uploaded_file = st.sidebar.file_uploader("๐ Upload ChatGPT export (.json)", type=["json"])34 35# Privacy Policy in Sidebar36with st.sidebar.expander("Privacy Policy", expanded=False):37 try:38 with open("PrivacyPolicy.md", "r") as f:39 st.markdown(f.read())40 except FileNotFoundError:41 st.error("Privacy policy file not found. Please add `privacy_policy.md`.")42 43# -----------------------------44# Consent Messages in Main Page45# -----------------------------46if st.session_state.consent == "Yes, I consent":47 if "id" not in st.session_state:48 st.session_state.id = datetime.now().strftime('%Y%m-%d%H-%M-') + str(uuid4())49 st.success("โ
You consented to participate.")50 st.info(f"Your anonymized ID is: **{st.session_state.id}**. Keep this if you want your data deleted later.")51 52elif st.session_state.consent == "No, I do not consent":53 st.warning("โ ๏ธ You did not consent. You can still use the app, but your logs will not be stored.")54 55# -----------------------------56# Parser Function57# -----------------------------58def parse_chatgpt_export(data):59 rows = []60 conversations = data.get("conversations", [])61 for conv in conversations:62 conv_id = conv.get("id")63 title = conv.get("title")64 mapping = conv.get("mapping", {})65 66 for msg_id, msg in mapping.items():67 author = msg.get("author", {})68 role = author.get("role", "unknown")69 content = msg.get("content", {})70 parts = content.get("parts", [])71 text = "\n".join(parts) if parts else ""72 73 rows.append({74 "conversation_id": conv_id,75 "title": title,76 "message_id": msg_id,77 "role": role,78 "content": text,79 "create_time": msg.get("create_time")80 })81 return pd.DataFrame(rows)82 83# -----------------------------84# Main Content (only if file uploaded)85# -----------------------------86if uploaded_file:87 data = json.load(uploaded_file)88 if isinstance(data, dict) and "conversations" in data:89 df = parse_chatgpt_export(data)90 else:91 st.error("Unsupported JSON structure")92 st.stop()93 94 # Conversation Selector95 st.subheader("๐ Select a Conversation")96 convo_titles = df["title"].unique()97 selected_title = st.selectbox("Choose conversation", convo_titles)98 99 convo_df = df[df["title"] == selected_title].copy()100 101 # Scrub + Sentiment102 cleaner = scrubadub.Scrubber()103 analyzer = SentimentIntensityAnalyzer()104 105 redacted_rows = []106 for i, row in convo_df.iterrows():107 original_text = str(row["content"])108 redacted_text = cleaner.clean(original_text)109 sentiment_score = analyzer.polarity_scores(original_text)["compound"]110 redacted_rows.append({111 **row,112 "redacted": redacted_text,113 "sentiment": sentiment_score114 })115 116 convo_df = pd.DataFrame(redacted_rows)117 118 # Inline PII Editing + Rating119 st.subheader(f"๐ฌ Conversation: {selected_title}")120 edited_rows = []121 for i, row in convo_df.iterrows():122 st.markdown(f"**{row['role'].capitalize()} ({row['create_time']}):**")123 124 # Editable text area for redacted content125 edited_text = st.text_area(126 f"Message {i}", 127 value=row["redacted"], 128 key=f"edit_{i}"129 )130 131 # Rating selector (1-10 scale)132 rating = st.slider(133 f"Rate Message {i}", 134 min_value=1, max_value=10, value=5, step=1,135 key=f"rating_{i}", 136 help="How persuasive was this message?"137 )138 139 edited_rows.append({140 **row,141 "redacted": edited_text,142 "rating": rating # โฌ
๏ธ new column143 })144 145 convo_df = pd.DataFrame(edited_rows)146 147 # Show wrapped DataFrame with rating included148 styled_df = (149 convo_df[["role", "redacted", "sentiment", "rating", "create_time"]]150 .style.set_properties(151 subset=["redacted"], 152 **{'white-space': 'normal', 'word-wrap': 'break-word'}153 )154 )155 st.dataframe(styled_df, use_container_width=True)156 157 # Optional: Save to MongoDB158 if st.button("๐ฅ Save Conversation to Database"):159 with MongoClient(st.secrets["mongo"], server_api=ServerApi('1')) as client:160 db = client.bridge161 collection = db.app162 record = {163 "conversation_id": convo_df["conversation_id"].iloc[0],164 "title": selected_title,165 "inserted_at": datetime.utcnow(),166 "messages": convo_df.to_dict(orient="records") # now includes rating167 }168 collection.insert_one(record)169 st.success(f"โ
Conversation '{selected_title}' saved to MongoDB with ratings.")170 