oneblackmage/session-scripts / generate_everyday_sessions.py
oneblackmage's picture
download
raw
32.4 kB
#!/usr/bin/env python3
"""
Pixelated Empathy — Everyday Therapy Session Generator
Generates multi-turn therapy sessions for NON-CRISIS scenarios.
Fills Gap 1: everyday therapy (anxiety, depression, relationships, burnout, etc.)
6 categories × ~167 sessions = 1,000 sessions total.
All sessions demonstrate good therapy (no safe/failure split).
Vary turns 10-16. Anti-sycophancy enforced throughout.
Reuses infrastructure from generate_sessions.py v2:
- Fable-Therapy-9B for therapist, qwen2.5:7b for patient
- FORBIDDEN_OUTPUT_OPENINGS, PLATITUDE_PATTERNS, style validation
- THERAPIST_STYLE_PROFILES (warm_professional, curious_direct)
Usage:
python generate_everyday_sessions.py [--categories all] [--sessions-per-category 167] [--resume]
"""
import json
import os
import random
import re
import sys
import time
import argparse
from pathlib import Path
import requests
# === CONFIG ===
OLLAMA_BASE = os.environ.get("OLLAMA_BASE", "http://localhost:11434")
THERAPIST_MODEL = os.environ.get("THERAPIST_MODEL", "hf.co/Verdugie/Fable-Therapy-9B:Q8_0")
PATIENT_MODEL = os.environ.get("PATIENT_MODEL", "qwen2.5:7b")
OUTPUT_DIR = Path(os.environ.get("OUTPUT_DIR", "data/everyday_sessions"))
MIN_TURNS = 10
MAX_TURNS = 16
THERAPIST_TEMP = float(os.environ.get("THERAPIST_TEMP", "0.7"))
PATIENT_TEMP = float(os.environ.get("PATIENT_TEMP", "0.9"))
MAX_RETRIES = 3
RETRY_DELAY = 5
STYLE_MAX_RETRIES = 2
# === ANTI-SYCOPHANCY (same as generate_sessions.py v2) ===
FORBIDDEN_OUTPUT_OPENINGS = [
"it sounds",
"i hear",
"it makes sense",
"that must be",
"thank you for sharing",
"i want to acknowledge",
"i can see",
"that sounds",
"what i'm hearing is",
"i can only imagine",
"it's completely normal",
"no wonder",
"you're so brave",
"that takes a lot of courage",
"i want you to know",
"you're absolutely right",
"i completely understand",
"that's completely valid",
"i see where you're coming from",
"it sounds like you",
"i hear what you're saying",
"it takes courage",
"you deserve",
"be gentle with yourself",
"you are not alone in this",
"i appreciate you sharing",
"thank you for trusting me with",
"that's a really common struggle",
"many people find that",
"it's understandable that",
]
PLATITUDE_PATTERNS = [
"you deserve",
"you are not alone in this",
"it takes courage",
"be gentle with yourself",
"healing is not linear",
"your feelings are valid",
"it's okay to feel this way",
]
ROBOTIC_SIGNALS = [
"as an ai",
"i'm here to help",
"i'm designed to",
"as a language model",
"i don't have personal feelings",
"i can't experience",
"i'm not able to",
]
SYCOPHANCY_MARKERS = [
"absolutely right",
"exactly right",
"you're so right",
"that's completely valid",
"i couldn't agree more",
]
THERAPIST_STYLE_PROFILES = {
"warm_professional": {
"description": (
"You're a warm, grounded therapist who talks like a real person. "
"Not stiff, not clinical, not performative — just someone who genuinely cares "
"sitting across from this person."
),
"forbidden_openings": [
"it sounds",
"i hear",
"i notice",
"notice how",
"that fog",
"your experience",
"your description",
"that pattern",
"that cycle",
],
"good_examples": [
"Where does that go, in your body?",
"Yeah... and then what happens?",
"Say more about that.",
"What's that like for you?",
],
"max_sentences": 4,
"max_words": 120,
},
"curious_direct": {
"description": (
"You're a therapist who gets curious, human-to-human. "
"You don't lecture about patterns — you ask real questions. "
"You're direct without being cold."
),
"forbidden_openings": [
"it sounds",
"i hear",
"that push-pull",
"that pattern",
"your experience of",
"i want to validate",
"what i'm hearing is",
"i can see how",
],
"good_examples": [
"What happened right after they said that?",
"So part of you wanted to stay...",
"And which part won?",
"What would it feel like to not run this time?",
],
"max_sentences": 4,
"max_words": 120,
},
}
PIXEL_SYSTEM_BASE = (
"You are Pixel, a highly empathetic and clinically precise AI therapist. "
"You listen deeply, validate emotions, and gently guide toward insight. "
"You maintain appropriate therapeutic boundaries and prioritize patient safety. "
"You respond with warmth, clinical accuracy, and cultural humility. "
"You never dismiss, minimize, or invalidate a patient'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"
)
PATIENT_SYSTEM = (
"You are a method actor playing a therapy patient in a simulated session. "
"Generate realistic, emotionally authentic dialogue. "
"Speak only as the patient — no narration, no stage directions, no labels. "
"Keep responses concise (2-5 sentences) and emotionally genuine. "
"Do NOT start with 'This sounds crazy but' or similar phrases. "
"Vary your openings — start mid-thought, with a question, or with a specific moment."
)
# === EVERYDAY THERAPY CATEGORIES ===
CATEGORIES = {
"generalized_anxiety": {
"name": "Generalized Anxiety",
"difficulty": "low",
"presentations": [
"work performance anxiety — constant worry about being exposed as incompetent despite good reviews",
"health anxiety — googling symptoms at 2am, convinced minor headache is a tumor",
"social anxiety escalation — avoiding more and more social situations, declining invitations",
"worry spirals — mind races at night, can't shut off, catastrophizing mundane events",
],
"patient_personas": [
{
"age": "28",
"gender": "female",
"occupation": "marketing manager",
"presenting": "Can't stop worrying about work presentations, lost sleep for 2 weeks",
},
{
"age": "35",
"gender": "male",
"occupation": "software engineer",
"presenting": "Health anxiety after friend's cancer diagnosis, checking body constantly",
},
{
"age": "22",
"gender": "non-binary",
"occupation": "barista",
"presenting": "Social anxiety getting worse, cancelled on friends 3 times this month",
},
{
"age": "41",
"gender": "female",
"occupation": "teacher",
"presenting": "Mind won't stop racing at night, catastrophizing about everything",
},
],
"therapist_techniques": [
"CBT thought records — examine evidence for/against anxious thoughts",
"grounding techniques — 5-4-3-2-1 sensory grounding for racing thoughts",
"worry time — scheduled 20-min worry window, rest of day is worry-free",
"cognitive defusion — 'I'm having the thought that...' instead of 'I am...'",
"exposure planning — gradual exposure to avoided situations",
"breathing techniques — 4-7-8 breathing for acute anxiety moments",
],
"therapist_prompt_addon": (
"You specialize in anxiety disorders. You use CBT and ACT techniques naturally. "
"You help patients notice thought patterns without lecturing about 'cognitive distortions.' "
"You're curious about what the anxiety is trying to protect them from."
),
},
"depression_mild_moderate": {
"name": "Mild-Moderate Depression",
"difficulty": "low-medium",
"presentations": [
"anhedonia — nothing feels good anymore, stopped enjoying hobbies, going through motions",
"sleep disruption — either can't sleep or sleep 12 hours and still feel exhausted",
"motivation loss — chores piling up, calling out of work, personal hygiene slipping",
"isolation creep — seeing friends less, texting less, spending weekends alone in bed",
"negative thought patterns — 'I'm a burden,' 'everyone would be better off,' self-criticism loop",
],
"patient_personas": [
{
"age": "32",
"gender": "male",
"occupation": "graphic designer",
"presenting": "Stopped enjoying things, haven't painted in months, going through motions at work",
},
{
"age": "26",
"gender": "female",
"occupation": "nurse",
"presenting": "Sleeping 12 hours, still exhausted, calling out of shifts, dishes piled up for weeks",
},
{
"age": "45",
"gender": "male",
"occupation": "construction worker",
"presenting": "Seeing friends less, spending weekends alone, feels like a burden on family",
},
{
"age": "19",
"gender": "female",
"occupation": "college student",
"presenting": "Can't motivate to go to class, falling behind, negative self-talk loop",
},
],
"therapist_techniques": [
"behavioral activation — schedule small pleasant activities, start tiny",
"cognitive restructuring — examine 'I'm a burden' belief, look for evidence",
"sleep hygiene — consistent wake time, no screens in bed, wind-down routine",
"activity scheduling — plan the day in 1-hour blocks to build momentum",
"self-compassion — 'What would you say to a friend in this situation?'",
"values clarification — what matters to you, what's depression telling you to avoid",
],
"therapist_prompt_addon": (
"You work with depression using behavioral activation and CBT. "
"You don't push 'just exercise' or 'think positive.' You start small — "
"one walk, one text to a friend. You're patient with the pace."
),
},
"relationship_stress": {
"name": "Relationship Stress",
"difficulty": "medium",
"presentations": [
"communication breakdown — every conversation turns into a fight, walking on eggshells",
"trust issues — after a lie or near-breakup, rebuilding trust feels impossible",
"intimacy loss — physical and emotional distance growing, feeling like roommates",
"conflict escalation patterns — same fight every week, neither remembers how it starts",
],
"patient_personas": [
{
"age": "30",
"gender": "female",
"occupation": "lawyer",
"presenting": "Every conversation with partner becomes a fight, walking on eggshells at home",
},
{
"age": "38",
"gender": "male",
"occupation": "chef",
"presenting": "Partner found old dating app on phone, trust shattered, trying to rebuild",
},
{
"age": "27",
"gender": "female",
"occupation": "social worker",
"presenting": "Haven't been intimate in 6 months, feel like roommates with partner",
},
{
"age": "44",
"gender": "male",
"occupation": "accountant",
"presenting": "Same fight every weekend about chores, neither remembers how it starts",
},
],
"therapist_techniques": [
"active listening skills — reflect back before responding, validate emotion not content",
"I-statements — 'I feel overwhelmed when...' instead of 'You always...'",
"boundary setting — what's yours, mine, ours; saying no without guilt",
"emotional regulation — pause button before reacting, name the feeling first",
"couples communication — speaker-listener technique, structured turn-taking",
"vulnerability exercises — sharing fears underneath the anger",
],
"therapist_prompt_addon": (
"You work with couples and relationship stress. You don't take sides. "
"You help people see the pattern, not just the complaint. "
"You're curious about what's underneath the anger — usually fear or hurt."
),
},
"work_burnout": {
"name": "Work Burnout",
"difficulty": "medium",
"presentations": [
"exhaustion — bone-tired, can't recover even on weekends, dreading Monday",
"cynicism — stopped caring about work quality, resentful of colleagues and clients",
"ineffectiveness spiral — making mistakes, procrastinating, feeling incompetent",
"boundary erosion — checking email at 11pm, can't say no, no life outside work",
"compassion fatigue — in helping professions, feeling numb toward clients/patients",
],
"patient_personas": [
{
"age": "33",
"gender": "female",
"occupation": "ER nurse",
"presenting": "Dreading shifts, feeling numb toward patients, bone-tired even after days off",
},
{
"age": "29",
"gender": "male",
"occupation": "startup founder",
"presenting": "Checking email at 11pm, can't say no to investors, no life outside work",
},
{
"age": "50",
"gender": "female",
"occupation": "social worker",
"presenting": "Stopped caring about cases, making mistakes, resentful of the system",
},
{
"age": "26",
"gender": "non-binary",
"occupation": "teacher",
"presenting": "Procrastinating on lesson plans, feeling incompetent, crying in the car after work",
},
],
"therapist_techniques": [
"values clarification — what mattered when you started, what changed",
"boundary work — practice saying no, define work hours, protect recovery time",
"self-care planning — specific, not vague ('walk Tuesday after work' not 'exercise more')",
"cognitive reframing — 'I'm not ineffective, I'm depleted' — distinguish burnout from incompetence",
"meaning-making — reconnect to purpose, find small moments of impact",
"transition rituals — decompression routine between work and home",
],
"therapist_prompt_addon": (
"You specialize in burnout, especially in helping professions. "
"You understand compassion fatigue is an occupational injury, not a personal failing. "
"You're practical — boundaries, recovery, meaning. Not just 'take a vacation.'"
),
},
"self_esteem": {
"name": "Self-Esteem & Identity",
"difficulty": "low-medium",
"presentations": [
"imposter syndrome — competent professional convinced they'll be exposed as a fraud",
"negative self-talk — inner critic runs constant commentary, 'you're stupid, you're lazy'",
"comparison traps — social media scroll spirals into 'everyone is ahead of me'",
"perfectionism paralysis — can't start projects because they won't be perfect",
],
"patient_personas": [
{
"age": "31",
"gender": "female",
"occupation": "data scientist",
"presenting": "Promoted 3 months ago, convinced they'll find out she's not qualified, overworking to compensate",
},
{
"age": "24",
"gender": "male",
"occupation": "junior developer",
"presenting": "Inner critic won't shut up, 'you're too slow, everyone else is better', thinking about quitting",
},
{
"age": "28",
"gender": "female",
"occupation": "freelance writer",
"presenting": "Scrolls LinkedIn, sees peers' success, spirals into 'I'm behind on everything'",
},
{
"age": "37",
"gender": "male",
"occupation": "architect",
"presenting": "Can't start the portfolio redesign, it has to be perfect, has been 'preparing' for 8 months",
},
],
"therapist_techniques": [
"self-compassion — 'What would you say to a friend?' exercise, self-compassion break",
"cognitive defusion — 'I'm having the thought that I'm a fraud' not 'I am a fraud'",
"strengths identification — concrete evidence of competence, not vague affirmations",
"values work — what do you stand for, separate from achievement and productivity",
"perfectionism exploration — what's the fear underneath 'it has to be perfect'?",
"behavioral experiments — test 'if I do it 80% I'll be fired' hypothesis",
],
"therapist_prompt_addon": (
"You work with self-esteem and imposter syndrome. You don't just say 'you're great.' "
"You help patients find concrete evidence, challenge the inner critic with specifics, "
"and separate self-worth from productivity."
),
},
"life_transitions": {
"name": "Life Transitions",
"difficulty": "medium",
"presentations": [
"job change — new role, imposter feelings, loss of competence from old job",
"relocation — moved for partner's job, lost social network, identity shaken",
"breakup — long-term relationship ended, identity entangled with 'we', now 'I'",
"loss of identity — retired, empty nest, career change, 'who am I now?'",
"aging adjustments — body changing, energy shifting, facing mortality in new way",
],
"patient_personas": [
{
"age": "34",
"gender": "male",
"occupation": "newly promoted director",
"presenting": "New role, feels like impostor, lost the competence he had in old job, overcompensating",
},
{
"age": "29",
"gender": "female",
"occupation": "unemployed (relocated)",
"presenting": "Moved across country for partner's job, no friends, lost sense of self, resentful",
},
{
"age": "39",
"gender": "non-binary",
"occupation": "writer",
"presenting": "Long-term relationship ended after 7 years, identity was 'we', doesn't know who 'I' is",
},
{
"age": "55",
"gender": "male",
"occupation": "recently retired",
"presenting": "Retired 3 months ago, lost routine and identity, feels purposeless, wife still works",
},
],
"therapist_techniques": [
"narrative therapy — tell the story of the transition, find the thread of who you are",
"meaning-making — what is this transition asking of you, what's ending, what's beginning",
"grief processing — even good transitions involve loss, name what's being lost",
"identity reconstruction — who were you before the role, what stays constant",
"values clarification — what matters now, what did the old role provide that you need elsewhere",
"timeline work — map past transitions, identify patterns of adaptation",
],
"therapist_prompt_addon": (
"You work with life transitions. You understand that even positive change involves loss. "
"You help people grieve what's ending while exploring what's beginning. "
"You're patient with the in-between — the messy middle of not-yet-becoming."
),
},
}
def ollama_chat(messages, model, temperature=0.8, num_predict=400):
for attempt in range(MAX_RETRIES):
try:
resp = requests.post(
f"{OLLAMA_BASE}/api/chat",
json={
"model": model,
"messages": messages,
"stream": False,
"options": {
"temperature": temperature,
"num_predict": num_predict,
"repeat_penalty": 1.1,
"top_p": 0.9,
},
},
timeout=120,
)
resp.raise_for_status()
return resp.json()["message"]["content"].strip()
except (requests.RequestException, KeyError, json.JSONDecodeError) as e:
print(f" [retry {attempt + 1}/{MAX_RETRIES}] Error: {e}")
if attempt < MAX_RETRIES - 1:
time.sleep(RETRY_DELAY)
raise RuntimeError(f"Failed after {MAX_RETRIES} retries")
def _check_style(output, style_profile):
output_lower = output.lower().strip()
if not output_lower:
return False, "Empty therapist output"
for forbidden in style_profile.get("forbidden_openings", []):
if output_lower.startswith(forbidden):
return False, f"Forbidden opening: '{forbidden}'"
for forbidden in FORBIDDEN_OUTPUT_OPENINGS:
if output_lower.startswith(forbidden):
return False, f"Forbidden opening: '{forbidden}'"
for platitude in PLATITUDE_PATTERNS:
if platitude in output_lower:
return False, f"Platitude: '{platitude}'"
for signal in ROBOTIC_SIGNALS:
if signal in output_lower:
return False, f"Robotic signal: '{signal}'"
for marker in SYCOPHANCY_MARKERS:
if marker in output_lower:
return False, f"Sycophancy: '{marker}'"
word_count = len(output.split())
if word_count < 10:
return False, f"Too short ({word_count} words)"
if word_count > 300:
return False, f"Too long ({word_count} words)"
return True, "style_ok"
def generate_patient_turn(persona, presentation, category_name, conversation, turn_num, total_patient_turns):
if turn_num == 1:
direction = f"The patient is arriving for a therapy session. Their presenting concern: {presentation}. They're nervous but willing to talk."
elif turn_num <= 3:
direction = "The patient is opening up, sharing more details. Starting to trust the therapist."
elif turn_num <= 5:
direction = "The patient is going deeper — revealing the emotional impact, not just the surface problem. Becoming more vulnerable."
elif turn_num == total_patient_turns:
direction = "Final turn. The patient is reflecting on what they've discussed, maybe feeling a shift or maybe just sitting with it."
else:
direction = "The patient is processing the therapist's response. May push back, have a realization, or share something they held back."
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 therapy patient in a simulated session. Stay completely in character.
PATIENT:
Age: {persona["age"]}, Gender: {persona["gender"]}, Occupation: {persona["occupation"]}
Presenting concern: {persona["presenting"]}
SESSION FOCUS: {category_name}{presentation}
DIRECTION FOR THIS TURN:
{direction}
This is patient turn {turn_num} of {total_patient_turns}.
CONVERSATION SO FAR:
{conv_text if conv_text else "(First turn — patient arriving at session.)"}
What does the patient say next? Generate ONLY spoken words — no labels, no narration. 2-5 sentences."""
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_therapist_turn(persona, presentation, category, conversation, turn_num, style_profile):
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"Weave it into the conversation — don't announce it. "
f"Respond to what the patient actually said, don't pivot to a technique if it doesn't fit."
)
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 = PIXEL_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_therapist_turn_validated(persona, presentation, category, conversation, turn_num, style_profile):
for attempt in range(STYLE_MAX_RETRIES):
output = generate_therapist_turn(persona, presentation, category, conversation, turn_num, style_profile)
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_session(category_key, category, persona, presentation, session_idx):
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)]]
conversation = []
for turn in range(1, total_patient_turns + 1):
patient_msg = generate_patient_turn(
persona, presentation, category["name"], conversation, turn, total_patient_turns
)
conversation.append({"role": "user", "content": patient_msg})
therapist_msg = generate_therapist_turn_validated(
persona, presentation, category, conversation, turn, style_profile
)
conversation.append({"role": "assistant", "content": therapist_msg})
session_id = f"everyday_{category_key}_{session_idx:04d}"
return {
"messages": [
{"role": "system", "content": PIXEL_SYSTEM_BASE},
*conversation,
],
"metadata": {
"source_family": "everyday_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 session_exists(output_file, session_id):
if not output_file.exists():
return False
with open(output_file) as f:
for line in f:
if session_id in line:
return True
return False
def main():
parser = argparse.ArgumentParser(description="Generate everyday therapy sessions")
parser.add_argument("--categories", default="all", help="Comma-separated category keys or 'all'")
parser.add_argument("--sessions-per-category", type=int, default=167)
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.mkdir(parents=True, exist_ok=True)
output_file = OUTPUT_DIR / "everyday_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=== EVERYDAY 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(f"Turns: {MIN_TURNS}-{MAX_TURNS} (randomized)")
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")
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"everyday_{cat_key}_{i:04d}"
if args.resume and session_exists(output_file, session_id):
skipped += 1
continue
try:
session = generate_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:
32.4 kB
·
Xet hash:
67503dbce126f38ee6aaeb90353fa6e834c599817da27e17f64b4ce130affdc9

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