File size: 6,902 Bytes
04c1883
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import sqlite3
from datetime import datetime
from pathlib import Path
import pandas as pd
import streamlit as st

# -----------------------------
# Config & constants
# -----------------------------
st.set_page_config(page_title="Topic Interest Survey", page_icon="🗳️", layout="centered")

DB_PATH = Path("interests.db")
TABLE = "responses"
HEADERS = ["timestamp", "name", "topics"]

TOPICS = [
    "Hamid — Mapping the Innovation Ecosystem of a Tech Sector",
    "Hamid — Public Narratives of Corporate AI Adoption",
    "Milad — Geography of Goods & Services (EUIPO trademarks)",
    "Milad — Cross‑Border Relations — Nordic Startup Hyperlinks",
    "Milad — AI Champions in the Periphery (Company websites)",
    "Milad — Diffusion of ISO 27001 (Company websites)",
    "Milad — Goods & Services Classification (Large corpora)",
    "Roman — Automation & Quality Evaluation (n8n logs)",
    "Roman — AI & Labour Markets (O*NET)",
    "Roman — Long‑Form Document Structuring",
    "Richard & Roman/Milad — Knowledge Graph Construction from Text",
    "Richard & Roman/Milad Optimising LLM Generation Settings",
]

# -----------------------------
# DB helpers
# -----------------------------
@st.cache_resource(show_spinner=False)
def get_conn():
    conn = sqlite3.connect(DB_PATH, check_same_thread=False)
    conn.execute("PRAGMA journal_mode=WAL;")
    conn.execute(
        f"""

        CREATE TABLE IF NOT EXISTS {TABLE} (

            id INTEGER PRIMARY KEY AUTOINCREMENT,

            timestamp TEXT NOT NULL,

            name TEXT NOT NULL,

            topics TEXT NOT NULL

        )

        """
    )
    conn.commit()
    return conn


def insert_row(conn, name: str, topics: list[str]):
    ts = datetime.now().isoformat(timespec="seconds")
    topics_str = ", ".join(topics)
    conn.execute(
        f"INSERT INTO {TABLE} (timestamp, name, topics) VALUES (?, ?, ?)",
        (ts, name.strip(), topics_str),
    )
    conn.commit()


def delete_row(conn, row_id: int):
    conn.execute(f"DELETE FROM {TABLE} WHERE id = ?", (row_id,))
    conn.commit()


def load_df(conn) -> pd.DataFrame:
    df = pd.read_sql_query(
        f"SELECT id, timestamp, name, topics FROM {TABLE} ORDER BY timestamp DESC", conn
    )
    if not df.empty:
        df["topic_list"] = df["topics"].str.split(", ")
    return df

# -----------------------------
# UI helpers
# -----------------------------

def clear_form_state():
    st.session_state.pop("name", None)
    st.session_state.pop("choices", None)


# -----------------------------
# App
# -----------------------------
conn = get_conn()

st.title("🗳️ Topic Interest Survey")
st.caption("Pick up to two topics, add your name, and see the public roster of interests.")

survey_tab, roster_tab = st.tabs(["Survey", "Roster"])

with survey_tab:
    with st.form("survey_form", clear_on_submit=False):
        name = st.text_input("Your name", key="name", placeholder="e.g., Chenghao Luo")
        choices = st.multiselect(
            "Choose topics (max 2)",
            options=TOPICS,
            key="choices",
            help="You can only pick at most two.",
        )
        submitted = st.form_submit_button("Submit interest")

        if submitted:
            # Validation
            if not name or not name.strip():
                st.error("Please enter your name.")
            elif len(choices) == 0 or len(choices) > 2:
                st.error("Please choose 1 or 2 topics.")
            else:
                try:
                    insert_row(conn, name, choices)
                    st.success("Thanks! Your interest was recorded.")
                    clear_form_state()
                except sqlite3.IntegrityError as e:
                    st.error(f"Duplicate? Could not save: {e}")
                except Exception as e:
                    st.error(f"Unexpected error: {e}")

with roster_tab:
    df = load_df(conn)
    if df is None or df.empty:
        st.info("No entries yet.")
    else:
        # Filters
        col1, col2 = st.columns([2, 1])
        with col1:
            name_filter = st.text_input("Filter by name", placeholder="type part of a name…")
        with col2:
            topic_filter = st.selectbox("Filter by topic", options=["(All)"] + TOPICS)

        df_view = df.copy()
        if name_filter:
            df_view = df_view[df_view["name"].str.contains(name_filter, case=False, na=False)]
        if topic_filter and topic_filter != "(All)":
            df_view = df_view[df_view["topics"].str.contains(topic_filter, na=False)]

        st.subheader("Roster")
        st.dataframe(
            df_view[["timestamp", "name", "topics"]].rename(
                columns={"timestamp": "Timestamp", "name": "Name", "topics": "Topics"}
            ),
            use_container_width=True,
            hide_index=True,
        )

        # Delete section
        st.divider()
        st.subheader("Delete a record")
        st.caption("Select a specific submission to delete. This cannot be undone.")
        # Build nice labels for selection
        options = [
            (
                int(r.id),
                f"#{int(r.id)}{r.name}{r.topics}{r.timestamp}"
            )
            for _, r in df.iterrows()
        ]
        if options:
            selected_label = st.selectbox(
                "Choose a record",
                options=[lbl for _, lbl in options],
                index=0,
                key="delete_select",
            )
            # Map back to id
            label_to_id = {lbl: rid for rid, lbl in options}
            col_del, col_warn = st.columns([1, 3])
            with col_del:
                if st.button("🗑️ Delete selected", type="primary"):
                    delete_row(conn, label_to_id[selected_label])
                    st.success("Record deleted. Refresh the tab to see updates.")
            with col_warn:
                st.info("Tip: Use filters above to narrow the list, then delete.")
        else:
            st.caption("No records to delete.")

        # Topic counts
        st.subheader("Topic counts")
        counts = (
            df.explode("topic_list")["topic_list"].value_counts().rename_axis("Topic").reset_index(name="Count")
        )
        st.bar_chart(counts.set_index("Topic"))

        # Download CSV
        csv = df[["timestamp", "name", "topics"]].to_csv(index=False).encode("utf-8")
        st.download_button(
            "⬇️ Download CSV",
            data=csv,
            file_name="topic_interests.csv",
            mime="text/csv",
        )

# Footer
st.write("")
st.caption("Built with Streamlit + SQLite. Data stored locally in interests.db.")