Beispiel #1
0
    def to_message_element(response):
        if isinstance(response, QuickReply):
            message = {"text": response.title}
            payload = json.dumps(
                response.payload if response.payload else response.title,
                default=json_serialize)
            key = 'callback_' + hashlib.md5(payload).hexdigest()
            db = get_redis()
            db.set(key, payload, ex=3600 * 24 * 7)
            message['callback_data'] = json.dumps(key)
            return [message]

        elif isinstance(response, Button):
            message = {"text": response.title}
            if response.payload:
                payload = json.dumps(response.payload, default=json_serialize)
                key = 'callback_' + hashlib.md5(payload).hexdigest()
                db = get_redis()
                db.set(key, payload, ex=3600 * 24 * 7)
                message['callback_data'] = json.dumps(key)
                return [message]
            elif response.url:
                message['url'] = response.url
                return [message]
            return []
        return None
Beispiel #2
0
 def accept_request(body, num_tries=1) -> bool:
     if body['type'] == 'message':
         uid = body['from']['id']
         chat_id = body['conversation']['id']
         get_redis().set('chat_message_id:{}'.format(chat_id),
                         body['id'])  # TODO
         MicrosoftInterface.set_base_url(chat_id, body['serviceUrl'])
         MicrosoftInterface.set_bot_id(chat_id, body['recipient']['id'])
         accept_user_message.delay(MicrosoftInterface.name,
                                   uid,
                                   body,
                                   chat_id=chat_id)
         return True
     return False
Beispiel #3
0
    def load_profile(uid, cache=True):
        fbid = FacebookInterface.uid_to_fbid(uid)

        db = get_redis()
        key = 'fb_profile_' + fbid

        if not cache or not db.exists(key):
            print('Loading fb profile...')

            url = "https://graph.facebook.com/v2.6/" + fbid
            params = {
                'fields':
                'first_name,last_name,profile_pic,locale,timezone,gender',
                'access_token': FacebookInterface.get_page_token_for_uid(uid)
            }
            res = requests.get(url, params=params)
            if not res.status_code == requests.codes.ok:
                print("!!!!!!!!!!!!!!!!!!!!!!! ERROR load_profile " +
                      res.status_code)
                return None

            db.set(key, json.dumps(res.json()),
                   ex=3600 * 24 * 14)  # save value, expire in 14 days

        return json.loads(db.get(key).decode('utf-8'))
Beispiel #4
0
 def record_bot_message(message):
     record = {'type': type(message).__name__}
     if isinstance(message, TextMessage):
         record['text'] = message.text
     print('Recording bot message: {}'.format(record))
     db = get_redis()
     db.lpush('test_actions', json.dumps({'type': 'bot', 'body': record}))
Beispiel #5
0
    def parse_message(raw_message, num_tries=1):
        print(raw_message)
        db = get_redis()
        if 'callback_query' in raw_message:
            key = json.loads(raw_message['callback_query']['data'],
                             object_hook=json_deserialize)
            if not db.exists(key):
                return {'entities': None, 'type': 'postback'}
            payload = json.loads(db.get(key).decode(encoding='UTF-8'))
            print("PAYLOAD", payload)
            payload['_message_text'] = [{'value': None}]
            return {'entities': payload, 'type': 'postback'}
        elif 'message' in raw_message:
            if 'sticker_id' in raw_message['message']:
                return TelegramInterface.parse_sticker(
                    raw_message['message']['sticker_id'])
            if 'attachments' in raw_message['message']:
                attachments = raw_message['message']['attachments']
                return TelegramInterface.parse_attachments(attachments)
            if 'quick_reply' in raw_message['message']:
                payload = json.loads(
                    raw_message['message']['quick_reply'].get('payload'),
                    object_hook=json_deserialize)
                if payload:
                    payload['_message_text'] = [{
                        'value':
                        raw_message['message']['text']
                    }]
                    return {'entities': payload, 'type': 'postback'}
            if 'text' in raw_message['message']:
                return parse_text_message(raw_message['message']['text'])

        return {'type': 'undefined'}
Beispiel #6
0
def accept_schedule_all_users(callback_name):
    print('Accepting scheduled callback {}'.format(callback_name))
    db = get_redis()
    interface_names = db.hgetall('session_interface')
    for uid in interface_names:
        interface_name = interface_names[uid].decode('utf-8')
        accept_schedule_callback(interface_name, uid.decode('utf-8'), callback_name)
Beispiel #7
0
 def record_start():
     logging.warning('Starting recording')
     db = get_redis()
     db.delete('test_actions')
     message = TextMessage(text="Starting to record ;)")\
         .add_button(PayloadButton(title="Stop recording", payload={"test_record": "stop"}))
     return message
Beispiel #8
0
 def _load_from_cache(self, text):
     if self.cache:
         db = get_redis()
         if db.hexists('wit_cache', text):
             parsed = pickle.loads(db.hget('wit_cache', text))
             self.log.debug('Got cached wit key: "{}" = {}'.format(self.cache_key, parsed))
             return parsed
     return None
Beispiel #9
0
 def get_bot_id(chat_id):
     if chat_id is None:
         raise Exception('Chat id must not be null')
     redis = get_redis()
     bot_id = redis.get('ms_reply_botid_' + str(chat_id))
     if bot_id is None:
         raise Exception('Bot ID not found for chat {}'.format(
             str(chat_id)))
     return bot_id.decode()
Beispiel #10
0
def accept_schedule_all_users(callback_name):
    print('Accepting scheduled callback {}'.format(callback_name))
    db = get_redis()
    interface_names = db.hgetall('session_interface')
    for uid in interface_names:
        interface_name = interface_names[uid].decode('utf-8')
        # TODO revise this
        interface = create_from_name(interface_name)
        session = ChatSession(interface, uid.decode('utf-8'))
        accept_schedule_callback(session.to_json(), callback_name)
Beispiel #11
0
def _run_test_module(name, benchmark=False):
    import importlib

    module = importlib.import_module('tests.' + name)
    importlib.reload(module)

    result = _run_test_actions(name, module.actions, benchmark=benchmark)
    test = {'name': name, 'result': result}
    db = get_redis()
    db.hset('test_results', name, json.dumps(test))
    return test
Beispiel #12
0
 def record_start():
     print('Starting recording')
     db = get_redis()
     db.delete('test_actions')
     return TextMessage("Starting recording ;)",
                        buttons=[{
                            'title': 'Stop recording',
                            'payload': {
                                'test_record': 'stop'
                            }
                        }])
Beispiel #13
0
 def accept_request(body):
     uid = body['user']['userId']
     chat_id = body['conversation']['conversationId']
     meta = {"uid": uid, "chat_id": chat_id}
     profile = Profile(uid, None, None)
     session = ChatSession(GoogleActionsInterface, chat_id, meta, profile)
     accept_user_message.delay(session.to_json(), body).get()
     # responses = GoogleActionsInterface.response_cache.get(session.chat_id)
     responses = get_redis().get(
         "response_for_{id}".format(id=session.chat_id))  # TODO
     return GoogleActionsInterface.convert_responses(
         session, responses.decode('utf8'))
Beispiel #14
0
 def set_bot_id(chat_id, bot_id):
     """
     Because the microsoft bot api doesn't send the requests to recipient "BOT_ID",
     but to recipient "BOT_ID@nnnn" instead and this ID is required to reply,
     it is saved in redis. When MS updates their documentation about IDs this will hopefully be removed.
     :param chat_id:
     :param bot_id:
     :return:
     """
     if chat_id is None or bot_id is None:
         raise Exception('Chat id and bot id must not be null')
     redis = get_redis()
     redis.set('ms_reply_botid_' + str(chat_id), str(bot_id))
Beispiel #15
0
def run_all_tests(request):
    modules = _get_test_modules('./tests/')

    print('Running tests: {}'.format(modules))
    tests = []
    db = get_redis()
    db.delete('test_results')
    for module in modules:
        print('Running tests "{}"'.format(module))
        tests.append(_run_test_module(module))

    db.set('test_time', str(datetime.datetime.now()))

    return JsonResponse(data=tests, safe=False)
Beispiel #16
0
 def record_user_message(message_type, message):
     print('Recording user {}: {}'.format(message_type, message))
     db = get_redis()
     db.lpush(
         'test_actions',
         json.dumps(
             {
                 'type': 'user',
                 'body': {
                     'type': message_type,
                     'entities': message
                 }
             },
             default=json_serialize))
Beispiel #17
0
 def persist_callback(payload) -> str:
     """
     Persists payload to be used with Telegram callbacks (which can be max. 64B)
     and returns a string that can be used to retrieve the payload from redis.
     The payload will be persisted for a week.
     :param  payload     Payload to be persisted in Redis.
     :return             Unique string associated with the payload, which can be sent to Telegram.
     """
     redis = get_redis()
     key = ''.join(random.choice(string.hexdigits) for i in range(63))
     while redis.exists(key):
         key = ''.join(random.choice(string.hexdigits) for i in range(63))
     redis.set(key, payload, ex=3600 * 24 * 7)
     return key
Beispiel #18
0
    def get_result():
        db = get_redis()
        actions = db.lrange('test_actions', 0, -1)
        response = """from golem.core.responses import *
from golem.core.tests import *

actions = []
"""
        state = None
        for action in actions[::-1]:
            action = json.loads(action.decode('utf-8'),
                                object_hook=json_deserialize)
            body = action['body']
            print('Action body: {}'.format(body))
            if action['type'] == 'user':
                if body['type'] == 'message':
                    text_entity = body['entities']['_message_text'][0]
                    text = text_entity['value']
                    message = 'UserTextMessage("{}")'.format(text)
                    for entity in body['entities']:
                        if entity.startswith('_'):
                            continue
                        value = body['entities'][entity][0].get('value')
                        if isinstance(value, str):
                            message += '.produces_entity("{}","{}")'.format(
                                entity, value)
                        else:
                            message += '.produces_entity("{}")'.format(entity)
                if body['type'] == 'postback':
                    text_entity = body['entities'].get('_message_text')[0]
                    text = text_entity['value']
                    message = 'UserButtonMessage("{}")'.format(text)
                response += "\n\n" + 'actions.append({})'.format(
                    message) + "\n"
            elif action['type'] == 'bot':
                message = 'BotMessage({})'.format(body['type'])
                if 'text' in body:
                    message += '.with_text("{}")'.format(body['text'])
                response += 'actions.append({})'.format(message)
            elif action['type'] == 'state':
                if body == state:
                    continue
                response += 'actions.append(StateChange("{}"))'.format(body)
                state = body
            response += "\n"

        return response
Beispiel #19
0
def accept_schedule_callback(interface_name, uid, callback_name):
    from golem.core.dialog_manager import DialogManager
    db = get_redis()
    active_time = float(db.hget('session_active', uid).decode('utf-8'))
    inactive_seconds = time.time() - active_time
    interface = create_from_name(interface_name)
    print('{} from {} was active {}'.format(uid, interface, active_time))
    parsed = {
        'type' : 'schedule',
        'entities' : {
            'intent' : '_schedule',
            '_inactive_seconds' : inactive_seconds,
            '_callback_name' : callback_name
        }
    }
    dialog = DialogManager(uid=uid, interface=interface)
    _process_message(dialog, parsed)
Beispiel #20
0
    def post_message(uid, chat_id, response):
        if uid and not chat_id:
            # TODO initiate conversation
            return

        message_id = get_redis().get('chat_message_id:{}'.format(chat_id))
        if message_id:
            message_id = message_id.decode()

        bot_id = MicrosoftInterface.get_bot_id(chat_id)

        payload = {
            "type": "message",
            "from": {
                "id": bot_id
            },
            "conversation": {
                "id": chat_id
            },
            "recipient": {
                "id": uid
            },
            "replyToId": message_id
        }
        payload.update(MicrosoftAdapter(chat_id).to_response(response))

        url = MicrosoftInterface.get_base_url(
            chat_id) + 'conversations/' + chat_id + '/activities'
        if message_id and False:  # replying to message TODO get and clear atomically or set timeout or something
            url += '/' + message_id
        headers = {
            "Authorization": "Bearer " + MicrosoftInterface.get_auth_token(),
            "Content-Type": "application/json"
        }
        logging.warning(url)
        logging.warning(payload)
        response = requests.post(url,
                                 data=json.dumps(payload),
                                 headers=headers)
        if response.status_code != 200:
            logging.warning(str(payload))
            logging.warning(response)
            logging.warning(response.text)
        response.raise_for_status()
Beispiel #21
0
    def get_base_url(chat_id) -> Optional[str]:
        """
        Loads the correct endpoint url for a chat from redis.
        :param chat_id: Id of the chat.
        :return: url, throws Exception if chat_id not valid or url not found
        """
        if not chat_id:
            raise Exception('Chat id must not be null')
        redis = get_redis()
        url = redis.get('ms_service_url_' + str(chat_id))
        if url is None:
            raise Exception('Service url not found for chat id ' +
                            str(chat_id))

        url = url.decode()
        if not url.endswith('/'):
            url += '/'
        url += 'v3/'
        return url
Beispiel #22
0
def accept_schedule_callback(session: dict, callback_name):
    session = ChatSession.from_json(session)
    from golem.core.dialog_manager import DialogManager
    db = get_redis()
    active_time = float(
        db.hget('session_active', session.chat_id).decode('utf-8'))
    inactive_seconds = time.time() - active_time
    print('{} from {} was active {}'.format(session.chat_id, session.interface,
                                            active_time))
    parsed = {
        'type': 'schedule',
        'entities': {
            'intent': '_schedule',
            '_inactive_seconds': inactive_seconds,
            '_callback_name': callback_name
        }
    }
    dialog = DialogManager(session)
    _process_message(dialog, parsed)
Beispiel #23
0
def fake_move_to_state(chat_id, state: str, entities=()):
    # TODO solve chat session saving and restoring
    session = get_redis().hget("chat_session", chat_id)

    if not (session and state):
        logging.warning("ChatSession or State is null")
        return

    import json
    session = json.loads(session.decode('utf-8'))
    session = ChatSession.from_json(session)
    state = str(state)
    from golem.core.dialog_manager import DialogManager
    logger.debug("Moving chat id {} to state {}".format(
        session.chat_id, state))
    dialog = DialogManager(session)
    msg_data = {'_state': state}
    for k, v in entities:
        msg_data[k] = [{"value": v}]
    dialog.process('schedule', msg_data)
Beispiel #24
0
def test(request):
    db = get_redis()
    results = db.hgetall('test_results')
    results = [
        json.loads(results[k].decode('utf-8')) for k in sorted(list(results))
    ] if results else []

    updated_time = db.get('test_time')
    updated_time = db.get('test_time').decode(
        'utf-8') if updated_time else None

    status = 'passed'
    avg = {'duration': 0, 'total': 0, 'init': 0, 'parsing': 0, 'processing': 0}
    passed = 0
    for test in results:
        result = test['result']
        if result['status'] == 'passed':
            passed += 1
            avg['duration'] += result['duration']
            avg['total'] += result['report']['avg']['total']
            avg['init'] += result['report']['avg']['init']
            avg['parsing'] += result['report']['avg']['parsing']
            avg['processing'] += result['report']['avg']['processing']
        elif status != 'exception':
            status = result['status']

    if passed > 0:
        for key in avg:
            avg[key] = avg[key] / passed

    context = {
        'tests': results,
        'avg': avg,
        'status': status,
        'updated_time': updated_time
    }
    template = loader.get_template('golem/test.html')
    return HttpResponse(template.render(context, request))
Beispiel #25
0
 def get_auth_token():
     """
     :returns: Auth token for Microsoft Bot API.
     """
     redis = get_redis()
     if redis.exists('ms_token'):
         return redis.get('ms_token').decode()
     else:
         url = 'https://login.microsoftonline.com/botframework.com/oauth2/v2.0/token'
         headers = {"Content-Type": "application/x-www-form-urlencoded"}
         payload = ('grant_type=client_credentials' + '&client_id=' +
                    settings.GOLEM_CONFIG.get('MS_BOT_ID') +
                    '&client_secret=' +
                    settings.GOLEM_CONFIG.get('MS_BOT_TOKEN') + '&scope=' +
                    'https://api.botframework.com/.default')
         response = requests.post(url, data=payload, headers=headers)
         if response.status_code != 200:
             logging.error(response.text)
             response.raise_for_status()
         auth_data = response.json()
         token = auth_data['access_token']
         ex = auth_data['expires_in']
         redis.set('ms_token', str(token), ex=ex)
         return token
Beispiel #26
0
    def load_profile(user_id, page_id, cache=True):

        db = get_redis()
        key = 'fb_profile_' + user_id

        if not cache or not db.exists(key):
            logging.debug('Loading fb profile...')

            url = "https://graph.facebook.com/v2.6/" + user_id
            params = {
                'fields':
                'first_name,last_name,profile_pic,locale,timezone,gender',
                'access_token': FacebookInterface.get_page_token(page_id)
            }
            res = requests.get(url, params=params)
            if not res.status_code == requests.codes.ok:
                logging.error("ERROR loading FB profile! Response: {}".format(
                    res.text))
                return {}

            db.set(key, json.dumps(res.json()),
                   ex=3600 * 24 * 14)  # save value, expire in 14 days

        return json.loads(db.get(key).decode('utf-8'))
Beispiel #27
0
 def save_to_cache(self, text, entities):
     if self.cache and 'date_interval' not in entities:
         db = get_redis()
         self.log.debug('Caching wit key: {} = {}'.format(text, entities))
         db.hset('wit_cache', text, pickle.dumps(entities))
Beispiel #28
0
 def post_message(session, response):
     GoogleActionsInterface.messages.append(response)
     get_redis().set("response_for_{id}".format(id=session.chat_id),
                     str(response))  # TODO
Beispiel #29
0
 def record_state_change(state):
     print('Recording state change: {}'.format(state))
     db = get_redis()
     db.lpush('test_actions', json.dumps({'type': 'state', 'body': state}))
Beispiel #30
0
 def clear_wit_cache(self):
     if self.cache:
         self.log.debug('Clearing Wit cache...')
         db = get_redis()
         db.delete('wit_cache')