Greg Thompson commited on
Commit
626c6ea
1 Parent(s): 20f623d

Add endpoint for conversation management of global and local states

Browse files
app.py CHANGED
@@ -17,6 +17,7 @@ from pydantic import BaseModel
17
 
18
  from mathtext_fastapi.logging import prepare_message_data_for_logging
19
  from mathtext_fastapi.conversation_manager import manage_conversation_response
 
20
  from mathtext_fastapi.nlu import evaluate_message_with_nlu
21
  from mathtext_fastapi.nlu import run_intent_classification
22
 
@@ -56,7 +57,40 @@ def text2int_ep(content: Text = None):
56
  return JSONResponse(content=content)
57
 
58
 
59
- @app.post("/manager")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
60
  async def programmatic_message_manager(request: Request):
61
  """
62
  Calls conversation management function to determine the next state
 
17
 
18
  from mathtext_fastapi.logging import prepare_message_data_for_logging
19
  from mathtext_fastapi.conversation_manager import manage_conversation_response
20
+ from mathtext_fastapi.v2_conversation_manager import manage_conversation_response
21
  from mathtext_fastapi.nlu import evaluate_message_with_nlu
22
  from mathtext_fastapi.nlu import run_intent_classification
23
 
 
57
  return JSONResponse(content=content)
58
 
59
 
60
+ @app.post("/v1/manager")
61
+ async def programmatic_message_manager(request: Request):
62
+ """
63
+ Calls conversation management function to determine the next state
64
+
65
+ Input
66
+ request.body: dict - message data for the most recent user response
67
+ {
68
+ "author_id": "+47897891",
69
+ "contact_uuid": "j43hk26-2hjl-43jk-hnk2-k4ljl46j0ds09",
70
+ "author_type": "OWNER",
71
+ "message_body": "a test message",
72
+ "message_direction": "inbound",
73
+ "message_id": "ABJAK64jlk3-agjkl2QHFAFH",
74
+ "message_inserted_at": "2022-07-05T04:00:34.03352Z",
75
+ "message_updated_at": "2023-02-14T03:54:19.342950Z",
76
+ }
77
+
78
+ Output
79
+ context: dict - the information for the current state
80
+ {
81
+ "user": "47897891",
82
+ "state": "welcome-message-state",
83
+ "bot_message": "Welcome to Rori!",
84
+ "user_message": "",
85
+ "type": "ask"
86
+ }
87
+ """
88
+ data_dict = await request.json()
89
+ context = manage_conversation_response(data_dict)
90
+ return JSONResponse(context)
91
+
92
+
93
+ @app.post("/v2/manager")
94
  async def programmatic_message_manager(request: Request):
95
  """
96
  Calls conversation management function to determine the next state
mathtext_fastapi/global_state_manager.py CHANGED
@@ -18,3 +18,6 @@ class GlobalStateManager(object):
18
  transitions=GlobalStateManager.transitions,
19
  initial=initial_state
20
  )
 
 
 
 
18
  transitions=GlobalStateManager.transitions,
19
  initial=initial_state
20
  )
21
+
22
+
23
+ curriculum = GlobalStateManager()
mathtext_fastapi/v2_conversation_manager.py ADDED
@@ -0,0 +1,196 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import base64
2
+ import copy
3
+ import dill
4
+ import os
5
+ import json
6
+ import jsonpickle
7
+ import pickle
8
+ import random
9
+ import requests
10
+ import mathtext_fastapi.global_state_manager as gsm
11
+
12
+ from dotenv import load_dotenv
13
+ from mathtext_fastapi.nlu import evaluate_message_with_nlu
14
+ from mathtext_fastapi.math_quiz_fsm import MathQuizFSM
15
+ from mathtext_fastapi.math_subtraction_fsm import MathSubtractionFSM
16
+ from supabase import create_client
17
+ from transitions import Machine
18
+
19
+ from scripts.quiz.generators import start_interactive_math
20
+ from scripts.quiz.hints import generate_hint
21
+
22
+ load_dotenv()
23
+
24
+ SUPA = create_client(
25
+ os.environ.get('SUPABASE_URL'),
26
+ os.environ.get('SUPABASE_KEY')
27
+ )
28
+
29
+
30
+ def pickle_and_encode_state_machine(state_machine):
31
+ dump = pickle.dumps(state_machine)
32
+ dump_encoded = base64.b64encode(dump).decode('utf-8')
33
+ return dump_encoded
34
+
35
+
36
+ def manage_math_quiz_fsm(user_message, contact_uuid, type):
37
+ fsm_check = SUPA.table('state_machines').select("*").eq(
38
+ "contact_uuid",
39
+ contact_uuid
40
+ ).execute()
41
+
42
+ # This doesn't allow for when one FSM is present and the other is empty
43
+ """
44
+ 1
45
+ data=[] count=None
46
+
47
+ 2
48
+ data=[{'id': 29, 'contact_uuid': 'j43hk26-2hjl-43jk-hnk2-k4ljl46j0ds09', 'addition3': None, 'subtraction': None, 'addition':
49
+
50
+ - but problem is there is no subtraction , but it's assuming there's a subtration
51
+
52
+ Cases
53
+ - make a completely new record
54
+ - update an existing record with an existing FSM
55
+ - update an existing record without an existing FSM
56
+ """
57
+ print("MATH QUIZ FSM ACTIVITY")
58
+ print("user_message")
59
+ print(user_message)
60
+ # Make a completely new entry
61
+ if fsm_check.data == []:
62
+ if type == 'addition':
63
+ math_quiz_state_machine = MathQuizFSM()
64
+ else:
65
+ math_quiz_state_machine = MathSubtractionFSM()
66
+ messages = [math_quiz_state_machine.response_text]
67
+ dump_encoded = pickle_and_encode_state_machine(math_quiz_state_machine)
68
+
69
+ SUPA.table('state_machines').insert({
70
+ 'contact_uuid': contact_uuid,
71
+ f'{type}': dump_encoded
72
+ }).execute()
73
+ # Update an existing record with a new state machine
74
+ elif not fsm_check.data[0][type]:
75
+ if type == 'addition':
76
+ math_quiz_state_machine = MathQuizFSM()
77
+ else:
78
+ math_quiz_state_machine = MathSubtractionFSM()
79
+ messages = [math_quiz_state_machine.response_text]
80
+ dump_encoded = pickle_and_encode_state_machine(math_quiz_state_machine)
81
+
82
+ SUPA.table('state_machines').update({
83
+ f'{type}': dump_encoded
84
+ }).eq(
85
+ "contact_uuid", contact_uuid
86
+ ).execute()
87
+ # Update an existing record with an existing state machine
88
+ elif fsm_check.data[0][type]:
89
+ undump_encoded = base64.b64decode(
90
+ fsm_check.data[0][type].encode('utf-8')
91
+ )
92
+ math_quiz_state_machine = pickle.loads(undump_encoded)
93
+
94
+ math_quiz_state_machine.student_answer = user_message
95
+ math_quiz_state_machine.correct_answer = str(math_quiz_state_machine.correct_answer)
96
+ messages = math_quiz_state_machine.validate_answer()
97
+ dump_encoded = pickle_and_encode_state_machine(math_quiz_state_machine)
98
+ SUPA.table('state_machines').update({
99
+ f'{type}': dump_encoded
100
+ }).eq(
101
+ "contact_uuid", contact_uuid
102
+ ).execute()
103
+ return messages
104
+
105
+
106
+ def retrieve_microlesson_content(context_data, user_message, microlesson, contact_uuid):
107
+ if context_data['local_state'] == 'addition-question-sequence' or \
108
+ user_message == 'add' or \
109
+ microlesson == 'addition':
110
+ messages = manage_math_quiz_fsm(user_message, contact_uuid, 'addition')
111
+
112
+ if user_message == 'exit':
113
+ state_label = 'exit'
114
+ else:
115
+ state_label = 'addition-question-sequence'
116
+
117
+ input_prompt = messages.pop()
118
+ message_package = {
119
+ 'messages': messages,
120
+ 'input_prompt': input_prompt,
121
+ 'state': state_label
122
+ }
123
+ elif context_data['local_state'] == 'subtraction-question-sequence' or \
124
+ user_message == 'subtract' or \
125
+ microlesson == 'subtraction':
126
+ messages = manage_math_quiz_fsm(user_message, contact_uuid, 'subtraction')
127
+
128
+ if user_message == 'exit':
129
+ state_label = 'exit'
130
+ else:
131
+ state_label = 'subtraction-question-sequence'
132
+
133
+ input_prompt = messages.pop()
134
+
135
+ message_package = {
136
+ 'messages': messages,
137
+ 'input_prompt': input_prompt,
138
+ 'state': state_label
139
+ }
140
+ print("MICROLESSON CONTENT RESPONSE")
141
+ print(message_package)
142
+ return message_package
143
+
144
+
145
+ curriculum_lookup_table = {
146
+ 'N1.1.1_G1': 'addition',
147
+ 'N1.1.1_G2': 'subtraction'
148
+ }
149
+
150
+
151
+ def lookup_local_state(next_state):
152
+ microlesson = curriculum_lookup_table[next_state]
153
+ return microlesson
154
+
155
+
156
+ def manage_conversation_response(data_json):
157
+ """ Calls functions necessary to determine message and context data """
158
+ print("V2 ENDPOINT")
159
+
160
+ user_message = ''
161
+
162
+ # nlu_response = evaluate_message_with_nlu(message_data)
163
+
164
+ context_data = {
165
+ 'contact_uuid': 'abcdefg',
166
+ 'current_state': 'N1.1.1_G2',
167
+ 'user_message': '1',
168
+ 'local_state': ''
169
+ }
170
+ print("STEP 1")
171
+ if not context_data['current_state']:
172
+ context_data['current_state'] = 'N1.1.1_G1'
173
+
174
+ curriculum_copy = copy.deepcopy(gsm.curriculum)
175
+
176
+ print("STEP 2")
177
+ if context_data['user_message'] == 'easier':
178
+ curriculum_copy.left()
179
+ next_state = curriculum_copy.state
180
+ elif context_data['user_message'] == 'harder':
181
+ curriculum_copy.right()
182
+ next_state = curriculum_copy.state
183
+ else:
184
+ next_state = context_data['current_state']
185
+
186
+ print("STEP 3")
187
+ microlesson = lookup_local_state(next_state)
188
+
189
+ print("microlesson")
190
+ print(microlesson)
191
+
192
+ microlesson_content = retrieve_microlesson_content(context_data, context_data['user_message'], microlesson, context_data['contact_uuid'])
193
+
194
+ print("STEP 4")
195
+ # combine microlesson content and context_data object
196
+ return context_data
scripts/make_request.py CHANGED
@@ -69,12 +69,13 @@ def run_simulated_request(endpoint, sample_answer, context=None):
69
  # run_simulated_request('nlu', 'eight, nine, ten')
70
  # run_simulated_request('nlu', '8, 9, 10')
71
  # run_simulated_request('nlu', '8')
72
- run_simulated_request('nlu', "I don't know")
73
  # run_simulated_request('nlu', "I don't know eight")
74
  # run_simulated_request('nlu', "I don't 9")
75
  # run_simulated_request('nlu', "0.2")
76
  # run_simulated_request('nlu', 'Today is a wonderful day')
77
  # run_simulated_request('nlu', 'IDK 5?')
 
78
  # run_simulated_request('manager', '')
79
  # run_simulated_request('manager', 'add')
80
  # run_simulated_request('manager', 'subtract')
 
69
  # run_simulated_request('nlu', 'eight, nine, ten')
70
  # run_simulated_request('nlu', '8, 9, 10')
71
  # run_simulated_request('nlu', '8')
72
+ # run_simulated_request('nlu', "I don't know")
73
  # run_simulated_request('nlu', "I don't know eight")
74
  # run_simulated_request('nlu', "I don't 9")
75
  # run_simulated_request('nlu', "0.2")
76
  # run_simulated_request('nlu', 'Today is a wonderful day')
77
  # run_simulated_request('nlu', 'IDK 5?')
78
+ run_simulated_request('v2/manager', '')
79
  # run_simulated_request('manager', '')
80
  # run_simulated_request('manager', 'add')
81
  # run_simulated_request('manager', 'subtract')