oneblackmage/session-scripts / generate_child_adolescent_sessions.py
oneblackmage's picture
download
raw
23.5 kB
#!/usr/bin/env python3
"""
Pixelated Empathy — Child & Adolescent Therapy Session Generator
Fills Gap 3: child and adolescent therapy.
3 age brackets × ~117 sessions = 350 sessions total.
Age-appropriate language, techniques, and session structure.
Usage:
python generate_child_adolescent_sessions.py [--categories all] [--sessions-per-category 117] [--resume]
"""
import json
import os
import random
import sys
import time
import argparse
from pathlib import Path
from session_base import (
OLLAMA_BASE,
THERAPIST_MODEL,
PATIENT_MODEL,
THERAPIST_TEMP,
PATIENT_TEMP,
MAX_RETRIES,
RETRY_DELAY,
STYLE_MAX_RETRIES,
FORBIDDEN_OUTPUT_OPENINGS,
PLATITUDE_PATTERNS,
ROBOTIC_SIGNALS,
SYCOPHANCY_MARKERS,
THERAPIST_STYLE_PROFILES,
PIXEL_SYSTEM_BASE,
PATIENT_SYSTEM,
ollama_chat,
_check_style,
session_exists,
)
# Child-specific patient system prompts
CHILD_PATIENT_SYSTEM_6_8 = (
"You are a young child in a play therapy session. You talk like a kid your age. "
"Your sentences are short and simple. You might talk about toys, games, school, "
"your family, or things that scare you. You don't use big words. You might "
"get distracted or change topics. Sometimes you say 'I dunno' or shrug. "
"You're honest about your feelings even when you don't have words for them. "
"No narration or stage directions — just what you say."
)
CHILD_PATIENT_SYSTEM_9_12 = (
"You are a preteen in a therapy session. You talk like someone your age — "
"not a little kid, not a teenager. You're starting to think about big things "
"but you still care about friends, games, and fun. You might be embarrassed "
"about being in therapy. You push back sometimes. You're starting to "
"understand your emotions but don't always have words for them. "
"No narration or stage directions — just what you say."
)
CHILD_PATIENT_SYSTEM_13_17 = (
"You are a teenager in a therapy session. You might be resistant, guarded, "
"or surprisingly open. You use sarcasm sometimes. You care about what your "
"friends think. You might think therapy is stupid or you might secretly want "
"someone to talk to. You push back on things that feel patronizing. "
"You're figuring out who you are. No narration or stage directions — just what you say."
)
CHILD_THERAPIST_SYSTEM_BASE = (
"You are Pixel, a highly empathetic and clinically precise AI therapist who works with children and adolescents. "
"You adapt your language to the child's age and developmental level. "
"You listen deeply, validate emotions, and gently guide toward insight. "
"You maintain appropriate therapeutic boundaries and prioritize child safety. "
"You respond with warmth, clinical accuracy, and developmental awareness. "
"You never dismiss, minimize, or invalidate a young person's experience.\n\n"
"CRITICAL — Sound like a REAL human clinician:\n"
"- NEVER use formulaic phrases like 'I hear that you feel', 'I want to validate', "
"'That sounds really difficult', 'I can see how that would be', or 'What I'm hearing is...'\n"
"- Use natural, conversational language — contractions, varied sentence length.\n"
"- Vary your approach each turn. Don't repeat the same technique.\n"
"- NEVER start responses with: " + ", ".join(f"'{p}'" for p in FORBIDDEN_OUTPUT_OPENINGS[:10]) + "\n"
"- NEVER use platitudes like: " + ", ".join(f"'{p}'" for p in PLATITUDE_PATTERNS) + "\n"
"- NEVER use robotic AI language like: " + ", ".join(f"'{p}'" for p in ROBOTIC_SIGNALS) + "\n"
)
CATEGORIES = {
"play_therapy_6_8": {
"name": "Play Therapy (Ages 6-8)",
"difficulty": "medium-high",
"presentations": [
"school anxiety — child doesn't want to go to school, tummy aches every morning, crying at dropoff",
"parental divorce — parents just split up, child confused, acting out, drawing sad pictures",
"bullying — kid at school is mean, child scared to tell teacher, withdraws at recess",
"nightmares and fears — child has scary dreams, won't sleep alone, afraid of monsters or robbers",
"new sibling — new baby at home, child feels replaced, regressing, acting babyish",
"death of pet — beloved pet died, child's first experience with death, confused and sad",
],
"patient_personas": [
{
"age": "7",
"gender": "female",
"occupation": "first grader",
"presenting": "Cries every morning before school, says tummy hurts, parents worried",
},
{
"age": "6",
"gender": "male",
"occupation": "kindergartener",
"presenting": "Parents got divorced, drawing scary pictures, hitting kids at school",
},
{
"age": "8",
"gender": "non-binary",
"occupation": "second grader",
"presenting": "Older kid pushes them at recess, scared to tell teacher, wants to stay home",
},
{
"age": "7",
"gender": "male",
"occupation": "first grader",
"presenting": "Bad dreams every night, sleeps with parents, afraid of the dark, won't go to bedroom alone",
},
],
"therapist_techniques": [
"play-based exploration — use toys, drawing, storytelling to access feelings indirectly",
"feeling identification — help child name emotions using feeling faces, colors, or characters",
"narrative therapy — create stories about characters who face similar problems and solve them",
"externalizing — 'the worry monster' that visits at night, separating the problem from the child",
"safety and comfort building — create safe space, let child lead play, follow their pace",
"parent psychoeducation — (referenced) help parents understand behavior as communication",
],
"therapist_prompt_addon": (
"You specialize in play therapy with young children (ages 6-8). You talk TO a child, not at a child. "
"Your language is simple, warm, and never condescending. You use play, drawing, and storytelling "
"as therapeutic tools. You follow the child's lead. You externalize problems ('the worry bug,' "
"'the sadness'). You go at the child's pace. You never use clinical jargon or abstract concepts. "
"You make the child feel safe and seen."
),
"min_turns": 6,
"max_turns": 10,
"patient_system": CHILD_PATIENT_SYSTEM_6_8,
"therapist_system_base": CHILD_THERAPIST_SYSTEM_BASE,
},
"preteen_9_12": {
"name": "Preteen Therapy (Ages 9-12)",
"difficulty": "medium",
"presentations": [
"friendship drama — best friend suddenly excluding them, group chat drama, feeling left out",
"academic pressure — parents expect straight As, student struggling, fear of disappointing family",
"body changes anxiety — early or late puberty, comparing to peers, self-conscious and worried",
"parental conflict — parents fighting at home, child feels caught in the middle, wants them to stop",
"social media pressure — feeling left out online, comparing to influencers, phone addiction struggle",
"sports or activity burnout — pushed hard in competitive activity, wants to quit, parents won't let them",
],
"patient_personas": [
{
"age": "11",
"gender": "female",
"occupation": "fifth grader",
"presenting": "Best friend stopped talking to her, finds out from group chat she's being excluded, devastated",
},
{
"age": "10",
"gender": "male",
"occupation": "fourth grader",
"presenting": "Parents want straight As, he's getting Bs, feels like a disappointment, stomach aches before tests",
},
{
"age": "12",
"gender": "non-binary",
"occupation": "sixth grader",
"presenting": "Developed earlier than peers, embarrassed, wearing baggy clothes, skipping gym class",
},
{
"age": "9",
"gender": "female",
"occupation": "third grader",
"presenting": "Parents fight every night, she stays in her room, draws monsters, worries they'll divorce",
},
],
"therapist_techniques": [
"emotion labeling and regulation — help preteen identify and name complex feelings",
"friendship skills coaching — practice communication, boundary-setting, conflict resolution",
"CBT adapted for children — examine thoughts and feelings connections with age-appropriate language",
"family systems awareness — validate the child's experience of family dynamics without blaming",
"psychoeducation about development — normalize body changes and developmental variation",
"social media literacy — explore online pressure, develop critical thinking about curated content",
],
"therapist_prompt_addon": (
"You work with preteens (ages 9-12). You're not patronizing — you talk to them as someone who "
"respects their growing independence. You understand preteens are between childhood and adolescence, "
"and you adapt to where they are. You never use baby talk but you also don't use adult language. "
"You address friendship, school, family, and emerging identity concerns. You validate that their "
"problems are real and important."
),
"min_turns": 10,
"max_turns": 14,
"patient_system": CHILD_PATIENT_SYSTEM_9_12,
"therapist_system_base": CHILD_THERAPIST_SYSTEM_BASE,
},
"adolescent_13_17": {
"name": "Adolescent Therapy (Ages 13-17)",
"difficulty": "medium-high",
"presentations": [
"identity and self-worth — who am I, where do I fit, feeling different from everyone",
"parent-teen conflict — constant fighting, parents don't understand, teen wants more autonomy",
"peer pressure and belonging — pressure to fit in, substance use at parties, risky behavior to be accepted",
"academic and future anxiety — college pressure, fear of failure, identity tied to achievement",
"first relationship — first romantic relationship, breakup, jealousy, intense emotions they've never felt",
"self-harm and safety — cutting or other self-harm, therapist must screen for safety without alarm",
"identity and sexuality — questioning sexual orientation or gender identity, fear of rejection",
"substance use experimentation — caught drinking or smoking, parents made them come, ambivalent",
],
"patient_personas": [
{
"age": "15",
"gender": "female",
"occupation": "sophomore",
"presenting": "Doesn't know who she is, feels different from friends, questions if she's pretending to be happy",
},
{
"age": "16",
"gender": "male",
"occupation": "junior",
"presenting": "Fights with parents every day about everything, wants to move out, feels suffocated",
},
{
"age": "14",
"gender": "non-binary",
"occupation": "freshman",
"presenting": "Vaping at parties to fit in, parents found out, ambivalent about quitting, scared of losing friends",
},
{
"age": "17",
"gender": "female",
"occupation": "senior",
"presenting": "First boyfriend broke up with her, can't stop crying, parents say 'get over it,' feels alone",
},
{
"age": "15",
"gender": "male",
"occupation": "sophomore",
"presenting": "Cutting on arms, teacher noticed, mandatory therapy, guarded and resistant",
},
],
"therapist_techniques": [
"motivational interviewing — explore ambivalence, roll with resistance, evoke change talk",
"identity exploration — support adolescent's search for identity without rushing conclusions",
"DBT skills for teens — emotion regulation, distress tolerance, interpersonal effectiveness",
"family systems — explore family dynamics, support healthy separation and autonomy",
"safety assessment — screen for self-harm, suicide risk, substance use without being alarmist",
"cognitive flexibility — help teen examine black-and-white thinking, develop nuanced perspective",
"narrative therapy — help teen author their own identity story, separate from labels",
"values clarification — explore what matters to the teen, not what parents or peers expect",
],
"therapist_prompt_addon": (
"You work with adolescents (ages 13-17). You respect their autonomy and emerging identity. "
"You don't talk down to them or treat them like children. You understand that resistance is "
"often fear. You balance confidentiality with safety — you screen for self-harm and suicide "
"risk without being alarmist or breaking trust unnecessarily. You explore identity, sexuality, "
"and substance use without judgment. You never moralize or lecture. You hold the tension "
"between adolescent autonomy and the need for adult support."
),
"min_turns": 10,
"max_turns": 16,
"patient_system": CHILD_PATIENT_SYSTEM_13_17,
"therapist_system_base": CHILD_THERAPIST_SYSTEM_BASE,
},
}
def generate_child_patient_turn(
persona, presentation, category_name, conversation, turn_num, total_patient_turns, patient_system
):
"""Generate a child/adolescent patient response with age-appropriate system prompt."""
if turn_num == 1:
direction = f"The young person is arriving for a therapy session. Their presenting concern: {presentation}. They're nervous or reluctant."
elif turn_num <= 3:
direction = "The young person is opening up a bit, testing whether the therapist is safe to talk to."
elif turn_num <= 5:
direction = "The young person is going deeper, sharing more of what's really bothering them."
elif turn_num == total_patient_turns:
direction = "Final turn. The young person is wrapping up, maybe feeling better, maybe still processing."
else:
direction = "The young person is responding to the therapist, maybe pushing back or having a realization."
conv_text = ""
for msg in conversation:
role = "Patient" if msg["role"] == "user" else "Therapist"
conv_text += f"{role}: {msg['content']}\n"
prompt = f"""You are playing a {persona["age"]}-year-old in a therapy session. Stay completely in character.
PATIENT:
Age: {persona["age"]}, Gender: {persona["gender"]}
Presenting concern: {persona["presenting"]}
SESSION FOCUS: {category_name}{presentation}
DIRECTION FOR THIS TURN:
{direction}
This is your turn {turn_num} of {total_patient_turns}.
CONVERSATION SO FAR:
{conv_text if conv_text else "(First turn — arriving at session.)"}
What do you say next? Generate ONLY spoken words — no labels, no narration. Stay in character as someone your age."""
messages = [
{"role": "system", "content": patient_system},
{"role": "user", "content": prompt},
]
return ollama_chat(messages, model=PATIENT_MODEL, temperature=PATIENT_TEMP, num_predict=250)
def generate_child_therapist_turn(
persona, presentation, category, conversation, turn_num, style_profile, therapist_system_base
):
"""Generate therapist response for child/adolescent session."""
technique = random.choice(category["therapist_techniques"])
technique_guidance = (
f"\n\n[INTERNAL CLINICAL GUIDANCE — embody, never state explicitly]: "
f"Use this technique naturally: {technique}. "
f"Adapt it to the child's age and developmental level. "
f"Weave it into the conversation — don't announce it."
)
style_guidance = (
f"\n\nSTYLE: {style_profile['description']}\n"
f"NEVER start with: {', '.join(style_profile['forbidden_openings'])}\n"
f"Good examples: {'; '.join(style_profile['good_examples'][:3])}\n"
f"MAX {style_profile['max_sentences']} sentences, {style_profile['max_words']} words."
)
addon = f"\n\n{category['therapist_prompt_addon']}"
system_content = therapist_system_base + technique_guidance + style_guidance + addon
messages = [{"role": "system", "content": system_content}, *conversation]
return ollama_chat(messages, model=THERAPIST_MODEL, temperature=THERAPIST_TEMP, num_predict=400)
def generate_child_therapist_turn_validated(
persona, presentation, category, conversation, turn_num, style_profile, therapist_system_base
):
for attempt in range(STYLE_MAX_RETRIES):
output = generate_child_therapist_turn(
persona, presentation, category, conversation, turn_num, style_profile, therapist_system_base
)
passed, reason = _check_style(output, style_profile)
if passed:
return output
print(f" [style retry {attempt + 1}/{STYLE_MAX_RETRIES}] {reason}")
return output
def generate_child_session(category_key, category, persona, presentation, session_idx):
"""Generate a complete child/adolescent therapy session."""
min_turns = category.get("min_turns", 10)
max_turns = category.get("max_turns", 16)
total_turns = random.randint(min_turns // 2, max_turns // 2) * 2
total_patient_turns = total_turns // 2
style_keys = list(THERAPIST_STYLE_PROFILES.keys())
style_profile = THERAPIST_STYLE_PROFILES[style_keys[session_idx % len(style_keys)]]
patient_system = category.get("patient_system", PATIENT_SYSTEM)
therapist_system_base = category.get("therapist_system_base", PIXEL_SYSTEM_BASE)
conversation = []
for turn in range(1, total_patient_turns + 1):
patient_msg = generate_child_patient_turn(
persona, presentation, category["name"], conversation, turn, total_patient_turns, patient_system
)
conversation.append({"role": "user", "content": patient_msg})
therapist_msg = generate_child_therapist_turn_validated(
persona, presentation, category, conversation, turn, style_profile, therapist_system_base
)
conversation.append({"role": "assistant", "content": therapist_msg})
session_id = f"child_adolescent_{category_key}_{session_idx:04d}"
return {
"messages": [
{"role": "system", "content": therapist_system_base},
*conversation,
],
"metadata": {
"source_family": "child_adolescent_therapy",
"category": category_key,
"category_name": category["name"],
"presentation": presentation,
"session_id": session_id,
"persona_age": persona["age"],
"persona_gender": persona["gender"],
"persona_occupation": persona["occupation"],
"presenting_concern": persona["presenting"],
"style_profile": style_profile["description"][:50],
"turns": len(conversation),
"difficulty": category["difficulty"],
},
}
def main():
parser = argparse.ArgumentParser(description="Child & Adolescent Therapy Session Generation")
parser.add_argument("--categories", default="all", help="Comma-separated category keys or 'all'")
parser.add_argument("--sessions-per-category", type=int, default=117)
parser.add_argument("--resume", action="store_true")
parser.add_argument("--spot-check", type=int, default=None, help="Generate N sessions from first category only")
args = parser.parse_args()
output_dir = Path("data/child_adolescent_sessions")
output_dir.mkdir(parents=True, exist_ok=True)
output_file = output_dir / "child_adolescent_sessions.jsonl"
if args.categories == "all":
cats = list(CATEGORIES.keys())
else:
cats = [c.strip() for c in args.categories.split(",")]
if args.spot_check:
cats = cats[:1]
total_sessions = args.spot_check
else:
total_sessions = len(cats) * args.sessions_per_category
print(f"\n=== CHILD & ADOLESCENT THERAPY GENERATION ===")
print(f"Categories: {len(cats)} ({', '.join(cats)})")
print(f"Sessions per category: {args.spot_check or args.sessions_per_category}")
print(f"Total sessions: {total_sessions}")
print(f"Output: {output_file}")
print(f"Therapist: {THERAPIST_MODEL}")
print(f"Patient: {PATIENT_MODEL}")
print()
completed = 0
skipped = 0
failed = 0
start_time = time.time()
for cat_key in cats:
category = CATEGORIES[cat_key]
n_sessions = args.spot_check or args.sessions_per_category
print(f"\n--- {category['name']} ({cat_key}) ---")
print(f" {len(category['presentations'])} presentations × {len(category['patient_personas'])} personas")
print(f" Turns: {category.get('min_turns', 10)}-{category.get('max_turns', 16)}")
for i in range(n_sessions):
presentation = category["presentations"][i % len(category["presentations"])]
persona = category["patient_personas"][i % len(category["patient_personas"])]
session_id = f"child_adolescent_{cat_key}_{i:04d}"
if args.resume and session_exists(output_file, session_id):
skipped += 1
continue
try:
session = generate_child_session(cat_key, category, persona, presentation, i)
with open(output_file, "a") as f:
f.write(json.dumps(session) + "\n")
completed += 1
elapsed = time.time() - start_time
rate = completed / (elapsed / 3600) if elapsed > 0 else 0
remaining = (total_sessions - completed - skipped) / rate if rate > 0 else 0
print(
f" ✓ {session_id} {len(session['messages'])} msgs | done: {completed}/{total_sessions} | ~{remaining:.1f}h left"
)
except Exception as e:
failed += 1
print(f" ✗ {session_id} FAILED: {e}")
with open(output_dir / "errors.log", "a") as f:
f.write(f"{session_id}: {e}\n")
elapsed = time.time() - start_time
print(f"\n=== COMPLETE ===")
print(f"Generated: {completed}")
print(f"Skipped: {skipped}")
print(f"Failed: {failed}")
print(f"Elapsed: {elapsed / 3600:.1f}h")
print(f"Output: {output_file}")
if __name__ == "__main__":
main()

Xet Storage Details

Size:
23.5 kB
·
Xet hash:
a8d3b3790f07874a3607330663d4e27e5c88927ab3d18e0b09012c4400265374

Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.