File size: 6,428 Bytes
448ed98
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5bcad58
448ed98
5bcad58
448ed98
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5bcad58
448ed98
 
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 streamlit as st
from qstn.prompt_builder import LLMPrompt, generate_likert_options
from qstn.utilities.prompt_templates import (
    LIST_OPTIONS_DEFAULT,
    SCALE_OPTIONS_DEFAULT,
)

from gui_elements.stateful_widget import StatefulWidgets

st.set_page_config(layout="wide")
st.title("Likert Scale Options Generator")
st.write(
    "This interface allows you to configure and generate Likert scale answer options by adjusting the parameters below."
)
st.divider()

if "questionnaires" not in st.session_state:
    st.error("You need to first upload a questionnaire and the population you want to survey.")
    st.stop()
    disabled = True
else:
    disabled = False

#if 'answer_texts_input' not in st.session_state:
    #st.session_state.answer_texts_input = "Strongly Disagree\nDisagree\nNeutral\nAgree\nStrongly Agree"

state = StatefulWidgets()

# Use a form to batch all inputs together
with st.container(border=True):
    # --- Main Configuration ---
    st.subheader("Main Configuration")
    col1, col2, col3 = st.columns(3)

    with col1:
        n_options = state.create(
            st.number_input,
            "n_options",
            "Number of Options (n)",
            initial_value=5,
            min_value=2,
            step=1,
            help="The total number of choices in the scale.",
        )

    with col2:
        idx_type = state.create(
            st.selectbox,
            "idx_type",
            "Index Type",
            initial_value="integer",
            options=["integer", "char_low", "char_up"],
            help="The type of index to use for the options.",
        )

    with col3:
        start_idx = state.create(
            st.number_input,
            "start_idx",
            "Starting Index",
            initial_value=1,
            step=1,
            help="The number to start counting from (e.g., 1).",
        )

    # --- Order and Structure Options ---
    st.subheader("Ordering and Structure")
    col1, col2, col3, col4 = st.columns(4)

    with col1:
        only_from_to_scale = state.create(
            st.checkbox,
            "only_from_to_scale",
            "From-To Scale Only",
            initial_value=False,
            help="If checked, only the first and last answer labels are display e.g. 1 Strongly Disagree to 5 Strongly agree.",
        )

    with col2:
        random_order = state.create(
            st.checkbox,
            "random_order",
            "Random Order",
            initial_value=False,
            help="Randomize the order of options.",
        )

    with col3:
        reversed_order = state.create(
            st.checkbox,
            "reversed_order",
            "Reversed Order",
            initial_value=False,
            help="Reverse the order of options.",
        )

    with col4:
        even_order = state.create(
            st.checkbox,
            "even_order",
            "Even Order",
            initial_value=False,
            help="If there is an uneven number of answer texts, the middle section is automatically removed.",
        )

    # --- Answer Texts Input ---
    st.subheader("Answer Texts")

    answer_texts = state.create(
        st.text_area,
        "answer_texts",
        "Enter Answer Texts (one per line)",
        initial_value="Strongly Disagree\nDisagree\nNeutral\nAgree\nStrongly Agree",
        height=150,
        help="Enter the labels for each answer option.",
    )

    # --- Advanced Configuration ---
    with st.expander("Advanced Configuration"):
        options_separator = state.create(
            st.text_input,
            "options_separator",
            "Options Separator",
            initial_value=", ",
            help="The character(s) used to separate options in the final string.",
        )
        list_prompt_template = state.create(
            st.text_area,
            "list_prompt_template",
            "List Prompt Template",
            initial_value=LIST_OPTIONS_DEFAULT,
            height=100,
            help="Write how the options should be presented to the model.",
        )
        scale_prompt_template = state.create(
            st.text_area,
            "scale_prompt_template",
            "Scale Prompt Template",
            initial_value=SCALE_OPTIONS_DEFAULT,
            height=100,
            help="Write how the options should be presented to the model.",
        )


    # The submit button for the form
    submitted = st.button("Confirm and Generate Options", disabled=disabled, type="primary", use_container_width=True)

    if st.button("Skip", use_container_width=True, icon="❌"):
        st.session_state.survey_options = None
        st.switch_page("pages/02_Prompt_Configuration.py")

# --- Processing and Output ---
if submitted:
    #print("Session state answer texts "+ st.session_state.answer_texts_input)
    #print(answer_texts_input)
    # Convert the raw text area string into a list of strings.
    answer_texts_list = [
        text.strip() for text in answer_texts.split("\n") if text.strip()
    ]

    # --- Input Validation ---
    validation_ok = True
    if only_from_to_scale and len(answer_texts_list) != 2:
        st.error(
            f"Error: When 'From-To Scale Only' is selected, you must provide exactly 2 answer texts. You provided {len(answer_texts_list)}."
        )
        validation_ok = False

    if not only_from_to_scale and len(answer_texts_list) != n_options:
        st.error(
            f"Error: The number of answer texts ({len(answer_texts_list)}) must match the 'Number of Options' ({n_options})."
        )
        validation_ok = False

    if reversed_order and random_order:
        st.error(f"Error: Reversed Order and Random Order cannot both be true.")
        validation_ok = False

    if validation_ok:
        survey_options = generate_likert_options(
            n=n_options,
            answer_texts=answer_texts_list,
            only_from_to_scale=only_from_to_scale,
            random_order=random_order,
            reversed_order=reversed_order,
            even_order=even_order,
            start_idx=start_idx,
            list_prompt_template=list_prompt_template,
            scale_prompt_template=scale_prompt_template,
            options_separator=options_separator,
            idx_type=idx_type,
        )

        st.session_state.survey_options = survey_options
        st.switch_page("pages/02_Prompt_Configuration.py")