def _build_pm_checkin(self, planner=None): if planner is None: planner = MessagerPlanner(possible_plans) if not self._is_done_am_checkin_today: planner.insert( Common.Messages.missed_checkin, post_hook=lambda: self._mark_pm_checkin_complete(False), ) elif not self._is_synced_recently(): planner.insert(PmCheckin.Messages.no_sync) else: if self._is_met_steps_goal_today(): planner.insert( PmCheckin.success_graph, post_hook=lambda: self._mark_pm_checkin_complete(True), ) else: planner.insert( PmCheckin.fail_graph, post_hook=lambda: self._mark_pm_checkin_complete(False), ) return planner
def _build_first_meeting(self, planner=None): if planner is None: planner = MessagerPlanner(possible_plans) planner.insert( FirstMeeting.first_meeting, post_hook=self._set_vars_after_first_meeting ) return planner
def _build_am_checkin(self, planner=None): if planner is None: planner = MessagerPlanner(possible_plans) if self._is_missed_pm_yesterday: planner.insert(Common.Messages.missed_checkin) planner.insert(AmCheckin.Messages.set_goal) planner.insert(self._build_am_questions()) planner.update_last_inserts_hooks( post_hook=self._am_checkin_closing_hook ) return planner
def build_interaction(self, interaction_type): self._planner = MessagerPlanner(self._interaction_builder.possible_graphs) if interaction_type == Interactions.ASK_TO_DO_EVALUATION: self._build_ask_to_do_evaluation() elif interaction_type == Interactions.FIRST_INTERACTION: self._build_first_interaction() elif interaction_type == Interactions.PROMPTED_INTERACTION: self._build_prompted_interaction() elif interaction_type == Interactions.SCHEDULED_INTERACTION: self._build_scheduled_interaction() elif interaction_type == Interactions.TOO_MANY_PROMPTED: self._build_too_many_prompted() else: raise ValueError("Not a valid interaction type") return self._planner
def _build_off_checkin(self, planner=None): if planner is None: planner = MessagerPlanner(possible_plans) if self._is_time_for_status_update(): if self._is_synced_recently(): if state_db.get(state_db.Keys.STEPS_TODAY) >= state_db.get(state_db.Keys.STEPS_GOAL): planner.insert(OffCheckin.Messages.give_status_met_goal) else: planner.insert(OffCheckin.Messages.give_status) else: planner.insert(OffCheckin.Messages.no_sync) planner.insert( Options.options, post_hook=lambda: state_db.set( state_db.Keys.IS_REDO_SCHEDULE, True ) ) return planner
def __init__(self, statedb, interaction_builder, interface=None, max_num_of_perseverance_readings=5): self._state_database = statedb self._interaction_builder = interaction_builder if interface is None: interface = TerminalClientAndServerInterface( database=self._state_database) self._interface = interface self._current_node_name = None self._current_interaction_type = None self._planner = MessagerPlanner( self._interaction_builder.possible_graphs) self._max_num_of_perseverance_readings = max_num_of_perseverance_readings self._num_of_days_to_prompt_goal_setting = 3
def build(self): planner = MessagerPlanner(possible_plans) if self._is_first_meeting(): self._build_first_meeting(planner) else: self._build_greeting(planner) if self.is_am_checkin(): self._build_am_checkin(planner) elif self.is_pm_checkin(): self._build_pm_checkin(planner) else: self._build_off_checkin(planner) self._build_closing(planner) return planner
state_db.set(state_db.Keys.SUGGESTED_STEPS_TODAY, 600) state_db.set(state_db.Keys.AM_CHECKIN_TIME, datetime.time(8, 0)) state_db.set(state_db.Keys.PM_CHECKIN_TIME, datetime.time(18, 0)) possible_plans = [ AmCheckin.Messages.big_5_question, AmCheckin.Messages.when_question, AmCheckin.Messages.set_goal, AmCheckin.where_graph, AmCheckin.how_busy_graph, AmCheckin.how_motivated_graph, AmCheckin.how_remember_graph, ] # Create a plan plan_ = MessagerPlanner(possible_plans) plan_.insert(AmCheckin.Messages.set_goal) plan_.insert(AmCheckin.where_graph) plan_.insert(AmCheckin.Messages.when_question) plan_.insert(AmCheckin.how_busy_graph) plan_.insert(AmCheckin.how_remember_graph) plan_.insert(AmCheckin.how_motivated_graph) for _ in range(3): plan_.insert(AmCheckin.Messages.big_5_question) ie = InteractionEngine(TerminalClientAndServerInterface(state_db), plan_, possible_plans) ie.run() print(state_db) print(param_db)
text_populator=text_populator, transitions='exit' ), ], start_node='closing' ) """ ORGANIZE CONTENT TO BE PLAYED """ interface_ = TerminalClientAndServerInterface(database=db) graphs_ = [greeting, basic_questions, psych_question, closing] # Create a plan plan_ = MessagerPlanner(graphs_) plan_.insert(greeting) plan_.insert(basic_questions) for _ in range(3): plan_.insert(psych_question) plan_.insert(closing) """ RUN IT! """ engine = InteractionEngine(interface_, plan_, graphs_) engine.run() print("=========================") print("Currently in the database")
def setUp(self) -> None: state_db.reset() self.true_plan = MessagerPlanner(possible_plans) self.builder = builder.PlanBuilder()
class TestPlanBuilder(unittest.TestCase): def setUp(self) -> None: state_db.reset() self.true_plan = MessagerPlanner(possible_plans) self.builder = builder.PlanBuilder() def test_select_first_meeting(self): self.true_plan.insert(FirstMeeting.first_meeting) self.assertFalse(state_db.is_set(state_db.Keys.FIRST_MEETING)) resulting_plan = self.builder.build() self.assertEqual(self.true_plan, resulting_plan) simulate_run_plan(resulting_plan) self.assertTrue(state_db.is_set(state_db.Keys.FIRST_MEETING)) def test_build_pm_with_goal_met(self): self.true_plan.insert([ PmCheckin.success_graph, ]) state_db.set(state_db.Keys.FIRST_MEETING, datetime.datetime.now()) state_db.set(state_db.Keys.LAST_FITBIT_SYNC, datetime.datetime.now()) state_db.set(state_db.Keys.STEPS_GOAL, 100) state_db.set(state_db.Keys.STEPS_TODAY, 200) state_db.set(state_db.Keys.IS_DONE_AM_CHECKIN_TODAY, True) state_db.set(state_db.Keys.FIRST_MEETING, datetime.datetime.now()) self.assertEqual(self.true_plan, self.builder._build_pm_checkin()) def test_build_pm_with_goal_fail(self): self.true_plan.insert([ PmCheckin.fail_graph, ]) state_db.set(state_db.Keys.IS_DONE_AM_CHECKIN_TODAY, True) state_db.set(state_db.Keys.FIRST_MEETING, datetime.datetime.now()) state_db.set(state_db.Keys.LAST_FITBIT_SYNC, datetime.datetime.now()) state_db.set(state_db.Keys.STEPS_GOAL, 200) state_db.set(state_db.Keys.STEPS_TODAY, 100) self.assertEqual(self.true_plan, self.builder._build_pm_checkin()) def test_run_am(self): state_db.set(state_db.Keys.SUGGESTED_STEPS_TODAY, 300) state_db.set(state_db.Keys.IS_DONE_AM_CHECKIN_TODAY, False) state_db.set(state_db.Keys.IS_MISSED_PM_YESTERDAY, False) hour, minute = 8, 0 checkin_time = datetime.time(hour, minute) state_db.set(state_db.Keys.AM_CHECKIN_TIME, checkin_time) with freeze_time(f"2011-11-1 {hour:02d}:{minute:02d}:59"): self.assertTrue(self.builder.is_am_checkin()) plan = self.builder._build_am_checkin() for _ in range(len(plan.plan) - 1): simulate_run_once(plan) self.assertTrue(self.builder.is_am_checkin()) simulate_run_once(plan) self.assertFalse(self.builder.is_am_checkin()) def test_run_pm(self): am_hour, am_minute = 8, 0 am_checkin_time = datetime.time(am_hour, am_minute) state_db.set(state_db.Keys.AM_CHECKIN_TIME, am_checkin_time) hour, minute = 18, 0 checkin_time = datetime.time(hour, minute) state_db.set(state_db.Keys.PM_CHECKIN_TIME, checkin_time) state_db.set(state_db.Keys.LAST_FITBIT_SYNC, datetime.datetime.now()) state_db.set(state_db.Keys.IS_DONE_AM_CHECKIN_TODAY, True) state_db.set(state_db.Keys.IS_DONE_PM_CHECKIN_TODAY, False) with freeze_time(f"2011-11-1 {hour:02d}:{minute:02d}:59"): self.assertFalse(self.builder.is_am_checkin()) state_db.set(state_db.Keys.STEPS_TODAY, 300) state_db.set(state_db.Keys.STEPS_GOAL, 600) self.assertTrue(self.builder.is_pm_checkin()) plan = self.builder._build_pm_checkin() for _ in range(len(plan.plan) - 1): simulate_run_once(plan) self.assertTrue(self.builder.is_pm_checkin()) simulate_run_once(plan) self.assertFalse(self.builder.is_pm_checkin()) def test_run_pm_updates_bkt(self): hour, minute = 18, 0 checkin_time = datetime.time(hour, minute) state_db.set(state_db.Keys.IS_DONE_AM_CHECKIN_TODAY, True) state_db.set(state_db.Keys.PM_CHECKIN_TIME, checkin_time) state_db.set(state_db.Keys.IS_DONE_PM_CHECKIN_TODAY, False) with freeze_time(f"2011-11-1 {hour:02d}:{minute:02d}:59"): self.assertTrue(self.builder.is_pm_checkin()) for _ in range(10): state_db.set(state_db.Keys.IS_DONE_PM_CHECKIN_TODAY, False) state_db.set(state_db.Keys.STEPS_TODAY, 100) state_db.set(state_db.Keys.STEPS_GOAL, 20) state_db.set(state_db.Keys.LAST_FITBIT_SYNC, datetime.datetime.now()) plan = self.builder._build_pm_checkin() pL_old = self.builder._bkt.get_automaticity() simulate_run_plan(plan) pL_new = self.builder._bkt.get_automaticity() self.assertLessEqual(pL_old, pL_new) for _ in range(10): state_db.set(state_db.Keys.IS_DONE_PM_CHECKIN_TODAY, False) state_db.set(state_db.Keys.STEPS_TODAY, 10) state_db.set(state_db.Keys.STEPS_GOAL, 20) state_db.set(state_db.Keys.LAST_FITBIT_SYNC, datetime.datetime.now()) plan = self.builder._build_pm_checkin() pL_old = self.builder._bkt.get_automaticity() simulate_run_plan(plan) pL_new = self.builder._bkt.get_automaticity() self.assertGreaterEqual(pL_old, pL_new) def test_get_num_implementation_intention_questions_to_ask(self): max_num_qs = 3 for automaticity, truth_num_qs in [ (0, 3), (0.01, 3), (0.1, 3), (0.24, 3), (0.26, 2), (0.49, 2), (0.51, 1), (0.74, 1), (0.76, 0), (0.99, 0), (1.0, 0), ]: self.assertEqual( truth_num_qs, self.builder._get_num_ii_questions(max_num_qs, automaticity)) for automaticity in [-1, -.01, 1.01, 2]: self.assertRaises(ValueError, self.builder._get_num_ii_questions, max_num_qs, automaticity) def test_is_time_for_status_update(self): am_checkin_hour = 8 am_checkin_min = 40 pm_checkin_hour = 18 pm_checkin_min = 21 assert pm_checkin_hour - 1 > am_checkin_hour state_db.set(state_db.Keys.AM_CHECKIN_TIME, datetime.time(am_checkin_hour, am_checkin_min)) state_db.set(state_db.Keys.PM_CHECKIN_TIME, datetime.time(pm_checkin_hour, pm_checkin_min)) for hour, minute in [ (0, 0), (am_checkin_hour - 1 % 24, am_checkin_min % 60), (am_checkin_hour % 24, am_checkin_min - 1 % 60), (am_checkin_hour % 24, am_checkin_min % 60), (am_checkin_hour % 24, am_checkin_min + 1 % 60), (am_checkin_hour + 1 % 24, am_checkin_min % 60), (pm_checkin_hour - 1 % 24, pm_checkin_min % 60), (pm_checkin_hour % 24, pm_checkin_min - 1 % 60), ]: with freeze_time(f"2011-11-1 {hour:02d}:{minute:02d}:59"): state_db.set(state_db.Keys.IS_DONE_AM_CHECKIN_TODAY, False) state_db.set(state_db.Keys.IS_DONE_PM_CHECKIN_TODAY, False) self.assertFalse(self.builder._is_time_for_status_update()) state_db.set(state_db.Keys.IS_DONE_AM_CHECKIN_TODAY, True) state_db.set(state_db.Keys.IS_DONE_PM_CHECKIN_TODAY, False) self.assertTrue(self.builder._is_time_for_status_update()) state_db.set(state_db.Keys.IS_DONE_AM_CHECKIN_TODAY, False) state_db.set(state_db.Keys.IS_DONE_PM_CHECKIN_TODAY, True) self.assertFalse(self.builder._is_time_for_status_update()) state_db.set(state_db.Keys.IS_DONE_AM_CHECKIN_TODAY, True) state_db.set(state_db.Keys.IS_DONE_PM_CHECKIN_TODAY, True) self.assertFalse(self.builder._is_time_for_status_update()) def test_is_pm_checkin_window(self): pm_checkin_hour = 18 pm_checkin_min = 21 state_db.set(state_db.Keys.PM_CHECKIN_TIME, datetime.time(pm_checkin_hour, pm_checkin_min)) for hour, minute in [ (pm_checkin_hour % 24, pm_checkin_min % 60), (pm_checkin_hour % 24, pm_checkin_min + 1 % 60), (23, 55), ]: with freeze_time(f"2011-11-1 {hour:02d}:{minute:02d}:59"): state_db.set(state_db.Keys.IS_DONE_PM_CHECKIN_TODAY, False) self.assertTrue(self.builder.is_pm_checkin()) def test_is_missed_am(self): am_checkin_hour = 8 am_checkin_min = 40 state_db.set(state_db.Keys.AM_CHECKIN_TIME, datetime.time(am_checkin_hour, am_checkin_min)) for hour, minute in [ (0, 0), (am_checkin_hour - 1 % 24, am_checkin_min % 60), (am_checkin_hour % 24, am_checkin_min - 1 % 60), (am_checkin_hour % 24, am_checkin_min % 60), (am_checkin_hour % 24, am_checkin_min + 1 % 60), ]: with freeze_time(f"2011-11-1 {hour:02d}:{minute:02d}:59"): state_db.set(state_db.Keys.IS_DONE_AM_CHECKIN_TODAY, False) self.assertFalse(self.builder._is_missed_am_checkin) time_after_allowed = param_db.get( param_db.Keys.MINS_AFTER_ALLOW_CHECKIN) for hour, minute in [ (am_checkin_hour % 24, am_checkin_min + 1 % 60), (am_checkin_hour + 1 % 24, am_checkin_min % 60), (am_checkin_hour + 1 % 24, am_checkin_min + 1 % 60), ]: with freeze_time(f"2011-11-1 {hour:02d}:{minute:02d}:59" ) as frozen_datetime: frozen_datetime.tick(delta=datetime.timedelta( minutes=time_after_allowed)) state_db.set(state_db.Keys.IS_DONE_AM_CHECKIN_TODAY, False) self.assertTrue(self.builder._is_missed_am_checkin) def test_get_set_bkt(self): pL0, pT0, pS0, pG0 = self.builder._bkt.get_params() observations = [True, False, True, True, False] self.builder._bkt_update_pL(observations) pL1, pT1, pS1, pG1 = self.builder._bkt.get_params() self.assertNotEqual(pL0, pL1) self.assertEqual(pT0, pT1) self.assertEqual(pS0, pS1) self.assertEqual(pG0, pG1) pL1_, pT1_, pS1_, pG1_ = self.builder._bkt.get_params() self.assertEqual(pL1, pL1_) self.assertEqual(pT1, pT1_) self.assertEqual(pS1, pS1_) self.assertEqual(pG1, pG1_) self.builder._bkt_update_full_model(observations) pL2, pT2, pS2, pG2 = self.builder._bkt.get_params() self.assertNotEqual(pL1, pL2) self.assertNotEqual(pT1, pT2) self.assertNotEqual(pS1, pS2) self.assertNotEqual(pG1, pG2) def test_bkt_operations(self): automaticity = self.builder._automaticity # True because of adding epsilon to make not degenerate self.assertLessEqual(state_db.get(state_db.Keys.BKT_pL), automaticity) old_pL = automaticity for _ in range(100): self.builder._bkt_update_pL(True) new_pL = self.builder._automaticity self.assertLessEqual(old_pL, new_pL) old_pL = new_pL self.assertLess(automaticity, old_pL)
class InteractionManager: def __init__(self, statedb, interaction_builder, interface=None, max_num_of_perseverance_readings=5): self._state_database = statedb self._interaction_builder = interaction_builder if interface is None: interface = TerminalClientAndServerInterface( database=self._state_database) self._interface = interface self._current_node_name = None self._current_interaction_type = None self._planner = MessagerPlanner( self._interaction_builder.possible_graphs) self._max_num_of_perseverance_readings = max_num_of_perseverance_readings self._num_of_days_to_prompt_goal_setting = 3 def run_interaction_once(self, interaction_type): if interaction_type not in Interactions.POSSIBLE_INTERACTIONS: raise ValueError("Not a valid interaction type") self.build_interaction(interaction_type) for node_name in self.run_engine_once(): yield node_name def run_engine_once(self): engine = InteractionEngine(self._interface, self._planner, self._interaction_builder.possible_graphs) for node_name in engine.modified_run(self._planner): yield node_name def build_interaction(self, interaction_type): self._planner = MessagerPlanner( self._interaction_builder.possible_graphs) if interaction_type == Interactions.ASK_TO_DO_SCHEDULED: self._build_ask_to_do_scheduled() elif interaction_type == Interactions.FIRST_INTERACTION: self._build_first_interaction() elif interaction_type == Interactions.PROMPTED_INTERACTION: self._build_prompted_interaction() elif interaction_type == Interactions.SCHEDULED_INTERACTION: self._build_scheduled_interaction() elif interaction_type == Interactions.TOO_MANY_PROMPTED: self._build_too_many_prompted() else: raise ValueError("Not a valid interaction type") return self._planner def _build_ask_to_do_scheduled(self): logging.info("Building ask to do scheduled") self._planner.insert( self._interaction_builder.interactions[ InteractionBuilder.Graphs.ASK_TO_DO_SCHEDULED], post_hook=self._set_vars_after_ask_to_do_scheduled, ) return self._planner def _build_first_interaction(self): logging.info("Building first interaction") self._planner.insert(self._interaction_builder.interactions[ InteractionBuilder.Graphs.INTRODUCE_QT], post_hook=self._set_vars_after_first_interaction) return self._planner def _build_prompted_interaction(self): logging.info("Building prompted interaction") self._planner.insert( self._interaction_builder.interactions[ InteractionBuilder.Graphs.PROMPTED_ASK_TO_CHAT], post_hook=self._set_vars_after_prompted_ask_to_chat) return self._planner def _build_scheduled_interaction(self): logging.info("Building scheduled interaction") self._planner.insert( self._interaction_builder.interactions[ InteractionBuilder.Graphs.SCHEDULED_ASK_TO_CHAT], post_hook=self._set_vars_after_scheduled_ask_to_chat) return self._planner def _build_too_many_prompted(self): logging.info("Building checkin limit reminder") self._planner.insert(plan=self._interaction_builder.interactions[ InteractionBuilder.Graphs.TOO_MANY_PROMPTED], post_hook=self._set_vars_after_too_many_prompted) return self._planner def _set_vars_after_ask_to_do_scheduled(self): if self._state_database.get(DatabaseKeys.IS_OFF_CHECKIN) == "Yes": self._state_database.set(DatabaseKeys.IS_OFF_CHECKIN, None) if self._state_database.get(DatabaseKeys.VIDEO_TO_PLAY): self._planner.insert( self._interaction_builder.interactions[ InteractionBuilder.Graphs.FEEDBACK_VIDEO], ) self._planner.insert(self._interaction_builder.interactions[ InteractionBuilder.Graphs.EVALUATION], post_hook=self._set_vars_after_evaluation) else: self._planner.insert( self._interaction_builder.interactions[ InteractionBuilder.Graphs.PROMPTED_ASK_TO_CHAT], post_hook=self._set_vars_after_prompted_ask_to_chat) def _set_vars_after_scheduled_ask_for_eval(self): if self._state_database.get(DatabaseKeys.IS_DO_EVALUATION) == "Yes": self._state_database.set(DatabaseKeys.IS_DO_EVALUATION, None) if self._state_database.get(DatabaseKeys.VIDEO_TO_PLAY): self._planner.insert( self._interaction_builder.interactions[ InteractionBuilder.Graphs.FEEDBACK_VIDEO], ) self._planner.insert(self._interaction_builder.interactions[ InteractionBuilder.Graphs.INTRODUCE_EVALUATION], post_hook=self._set_vars_after_interaction) self._planner.insert(self._interaction_builder.interactions[ InteractionBuilder.Graphs.EVALUATION], post_hook=self._set_vars_after_evaluation) self._planner.insert(self._interaction_builder.interactions[ InteractionBuilder.Graphs.POST_EVALUATION], post_hook=self._set_vars_after_interaction) self._planner.insert( self._interaction_builder.interactions[ InteractionBuilder.Graphs.ASK_TO_DO_PERSEVERANCE], post_hook=self._set_vars_after_ask_to_do_perseverance) def _set_vars_after_prompted_ask_to_chat(self): if self._state_database.get(DatabaseKeys.GOOD_TO_CHAT) == "Yes": self._state_database.set(DatabaseKeys.GOOD_TO_CHAT, None) self._planner.insert(self._interaction_builder.interactions[ InteractionBuilder.Graphs.PROMPTED_CHECKIN], post_hook=self._set_vars_after_prompted) else: self._planner.insert(self._interaction_builder.interactions[ InteractionBuilder.Graphs.PROMPTED_PLAN_NEXT_CHECKIN], post_hook=self._set_vars_after_interaction) def _set_vars_after_scheduled_ask_to_chat(self): if self._state_database.get(DatabaseKeys.GOOD_TO_CHAT) == "Yes": self._state_database.set(DatabaseKeys.GOOD_TO_CHAT, None) self._planner.insert( self._interaction_builder.interactions[ InteractionBuilder.Graphs.SCHEDULED_CHECKIN], ) self._planner.insert( self._interaction_builder.interactions[ InteractionBuilder.Graphs.ASK_TO_DO_EVALUATION], post_hook=self._set_vars_after_scheduled_ask_for_eval) else: self._state_database.set(DatabaseKeys.GOOD_TO_CHAT, None) self._planner.insert(self._interaction_builder.interactions[ InteractionBuilder.Graphs.PLAN_NEXT_CHECKIN], post_hook=self._set_vars_after_interaction) def _set_vars_after_ask_to_do_perseverance(self): if self._state_database.get( DatabaseKeys.IS_START_PERSEVERANCE) == "Yes": self._state_database.set(DatabaseKeys.IS_START_PERSEVERANCE, None) self._planner.insert(plan=self._interaction_builder.interactions[ InteractionBuilder.Graphs.PERSEVERANCE], post_hook=self._set_vars_after_perseverance) else: if self._is_do_mindfulness(): self._planner.insert( plan=self._interaction_builder.interactions[ InteractionBuilder.Graphs.MINDFULNESS], post_hook=self._set_vars_after_mindfulness) if self._is_do_goal_setting(): self._planner.insert( plan=self._interaction_builder.interactions[ InteractionBuilder.Graphs.GOAL_SETTING], post_hook=self._set_vars_after_goal_setting) self._planner.insert(plan=self._interaction_builder.interactions[ InteractionBuilder.Graphs.PLAN_CHECKIN_TOMORROW], post_hook=self._set_vars_after_interaction) def _set_vars_after_evaluation(self): self._state_database.set(DatabaseKeys.IS_DONE_EVAL_TODAY, True) eval_index = self._state_database.get(DatabaseKeys.READING_EVAL_INDEX) self._state_database.set(DatabaseKeys.READING_EVAL_INDEX, eval_index + 1) self._set_vars_after_interaction() def _set_vars_after_interaction(self): self._state_database.set(DatabaseKeys.IS_PROMPTED_BY_USER, False) self._state_database.set(DatabaseKeys.IS_INTERACTION_FINISHED, True) self._state_database.set(DatabaseKeys.LAST_INTERACTION_DATETIME, datetime.datetime.now()) def _set_vars_after_first_interaction(self): if self._state_database.get(DatabaseKeys.GOOD_TO_CHAT) == "Yes": self._state_database.set(DatabaseKeys.GOOD_TO_CHAT, None) self._planner.insert( self._interaction_builder.interactions[ InteractionBuilder.Graphs.SCHEDULED_CHECKIN], ) self._planner.insert( self._interaction_builder.interactions[ InteractionBuilder.Graphs.ASK_TO_DO_EVALUATION], post_hook=self._set_vars_after_scheduled_ask_for_eval) else: self._state_database.set(DatabaseKeys.GOOD_TO_CHAT, None) self._planner.insert(self._interaction_builder.interactions[ InteractionBuilder.Graphs.PLAN_NEXT_CHECKIN], post_hook=self._set_vars_after_interaction) self._state_database.set(DatabaseKeys.FIRST_INTERACTION_DATETIME, datetime.datetime.now()) def _set_vars_after_goal_setting(self): self._state_database.set( DatabaseKeys.NUM_OF_DAYS_SINCE_LAST_GOAL_SETTING, 0) self._set_vars_after_interaction() def _set_vars_after_mindfulness(self): self._state_database.set( DatabaseKeys.NUM_OF_DAYS_SINCE_LAST_MINDFULNESS, 0) self._set_vars_after_interaction() def _set_vars_after_perseverance(self): perseverance_counter = self._state_database.get( DatabaseKeys.PERSEVERANCE_COUNTER) + 1 self._state_database.set(DatabaseKeys.PERSEVERANCE_COUNTER, perseverance_counter) if perseverance_counter >= self._max_num_of_perseverance_readings: self._planner.insert(plan=self._interaction_builder.interactions[ InteractionBuilder.Graphs.REWARD]) self._planner.insert(plan=self._interaction_builder.interactions[ InteractionBuilder.Graphs.PLAN_CHECKIN_TOMORROW]) else: self._planner.insert( plan=self._interaction_builder.interactions[ InteractionBuilder.Graphs.CONTINUE_PERSEVERANCE], post_hook=self._set_vars_after_continue_perseverance) def _set_vars_after_continue_perseverance(self): if self._state_database.get( DatabaseKeys.IS_CONTINUE_PERSEVERANCE) == "Continue": self._planner.insert(plan=self._interaction_builder.interactions[ InteractionBuilder.Graphs.PERSEVERANCE], post_hook=self._set_vars_after_perseverance) else: self._planner.insert(plan=self._interaction_builder.interactions[ InteractionBuilder.Graphs.REWARD]) self._planner.insert(plan=self._interaction_builder.interactions[ InteractionBuilder.Graphs.PLAN_CHECKIN_TOMORROW], post_hook=self._set_vars_after_interaction) def _set_vars_after_prompted(self): num_of_prompted_today = self._state_database.get( DatabaseKeys.NUM_OF_PROMPTED_TODAY) + 1 self._state_database.set(DatabaseKeys.NUM_OF_PROMPTED_TODAY, num_of_prompted_today) self._state_database.set(DatabaseKeys.IS_PROMPTED_BY_USER, False) self._state_database.set(DatabaseKeys.IS_DONE_PROMPTED_TODAY, True) self._set_vars_after_interaction() def _set_vars_after_too_many_prompted(self): self._set_vars_after_interaction() self._state_database.set(DatabaseKeys.IS_PROMPTED_BY_USER, False) def _is_do_mindfulness(self): last_5_scores = self._state_database.get( DatabaseKeys.LAST_5_EVAL_SCORES) if len(last_5_scores) > 0: average_eval_score = sum(last_5_scores) / len(last_5_scores) else: average_eval_score = 0 return self._days_since_first_interaction() >= 7 \ and self._state_database.get(DatabaseKeys.FEELINGS_INDEX) <= 3 \ and self._state_database.get(DatabaseKeys.CURRENT_EVAL_SCORE) < average_eval_score def _is_do_goal_setting(self): last_5_scores = self._state_database.get( DatabaseKeys.LAST_5_EVAL_SCORES) if len(last_5_scores) > 0: average_eval_score = sum(last_5_scores) / len(last_5_scores) else: average_eval_score = 0 return self._days_since_first_interaction() >= 7 \ and self._state_database.get(DatabaseKeys.FEELINGS_INDEX) <= 3 \ and self._state_database.get(DatabaseKeys.NUM_OF_DAYS_SINCE_LAST_GOAL_SETTING) >= 7 \ and self._state_database.get(DatabaseKeys.NUM_OF_DAYS_SINCE_LAST_PROMPT) >= self._num_of_days_to_prompt_goal_setting \ and self._state_database.get(DatabaseKeys.NUM_OF_DAYS_SINCE_LAST_PERSEVERANCE) >= self._num_of_days_to_prompt_goal_setting \ and self._state_database.get(DatabaseKeys.CURRENT_EVAL_SCORE) < average_eval_score def _days_since_first_interaction(self): first_interaction_datetime = self._state_database.get( DatabaseKeys.FIRST_INTERACTION_DATETIME) if first_interaction_datetime is None: num_of_days = 0 else: current_date = datetime.datetime.now().date() num_of_days = (current_date - self._state_database.get( DatabaseKeys.FIRST_INTERACTION_DATETIME).date()).days return num_of_days @property def current_node_name(self): return self._current_node_name
PmCheckin.fail_graph ] steps_today = 300 steps_goal = 600 last_sync = ( datetime.datetime.now() - datetime.timedelta(minutes=param_db.get(param_db.Keys.MINS_BEFORE_WARNING_ABOUT_FITBIT_NOT_SYNCING) + 1) ) state_db.set(state_db.Keys.LAST_FITBIT_SYNC, last_sync) state_db.set(state_db.Keys.STEPS_TODAY, steps_today) state_db.set(state_db.Keys.STEPS_GOAL, steps_goal) # Create a plan plan_ = MessagerPlanner(possible_plans) if (datetime.datetime.now() - last_sync).seconds // 60 > \ param_db.get(param_db.Keys.MINS_BEFORE_WARNING_ABOUT_FITBIT_NOT_SYNCING): plan_.insert(PmCheckin.Messages.no_sync) else: if steps_goal <= steps_today: plan_.insert(PmCheckin.success_graph) else: plan_.insert(PmCheckin.fail_graph) ie = InteractionEngine(TerminalClientAndServerInterface(state_db), plan_, possible_plans) ie.run() print(state_db) print(param_db)
from abm_grant_interaction import state_db, param_db from abm_grant_interaction.goal_setter.goal_calculator import GoalCalculator from abm_grant_interaction.interactions.first_meeting import FirstMeeting from interaction_engine import InteractionEngine from interaction_engine.planner import MessagerPlanner from interaction_engine.interfaces import TerminalClientAndServerInterface possible_plans = [ FirstMeeting.first_meeting ] # Create a plan plan_ = MessagerPlanner(possible_plans) plan_.insert(FirstMeeting.first_meeting) steps_last_week = 3000 goal_calc = GoalCalculator() week_goal = goal_calc.get_week_goal(steps_last_week=steps_last_week, weeks_remaining=6) day_goal = goal_calc.get_day_goal(week_goal, 0, 7) state_db.set(state_db.Keys.STEPS_LAST_WEEK, steps_last_week) state_db.set(state_db.Keys.SUGGESTED_STEPS_TODAY, day_goal) ie = InteractionEngine(TerminalClientAndServerInterface(state_db), plan_, possible_plans) ie.run() print(state_db) print(param_db)
class InteractionManager: def __init__(self, statedb, interaction_builder, interface=None, max_num_of_perseverance_readings=5): self._state_database = statedb self._interaction_builder = interaction_builder if interface is None: interface = TerminalClientAndServerInterface( database=self._state_database) self._interface = interface self._current_node_name = None self._current_interaction_type = None self._planner = MessagerPlanner( self._interaction_builder.possible_graphs) self._max_num_of_perseverance_readings = max_num_of_perseverance_readings self._num_of_days_to_prompt_goal_setting = 3 def run_interaction_once(self, interaction_type): if interaction_type not in Interactions.POSSIBLE_INTERACTIONS: raise ValueError("Not a valid interaction type") self.build_interaction(interaction_type) self.run_engine_once() def run_engine_once(self): engine = InteractionEngine(self._interface, self._planner, self._interaction_builder.possible_graphs) for node_name in engine.modified_run(self._planner): self._current_node_name = node_name def build_interaction(self, interaction_type): self._planner = MessagerPlanner( self._interaction_builder.possible_graphs) if interaction_type == Interactions.ASK_TO_DO_SCHEDULED: self._build_ask_to_do_scheduled() elif interaction_type == Interactions.FIRST_INTERACTION: self._build_first_interaction() elif interaction_type == Interactions.PROMPTED_INTERACTION: self._build_prompted_interaction() elif interaction_type == Interactions.SCHEDULED_INTERACTION: self._build_scheduled_interaction() elif interaction_type == Interactions.TOO_MANY_PROMPTED: self._build_too_many_prompted() else: raise ValueError("Not a valid interaction type") return self._planner def _build_ask_to_do_scheduled(self): logging.info("Building ask to do scheduled") self._planner.insert( self._interaction_builder.interactions[ InteractionBuilder.Graphs.ASK_TO_DO_SCHEDULED], post_hook=self._set_vars_after_ask_to_do_scheduled, ) return self._planner def _build_first_interaction(self): logging.info("Building first interaction") self._planner.insert(self._interaction_builder.interactions[ InteractionBuilder.Graphs.INTRODUCE_QT], post_hook=self._set_vars_after_first_interaction) return self._planner def _build_prompted_interaction(self): logging.info("Building prompted interaction") self._planner.insert( self._interaction_builder.interactions[ InteractionBuilder.Graphs.PROMPTED_ASK_TO_CHAT], post_hook=self._set_vars_after_prompted_ask_to_chat) return self._planner def _build_scheduled_interaction(self): logging.info("Building scheduled interaction") self._planner.insert( self._interaction_builder.interactions[ InteractionBuilder.Graphs.SCHEDULED_ASK_TO_CHAT], post_hook=self._set_vars_after_scheduled_ask_to_chat) return self._planner def _build_too_many_prompted(self): logging.info("Building checkin limit reminder") self._planner.insert(plan=self._interaction_builder.interactions[ InteractionBuilder.Graphs.TOO_MANY_PROMPTED], post_hook=self._set_vars_after_too_many_prompted) return self._planner def _set_vars_after_ask_to_do_scheduled(self): if self._state_database.get("is off checkin") == "Yes": self._state_database.set("is off checkin", None) if self._state_database.get("video to play"): self._planner.insert( self._interaction_builder.interactions[ InteractionBuilder.Graphs.FEEDBACK_VIDEO], ) self._planner.insert(self._interaction_builder.interactions[ InteractionBuilder.Graphs.EVALUATION], post_hook=self._set_vars_after_evaluation) else: self._planner.insert( self._interaction_builder.interactions[ InteractionBuilder.Graphs.PROMPTED_ASK_TO_CHAT], post_hook=self._set_vars_after_prompted_ask_to_chat) def _set_vars_after_scheduled_ask_for_eval(self): if self._state_database.get("is do evaluation") == "Yes": self._state_database.set("is do evaluation", None) if self._state_database.get("video to play"): self._planner.insert( self._interaction_builder.interactions[ InteractionBuilder.Graphs.FEEDBACK_VIDEO], ) self._planner.insert(self._interaction_builder.interactions[ InteractionBuilder.Graphs.EVALUATION], post_hook=self._set_vars_after_evaluation) self._planner.insert( self._interaction_builder.interactions[ InteractionBuilder.Graphs.ASK_TO_DO_PERSEVERANCE], post_hook=self._set_vars_after_ask_to_do_perseverance) def _set_vars_after_prompted_ask_to_chat(self): if self._state_database.get("good to chat") == "Yes": self._state_database.set("good to chat", None) self._planner.insert(self._interaction_builder.interactions[ InteractionBuilder.Graphs.PROMPTED_CHECKIN], post_hook=self._set_vars_after_prompted) else: self._planner.insert(self._interaction_builder.interactions[ InteractionBuilder.Graphs.PROMPTED_PLAN_NEXT_CHECKIN], post_hook=self._set_vars_after_interaction) def _set_vars_after_scheduled_ask_to_chat(self): if self._state_database.get("good to chat") == "Yes": self._state_database.set("good to chat", None) self._planner.insert( self._interaction_builder.interactions[ InteractionBuilder.Graphs.SCHEDULED_CHECKIN], ) self._planner.insert( self._interaction_builder.interactions[ InteractionBuilder.Graphs.ASK_TO_DO_EVALUATION], post_hook=self._set_vars_after_scheduled_ask_for_eval) else: self._state_database.set("good to chat", None) self._planner.insert(self._interaction_builder.interactions[ InteractionBuilder.Graphs.PLAN_NEXT_CHECKIN], post_hook=self._set_vars_after_interaction) def _set_vars_after_ask_to_do_perseverance(self): if self._state_database.get("is start perseverance") == "Yes": self._state_database.set("is start perseverance", None) self._planner.insert(plan=self._interaction_builder.interactions[ InteractionBuilder.Graphs.PERSEVERANCE], post_hook=self._set_vars_after_perseverance) else: if self._is_do_mindfulness(): self._planner.insert( plan=self._interaction_builder.interactions[ InteractionBuilder.Graphs.MINDFULNESS], post_hook=self._set_vars_after_mindfulness) if self._is_do_goal_setting(): self._planner.insert( plan=self._interaction_builder.interactions[ InteractionBuilder.Graphs.GOAL_SETTING], post_hook=self._set_vars_after_goal_setting) self._planner.insert(plan=self._interaction_builder.interactions[ InteractionBuilder.Graphs.PLAN_CHECKIN_TOMORROW], post_hook=self._set_vars_after_interaction) def _set_vars_after_evaluation(self): self._state_database.set("is done eval today", True) eval_index = self._state_database.get("reading eval index") self._state_database.set("reading eval index", eval_index + 1) # also need to calculate and save reading speed self._set_vars_after_interaction() def _set_vars_after_interaction(self): self._state_database.set("is prompted by user", False) self._state_database.set("is interaction finished", True) self._state_database.set("last interaction datetime", datetime.datetime.now()) def _set_vars_after_first_interaction(self): self._state_database.set("first interaction datetime", datetime.datetime.now()) self._set_vars_after_interaction() def _set_vars_after_goal_setting(self): self._state_database.set("num of days since last goal setting", 0) self._set_vars_after_interaction() def _set_vars_after_mindfulness(self): self._state_database.set( "num of days since last _set_vars_after_mindfulness", 0) self._set_vars_after_interaction() def _set_vars_after_perseverance(self): perseverance_counter = self._state_database.get( "perseverance counter") + 1 self._state_database.set("perseverance counter", perseverance_counter) if perseverance_counter >= self._max_num_of_perseverance_readings: self._planner.insert(plan=self._interaction_builder.interactions[ InteractionBuilder.Graphs.REWARD]) self._planner.insert(plan=self._interaction_builder.interactions[ InteractionBuilder.Graphs.PLAN_CHECKIN_TOMORROW]) else: self._planner.insert( plan=self._interaction_builder.interactions[ InteractionBuilder.Graphs.CONTINUE_PERSEVERANCE], post_hook=self._set_vars_after_continue_perseverance) def _set_vars_after_continue_perseverance(self): if self._state_database.get("is continue perseverance") == "Continue": self._planner.insert(plan=self._interaction_builder.interactions[ InteractionBuilder.Graphs.PERSEVERANCE], post_hook=self._set_vars_after_perseverance) else: self._planner.insert(plan=self._interaction_builder.interactions[ InteractionBuilder.Graphs.REWARD]) self._planner.insert(plan=self._interaction_builder.interactions[ InteractionBuilder.Graphs.PLAN_CHECKIN_TOMORROW], post_hook=self._set_vars_after_interaction) def _set_vars_after_prompted(self): num_of_prompted_today = self._state_database.get( "num of prompted today") + 1 self._state_database.set("num of prompted today", num_of_prompted_today) self._state_database.set("is prompted by user", False) self._state_database.set("is done prompted today", True) self._set_vars_after_interaction() def _set_vars_after_too_many_prompted(self): self._set_vars_after_interaction() self._state_database.set("is prompted by user", False) def _is_do_mindfulness(self): last_5_scores = self._state_database.get("last 5 eval scores") if len(last_5_scores) > 0: average_eval_score = sum(last_5_scores) / len(last_5_scores) else: average_eval_score = 0 return self._days_since_first_interaction() >= 7 \ and self._state_database.get("feelings index") <= 3 \ and self._state_database.get("current eval score") < average_eval_score def _is_do_goal_setting(self): last_5_scores = self._state_database.get("last 5 eval scores") if len(last_5_scores) > 0: average_eval_score = sum(last_5_scores) / len(last_5_scores) else: average_eval_score = 0 return self._days_since_first_interaction() >= 7 \ and self._state_database.get("feelings index") <= 3 \ and self._state_database.get("num of days since last goal setting") >= 7 \ and self._state_database.get("num of days since last prompt") >= self._num_of_days_to_prompt_goal_setting \ and self._state_database.get("num of days since last perseverance") >= self._num_of_days_to_prompt_goal_setting \ and self._state_database.get("current eval score") < average_eval_score def _days_since_first_interaction(self): first_interaction_datetime = self._state_database.get( "first interaction datetime") if first_interaction_datetime is None: num_of_days = 0 else: current_date = datetime.datetime.now().date() num_of_days = ( current_date - self._state_database.get("first interaction datetime").date() ).days return num_of_days @property def current_node_name(self): return self._current_node_name