try : from server.disorders import get_disorder_info except ImportError: from disorders import get_disorder_info def disorder_similarity(disorder1, disorder2): """ Calculate similarity between two disorders based on their symptoms and trigger keywords. Args: disorder1 (str): Name of the first disorder. disorder2 (str): Name of the second disorder. Returns: str: Similarity level ("full","partial","wrong") based on symptom and trigger keyword overlap. """ info1 = get_disorder_info(disorder1) info2 = get_disorder_info(disorder2) symptoms1 = set(info1.get("symptoms", {}).get("emotional", [])) symptoms2 = set(info2.get("symptoms", {}).get("emotional", [])) triggers1 = set(info1.get("trigger_keywords", [])) triggers2 = set(info2.get("trigger_keywords", [])) symptom_overlap = len(symptoms1.intersection(symptoms2)) / max(len(symptoms1), 1) trigger_overlap = len(triggers1.intersection(triggers2)) / max(len(triggers1), 1) if symptom_overlap > 0.7 and trigger_overlap > 0.7: return "full" elif symptom_overlap > 0.3 and trigger_overlap > 0.3: return "partial" else: return "wrong" def check_action_repeat(action_sequence, current_action): """ Check if the current action has been repeated in the recent action sequence. Args: action_sequence (List[str]): List of recent action types taken by the agent. current_action (str): The action type of the current step. Returns: float: A penalty value based on the frequency of the current action in the recent sequence. """ repeat_count = action_sequence.count(current_action) if repeat_count > 2: return -0.5 # High penalty for excessive repetition elif repeat_count > 0: return -0.2 # Moderate penalty for some repetition else: return 0.0 # No penalty for unique actions def normalize(score, min_score, max_score): if max_score == min_score: return 0.0 return max(0.0, min(1.0, (score - min_score) / (max_score - min_score))) def calculate_reward( disorder, action_type, task_difficulty, diagnosis=None, action_sequence=None, state=None ): """Calculate reward based on the agent's action, diagnosis, and the patient's state. Args: disorder (str): The actual disorder of the patient. action_type (str): The type of action taken by the agent. task_difficulty (str): The difficulty level of the task ("easy", "medium", "hard"). diagnosis (str, optional): The diagnosis provided by the agent, if any. action_sequence (List[str], optional): The sequence of recent actions taken by the agent. state (MentalState, optional): The current state of the patient. Returns: float: A reward value between 0.0 and 1.0 based on the quality of the action and diagnosis. """ score = 0.0 # ========================= # EASY → correctness only # ========================= if task_difficulty == "easy": if action_type == "diagnose" and diagnosis: similarity = disorder_similarity(disorder, diagnosis) if similarity == "full": score = 1.0 elif similarity == "partial": score = 0.5 else: score = 0.0 else: score = 0.1 # small reward for non-diagnose steps return score # already normalized # ========================= # MEDIUM → strategy # ========================= elif task_difficulty == "medium": # Action quality (0 → 1 range) action_score = { "ask_open": 0.6, "ask_direct": 0.4, "reflect": 0.8, "ask_risk": 0.5, "diagnose": 0.0 }.get(action_type, 0.0) # Diagnosis score diagnosis_score = 0.0 if action_type == "diagnose" and diagnosis: if len(diagnosis)==1: similarity = disorder_similarity(disorder, diagnosis[-1]) if similarity == "full": diagnosis_score = 1.0 elif similarity == "partial": diagnosis_score = 0.5 else: diagnosis_score = 0.0 else: diagnosis_score=0.0 for d in diagnosis: similarity=disorder_similarity(disorder,d) if similarity=="full": diagnosis_score+=0.5 elif diagnosis_score=="partial": diagnosis_score+=0.3 else: diagnosis_score-=0.5 diagnosis_score=normalize(diagnosis_score,0.0,1.0) # Repetition penalty (converted to positive scale) repeat_penalty = 0.0 if action_sequence: penalty = check_action_repeat(action_sequence, action_type) repeat_penalty = max(0.0, 1.0 + penalty) # convert (-0.5 → 0.5) # Combine (weighted) score = ( 0.4 * action_score + 0.4 * diagnosis_score + 0.2 * repeat_penalty ) return max(0.0, min(1.0, score)) # ========================= # HARD → empathy + safety + depth # ========================= elif task_difficulty == "hard": # EMPATHY empathy_score = { "reflect": 1.0, "ask_open": 0.7, "ask_risk": 0.8, "ask_direct": 0.3, "diagnose": 0.0 }.get(action_type, 0.0) # SAFETY safety_score = 0.5 # neutral if state: if state.risk_level == "high": if action_type == "ask_risk": safety_score = 1.0 else: safety_score = 0.0 # DEPTH depth_score = 0.0 if state: depth_score = (state.trust_level + state.openness) / 2.0 # Diagnosis (less important here) diagnosis_score = 0.0 if action_type == "diagnose" and diagnosis: similarity = disorder_similarity(disorder, diagnosis) if similarity == "full": diagnosis_score = 0.8 elif similarity == "partial": diagnosis_score = 0.4 else: diagnosis_score = 0.0 # Repetition repeat_score = 1.0 if action_sequence: penalty = check_action_repeat(action_sequence, action_type) repeat_score = max(0.0, 1.0 + penalty) # Final weighted score score = ( 0.3 * empathy_score + 0.25 * safety_score + 0.2 * depth_score + 0.15 * diagnosis_score + 0.1 * repeat_score ) return max(0.0, min(1.0, score)) return 0.0