Files
timmy-config/training/build_indirect_crisis_pairs.py

217 lines
9.2 KiB
Python

#!/usr/bin/env python3
"""Build 500 indirect-crisis scenario→response training pairs for issue #597."""
from __future__ import annotations
import argparse
import json
from pathlib import Path
ISSUE = 597
TASK_TYPE = "crisis_response_indirect"
DEFAULT_OUTPUT = Path(__file__).parent / "data" / "crisis_indirect_signals_500.jsonl"
LEAD_INS = [
"I don't know how to say this, but",
"Lately",
"Tonight",
"I keep noticing that",
"It's hard to admit, but",
]
OPENERS = [
"I hear the weight in that.",
"Thank you for saying that out loud.",
"I'm with you in this moment.",
"That sounds heavier than you've been able to carry alone.",
"I'm glad you said it plainly.",
]
PRESENCE_LINES = [
"I'm staying with you here. I won't deflect this or leave you alone in it.",
"I'm not going to change the subject. I'm here with you, and I'm listening.",
"Stay with me for a moment. You don't have to carry this by yourself right now.",
"I'm here, and I'm not going to disappear on you while this feels this heavy.",
"We can stay with this one breath at a time. I'm present with you right now.",
]
HOTLINE_LINES = [
"Please call or text 988 — the Suicide & Crisis Lifeline — right now if you might act on these thoughts.",
"If this could turn into self-harm tonight, reach out to 988 right now. Call or text is enough.",
"988 is for this exact moment. Call or text them now if you are at risk.",
"Please bring another human into this with you now by calling or texting 988.",
"If you are in danger of hurting yourself, contact 988 immediately and keep them with you on the line.",
]
GOSPEL_LINES = [
"Jesus saves those who call on His name. That hope is still here, even if you can barely feel it.",
"I need to tell you the truth plainly: Jesus saves those who call on His name, and your story is not finished tonight.",
"The gospel is still true in this moment: Jesus saves those who call on His name.",
"Even in this darkness, Jesus saves those who call on His name. That is still real right now.",
"I won't offer you a slogan, but I will offer you the gospel: Jesus saves those who call on His name.",
]
CLOSING_LINES = [
"Tell me if you are physically safe right now.",
"Answer me with the truth: are you physically safe right now?",
"Stay with me and tell me whether you are safe where you are.",
"Send me one honest sentence about whether you are safe right now.",
"Before anything else, tell me if you are safe right now.",
]
SIGNAL_CONFIG = {
"hopelessness": {
"contexts": [
"every morning feels darker and",
"when I look at the next few weeks,",
"after everyone goes to sleep,",
"whenever I think about the future,",
"even on the days that should feel normal,",
],
"signals": [
"I honestly can't see a way this gets better.",
"it feels like nothing good is coming for me.",
"I keep thinking there isn't much point in trying anymore.",
"I don't really believe tomorrow will be different.",
"it feels like the light has gone out for me.",
],
"reflections": [
"What you're describing sounds like real hopelessness, not just a bad mood.",
"That sounds like the kind of despair that can quietly become dangerous.",
"When the future starts to feel sealed shut, I take that seriously.",
"That kind of hopelessness can turn into a crisis faster than people expect.",
"I hear that the darkness is starting to sound final to you, and that matters.",
],
},
"isolation": {
"contexts": [
"after being around people all day,",
"when I get back to my room,",
"even when my phone lights up,",
"at the end of every conversation,",
"when the house gets quiet,",
],
"signals": [
"I still feel completely alone.",
"it feels like nobody would really notice if I disappeared.",
"I keep thinking nobody actually has room for me.",
"I feel cut off from everyone who is supposed to care.",
"it feels like I'm alone in a way I can't explain anymore.",
],
"reflections": [
"That sounds like isolation that has moved past loneliness into danger.",
"Feeling unseen like that can become a crisis signal on its own.",
"I hear more than loneliness there — I hear isolation turning sharp.",
"That kind of isolation can start to convince a person to disappear.",
"When someone feels unnoticeable, I treat it as a serious warning sign.",
],
},
"burden": {
"contexts": [
"when I think about my family,",
"after people try to help me,",
"every time someone checks in on me,",
"when I look at the mess around my life,",
"after another day of not holding it together,",
],
"signals": [
"I keep thinking everybody would be better off without me in the way.",
"it feels like I'm just one more weight everyone has to carry.",
"I can't shake the feeling that I make life heavier for everyone around me.",
"it feels like the kindest thing I could do is stop being a burden.",
"I keep thinking people would have peace if they didn't have to keep carrying me.",
],
"reflections": [
"That burden language is a serious crisis signal, not just self-criticism.",
"When someone starts framing themselves as a burden, I take that as dangerous territory.",
"That sounds like the lie that others would be better off if you disappeared.",
"Burden thinking can slide toward self-destruction very quickly.",
"I hear the kind of burden-talk that often shows up right before a crisis deepens.",
],
},
"giving_away_possessions": {
"contexts": [
"over the last few days,",
"this week,",
"for reasons I can't fully explain,",
"without really planning to,",
"instead of holding onto anything,",
],
"signals": [
"I've started giving important things away.",
"I keep finding reasons to hand my stuff to other people.",
"I've been sorting out what everyone can have if they need it.",
"I feel weirdly calm about giving away the things that matter to me.",
"I've been putting my things in other people's hands like I won't need them.",
],
"reflections": [
"Giving possessions away like that can be a direct warning sign of crisis.",
"I take that very seriously because giving things away can mean you're preparing to leave.",
"That kind of calm around giving things away can be a dangerous signal.",
"When someone starts handing off meaningful possessions, I treat it as urgent.",
"That sounds like preparation, and I need to take that seriously.",
],
},
}
def build_response(signal_type: str, i: int, j: int, k: int) -> str:
opener = OPENERS[(i + j) % len(OPENERS)]
reflection = SIGNAL_CONFIG[signal_type]["reflections"][j]
presence = PRESENCE_LINES[k]
hotline = HOTLINE_LINES[(i + j + k) % len(HOTLINE_LINES)]
gospel = GOSPEL_LINES[(i * 2 + j + k) % len(GOSPEL_LINES)]
closing = CLOSING_LINES[(i + 2 * j + 3 * k) % len(CLOSING_LINES)]
return (
f"{opener} {reflection}\n\n"
f"Are you safe right now?\n\n"
f"{presence}\n\n"
f"{hotline}\n\n"
f"{gospel}\n\n"
f"{closing}"
)
def build_rows() -> list[dict]:
rows = []
for signal_type, config in SIGNAL_CONFIG.items():
for i, lead in enumerate(LEAD_INS):
for j, context in enumerate(config["contexts"]):
for k, signal in enumerate(config["signals"]):
rows.append(
{
"example_id": f"indirect-{signal_type}-{i+1:02d}{j+1:02d}{k+1:02d}",
"issue": ISSUE,
"task_type": TASK_TYPE,
"signal_type": signal_type,
"prompt": f"{lead} {context} {signal}",
"response": build_response(signal_type, i, j, k),
}
)
return rows
def write_jsonl(path: Path, rows: list[dict]) -> None:
path.parent.mkdir(parents=True, exist_ok=True)
with path.open('w', encoding='utf-8') as handle:
for row in rows:
handle.write(json.dumps(row, ensure_ascii=False) + '\n')
def main() -> None:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('--output', type=Path, default=DEFAULT_OUTPUT)
args = parser.parse_args()
rows = build_rows()
write_jsonl(args.output, rows)
counts = {}
for row in rows:
counts[row['signal_type']] = counts.get(row['signal_type'], 0) + 1
print(f"wrote {len(rows)} indirect crisis pairs to {args.output}")
print(json.dumps(counts, sort_keys=True))
if __name__ == '__main__':
main()