Exemplo n.º 1
0
def delete_model(name, username=None, password=None, cookies_file=None):
    """Delete a model from model name or model ID"""
    model_id = get_model_id(name, username, password, cookies_file)

    data = {"session_id": "-1",
            "project_id": "-1",
            "page": "/model/{}/dashboard".format(model_id),
            "query_params": {},
            "host": "developer.nuance.com",
            "port": "",
            "protocol": "https",
            "category": "model",
            "action": "delete",
            "label": "cancelled",
            "value": model_id}

    url = "https://developer.nuance.com/mix/nlu/bolt/ubt"
    result = requests.post(url, data=json.dumps(data),
                           cookies=cookies)  # pylint: disable=E0602

    if result.status_code != 200:
        raise PyNuanceError("Bad HTTP status code during the model deletion")

    url = "https://developer.nuance.com/mix/nlu/api/v1/projects/{}".format(model_id)
    result = requests.delete(url,
                             cookies=cookies)  # pylint: disable=E0602

    if result.status_code != 204:
        raise PyNuanceError("Bad HTTP status code during the model deletion")
Exemplo n.º 2
0
def get_model_id(name, username=None, password=None, cookies_file=None):
    """Get model ID from model name.

    If name is already a model ID, this function can help to validate the existance of the model.

    Raise if there are 2 or more models with the same name.
    """
    models = list_models(username, password, cookies_file)

    model_id = None
    for model in models:
        if model.get("name") == name and model_id is not None:
            raise PyNuanceError("There at least two models with the same name. "
                                "Please use the model ID instead")
        elif model.get("name") == name:
            model_id = model.get("id")
        try:
            if model.get("id") == int(name):
                model_id = int(name)
                break
        except ValueError:
            pass
    if model_id is None:
        raise PyNuanceError("Model '{}' not found".format(name))

    return model_id
Exemplo n.º 3
0
def create_model(name, language,
                 username=None, password=None, cookies_file=None):  # pylint: disable=W0613
    """Create a new model in Nuance Mix."""
    # Check language
    voices_by_lang = dict([(l['code'], l['voice']) for l in LANGUAGES.values()])
    if language not in voices_by_lang:
        raise PyNuanceError("Error: language should be in "
                            "{}".format(', '.join(voices_by_lang.keys())))
    # First request
    data = {"name": name,
            "domains": [],
            "locale": language,
            "sources": []}
    headers = {"Content-Type": "application/json;charset=UTF-8"}
    url = "https://developer.nuance.com/mix/nlu/api/v1/projects"
    result = requests.post(url, data=json.dumps(data), headers=headers,
                           cookies=cookies)  # pylint: disable=E0602
    if result.status_code != 200:
        raise PyNuanceError("Unknown HTTP error on the first request")
    model_json = result.json()
    model_id = model_json.get("id")
    if model_id is None:
        raise PyNuanceError("The HTTP create request did not return the new model ID")
    # Second request
    data = {"session_id": "-1",
            "project_id": "-1",
            "page": "/models/",
            "query_params": {},
            "host": "developer.nuance.com",
            "port": "",
            "protocol": "https",
            "category": "model",
            "action": "create",
            "label": name,
            "value": ""}
    url = "https://developer.nuance.com/mix/nlu/bolt/ubt"
    result = requests.post(url, data=json.dumps(data),
                           cookies=cookies)  # pylint: disable=E0602
    res_json = result.json()
    if res_json != {}:
        raise PyNuanceError("Unknown HTTP error on the second request")
    # Third request
    url_put_3 = "https://developer.nuance.com/mix/nlu/api/v1/projects/{}".format(model_id)
    requests.put(url_put_3,
                 cookies=cookies)  # pylint: disable=E0602

    # Result model
    return model_json
Exemplo n.º 4
0
def understand_audio(app_id, app_key, context_tag, language, logger=None):
    """NLU audio wrapper"""
    # transform language
    if logger is None:
        logger = logging.getLogger("pynuance").getChild("nlu").getChild("audio")
    nlu_language = NLU_LANGUAGES.get(language)
    if nlu_language is None:
        raise PyNuanceError("Language should be in "
                            "{}".format(", ".join(NLU_LANGUAGES.keys())))

    try:
        loop = asyncio.get_event_loop()
    except RuntimeError:
        logger.debug("Get New event loop")
        loop = asyncio.new_event_loop()
        asyncio.set_event_loop(loop)

    interpretations = {}
    with Recorder(loop=loop) as recorder:
        interpretations = loop.run_until_complete(_nlu_audio(
            loop,
            "https://ws.dev.nuance.com",
            app_id,
            binascii.unhexlify(app_key),
            context_tag,
            nlu_language,
            recorder=recorder,
            logger=logger,))
    # loop.close()
    if interpretations is False:
        # The user did not speak
        return {}

    return interpretations
Exemplo n.º 5
0
def understand_text(app_id, app_key, context_tag, language, text, logger=None):
    """Nlu text wrapper"""
    if logger is None:
        logger = logging.getLogger("pynuance").getChild("nlu").getChild("text")
    # transform language
    nlu_language = NLU_LANGUAGES.get(language)
    if nlu_language is None:
        raise PyNuanceError("Language should be in "
                            "{}".format(", ".join(NLU_LANGUAGES.keys())))

    logger.debug("Text received: {}".format(text))
    try:
        loop = asyncio.get_event_loop()
    except RuntimeError:
        logger.debug("Get New event loop")
        loop = asyncio.new_event_loop()
        asyncio.set_event_loop(loop)

    # TODO: try/except
    interpretations = loop.run_until_complete(
        _nlu_text("https://ws.dev.nuance.com",
                  app_id,
                  binascii.unhexlify(app_key),
                  context_tag,
                  text,
                  nlu_language,
                  logger,
                  ))
    # loop.close()
    if interpretations is False:
        # The user did not speak
        return {}

    return interpretations
Exemplo n.º 6
0
def _dev_login(username=None, password=None):
    """Login to Nuance developer page

    URL: https://developer.nuance.com/public/index.php
    """
    headers = {"Content-Type": "application/x-www-form-urlencoded"}
    if username is None:
        username = input("Username: "******"Nuance dev password: "******"form": "login",
        "command": "login",
        "next": "",
        "username": username,
        "password": password,
        "login": "",
    }
    params = {"task": "login"}
    url = "https://developer.nuance.com/public/index.php"
    result = requests.post(url,
                           data=data_login,
                           params=params,
                           allow_redirects=False)

    # Go to account page
    params = {"task": "account"}
    url = "https://developer.nuance.com/public/index.php"
    account_result = requests.get(url, params=params, cookies=result.cookies)

    if account_result.text.find("Edit My Profile") == -1:
        raise PyNuanceError("Can not login to Nuance dev")
    return result.cookies
Exemplo n.º 7
0
def mix_activated(username=None, password=None, cookies_file=None):  # pylint: disable=W0613
    """Check if the account has access to Nuance Mix.

    URL: https://developer.nuance.com/mix/nlu/#/models/

    :returns: * True means Mix account activated.
              * False means Mix is being created or not requested
    :rtype: bool
    """
    # Check mix status
    url = "https://developer.nuance.com/public/index.php"
    result = requests.get(url, params={"task": "mix"},
                          cookies=cookies)  # pylint: disable=E0602

    # If "You're on the list!" is here, you just have to wait
    soup = BeautifulSoup(result.text, 'html.parser')
    waiting_node = soup.find("h4", text="You're on the list!")
    ok_node = soup.find("h4", text="Congratulations!")

    if waiting_node.parent.parent.parent.attrs.get('style') != 'display: none':
        return False
    elif ok_node.parent.parent.parent.attrs.get('style') != 'display: none':
        return True
    else:
        raise PyNuanceError("Mix account state unknown")
Exemplo n.º 8
0
        def wrapper(*args_, **kwargs_):
            # Get cookies
            func_args = inspect.getargspec(func)
            attr_dict = {
                "cookies_file": None,
                "username": None,
                "password": None,
            }
            for attr in attr_dict:
                # Trying to get value in args
                if attr not in func_args.args:
                    error_msg = ("Can not use Nuance login decorator for `{}`"
                                 " function. Arg `{}` missing".format(
                                     func.__name__, attr))
                    raise PyNuanceError(error_msg)
                arg_ind = func_args.args.index(attr)
                try:
                    attr_dict[attr] = args_[arg_ind]
                except IndexError:
                    # Not found so set it as None
                    attr_dict[attr] = None
                if attr_dict[attr] is None:
                    # Trying to get value in kwargs
                    attr_dict[attr] = kwargs_.get(attr)

            if attr_dict["cookies_file"] is not None:
                # Using old cookies
                cookies = get_cookies(attr_dict["cookies_file"], website)
                func.__globals__['cookies'] = cookies
            else:
                # Trying to get cookies using username/password
                if website == "mix":
                    cookies = _mix_login(attr_dict.get('username'),
                                         attr_dict.get('password'))
                    func.__globals__['cookies'] = cookies
                elif website == "dev":
                    cookies = _dev_login(attr_dict.get('username'),
                                         attr_dict.get('password'))
                    func.__globals__['cookies'] = cookies
                else:
                    raise PyNuanceError("Bad website parameter")
            return func(*args_, **kwargs_)
Exemplo n.º 9
0
def parse_credentials(file_path):

    with open(file_path) as f_creds:
        cred_json = json.load(f_creds)
        for attr in ("appId", "appKey"):
            if attr not in cred_json.keys():
                raise PyNuanceError(
                    "Missing {} in credentials file".format(attr))

        return cred_json["appId"], cred_json["appKey"], cred_json.get(
            "context_tag")
Exemplo n.º 10
0
def _mix_login(username=None, password=None):
    # Login
    if username is None:
        username = input("Username: "******"Nuance dev password: "******"Content-Type": "application/json;charset=UTF-8"}
    data_login = {"username": username, "password": password}
    url = "https://developer.nuance.com/mix/nlu/bolt/login"
    result = requests.post(url, data=json.dumps(data_login), headers=headers)
    if not result.json().get('status', False):
        raise PyNuanceError("Can not connect")
    return result.cookies
Exemplo n.º 11
0
def get_credentials(username=None, password=None, cookies_file=None):  # pylint: disable=W0613
    """Get credentials from Nuance dev page"""
    credentials = {"appId": None,
                   "appKey": None,
                   }
    # Go to sandbox page to get credentials
    url = "https://developer.nuance.com/public/index.php"
    # pylint: disable=E0602
    result = requests.get(url, params={"task": "credentials"}, cookies=cookies)
    # pylint: enable=E0602
    if result.status_code != 200:
        raise PyNuanceError("Can not go to {}".format(url))
    # parse html page
    soup = BeautifulSoup(result.text, 'html.parser')
    # Get app id
    appid_label_node = soup.find('label', text="App Id")
    if appid_label_node is None:
        raise PyNuanceError("Can not go to {}".format(url))
    credentials["appId"] = appid_label_node.parent.text.replace("App Id", "").strip()
    # Get app key
    appkey_label_node = soup.find('label', text="App Key")
    credentials["appKey"] = appkey_label_node.parent.find("code").text.strip()
    return credentials
Exemplo n.º 12
0
def text_to_speech(app_id, app_key, language, voice, codec, text, logger=None):
    """Read a text with a given language, voice and code"""
    if logger is None:
        logger = logging.getLogger("pynuance").getChild("tts")
    voices_by_lang = dict([(l['code'], l['voice'])
                           for l in LANGUAGES.values()])
    if language not in voices_by_lang:
        raise PyNuanceError("Language should be in "
                            "{}".format(", ".join(voices_by_lang.keys())))
    if voice not in voices_by_lang[language]:
        raise PyNuanceError("Voice should be in "
                            "{}".format(', '.join(voices_by_lang[language])))

    _loop = asyncio.get_event_loop()
    _loop.run_until_complete(
        do_synthesis("https://ws.dev.nuance.com/v1/",
                     app_id,
                     binascii.unhexlify(app_key),
                     language,
                     voice,
                     codec,
                     text,
                     logger=logger))
    _loop.stop()
Exemplo n.º 13
0
def _nlu_audio(loop, url, app_id, app_key, context_tag,  # pylint: disable=R0914
               language, recorder, logger):
    """Trying to understand audio"""
    # Websocket client
    client = WebsocketConnection(url, logger)
    yield from client.connect(app_id, app_key)

    # Init Nuance communication
    audio_type = 'audio/x-speex;mode=wb'
    client.send_message({
        'message': 'connect',
        'device_id': '55555500000000000000000000000000',
        'codec': audio_type
    })

    _, msg = yield from client.receive()

    # logger.debug(msg)  # Should be a connected message

    client.send_message({
        'message': 'query_begin',
        'transaction_id': 123,

        'command': 'NDSP_ASR_APP_CMD',
        'language': language,
        'context_tag': context_tag,
    })

    connection_handshake(client)

    receivetask = asyncio.ensure_future(client.receive())
    audiotask = asyncio.ensure_future(recorder.dequeue())

    yield from listen_microphone(loop, client, recorder, audiotask, receivetask, logger)

    recorder.stop()

    logger.debug("Send last message to Mix")
    client.send_message({
        'message': 'audio_end',
        'audio_id': 456,
    })

    interpretation = {}
    while True:
        yield from asyncio.wait((receivetask,), loop=loop)
        try:
            _, msg = receivetask.result()
        except aiohttp.errors.ServerDisconnectedError:
            raise PyNuanceError("Error, check your context tag {} existence "
                                "in MIX".format(context_tag))
        logger.debug(msg)

        if msg['message'] == 'query_end':
            break
        else:
            interpretation = msg

        receivetask = asyncio.ensure_future(client.receive())

    client.close()
    return interpretation
Exemplo n.º 14
0
def model_build_attach(name, build_version=None, context_tag="latest",
                       username=None, password=None, cookies_file=None):
    """Attach model version to a Nuance App

    For now, only SandBoxApp is supported by pynuance
    """
    # TODO validate context_tag
    headers = {"Content-Type": "application/json;charset=UTF-8"}
    # Get model ID
    model = get_model(name, username, password, cookies_file)
    model_id = model.get("id")
    # Get buildID
    build_id = None
    if build_version is not None:
        for build in model.get("builds", []):
            if int(build_version) == build.get("version"):
                build_id = build.get("id")
                break
        if build_id is None:
            raise Exception("Build not found")
    # Get SandBox app ID
    url = "https://developer.nuance.com/mix/nlu/bolt/applications"
    params = {"configurations": "true"}
    result = requests.get(url, params=params,
                          cookies=cookies)  # pylint: disable=E0602
    app_id = None
    for app in result.json().get("applications"):
        if app['name'] == 'Sandbox App':
            app_id = app['id']
            break
    # Get NMAID
    url = "https://developer.nuance.com/mix/nlu/bolt/nmaids"
    result = requests.get(url,
                          cookies=cookies)  # pylint: disable=E0602
    nmaids = [app['nmaid'] for app in result.json()['data'] if app['app_id'] == app_id]
    if len(nmaids) < 1:
        raise PyNuanceError("Can not get nmaid")
    nmaid = nmaids[0]
    # Attach
    data = {"nmaid": nmaid,
            "project_id": model_id, "tag": context_tag}
    url = "https://developer.nuance.com/mix/nlu/bolt/applications/{}/configurations".format(app_id)
    result = requests.post(url, data=json.dumps(data), headers=headers,
                           cookies=cookies)  # pylint: disable=E0602
    conf_id = result.json().get("id")
    if conf_id is None:
        raise PyNuanceError("Can not find configuration ID")

    data = {"page": "/model/{}/publish".format(model_id),
            "query_params": {},
            "host": "developer.nuance.com",
            "port": 443,
            "protocol": "https",
            "category": "publish",
            "action": "associate-to-app",
            "label": "finish",
            "value": ""}
    url = "https://developer.nuance.com/mix/nlu/bolt/ubt"
    result = requests.post(url, data=json.dumps(data), headers=headers,
                           cookies=cookies)  # pylint: disable=E0602

    url = ("https://developer.nuance.com/mix/nlu/bolt/applications/{}/"
           "configurations/{}/settings".format(app_id, conf_id))
    result = requests.put(url, data=json.dumps({}), headers=headers,
                          cookies=cookies)  # pylint: disable=E0602

    url = ("https://developer.nuance.com/mix/nlu/bolt/applications/{}/"
           "configurations/{}/models".format(app_id, conf_id))
    if build_id is not None:
        data = [{"model_id": "{}".format(model_id),
                 "build_id": "{}".format(build_id),
                 "build_version": "{}".format(build_version)}]
    else:
        data = [{"model_id": "{}".format(model_id)}]
    requests.put(url, data=json.dumps(data), headers=headers,
                 cookies=cookies)  # pylint: disable=E0602