Beispiel #1
0
def test_file_upload_without_login():
    with pytest.raises(CapeException):
        cc = CapeClient(API_URL)
        fh = open("/tmp/cape_api.txt", "w")
        fh.write(document_text)
        fh.close()
        cc.add_document("Cape API Documentation",
                        file_path="/tmp/cape_api.txt")
Beispiel #2
0
def add_paraphrase(message, channel, bot, slack_client):
    if bot['slack_key'] not in previous_replies or previous_replies[bot['slack_key']] is None:
        slack_client.api_call("chat.postMessage", channel=channel,
                              text="Please ask a question or create a new saved reply so that I know what to add a paraphrase to.", as_user=True)
        return
    try:
        question = message.split(".add-paraphrase")[1]
        reply_id = previous_replies[bot['slack_key']]
        cape_admin_token = bot['cape_admin_token']
        admin_client = CapeClient(API_BASE, admin_token=cape_admin_token)
        admin_client.add_paraphrase_question(reply_id, question)
        slack_client.api_call("chat.postMessage", channel=channel,
                              text="Thanks, I'll remember that!", as_user=True)
    except CapeException as e:
        slack_client.api_call("chat.postMessage", channel=channel,
                              text=e.message, as_user=True)
Beispiel #3
0
def explain(channel, bot, slack_client):
    if bot['slack_key'] not in previous_answers:
        return
    previous = previous_answers[bot['slack_key']][last_answer[bot['slack_key']]]
    if previous['sourceType'] == 'document':
        slack_client.api_call("chat.postMessage", channel=channel,
                              text="I found that in the document '%s'" % previous['sourceId'], as_user=True)
    else:
        try:
            cape_admin_token = bot['cape_admin_token']
            admin_client = CapeClient(API_BASE, admin_token=cape_admin_token)
            saved_reply = admin_client.get_saved_replies(saved_reply_ids=[previous['sourceId']])['items'][0]
            slack_client.api_call("chat.postMessage", channel=channel,
                                  text="I thought you asked: %s" % saved_reply['canonicalQuestion'], as_user=True)
        except CapeException as e:
            slack_client.api_call("chat.postMessage", channel=channel,
                                  text=e.message, as_user=True)
Beispiel #4
0
def create_demo_user(api_url):
    log('Creating demo user')
    client = CapeClient(api_url)
    new_user_parameters = {
        'userId': cape_frontend_settings.DEMO_USER_LOGIN,
        'password': cape_frontend_settings.DEMO_USER_PASSWORD,
        'token': cape_frontend_settings.DEMO_USER_TOKEN,
        'superAdminToken': cape_frontend_settings.BACKEND_SUPER_ADMIN_TOKEN,
    }
    url = 'user/create-user?'
    for k, v in new_user_parameters.items():
        url += "%s=%s&" % (k, v)
    response = client._raw_api_call(url)
    assert response.status_code == 200, "Could not create demo user"
    client.login(cape_frontend_settings.DEMO_USER_LOGIN,
                 cape_frontend_settings.DEMO_USER_PASSWORD)
    log(f'Demo user created with token {cape_frontend_settings.DEMO_USER_TOKEN}'
        )
Beispiel #5
0
def add_saved_reply(message, channel, bot, slack_client):
    try:
        message = message.split(".add-saved-reply")[1]
        question, answer = message.split('|', 1)
    except Exception as e:
        slack_client.api_call("chat.postMessage", channel=channel,
                              text="Sorry, I didn't understand that. The usage for .add-saved-reply is: .add-saved-reply question | answer", as_user=True)
        print("Add saved reply failed: ", e, "Message: ", message)
        return
    
    try:
        cape_admin_token = bot['cape_admin_token']
        admin_client = CapeClient(API_BASE, admin_token=cape_admin_token)
        reply_id = admin_client.add_saved_reply(question, answer)['replyId']
        previous_replies[bot['slack_key']] = reply_id
        slack_client.api_call("chat.postMessage", channel=channel,
                              text="Thanks, I'll remember that!", as_user=True)
    except CapeException as e:
        slack_client.api_call("chat.postMessage", channel=channel,
                              text=e.message, as_user=True)
Beispiel #6
0
def wait_for_backend():
    if not cape_frontend_settings.WAIT_FOR_BACKENDS:
        return
    demo_user_created = not cape_frontend_settings.CREATE_DEMO_ACCOUNT_ON_INIT
    num_backends = len(cape_frontend_settings.BACKENDS_API_URL)
    backends_left = set(cape_frontend_settings.BACKENDS_API_URL)
    while backends_left:
        log(f"Frontend waiting for backends to initialize {len(backends_left)}/{num_backends}"
            )
        current_url = backends_left.pop()
        try:
            reachable = requests.get(current_url[:-4],
                                     timeout=1).status_code == 200
        except Exception:
            reachable = False
        if not reachable:
            log(f'Could not reach backend {current_url}, retrying ...')
            backends_left.add(current_url)
            time.sleep(1)
            continue
        if not demo_user_created:
            create_demo_user(current_url)
        client = CapeClient(current_url)
        client.login(cape_frontend_settings.DEMO_USER_LOGIN,
                     cape_frontend_settings.DEMO_USER_PASSWORD)
        client.answer(
            question="How many people were present ?",
            text=
            "Yesterday at the demonstration, 500 people assisted the event.")
    log("All backends started")
Beispiel #7
0
def test_emails(email_cape_client: CapeClient):
    #
    # Testing Bob->Cape Error->Bob
    #
    user_token = email_cape_client.get_user_token()
    question = 'What colour is the sky ?'
    cape_email = f"{user_token}@{TEST_RECEIVE_EMAIL_DOMAIN}"
    bob_email = f"bob@{TEST_SEND_EMAIL_DOMAIN}"
    alice_email = f"alice@{TEST_SEND_EMAIL_DOMAIN}"
    answer = "The sky is blue."
    random_key = str(uuid4())
    bob_email_content = f"Hello {random_key},\n{question}\nRegards,\nBob"
    alice_answer = f"Hello {random_key},\n {answer} \nRegards,\nAlice"
    bob_email_subject = "Test sky colour"
    # First attempt we get an error for not setting forward email
    _mailgun_send(email_from=bob_email, email_to=cape_email, email_subject=bob_email_subject,
                  email_text=bob_email_content)
    time.sleep(MAILGUN_WAIT_PERIOD)
    sent_body_plain = _mailgun_get_last_email(cape_email)['body-plain']
    assert random_key in sent_body_plain
    assert question in sent_body_plain
    error_response = _mailgun_get_last_email(bob_email)['body-plain']
    assert 'Sorry, this Cape AI account has not yet been configured for email access. \nPlease contact your Cape administrator to set this up.' in error_response
    assert email_cape_client.get_profile()['forwardEmail'] is None
    assert email_cape_client.set_forward_email(alice_email)
    assert email_cape_client.get_profile()['forwardEmail'] == alice_email
    assert email_cape_client.get_profile()['forwardEmailVerified'] == False
    time.sleep(MAILGUN_WAIT_PERIOD)
    verification_token_text = _mailgun_get_last_email(alice_email)['body-plain']
    verification_token = verification_token_text.split("verifiedEmailToken=")[1].split("\n")[0]
    email_cape_client._raw_api_call('user/verify-forward-email', {"verifiedEmailToken":verification_token})
    assert email_cape_client.get_profile()['forwardEmailVerified'] == True
    time.sleep(60)  # we wait for the forwardEmailVerified attribute to be propagated across nodes
    #
    # Testing Bob->Cape Suggestions->Alice->Cape New Saved Reply->Bob
    #
    _mailgun_send(email_from=bob_email, email_to=cape_email, email_subject=bob_email_subject,
                  email_text=bob_email_content)
    time.sleep(MAILGUN_WAIT_PERIOD)
    sent_body_plain = _mailgun_get_last_email(cape_email)['body-plain']
    reply = _mailgun_get_last_email(alice_email)
    suggestions: str = reply['body-plain']
    assert random_key in sent_body_plain
    assert question in sent_body_plain
    assert random_key in suggestions
    assert """==Cape AI Suggestions==""" in suggestions
    # mailgun's plain-text version adds line breaks when encountering our <b> tags around the answer
    suggestions = suggestions.replace("\n", "")
    assert suggestions.index("sky is blue") < suggestions.index("colour is red") < suggestions.index("like pizzas")
    # Alice replies with the answer
    test_sender = reply['Sender'].replace('thecape.ai', TEST_RECEIVE_EMAIL_DOMAIN)
    _mailgun_send(email_from=alice_email, email_to=test_sender,
                  email_subject="Re: " + bob_email_subject,
                  email_text=alice_answer)
    time.sleep(MAILGUN_WAIT_PERIOD)
    alice_response = _mailgun_get_last_email(test_sender)['body-plain']
    assert answer in alice_response
    bob_response = _mailgun_get_last_email(bob_email)['body-plain']
    assert answer in bob_response
    assert random_key in bob_response
    #
    # Testing Bob->Cape Saved Reply->Bob
    #
    random_key = str(uuid4())
    bob_email_content = f"Hello {random_key},\n{question}\nRegards,\nBob"
    _mailgun_send(email_from=bob_email, email_to=cape_email, email_subject=bob_email_subject,
                  email_text=bob_email_content)
    time.sleep(MAILGUN_WAIT_PERIOD)
    sent_body_plain = _mailgun_get_last_email(cape_email)['body-plain']
    bob_response = _mailgun_get_last_email(bob_email)['body-plain']
    assert answer in bob_response
    assert random_key in sent_body_plain
    assert question in sent_body_plain
    assert random_key in bob_response
Beispiel #8
0
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

import os
import time
from bots import bots
from slackclient import SlackClient
from cape.client import CapeClient, CapeException


READ_WEBSOCKET_DELAY = 1 # Delay in seconds between reading from firehose
API_BASE='https://responder.thecape.ai/api'

cc = CapeClient(API_BASE)
previous_answers = {}
last_answer = {}
previous_replies = {}


def handle_question(question, channel, bot, slack_client):
    cape_token = bot['cape_token']
    answers = cc.answer(question, cape_token, number_of_items=5)
    if len(answers) > 0:
        print(question, answers[0]['answerText'])
        previous_answers[bot['slack_key']] = answers
        last_answer[bot['slack_key']] = 0
        if answers[0]['sourceType'] == 'saved_reply':
            previous_replies[bot['slack_key']] = answers[0]['sourceId']
        else:
# -*- coding: utf-8 -*-
"""
Created on Fri Oct 16 12:41:46 2020

@author: Carl
"""

from flask import Flask, render_template, jsonify, request
from cape.client import CapeClient
from settings import USERNAME, PASSWORD

app = Flask(__name__)

_CAPE_CLIENT = CapeClient()
_CAPE_CLIENT.login(USERNAME, PASSWORD)

_LAST_DOC_ID = None
_ANSWER_TOKEN = _CAPE_CLIENT.get_user_token()


@app.route('/')
def index():
    return render_template('index.html')


@app.route('/add_document', methods=['POST'])
def add_document():
    global _LAST_DOC_ID
    doc_text = request.form.get('doc', "")
    _LAST_DOC_ID = _CAPE_CLIENT.upload_document(title='ctrl_f_doc',
                                                text=doc_text,
Beispiel #10
0
def cc():
    client = CapeClient(API_URL)
    client.login('testuser', 'testpass')
    yield client
    client.logout()
Beispiel #11
0
def test_login():
    cc = CapeClient(API_URL)
    assert cc.logged_in() == False
    cc.login('blo', 'bla')
    assert cc.logged_in() == True
Beispiel #12
0
def test_get_token_without_login():
    with pytest.raises(CapeException):
        cc = CapeClient(API_URL)
        cc.get_user_token()
Beispiel #13
0
def test_failed_login():
    with pytest.raises(CapeException):
        cc = CapeClient(UNLUCKY_API_URL)
        cc.login('invalid', 'invalid')
Beispiel #14
0
        this parsing function returns None unless a message is
        directed at the Bot, based on its ID.
    """
    output_list = slack_rtm_output
    if output_list and len(output_list) > 0:
        for output in output_list:
            at_bot = "<@%s>" % BOT_ID
            if output and 'text' in output and at_bot in output[
                    'text'] and 'channel' in output:
                # return text after the @ mention, whitespace removed
                return output['text'].split(at_bot)[1].strip(), \
                       output['channel']
    return None, None


if __name__ == "__main__":
    slack_client = SlackClient(SLACK_KEY)
    cape_client = CapeClient()

    if slack_client.rtm_connect():
        print("Connected")
    else:
        print("Failed to connect")
        sys.exit()

    while True:
        message, channel = parse_slack_output(slack_client.rtm_read())
        if message and channel:
            handle_question(message, channel, slack_client, cape_client)
        time.sleep(READ_WEBSOCKET_DELAY)
Beispiel #15
0
def test_text_upload_without_login():
    with pytest.raises(CapeException):
        cc = CapeClient(API_URL)
        cc.add_document("Cape API Documentation",
                        document_text,
                        origin='cape_api.txt')
Beispiel #16
0
        return

    try:
	# Create a new saved reply
        cape_client.add_saved_reply(question, answer)
        slack_client.api_call("chat.postMessage", channel=channel,
                              text="Thanks, I'll remember that!", as_user=True)
    except CapeException as e:
	# Inform the user of any errors encountered when adding their saved reply
        slack_client.api_call("chat.postMessage", channel=channel,
                              text=e.message, as_user=True)


if __name__ == "__main__":
    slack_client = SlackClient(SLACK_KEY)
    cape_client = CapeClient(admin_token=CAPE_ADMIN_TOKEN)

    if slack_client.rtm_connect():
        print("Connected")
    else:
        print("Failed to connect")
        sys.exit()

    while True:
        message, channel = parse_slack_output(slack_client.rtm_read())
        if message and channel:
            if message.lower().startswith(".add-saved-reply"):
                add_saved_reply(message, channel, slack_client, cape_client)
            else:
                handle_question(message, channel, slack_client, cape_client)
        time.sleep(READ_WEBSOCKET_DELAY)