Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -53,26 +53,26 @@ yes_no_labels = ['no','yes']
|
|
| 53 |
yes_no_other_labels = ['no','yes','other']
|
| 54 |
default_labels = agreement_labels
|
| 55 |
|
| 56 |
-
|
| 57 |
-
|
| 58 |
-
|
| 59 |
-
|
| 60 |
-
|
| 61 |
-
|
| 62 |
-
|
| 63 |
-
|
| 64 |
-
|
| 65 |
-
|
| 66 |
-
|
| 67 |
-
|
| 68 |
-
"
|
| 69 |
-
"
|
| 70 |
-
"
|
| 71 |
-
"
|
| 72 |
-
"
|
| 73 |
"Other"]
|
| 74 |
|
| 75 |
-
default_choices =
|
| 76 |
|
| 77 |
consent_text = '''
|
| 78 |
## Consent Form
|
|
@@ -127,12 +127,14 @@ fields: List[Field] = [
|
|
| 127 |
title="Level of priority", other_params={'labels': priority_labels}, mandatory=True),
|
| 128 |
]),
|
| 129 |
|
| 130 |
-
Field(type="container", title="**Rupture
|
| 131 |
-
Field(name="
|
| 132 |
-
|
| 133 |
-
|
| 134 |
-
|
| 135 |
-
|
|
|
|
|
|
|
| 136 |
]),
|
| 137 |
|
| 138 |
Field(type="container", title="**True-To-Patient-Prompt Properties**", children=[
|
|
@@ -332,6 +334,69 @@ def render_dialogue(md_path: str,
|
|
| 332 |
st_html(html_doc, height=height_px + (16 if show_border else 0), scrolling=False)
|
| 333 |
|
| 334 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 335 |
#################################### Streamlit App ####################################
|
| 336 |
|
| 337 |
# Function to navigate rows
|
|
@@ -397,6 +462,8 @@ def show_field(f: Field, index: int, data_collected):
|
|
| 397 |
show_field(child, index, data_collected)
|
| 398 |
case 'skip_checkbox':
|
| 399 |
st.checkbox(f.title, key=f.name, value=False)
|
|
|
|
|
|
|
| 400 |
else:
|
| 401 |
key = f.name + str(index)
|
| 402 |
st.session_state.data_inputs_keys.append(f.name)
|
|
@@ -516,13 +583,48 @@ def show_fields(fields: List[Field]):
|
|
| 516 |
st.session_state.form_displayed = st.session_state.current_index
|
| 517 |
|
| 518 |
def prep_and_save_data(index, skip_sample):
|
| 519 |
-
|
| 520 |
'user_id': st.session_state.user_id,
|
| 521 |
'index': st.session_state.current_index,
|
| 522 |
**(st.session_state.data.iloc[index][COLS_TO_SAVE].to_dict() if 0 <= index < len(st.session_state.data) else {}),
|
| 523 |
**{k: st.session_state[k + str(index)] for k in st.session_state.data_inputs_keys},
|
| 524 |
'skip': skip_sample
|
| 525 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 526 |
|
| 527 |
st.set_page_config(layout='wide')
|
| 528 |
# Title of the app
|
|
|
|
| 53 |
yes_no_other_labels = ['no','yes','other']
|
| 54 |
default_labels = agreement_labels
|
| 55 |
|
| 56 |
+
MAX_RUPTURE_MARKERS = 8 # 1 initial + up to 7 extra
|
| 57 |
+
RUPTURE_LINE_INPUT_TYPE = "number" # or "text" if your line numbers aren't pure ints
|
| 58 |
+
|
| 59 |
+
rupture_choices = ["Denial",
|
| 60 |
+
"Minimal response",
|
| 61 |
+
"Abstract communication",
|
| 62 |
+
"Avoidant storytelling and/or topic-shifting",
|
| 63 |
+
"Deferential / appeasing behavior",
|
| 64 |
+
"Content/affect split (i.e. talking content vs emotional tone mismatch)",
|
| 65 |
+
"Self-criticism and/or hopelessness",
|
| 66 |
+
"Complaints or concerns about the therapist",
|
| 67 |
+
"Patient rejects therapist intervention",
|
| 68 |
+
"Complaints/concerns about the activities of therapy",
|
| 69 |
+
"Complaints/concerns about the parameters of therapy (e.g. scheduling, rules)",
|
| 70 |
+
"Complaints/concerns about progress in therapy",
|
| 71 |
+
"Patient defends self against therapist",
|
| 72 |
+
"Efforts to control or pressure the therapist",
|
| 73 |
"Other"]
|
| 74 |
|
| 75 |
+
default_choices = rupture_choices
|
| 76 |
|
| 77 |
consent_text = '''
|
| 78 |
## Consent Form
|
|
|
|
| 127 |
title="Level of priority", other_params={'labels': priority_labels}, mandatory=True),
|
| 128 |
]),
|
| 129 |
|
| 130 |
+
Field(type="container", title="**Rupture Markers**", children=[
|
| 131 |
+
Field(name="rupture_markers", type="rupture_markers",
|
| 132 |
+
title="Select rupture markers noted in the session, include line numbers where rupture is found.", mandatory=False),
|
| 133 |
+
# Field(name="rupture_marker", type="multiselect",
|
| 134 |
+
# title="What type of rupture markers are found? *(Select only one)*",
|
| 135 |
+
# other_params={'choices': rupture_choices}, mandatory=True, following_mandatory_values=['Other (please specify)']),
|
| 136 |
+
# Field(name="rupture_marker", type="text", title="What lines demonstrate the rupture markers you notice?", mandatory=False),
|
| 137 |
+
# Field(name="rupture_marker_other", type="text", title="*If Other, please specify:*", mandatory=False),
|
| 138 |
]),
|
| 139 |
|
| 140 |
Field(type="container", title="**True-To-Patient-Prompt Properties**", children=[
|
|
|
|
| 334 |
st_html(html_doc, height=height_px + (16 if show_border else 0), scrolling=False)
|
| 335 |
|
| 336 |
|
| 337 |
+
def render_rupture_markers_widget(index: int, choices: list[str]):
|
| 338 |
+
"""Dynamic list of (rupture_marker_i, line_a_i, line_b_i) with Add/Remove."""
|
| 339 |
+
count_key = f"rupture_count_{index}"
|
| 340 |
+
if count_key not in st.session_state:
|
| 341 |
+
st.session_state[count_key] = 1 # start with one block
|
| 342 |
+
|
| 343 |
+
count = st.session_state[count_key]
|
| 344 |
+
|
| 345 |
+
st.markdown("**What rupture markers are found?** *(one per row; max 8)*")
|
| 346 |
+
|
| 347 |
+
# render the i=1..count rows
|
| 348 |
+
for i in range(1, count + 1):
|
| 349 |
+
col1, col2, col3 = st.columns([3, 1, 1])
|
| 350 |
+
|
| 351 |
+
marker_key = f"rupture_marker_{i}_{index}"
|
| 352 |
+
a_key = f"rupture_marker_{i}_line_a_{index}"
|
| 353 |
+
b_key = f"rupture_marker_{i}_line_b_{index}"
|
| 354 |
+
|
| 355 |
+
with col1:
|
| 356 |
+
st.selectbox(
|
| 357 |
+
f"Rupture marker {i}",
|
| 358 |
+
options=choices,
|
| 359 |
+
key=marker_key,
|
| 360 |
+
index=(choices.index(st.session_state.get(marker_key))
|
| 361 |
+
if st.session_state.get(marker_key) in choices else 0)
|
| 362 |
+
if st.session_state.get(marker_key) is not None else 0
|
| 363 |
+
)
|
| 364 |
+
|
| 365 |
+
# line inputs (number or text)
|
| 366 |
+
with col2:
|
| 367 |
+
if RUPTURE_LINE_INPUT_TYPE == "number":
|
| 368 |
+
st.number_input(f"Lines: {i} – from", min_value=1, step=1, key=a_key)
|
| 369 |
+
else:
|
| 370 |
+
st.text_input(f"Lines: {i} – from", key=a_key, value=st.session_state.get(a_key, ""))
|
| 371 |
+
|
| 372 |
+
with col3:
|
| 373 |
+
if RUPTURE_LINE_INPUT_TYPE == "number":
|
| 374 |
+
st.number_input(f"Lines: {i} – to", min_value=1, step=1, key=b_key)
|
| 375 |
+
else:
|
| 376 |
+
st.text_input(f"Lines: {i} – to", key=b_key, value=st.session_state.get(b_key, ""))
|
| 377 |
+
|
| 378 |
+
st.markdown("---")
|
| 379 |
+
|
| 380 |
+
# add/remove buttons
|
| 381 |
+
a_col, b_col = st.columns([1, 1])
|
| 382 |
+
with a_col:
|
| 383 |
+
st.button(
|
| 384 |
+
"➕ Add another rupture marker",
|
| 385 |
+
key=f"add_rup_{index}",
|
| 386 |
+
disabled=(count >= MAX_RUPTURE_MARKERS),
|
| 387 |
+
on_click=lambda: st.session_state.__setitem__(count_key, min(MAX_RUPTURE_MARKERS, st.session_state[count_key] + 1))
|
| 388 |
+
)
|
| 389 |
+
with b_col:
|
| 390 |
+
st.button(
|
| 391 |
+
"➖ Remove last",
|
| 392 |
+
key=f"remove_rup_{index}",
|
| 393 |
+
disabled=(count <= 1),
|
| 394 |
+
on_click=lambda: st.session_state.__setitem__(count_key, max(1, st.session_state[count_key] - 1))
|
| 395 |
+
)
|
| 396 |
+
|
| 397 |
+
# info text
|
| 398 |
+
st.caption(f"{st.session_state[count_key]}/{MAX_RUPTURE_MARKERS} markers")
|
| 399 |
+
|
| 400 |
#################################### Streamlit App ####################################
|
| 401 |
|
| 402 |
# Function to navigate rows
|
|
|
|
| 462 |
show_field(child, index, data_collected)
|
| 463 |
case 'skip_checkbox':
|
| 464 |
st.checkbox(f.title, key=f.name, value=False)
|
| 465 |
+
case 'rupture_markers':
|
| 466 |
+
render_rupture_markers_widget(index, rupture_choices)
|
| 467 |
else:
|
| 468 |
key = f.name + str(index)
|
| 469 |
st.session_state.data_inputs_keys.append(f.name)
|
|
|
|
| 583 |
st.session_state.form_displayed = st.session_state.current_index
|
| 584 |
|
| 585 |
def prep_and_save_data(index, skip_sample):
|
| 586 |
+
payload = {
|
| 587 |
'user_id': st.session_state.user_id,
|
| 588 |
'index': st.session_state.current_index,
|
| 589 |
**(st.session_state.data.iloc[index][COLS_TO_SAVE].to_dict() if 0 <= index < len(st.session_state.data) else {}),
|
| 590 |
**{k: st.session_state[k + str(index)] for k in st.session_state.data_inputs_keys},
|
| 591 |
'skip': skip_sample
|
| 592 |
+
}
|
| 593 |
+
# normalize rupture markers -> always write 8 slots
|
| 594 |
+
count_key = f"rupture_count_{index}"
|
| 595 |
+
count = st.session_state.get(count_key, 1)
|
| 596 |
+
for i in range(1, MAX_RUPTURE_MARKERS + 1):
|
| 597 |
+
m_key = f"rupture_marker_{i}_{index}"
|
| 598 |
+
a_key = f"rupture_marker_{i}_line_a_{index}"
|
| 599 |
+
b_key = f"rupture_marker_{i}_line_b_{index}"
|
| 600 |
+
|
| 601 |
+
# export names WITHOUT the trailing _{index}, so your JSON uses a stable schema:
|
| 602 |
+
out_m = f"rupture_marker_{i}"
|
| 603 |
+
out_a = f"rupture_marker_{i}_line_a"
|
| 604 |
+
out_b = f"rupture_marker_{i}_line_b"
|
| 605 |
+
|
| 606 |
+
if i <= count:
|
| 607 |
+
marker_val = st.session_state.get(m_key)
|
| 608 |
+
line_a_val = st.session_state.get(a_key)
|
| 609 |
+
line_b_val = st.session_state.get(b_key)
|
| 610 |
+
|
| 611 |
+
# Basic sanity: if numbers, coerce order (optional)
|
| 612 |
+
if RUPTURE_LINE_INPUT_TYPE == "number":
|
| 613 |
+
try:
|
| 614 |
+
if line_a_val is not None and line_b_val is not None and line_a_val > line_b_val:
|
| 615 |
+
line_a_val, line_b_val = line_b_val, line_a_val
|
| 616 |
+
except Exception:
|
| 617 |
+
pass
|
| 618 |
+
|
| 619 |
+
payload[out_m] = marker_val if marker_val not in ("", None) else None
|
| 620 |
+
payload[out_a] = line_a_val if line_a_val not in ("", None) else None
|
| 621 |
+
payload[out_b] = line_b_val if line_b_val not in ("", None) else None
|
| 622 |
+
else:
|
| 623 |
+
payload[out_m] = None
|
| 624 |
+
payload[out_a] = None
|
| 625 |
+
payload[out_b] = None
|
| 626 |
+
|
| 627 |
+
save_data(payload)
|
| 628 |
|
| 629 |
st.set_page_config(layout='wide')
|
| 630 |
# Title of the app
|