"""Case study viewer โ€” browse saved workflow conversations without API keys.""" import json from pathlib import Path import streamlit as st # Search paths for saved conversations and case-study-memory examples _APP_ROOT = Path(__file__).resolve().parent.parent # streamlit-client/ _PROJECT_ROOT = _APP_ROOT.parent # SciDER/ _CASE_STUDY_DIRS = [ _APP_ROOT / "saved_chats", # conversations saved by the app's own workflows _PROJECT_ROOT / "case-study-memory", # pre-bundled example case studies _APP_ROOT / "case-study-memory", ] def list_case_studies() -> list[tuple[Path, dict]]: """List all chat_history.json files in case-study-memory directories.""" results = [] seen = set() for base in _CASE_STUDY_DIRS: if not base.exists(): continue dirs = sorted( [d for d in base.iterdir() if d.is_dir() and (d / "chat_history.json").exists()], key=lambda x: x.stat().st_mtime, reverse=True, ) for memo_dir in dirs: chat_file = memo_dir / "chat_history.json" key = str(chat_file.resolve()) if key in seen: continue seen.add(key) try: with open(chat_file, encoding="utf-8") as f: data = json.load(f) ts = data.get("timestamp", "")[:19].replace("T", " ") wf = data.get("workflow_type", "unknown") query = data.get("metadata", {}).get("query", "") label = (query[:80] + "...") if len(query) > 83 else (query or memo_dir.name) results.append((chat_file, {"label": label, "timestamp": ts, "workflow_type": wf})) except Exception: results.append( ( chat_file, {"label": memo_dir.name, "timestamp": "", "workflow_type": "unknown"}, ) ) return results _WORKFLOW_LABELS = { "ideation": "Ideation", "data": "Data Analysis", "experiment": "Experiment", "full": "Full Pipeline", } def render_case_study_viewer(): """Render the case study browser UI.""" st.markdown( """
๐Ÿ“š
Case Studies
Browse saved workflow conversations and workspace artifacts
""", unsafe_allow_html=True, ) available = list_case_studies() if not available: st.info("No case studies found. Run a workflow first to save conversations.") return options = [f"{m['label']} ({m['workflow_type']}, {m['timestamp']})" for _, m in available] idx = st.selectbox( "Select a case study", range(len(options)), format_func=lambda i: options[i], key="case_study_select", ) selected_path = available[idx][0] selected_meta = available[idx][1] with open(selected_path, encoding="utf-8") as f: data = json.load(f) # Metadata card wf_type = selected_meta["workflow_type"] wf_label = _WORKFLOW_LABELS.get(wf_type, wf_type.title()) query = data.get("metadata", {}).get("query", selected_meta["label"]) ts = selected_meta["timestamp"] st.markdown( f"""

{query}

{wf_label}  ยท  {ts}

""", unsafe_allow_html=True, ) # Workflow type badge + message count msg_count = len(data.get("messages", [])) st.markdown( f"{wf_label}  " f"{msg_count} messages", unsafe_allow_html=True, ) st.divider() messages = data.get("messages", []) for m in messages: with st.chat_message(m["role"]): st.markdown(m["content"]) # Show workspace files if available from components.file_browser import render_file_browser, render_workspace_download case_dir = selected_path.parent ws_dir = case_dir / "workspace" browse_dir = ws_dir if ws_dir.exists() else case_dir render_file_browser(browse_dir, key_prefix="cs_fb") render_workspace_download(browse_dir, key_prefix="cs_dl")