jmisak's picture
Upload drift.py
5785495 verified
def normalize_emotional_state(persona):
"""Extract and normalize emotional state from the new persona structure."""
default = {
"anxiety": 0.5,
"trust": 0.5,
"openness": 0.5,
"mode": "baseline",
"emotional_memory": []
}
return persona.get("default_state", default).copy()
def apply_context_shift(persona, scenario):
"""Apply contextual scenario effects to persona's current emotional state."""
state = normalize_emotional_state(persona)
effects = scenario.get("effects", {})
for key, change in effects.items():
if key in state and isinstance(state[key], (int, float)):
current_value = state[key]
new_value = current_value + change
state[key] = max(0.0, min(1.0, round(new_value, 3)))
persona["default_state"] = state
return persona
def get_current_mode(state):
"""Determine the client's current emotional mode based on emotional state values."""
anxiety = state.get("anxiety", 0.5)
trust = state.get("trust", 0.5)
openness = state.get("openness", 0.5)
# Raised thresholds significantly to prevent premature crisis states
if anxiety > 0.85: # Was 0.8 - now much harder to reach decompensating
return "decompensating"
if anxiety > 0.75 and trust < 0.25: # Was 0.6 and 0.3 - much higher bar for triggered
return "triggered"
if openness < 0.3 and trust < 0.4: # Was 0.4 and 0.5 - harder to be guarded
return "guarded"
if trust > 0.7 and openness > 0.7: # Was 0.6 - higher bar for trusting too
return "trusting"
if anxiety < 0.3 and openness > 0.6: # Was 0.4 and 0.5 - adjusted
return "recovering"
return state.get("mode", "baseline")
def calculate_state_change(state, student_response):
"""Calculate how the student's response affects the client's emotional state."""
if hasattr(student_response, 'value'):
student_response = student_response.value
student_response = str(student_response) if student_response is not None else ""
response_lower = student_response.lower()
validating_words = ["understand", "sounds like", "seems", "feel", "must be", "makes sense"]
open_questions = ["tell me more", "what's that like", "how", "what"]
empathy_phrases = ["hard", "difficult", "challenging", "tough"]
advice_words = ["should", "need to", "have to", "must", "why don't you"]
minimizing = ["just", "simply", "easy", "only", "at least"]
validation_score = sum(1 for word in validating_words if word in response_lower)
open_q_score = sum(1 for phrase in open_questions if phrase in response_lower)
empathy_score = sum(1 for phrase in empathy_phrases if phrase in response_lower)
advice_score = sum(1 for word in advice_words if word in response_lower)
minimizing_score = sum(1 for word in minimizing if word in response_lower)
# Reduced magnitude significantly - was causing too-fast emotional escalation
positive_impact = (validation_score * 0.02 + open_q_score * 0.015 + empathy_score * 0.01) # Was 0.05, 0.04, 0.03
negative_impact = (advice_score * 0.03 + minimizing_score * 0.025) # Was 0.08, 0.06
changes = {
"trust": positive_impact * 0.5 - negative_impact * 0.3, # Was 0.8 and 0.5 - reduced multipliers
"anxiety": negative_impact * 0.3 - positive_impact * 0.2, # Was 0.5 and 0.3 - reduced
"openness": positive_impact * 0.3 - negative_impact * 0.15 # Was 0.4 and 0.2 - reduced
}
word_count = len(student_response.split())
if word_count < 5:
changes["trust"] -= 0.02 # Was 0.05 - reduced
elif word_count > 100:
changes["anxiety"] += 0.02 # Was 0.05 - reduced
return changes
def apply_response_effects(state, student_response):
"""Apply the effects of the student's response to the client's emotional state."""
changes = calculate_state_change(state, student_response)
for key, change in changes.items():
if key in state and isinstance(state[key], (int, float)):
current_value = state[key]
new_value = current_value + change
state[key] = max(0.0, min(1.0, round(new_value, 3)))
return state
def generate_teaching_note(state, student_response, mode, persona=None):
"""Generate pedagogical feedback based on the literary interaction."""
response_lower = student_response.lower()
notes = []
# Get character-specific context if available
char_name = persona.get("persona_name", "the character") if persona else "the character"
source_text = persona.get("source_text", {}) if persona else {}
author = source_text.get("author", "the author")
title = source_text.get("title", "the text")
# Question quality - literary analysis focused
if any(word in response_lower for word in ["why did you", "why do you", "why are you"]):
notes.append("πŸ’­ <strong style='color: #2d3748;'>Literary Technique</strong>: 'Why' questions can sound accusatory. Consider using 'what' or 'how' to explore motivations more naturally (e.g., 'What were you thinking when...' or 'How did that moment feel?')")
if any(word in response_lower for word in ["should", "need to", "have to"]):
notes.append("πŸ“š <strong style='color: #2d3748;'>Character Analysis Tip</strong>: Avoid directive language like 'should' - it judges the character. Instead, explore their perspective: 'What other choices did you consider?' This reveals internal conflict.")
if response_lower.count("?") > 2:
notes.append("🎯 <strong style='color: #2d3748;'>Focus Your Inquiry</strong>: Multiple questions can overwhelm. Pick your most important question for deeper exploration of theme, motivation, or symbolism.")
# Question depth - connect to literary concepts
if len(student_response.split()) < 8:
if author and title:
notes.append(f"πŸ“– <strong style='color: #2d3748;'>Add Textual Context</strong>: Reference specific moments from '{title}' to ground your question. Connect to scenes, relationships, or conflicts from {author}'s narrative.")
else:
notes.append("πŸ“– <strong style='color: #2d3748;'>Add Textual Context</strong>: Reference specific moments from the story to ground your question in the character's actual experiences.")
if any(phrase in response_lower for phrase in ["tell me about", "tell me more", "what's that like", "how do you feel"]):
notes.append("βœ… <strong style='color: #2d3748;'>Strong Question</strong>: Open-ended questions like this encourage the character to reveal subtext, internal conflict, and thematic depth. This is effective literary analysis.")
if any(word in response_lower for word in ["symbol", "represent", "meaning", "theme"]):
notes.append("🌟 <strong style='color: #2d3748;'>Excellent</strong>: You're connecting character experience to broader literary themes. This kind of analysis reveals how authors use character to explore universal ideas.")
# Character engagement - literary context
if mode == "triggered" and state.get("trust", 0) < 0.4:
if author:
notes.append(f"⚠️ <strong style='color: #2d3748;'>Character Defensive</strong>: Notice how {char_name} withdraws when challenged - this mirrors how {author} shows psychological realism. Try questions that validate their experience first.")
else:
notes.append("⚠️ <strong style='color: #2d3748;'>Character Defensive</strong>: The character is withdrawing. Try questions that validate their experience before probing deeper.")
if mode == "trusting" and state.get("anxiety", 0) > 0.6:
notes.append("✨ <strong style='color: #2d3748;'>Key Moment</strong>: The character is vulnerable right now - this is where authors reveal crucial backstory and motivation. Press deeper into their fears and desires.")
if mode == "decompensating":
notes.append("πŸ“Š <strong style='color: #2d3748;'>Character State</strong>: The character is emotionally overwhelmed. In literary analysis, these breaking points often reveal theme. Consider: What does this breakdown tell us about the story's larger meaning?")
if mode == "recovering":
notes.append("πŸ” <strong style='color: #2d3748;'>Reflection Point</strong>: The character is stabilizing. Good time to ask: 'What have you learned?' or 'How have you changed?' - this reveals character development.")
# Add literary context based on specific terms used
if any(word in response_lower for word in ["choice", "decision", "decide"]):
notes.append("πŸ’‘ <strong style='color: #2d3748;'>Theme Connection</strong>: You're exploring agency and choice - a key theme in literature. How does paralysis or action define this character?")
if any(word in response_lower for word in ["family", "mother", "father", "parent", "sister", "brother"]):
notes.append("πŸ‘¨β€πŸ‘©β€πŸ‘§ <strong style='color: #2d3748;'>Family Dynamics</strong>: You're examining how family obligations shape identity - analyze how the author uses familial duty to explore broader social constraints.")
if not notes:
notes.append("βœ… <strong style='color: #2d3748;'>Good Engagement</strong>: You're exploring the character thoughtfully. Consider connecting their responses to the story's central themes and conflicts.")
# Join notes with proper line breaks for HTML rendering
return "<br><br>".join(notes)