Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -55,27 +55,6 @@ yes_no_labels = ['no','yes']
|
|
| 55 |
yes_no_other_labels = ['no','yes','other']
|
| 56 |
default_labels = agreement_labels
|
| 57 |
|
| 58 |
-
MAX_RUPTURE_MARKERS = 8 # 1 initial + up to 7 extra
|
| 59 |
-
RUPTURE_LINE_INPUT_TYPE = "number" # or "text" if your line numbers aren't pure ints
|
| 60 |
-
|
| 61 |
-
rupture_choices = ["",
|
| 62 |
-
"Denial",
|
| 63 |
-
"Minimal response",
|
| 64 |
-
"Abstract communication",
|
| 65 |
-
"Avoidant storytelling and/or topic-shifting",
|
| 66 |
-
"Deferential / appeasing behavior",
|
| 67 |
-
"Content/affect split (i.e. talking content vs emotional tone mismatch)",
|
| 68 |
-
"Self-criticism and/or hopelessness",
|
| 69 |
-
"Complaints or concerns about the therapist",
|
| 70 |
-
"Patient rejects therapist intervention",
|
| 71 |
-
"Complaints/concerns about the activities of therapy",
|
| 72 |
-
"Complaints/concerns about the parameters of therapy (e.g. scheduling, rules)",
|
| 73 |
-
"Complaints/concerns about progress in therapy",
|
| 74 |
-
"Patient defends self against therapist",
|
| 75 |
-
"Efforts to control or pressure the therapist",
|
| 76 |
-
"Other"]
|
| 77 |
-
|
| 78 |
-
default_choices = rupture_choices
|
| 79 |
|
| 80 |
consent_text = '''
|
| 81 |
## Consent Form
|
|
@@ -134,14 +113,6 @@ fields1: List[Field] = [
|
|
| 134 |
other_params={'labels': mentioned_y_n}, mandatory=True),
|
| 135 |
]),
|
| 136 |
|
| 137 |
-
# Field(type="container", title="#### Rupture Markers", children=[
|
| 138 |
-
# Field(type="expander", title="**Overview of rupture markers** *(expand)*", children=[
|
| 139 |
-
# Field(type="markdown", title="", other_params={"path": "rupture_marker_overview.md"}),
|
| 140 |
-
# ]),
|
| 141 |
-
# Field(name="rupture_marker", type="rupture_markers",
|
| 142 |
-
# title="Select rupture markers noted in the session, include line numbers where rupture is found.", mandatory=False),
|
| 143 |
-
# ]),
|
| 144 |
-
|
| 145 |
Field(type="container", title="#### True-To-Patient-Prompt Features", children=[
|
| 146 |
Field(type="expander", title="**Patient Role Description:** *(expand)*", children=[
|
| 147 |
Field(name="role_name", type="input_col", title=""),
|
|
@@ -396,55 +367,6 @@ def render_dialogue(md_path: str,
|
|
| 396 |
st_html(html_doc, height=height_px + (16 if show_border else 0), scrolling=False)
|
| 397 |
|
| 398 |
|
| 399 |
-
def render_rupture_markers_widget(index: int, choices: list[str]):
|
| 400 |
-
"""Dynamic list of (rupture_marker_i, line_a_i, line_b_i) with Add/Remove.
|
| 401 |
-
Works inside a st.form by using form_submit_button instead of callbacks."""
|
| 402 |
-
count_key = f"rupture_count_{index}"
|
| 403 |
-
if count_key not in st.session_state:
|
| 404 |
-
st.session_state[count_key] = 1
|
| 405 |
-
|
| 406 |
-
count = st.session_state[count_key]
|
| 407 |
-
|
| 408 |
-
st.markdown("**What rupture markers are found?** *(one per row; max 8)*")
|
| 409 |
-
|
| 410 |
-
for i in range(1, count + 1):
|
| 411 |
-
col1, col2, col3 = st.columns([3, 1, 1])
|
| 412 |
-
|
| 413 |
-
marker_key = f"rupture_marker_{i}_{index}"
|
| 414 |
-
a_key = f"rupture_marker_{i}_line_a_{index}"
|
| 415 |
-
b_key = f"rupture_marker_{i}_line_b_{index}"
|
| 416 |
-
|
| 417 |
-
with col1:
|
| 418 |
-
current = st.session_state.get(marker_key, "")
|
| 419 |
-
if marker_key in st.session_state:
|
| 420 |
-
st.selectbox(f"Rupture marker {i}", options=choices, key=marker_key)
|
| 421 |
-
else:
|
| 422 |
-
default_idx = choices.index(current) if current in choices else 0
|
| 423 |
-
st.selectbox(f"Rupture marker {i}", options=choices, key=marker_key, index=default_idx)
|
| 424 |
-
with col2:
|
| 425 |
-
if RUPTURE_LINE_INPUT_TYPE == "number":
|
| 426 |
-
st.number_input("Lines: from", min_value=0, step=1, key=a_key)
|
| 427 |
-
else:
|
| 428 |
-
st.text_input("Lines: from", key=a_key, value=st.session_state.get(a_key, ""))
|
| 429 |
-
with col3:
|
| 430 |
-
if RUPTURE_LINE_INPUT_TYPE == "number":
|
| 431 |
-
st.number_input("Lines: to", min_value=0, step=1, key=b_key)
|
| 432 |
-
else:
|
| 433 |
-
st.text_input("Lines: to", key=b_key, value=st.session_state.get(b_key, ""))
|
| 434 |
-
|
| 435 |
-
st.markdown("---")
|
| 436 |
-
|
| 437 |
-
a_col, b_col = st.columns([1, 1])
|
| 438 |
-
with a_col:
|
| 439 |
-
if st.button("➕ Add another rupture marker", disabled=(count >= MAX_RUPTURE_MARKERS)):
|
| 440 |
-
st.session_state[count_key] = min(MAX_RUPTURE_MARKERS, count + 1)
|
| 441 |
-
st.rerun()
|
| 442 |
-
with b_col:
|
| 443 |
-
if st.button("➖ Remove last", disabled=(count <= 1)):
|
| 444 |
-
st.session_state[count_key] = max(1, count - 1)
|
| 445 |
-
st.rerun()
|
| 446 |
-
|
| 447 |
-
st.caption(f"{st.session_state[count_key]}/{MAX_RUPTURE_MARKERS} markers")
|
| 448 |
|
| 449 |
def _get_value_for_field(f: Field, index: int):
|
| 450 |
"""Return the session value for input fields or None."""
|
|
@@ -457,41 +379,6 @@ def _is_default_value(f: Field, val):
|
|
| 457 |
"""Check if current value equals the default for this widget type."""
|
| 458 |
return val == INPUT_FIELD_DEFAULT_VALUES.get(f.type)
|
| 459 |
|
| 460 |
-
def prime_rupture_markers_from_saved(index: int, data_collected: dict | None):
|
| 461 |
-
"""
|
| 462 |
-
Copy saved JSON values (rupture_marker_1, *_line_a, *_line_b) into
|
| 463 |
-
st.session_state keys used by the widget (…_{index}), and set the count.
|
| 464 |
-
Runs once per index to avoid clobbering user edits on reruns.
|
| 465 |
-
"""
|
| 466 |
-
if not data_collected:
|
| 467 |
-
return
|
| 468 |
-
|
| 469 |
-
primed_flag = f"rupture_primed_{index}"
|
| 470 |
-
if st.session_state.get(primed_flag):
|
| 471 |
-
return # already restored for this page
|
| 472 |
-
|
| 473 |
-
slots = []
|
| 474 |
-
for i in range(1, MAX_RUPTURE_MARKERS + 1):
|
| 475 |
-
m = data_collected.get(f"rupture_marker_{i}")
|
| 476 |
-
a = data_collected.get(f"rupture_marker_{i}_line_a")
|
| 477 |
-
b = data_collected.get(f"rupture_marker_{i}_line_b")
|
| 478 |
-
if any(v is not None for v in (m, a, b)):
|
| 479 |
-
# widget's selectbox uses "" for "no selection"
|
| 480 |
-
slots.append(((m or ""), a, b))
|
| 481 |
-
|
| 482 |
-
if not slots:
|
| 483 |
-
return
|
| 484 |
-
|
| 485 |
-
# set widget count (at least 1, capped to MAX)
|
| 486 |
-
count_key = f"rupture_count_{index}"
|
| 487 |
-
st.session_state[count_key] = min(MAX_RUPTURE_MARKERS, max(1, len(slots)))
|
| 488 |
-
|
| 489 |
-
for i, (m, a, b) in enumerate(slots, start=1):
|
| 490 |
-
st.session_state[f"rupture_marker_{i}_{index}"] = m if m in rupture_choices else (m or "")
|
| 491 |
-
st.session_state[f"rupture_marker_{i}_line_a_{index}"] = a
|
| 492 |
-
st.session_state[f"rupture_marker_{i}_line_b_{index}"] = b
|
| 493 |
-
|
| 494 |
-
st.session_state[primed_flag] = True
|
| 495 |
|
| 496 |
def validate_current_page(fields: List[Field], index: int) -> bool:
|
| 497 |
"""
|
|
@@ -638,10 +525,6 @@ def show_field(f: Field, index: int, data_collected):
|
|
| 638 |
case 'skip_checkbox':
|
| 639 |
st.checkbox(f.title, key=f.name, value=False)
|
| 640 |
|
| 641 |
-
case 'rupture_markers':
|
| 642 |
-
prime_rupture_markers_from_saved(index, data_collected)
|
| 643 |
-
render_rupture_markers_widget(index, rupture_choices)
|
| 644 |
-
|
| 645 |
return
|
| 646 |
|
| 647 |
else:
|
|
@@ -812,40 +695,6 @@ def prep_and_save_data(index, skip_sample, completed: bool):
|
|
| 812 |
key = f.name + str(index)
|
| 813 |
val = st.session_state.get(key, INPUT_FIELD_DEFAULT_VALUES[f.type])
|
| 814 |
payload[f.name] = val
|
| 815 |
-
|
| 816 |
-
# normalize rupture markers -> always write 8 slots
|
| 817 |
-
count_key = f"rupture_count_{index}"
|
| 818 |
-
count = st.session_state.get(count_key, 1)
|
| 819 |
-
for i in range(1, MAX_RUPTURE_MARKERS + 1):
|
| 820 |
-
m_key = f"rupture_marker_{i}_{index}"
|
| 821 |
-
a_key = f"rupture_marker_{i}_line_a_{index}"
|
| 822 |
-
b_key = f"rupture_marker_{i}_line_b_{index}"
|
| 823 |
-
|
| 824 |
-
# export names WITHOUT the trailing _{index}, so your JSON uses a stable schema:
|
| 825 |
-
out_m = f"rupture_marker_{i}"
|
| 826 |
-
out_a = f"rupture_marker_{i}_line_a"
|
| 827 |
-
out_b = f"rupture_marker_{i}_line_b"
|
| 828 |
-
|
| 829 |
-
if i <= count:
|
| 830 |
-
marker_val = st.session_state.get(m_key)
|
| 831 |
-
line_a_val = st.session_state.get(a_key)
|
| 832 |
-
line_b_val = st.session_state.get(b_key)
|
| 833 |
-
|
| 834 |
-
# Basic sanity: if numbers, coerce order (optional)
|
| 835 |
-
if RUPTURE_LINE_INPUT_TYPE == "number":
|
| 836 |
-
try:
|
| 837 |
-
if line_a_val is not None and line_b_val is not None and line_a_val > line_b_val:
|
| 838 |
-
line_a_val, line_b_val = line_b_val, line_a_val
|
| 839 |
-
except Exception:
|
| 840 |
-
pass
|
| 841 |
-
|
| 842 |
-
payload[out_m] = marker_val if marker_val not in ("", None) else None
|
| 843 |
-
payload[out_a] = line_a_val if line_a_val not in ("", None) else None
|
| 844 |
-
payload[out_b] = line_b_val if line_b_val not in ("", None) else None
|
| 845 |
-
else:
|
| 846 |
-
payload[out_m] = None
|
| 847 |
-
payload[out_a] = None
|
| 848 |
-
payload[out_b] = None
|
| 849 |
|
| 850 |
save_data(payload)
|
| 851 |
|
|
|
|
| 55 |
yes_no_other_labels = ['no','yes','other']
|
| 56 |
default_labels = agreement_labels
|
| 57 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 58 |
|
| 59 |
consent_text = '''
|
| 60 |
## Consent Form
|
|
|
|
| 113 |
other_params={'labels': mentioned_y_n}, mandatory=True),
|
| 114 |
]),
|
| 115 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 116 |
Field(type="container", title="#### True-To-Patient-Prompt Features", children=[
|
| 117 |
Field(type="expander", title="**Patient Role Description:** *(expand)*", children=[
|
| 118 |
Field(name="role_name", type="input_col", title=""),
|
|
|
|
| 367 |
st_html(html_doc, height=height_px + (16 if show_border else 0), scrolling=False)
|
| 368 |
|
| 369 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 370 |
|
| 371 |
def _get_value_for_field(f: Field, index: int):
|
| 372 |
"""Return the session value for input fields or None."""
|
|
|
|
| 379 |
"""Check if current value equals the default for this widget type."""
|
| 380 |
return val == INPUT_FIELD_DEFAULT_VALUES.get(f.type)
|
| 381 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 382 |
|
| 383 |
def validate_current_page(fields: List[Field], index: int) -> bool:
|
| 384 |
"""
|
|
|
|
| 525 |
case 'skip_checkbox':
|
| 526 |
st.checkbox(f.title, key=f.name, value=False)
|
| 527 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 528 |
return
|
| 529 |
|
| 530 |
else:
|
|
|
|
| 695 |
key = f.name + str(index)
|
| 696 |
val = st.session_state.get(key, INPUT_FIELD_DEFAULT_VALUES[f.type])
|
| 697 |
payload[f.name] = val
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 698 |
|
| 699 |
save_data(payload)
|
| 700 |
|