File size: 16,756 Bytes
fd01b80 | 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 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 | """
Tutorial & Help page for the QSTN GUI.
Use ?section=start|options|prompts|inference|overview to deep-link to a section.
"""
import streamlit as st
st.set_page_config(page_title="Tutorial & Help", layout="wide")
st.title("π QSTN Tutorial & Help")
st.markdown("Full documentation of every option in the GUI. Use the sections below or jump to a step from the links.")
# Section keys for deep linking
SECTION_START = "start"
SECTION_OPTIONS = "options"
SECTION_PROMPTS = "prompts"
SECTION_INFERENCE = "inference"
SECTION_OVERVIEW = "overview"
section_param = st.query_params.get("section", SECTION_START)
# Quick jump links
st.markdown("**Jump to:** ")
cols = st.columns(5)
with cols[0]:
st.page_link("pages/00_Tutorial.py", label="Start", query_params={"section": SECTION_START})
with cols[1]:
st.page_link("pages/00_Tutorial.py", label="Answer options", query_params={"section": SECTION_OPTIONS})
with cols[2]:
st.page_link("pages/00_Tutorial.py", label="Prompts", query_params={"section": SECTION_PROMPTS})
with cols[3]:
st.page_link("pages/00_Tutorial.py", label="Inference", query_params={"section": SECTION_INFERENCE})
with cols[4]:
st.page_link("pages/00_Tutorial.py", label="Run & results", query_params={"section": SECTION_OVERVIEW})
st.divider()
# =============================================================================
# 1. START PAGE
# =============================================================================
with st.expander("**1. Start page β Sessions, questionnaire & population**", expanded=(section_param == SECTION_START)):
st.markdown("On the **Start** page you create or load a session, upload your data, and build the survey. All work is saved per session.")
st.markdown("**Session options** (no replica): Continue Last Session, Start New Session, Switch to another session (dropdown), Create New, View Saved Sessions (Load/Delete).")
st.subheader("Data upload")
with st.container(border=True):
_c1, _c2 = st.columns(2)
with _c1:
st.text_input("Select a questionnaire to start with", value="", disabled=True, key="tutorial_start_quest")
st.caption("File upload for the **questionnaire** CSV. One row per question. Required columns: `questionnaire_item_id`, `question_content`, `question_stem` (optional).")
with _c2:
st.text_input("Select a population to start with", value="", disabled=True, key="tutorial_start_pop")
st.caption("File upload for the **population** CSV. One row per persona. Required columns: `questionnaire_name`, `system_prompt`, `questionnaire_instruction`.")
st.button("Confirm and Prepare Questionnaire", disabled=True, key="tutorial_start_btn")
st.caption("Builds the survey and goes to **Answer options**. Use **Clear** under each upload to reset to example data.")
st.subheader("Next step")
st.page_link("Start_Page.py", label="β Go to Start page")
# =============================================================================
# 2. ANSWER OPTIONS (LIKERT SCALE OPTIONS GENERATOR)
# =============================================================================
with st.expander("**2. Answer options β Likert scales & response format**", expanded=(section_param == SECTION_OPTIONS)):
st.markdown("This page configures how the LLM sees answer options and how the model outputs its answer (free text, JSON, or constrained choice).")
with st.container(border=True):
st.subheader("Main Configuration")
_col1, _col2, _col3 = st.columns(3)
with _col1:
st.number_input("Number of Options (n)", value=5, min_value=2, step=1, disabled=True, key="tutorial_opt_n")
st.caption("Total number of choices in the scale (e.g. 5 for a 5-point scale). Minimum 2.")
with _col2:
st.selectbox("Index Type", options=["integer", "char_low", "char_up"], index=0, disabled=True, key="tutorial_opt_idx")
st.caption("How options are labeled: integer (1,2,3β¦), char_low (a,b,cβ¦), or char_up (A,B,Cβ¦).")
with _col3:
st.number_input("Starting Index", value=1, step=1, disabled=True, key="tutorial_opt_start")
st.caption("Number to start counting from (e.g. 1).")
st.subheader("Ordering and Structure")
_co1, _co2, _co3, _co4 = st.columns(4)
with _co1:
st.checkbox("From-To Scale Only", value=False, disabled=True, key="tutorial_opt_ft")
st.caption("Only first and last labels shown (e.g. β1 Strongly Disagree to 5 Strongly Agreeβ). Requires exactly 2 answer texts.")
with _co2:
st.checkbox("Random Order", value=False, disabled=True, key="tutorial_opt_rand")
st.caption("Randomize option order per prompt. Cannot combine with Reversed Order.")
with _co3:
st.checkbox("Reversed Order", value=False, disabled=True, key="tutorial_opt_rev")
st.caption("Reverse option order (e.g. 5β1).")
with _co4:
st.checkbox("Even Order", value=False, disabled=True, key="tutorial_opt_even")
st.caption("If odd number of labels, middle option is removed.")
st.subheader("Answer Texts")
st.text_area("Enter Answer Texts (one per line)", value="Strongly Disagree\nDisagree\nNeutral\nAgree\nStrongly Agree", height=120, disabled=True, key="tutorial_opt_texts")
st.caption("One label per line. Number of lines must match **Number of Options** (or 2 if From-To Scale Only).")
st.subheader("Response Generation Method")
st.checkbox("Output Indices Only", value=False, disabled=True, key="tutorial_opt_outidx")
st.caption("If checked, model outputs only indices (e.g. 1, 2) instead of full text (e.g. 1: Strongly Disagree). Applies to all methods below.")
st.selectbox("Response Generation Method", options=["None", "JSON Single Answer", "JSON All Options (Probabilities)", "JSON with Reasoning", "Choice"], index=0, disabled=True, key="tutorial_opt_rgm")
st.markdown("**Details by option:**")
st.markdown("""
- **None** β Model returns free text; no structured output. You must parse the response yourself. No extra configuration on this page.
- **JSON Single Answer** β Model returns a single selected answer in JSON (e.g. one chosen option per question). Parsing is automatic; use when you want one answer per item.
- **JSON All Options (Probabilities)** β Model returns a probability (or score) for each option. Use when you want a distribution over choices rather than a single pick. Parsing expects this structure.
- **JSON with Reasoning** β Model returns reasoning text plus the chosen answer in JSON. Use when you need both explanation and a structured answer. Parsing extracts both.
- **Choice** β Model must pick exactly one value from a fixed list. When selected, **Allowed Choices** appears: one choice per line, either indices only (e.g. 1, 2, 3) or with labels (e.g. 1: Strongly Disagree). **Output Indices Only** controls whether the model returns indices or full labels. Parsing uses the same list.
""")
st.subheader("Next step")
st.page_link("pages/01_Option_Prompt.py", label="β Go to Answer options")
# =============================================================================
# 3. PROMPT CONFIGURATION
# =============================================================================
with st.expander("**3. Prompt configuration β System prompt & instructions**", expanded=(section_param == SECTION_PROMPTS)):
st.markdown("Edit the system and user prompts the LLM sees. Use the checkboxes to copy the current prompts to all questionnaires on confirm.")
with st.container(border=True):
st.subheader("Configuration")
st.checkbox("On update: change all System Prompts", value=True, disabled=True, key="tutorial_prompt_chg_sys")
st.caption("When you click Confirm and Prepare Questionnaire, the current system prompt is applied to **all** questionnaires (missing placeholders added to others).")
st.checkbox("On update: change all questionnaire instructions", value=True, disabled=True, key="tutorial_prompt_chg_inst")
st.caption("Same for the main prompt (instructions); all questionnaires get this text.")
st.text_area("System prompt", value="You are a student.", height=80, disabled=True, key="tutorial_prompt_sys")
st.caption("The system message sent to the model (e.g. role or context).")
st.text_area("Prompt", value="Please answer the following questions.", height=80, disabled=True, key="tutorial_prompt_user")
st.caption("User-facing instructions given before the questions.")
st.write("**Insert Placeholder:**")
_pb1, _pb2, _pb3, _pb4 = st.columns(4)
with _pb1:
st.button("Prompt Questions", disabled=True, key="tutorial_prompt_btn_p")
with _pb2:
st.button("Prompt Options", disabled=True, key="tutorial_prompt_btn_o")
with _pb3:
st.button("Automatic Output", disabled=True, key="tutorial_prompt_btn_a")
with _pb4:
st.button("JSON Template", disabled=True, key="tutorial_prompt_btn_j")
st.caption("Type shortcut (-P, -O, -A, -J) in system or main prompt, then click to replace with placeholder. **Prompt Questions**: where question text goes. **Prompt Options**: where answer options go (configure options first). **Automatic Output**: JSON/output instructions. **JSON Template**: JSON schema for response.")
st.text_area("Question Stem", value="How do you feel about?", height=80, disabled=True, key="tutorial_prompt_stem")
st.caption("Template for each question. Use **Question Content** placeholder (-Q) so the actual item (e.g. βCoffeeβ) is inserted.")
st.checkbox("Randomize the order of items", value=False, disabled=True, key="tutorial_prompt_rand")
st.caption("If checked, question order is randomized per questionnaire.")
st.caption("**Live Preview** (on the real page) shows prompts with placeholders filled; use **Update Preview** to refresh. The **paginator** switches which questionnaire you edit.")
st.subheader("Next step")
st.page_link("pages/02_Prompt_Configuration.py", label="β Go to Prompt configuration")
# =============================================================================
# 4. INFERENCE SETTINGS
# =============================================================================
with st.expander("**4. Inference settings β API client & model**", expanded=(section_param == SECTION_INFERENCE)):
st.markdown("Configure where the LLM is called (API URL, key) and how (model, temperature, etc.). Values are used on Final overview when you run the survey.")
_inf_col1, _inf_col2 = st.columns(2)
with _inf_col1:
with st.container(border=True):
st.subheader("1. Client Configuration")
st.text_input("API Key", value="", type="password", disabled=True, key="tutorial_inf_apikey")
st.caption("Your OpenAI API key (or leave empty for local vLLM). Handled securely.")
st.text_input("Base URL", value="", placeholder="https://api.openai.com/v1", disabled=True, key="tutorial_inf_base")
st.caption("API base URL. For **local vLLM** use `http://localhost:8000/v1`. Optional: Organization ID, Project ID.")
st.number_input("Timeout (seconds)", value=20, min_value=1, disabled=True, key="tutorial_inf_timeout")
st.caption("Request timeout in seconds.")
st.number_input("Max Retries", value=2, min_value=0, disabled=True, key="tutorial_inf_retries")
st.caption("Number of retries for failed requests. Advanced: JSON for default_headers, default_query, etc.")
with _inf_col2:
with st.container(border=True):
st.subheader("2. Inference Configuration")
st.text_input("Model Name", value="", placeholder="meta-llama/Llama-3.1-70B-Instruct", disabled=True, key="tutorial_inf_model")
st.caption("Model ID. Must match your API/vLLM (e.g. `meta-llama/Llama-3.2-3B-Instruct` for vLLM).")
st.slider("Temperature", 0.0, 2.0, 1.0, 0.01, disabled=True, key="tutorial_inf_temp")
st.caption("Randomness (0β2). Lower = more deterministic.")
st.number_input("Max Tokens", value=1024, min_value=1, disabled=True, key="tutorial_inf_maxtok")
st.caption("Maximum tokens to generate per completion.")
st.slider("Top P", 0.0, 1.0, 1.0, 0.01, disabled=True, key="tutorial_inf_topp")
st.caption("Nucleus sampling: consider tokens with cumulative probability up to this value.")
st.number_input("Seed", value=42, min_value=0, disabled=True, key="tutorial_inf_seed")
st.caption("Seed for reproducible sampling. Advanced: JSON for stop, presence_penalty, frequency_penalty, logit_bias.")
st.subheader("Using local vLLM")
st.markdown("""
1. Start the vLLM server, e.g.:
```bash
python -m vllm.entrypoints.openai.api_server --model meta-llama/Llama-3.2-3B-Instruct --max-model-len 8192
```
2. In the GUI: set **Base URL** to `http://localhost:8000/v1` and **Model name** to the same model ID (e.g. `meta-llama/Llama-3.2-3B-Instruct`).
3. Click **Generate Configuration & Code** to save; then go to **Final overview** to run the survey.
""")
st.subheader("Next step")
st.markdown("Click **Generate Configuration & Code** to save client and inference config and go to **Final overview**.")
st.page_link("pages/03_Inference_Setting.py", label="β Go to Inference settings")
# =============================================================================
# 5. FINAL OVERVIEW & RUN
# =============================================================================
with st.expander("**5. Final overview β Run survey & save results**", expanded=(section_param == SECTION_OVERVIEW)):
st.markdown("Read-only inference summary, prompt preview for the selected method, then run the survey and save results.")
with st.container(border=True):
st.subheader("βοΈ Inference Parameters")
st.text_input("Model Name", value="meta-llama/Llama-3.2-3B-Instruct", disabled=True, key="tutorial_overview_model")
st.caption("Shown from Inference settings (not editable here). Change on **Inference settings** page.")
st.slider("Temperature", 0.0, 2.0, 1.0, 0.01, disabled=True, key="tutorial_overview_temp")
st.number_input("Max Tokens", value=1024, min_value=1, disabled=True, key="tutorial_overview_maxtok")
st.selectbox("Questionnaire Method", options=["Single item", "Battery", "Sequential"], index=0, disabled=True, key="tutorial_overview_method")
st.caption("**Single item**: one question per API call. **Battery**: all questions in one call. **Sequential**: all in one thread with conversation history. Affects prompts and result parsing.")
st.markdown("**Details by option:**")
st.markdown("""
- **Single item** β One question is sent per API call; the model sees only that question (and system/instruction context). Preview on the page shows the first few items so you can check how each is prompted.
- **Battery** β All questions are sent in one API call; the model sees the full list and responds once. Preview shows one combined prompt.
- **Sequential** β All questions are sent in one conversation thread with history; the model sees prior Q&A. Preview shows one combined flow. Parsing respects the conversation structure.
""")
st.caption("**Live preview** (on the real page): for Single item, first few items shown; for Battery/Sequential, one combined preview. **Paginator** switches questionnaire.")
with st.container(border=True):
st.subheader("πΎ Save Results")
st.text_input("Save File", value="questionnaire_results.csv", disabled=True, key="tutorial_overview_savefile")
st.caption("Filename for the CSV. If you omit `.csv`, it is appended.")
st.button("Save Results", disabled=True, key="tutorial_overview_savebtn")
st.caption("Downloads the results table as CSV. Appears after you click **Confirm and Run Questionnaire** and inference finishes.")
st.page_link("pages/04_Final_Overview.py", label="β Go to Final overview")
st.divider()
st.subheader("Workflow summary")
st.markdown("**Start** (upload data, confirm) β **Answer options** (scale + response method, confirm) β **Prompt configuration** (prompts + placeholders, confirm) β **Inference settings** (API + model, generate config) β **Final overview** (run & save).")
|