Team Ai
Apppublic

TangibleAI/mathtext-fastapi

sourceHugging Faceagpl-3.0updated 3y agoView on Hugging Face
1likes
v2_conversation_manager.py272 linesDownload Raw Back to mathtext_fastapi
1import base642import copy3import dill4import os5import json6import jsonpickle7import pickle8import random9import requests10import mathtext_fastapi.global_state_manager as gsm11 12from dotenv import load_dotenv13from mathtext_fastapi.nlu import evaluate_message_with_nlu14from mathtext_fastapi.math_quiz_fsm import MathQuizFSM15from mathtext_fastapi.math_subtraction_fsm import MathSubtractionFSM16from supabase import create_client17from transitions import Machine18 19from mathactive.generators import start_interactive_math20from mathactive.hints import generate_hint21from mathactive.microlessons import num_one22 23load_dotenv()24 25SUPA = create_client(26    os.environ.get('SUPABASE_URL'),27    os.environ.get('SUPABASE_KEY')28)29 30 31def pickle_and_encode_state_machine(state_machine):32    dump = pickle.dumps(state_machine)33    dump_encoded = base64.b64encode(dump).decode('utf-8')34    return dump_encoded35 36 37def manage_math_quiz_fsm(user_message, contact_uuid, type):38    fsm_check = SUPA.table('state_machines').select("*").eq(39        "contact_uuid",40        contact_uuid41    ).execute()42 43    # This doesn't allow for when one FSM is present and the other is empty44    """45    146    data=[] count=None47    48    249    data=[{'id': 29, 'contact_uuid': 'j43hk26-2hjl-43jk-hnk2-k4ljl46j0ds09', 'addition3': None, 'subtraction': None, 'addition': 50 51    - but problem is there is no subtraction , but it's assuming there's a subtration52 53    Cases54    - make a completely new record55    - update an existing record with an existing FSM56    - update an existing record without an existing FSM57    """58    print("MATH QUIZ FSM ACTIVITY")59    print("user_message")60    print(user_message)61    # Make a completely new entry62    if fsm_check.data == []:63        if type == 'addition':64            math_quiz_state_machine = MathQuizFSM()65        else:66            math_quiz_state_machine = MathSubtractionFSM()67        messages = [math_quiz_state_machine.response_text]68        dump_encoded = pickle_and_encode_state_machine(math_quiz_state_machine)69 70        SUPA.table('state_machines').insert({71            'contact_uuid': contact_uuid,72            f'{type}': dump_encoded73        }).execute()74    # Update an existing record with a new state machine75    elif not fsm_check.data[0][type]:76        if type == 'addition':77            math_quiz_state_machine = MathQuizFSM()78        else:79            math_quiz_state_machine = MathSubtractionFSM()80        messages = [math_quiz_state_machine.response_text]81        dump_encoded = pickle_and_encode_state_machine(math_quiz_state_machine)82 83        SUPA.table('state_machines').update({84            f'{type}': dump_encoded85        }).eq(86            "contact_uuid", contact_uuid87        ).execute()      88    # Update an existing record with an existing state machine89    elif fsm_check.data[0][type]:90        undump_encoded = base64.b64decode(91            fsm_check.data[0][type].encode('utf-8')92        )93        math_quiz_state_machine = pickle.loads(undump_encoded)94 95        math_quiz_state_machine.student_answer = user_message96        math_quiz_state_machine.correct_answer = str(math_quiz_state_machine.correct_answer)97        messages = math_quiz_state_machine.validate_answer()98        dump_encoded = pickle_and_encode_state_machine(math_quiz_state_machine)          99        SUPA.table('state_machines').update({100            f'{type}': dump_encoded101        }).eq(102            "contact_uuid", contact_uuid103        ).execute()104    return messages105 106 107def retrieve_microlesson_content(context_data, user_message, microlesson, contact_uuid):108    # TODO: This is being filtered by both the local and global states, so not changing109    if 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_label122        }123    elif context_data['local_state'] == 'addition2' or microlesson == 'addition2':124        if user_message == 'harder' or user_message == 'easier':125            user_message = ''126        message_package = num_one.process_user_message(contact_uuid, user_message)127        message_package['state'] = 'addition2'128        message_package['input_prompt'] = '?'129 130    elif context_data['local_state'] == 'subtraction-question-sequence' or \131        user_message == 'subtract' or \132        microlesson == 'subtraction':133        messages = manage_math_quiz_fsm(user_message, contact_uuid, 'subtraction')134 135        if user_message == 'exit':136            state_label = 'exit'137        else:138            state_label = 'subtraction-question-sequence'139 140        input_prompt = messages.pop()141 142        message_package = {143            'messages': messages,144            'input_prompt': input_prompt,145            'state': state_label146        }147    print("MICROLESSON CONTENT RESPONSE")148    print(message_package)149    return message_package150 151 152curriculum_lookup_table = {153    'N1.1.1_G1': 'addition',154    'N1.1.1_G2': 'addition2',155    'N1.1.2_G1': 'subtraction'156}157 158 159def lookup_local_state(next_state):160    microlesson = curriculum_lookup_table[next_state]161    return microlesson162 163 164def create_text_message(message_text, whatsapp_id):165    """ Fills a template with input values to send a text message to Whatsapp166 167    Inputs168    - message_text: str - the content that the message should display169    - whatsapp_id: str - the message recipient's phone number170 171    Outputs172    - message_data: dict - a preformatted template filled with inputs173    """174    message_data = {175        "preview_url": False,176        "recipient_type": "individual",177        "to": whatsapp_id,178        "type": "text",179        "text": {180            "body": message_text181        }182    }183    return message_data184 185 186def manage_conversation_response(data_json):187    """ Calls functions necessary to determine message and context data """188    print("V2 ENDPOINT")189 190    # whatsapp_id = data_json['author_id']191    message_data = data_json['message_data']192    context_data = data_json['context_data']193    whatsapp_id = message_data['author_id']194    user_message = message_data['message_body']195    print("MESSAGE DATA")196    print(message_data)197    print("CONTEXT DATA")198    print(context_data)199    print("=================")200 201    # nlu_response = evaluate_message_with_nlu(message_data)202 203    # context_data = {204    #     'contact_uuid': 'abcdefg',205    #     'current_state': 'N1.1.1_G2',206    #     'user_message': '1',207    #     'local_state': ''208    # }209    print("STEP 1")210    print(data_json)211    print(f"1: {context_data['current_state']}")212    if not context_data['current_state']:213        context_data['current_state'] = 'N1.1.1_G1'214    print(f"2: {context_data['current_state']}")215 216    curriculum_copy = copy.deepcopy(gsm.curriculum)217    curriculum_copy.state = context_data['current_state']218    print("STEP 2")219    if user_message == 'easier':220        curriculum_copy.left()221        next_state = curriculum_copy.state222    elif user_message == 'harder':223        curriculum_copy.right()224        next_state = curriculum_copy.state225    else:226        next_state = context_data['current_state']227    print("next_state")228    print(next_state)229 230    print("STEP 3")231    microlesson = lookup_local_state(next_state)232 233    print("microlesson")234    print(microlesson)235 236    microlesson_content = retrieve_microlesson_content(context_data, user_message, microlesson, context_data['contact_uuid'])237 238    headers = {239        'Authorization': f"Bearer {os.environ.get('TURN_AUTHENTICATION_TOKEN')}",240        'Content-Type': 'application/json'241    }242 243    # Send all messages for the current state before a user input prompt (text/button input request)244    for message in microlesson_content['messages']:245        data = create_text_message(message, whatsapp_id)246 247        # print("data")248        # print(data)249 250        r = requests.post(251            f'https://whatsapp.turn.io/v1/messages',252            data=json.dumps(data),253            headers=headers254        )255 256    print("STEP 4")257    # combine microlesson content and context_data object258 259    updated_context = {260        "context": {261            "contact_id": whatsapp_id,262            "contact_uuid": context_data['contact_uuid'],263            "current_state": next_state,264            "local_state": microlesson_content['state'],265            "bot_message": microlesson_content['input_prompt'],266            "user_message": user_message,267            "type": 'ask'268        }269    }270    print(updated_context)271    return updated_context272