Beispiel #1
0
    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
Beispiel #2
0
    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
Beispiel #3
0
    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
Beispiel #5
0
    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
Beispiel #7
0
    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)
Beispiel #9
0
            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")
Beispiel #10
0
    def setUp(self) -> None:

        state_db.reset()

        self.true_plan = MessagerPlanner(possible_plans)
        self.builder = builder.PlanBuilder()
Beispiel #11
0
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)
Beispiel #15
0
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