Example #1
0
def query_traveltime_api(
    startloc: Union[str, LatLonTuple],
    endloc: Union[str, LatLonTuple],
    mode: str = "walking",
) -> Optional[Dict]:
    """Look up travel time between two places, given a particular mode
    of transportation, i.e. one of the modes in _TRAVEL_MODES.
    The location arguments can be names, to be resolved by the API, or
    a tuple of coordinates, e.g. (64.156742, -21.949426)
    Uses Google Maps' Distance Matrix API. For more info, see:
    https://developers.google.com/maps/documentation/distance-matrix/intro
    """
    assert mode in _TRAVEL_MODES

    # Load API key
    key = read_api_key("GoogleServerKey")
    if not key:
        # No key, can't query the API
        logging.warning("No API key for travel time lookup")
        return None

    # Format query string args
    p1 = "{0},{1}".format(
        *startloc) if isinstance(startloc, tuple) else startloc
    p2 = "{0},{1}".format(*endloc) if isinstance(endloc, tuple) else endloc

    # Send API request
    url = _MAPS_API_TRAVELTIME_URL.format(p1, p2, mode, key)
    res = query_json_api(url)

    return res
Example #2
0
def get_staticmap_image(
    latitude: float,
    longitude: float,
    zoom: int = 6,
    width: int = 180,
    height: int = 180,
) -> Optional[BytesIO]:
    """ Request image from Google Static Maps API, return image data as bytes """
    key = read_api_key("GoogleServerKey")
    if not key:
        return None

    url = STATICMAP_URL.format(zoom, width, height, key, latitude, longitude)
    # TODO: Use urllib instead of requests here
    try:
        r = requests.get(url, stream=True)
    except Exception as e:
        logging.warning(str(e))
        return None

    if r.status_code == 200:
        r.raw.decode_content = True
        return BytesIO(r.raw.data)

    logging.warning("Status {0} when requesting static map image".format(
        r.status_code))
    return None
Example #3
0
def in_ci_environment() -> bool:
    """ This function determines whether the tests are running in the
        continuous integration environment by checking if the API key
        is a dummy value (set in CI config). """
    global DUMMY_API_KEY
    try:
        return read_api_key("GreynirServerKey") == DUMMY_API_KEY
    except Exception:
        return False
Example #4
0
def query_geocode_api_coords(lat: float, lon: float) -> Optional[Dict]:
    """ Look up coordinates in Google's geocode API. """
    # Load API key
    key = read_api_key("GoogleServerKey")
    if not key:
        # No key, can't query Google location API
        logging.warning("No API key for coordinates lookup")
        return None

    # Send API request
    res = query_json_api(_MAPS_API_COORDS_URL.format(lat, lon, key))

    return res
Example #5
0
def register_query_data_api(version=1):
    """
    Stores or updates query data for the given client ID

    Hinrik's comment:
    Data format example from js code
    {
        'device_id': device_id,
        'key': 'smartlights',
        'data': {
            'smartlights': {
                'selected_light': 'philips_hue',
                'philips_hue': {
                    'username': username,
                    'ipAddress': internalipaddress
                }
            }
        }
    }

    """

    if not (1 <= version <= 1):
        return better_jsonify(valid=False, reason="Unsupported version")

    qdata = request.json
    if qdata is None:
        return better_jsonify(valid=False, errmsg="Empty request.")

    # Calling this endpoint requires the Greynir API key
    key = qdata.get("api_key")
    gak = read_api_key("GreynirServerKey")
    if not gak or not key or key != gak:
        return better_jsonify(valid=False, errmsg="Invalid or missing API key.")

    if (
        not qdata
        or "data" not in qdata
        or "key" not in qdata
        or "client_id" not in qdata
    ):
        return better_jsonify(valid=False, errmsg="Missing parameters.")

    success = QueryObject.store_query_data(
        qdata["client_id"], qdata["key"], qdata["data"]
    )
    if success:
        return better_jsonify(valid=True, msg="Query data registered")

    return better_jsonify(valid=False, errmsg="Error registering query data.")
Example #6
0
def query_geocode_api_addr(addr: str) -> Optional[Dict]:
    """ Look up address in Google's geocode API. """
    # Load API key
    key = read_api_key("GoogleServerKey")
    if not key:
        # No key, can't query the API
        logging.warning("No API key for address lookup")
        return None

    # Send API request
    url = _MAPS_API_ADDR_URL.format(addr, key)
    res = query_json_api(url)

    return res
Example #7
0
def query_ja_api(q: str) -> Optional[Dict[str, Any]]:
    """ Send query to ja.is API """
    key = read_api_key("JaServerKey")
    if not key:
        # No key, can't query the API
        logging.warning("No API key for ja.is")
        return None

    qdict = {"q": q}
    headers = {"Authorization": key}

    # Send API request, get back parsed JSON
    url = _JA_API_URL.format(urlencode(qdict))
    res = query_json_api(url, headers=headers)

    return res
Example #8
0
def speech_api(version=1):
    """ Send in text, receive URL to speech-synthesised audio file. """

    if not (1 <= version <= 1):
        return better_jsonify(valid=False, reason="Unsupported version")

    reply: Dict[str, Any] = dict(err=True)

    # Calling this endpoint requires the Greynir API key
    key = request.values.get("api_key")
    gak = read_api_key("GreynirServerKey")
    if not gak or not key or key != gak:
        reply["errmsg"] = "Invalid or missing API key."
        return better_jsonify(**reply)

    text = request.values.get("text")
    if not text:
        return better_jsonify(**reply)

    fmt = request.values.get("format", "ssml")
    if fmt not in ["text", "ssml"]:
        fmt = "ssml"
    voice_id = request.values.get("voice_id", "Dora")
    speed = request.values.get("voice_speed", 1.0)
    if not isinstance(speed, float):
        try:
            speed = float(speed)
            if speed < 0.1 or speed > 3.0:
                speed = 1.0
        except Exception:
            speed = 1.0

    try:
        url = get_synthesized_text_url(
            text, txt_format=fmt, voice_id=voice_id, speed=speed
        )
    except Exception:
        return better_jsonify(**reply)

    reply["audio_url"] = url
    reply["err"] = False

    return better_jsonify(**reply)
Example #9
0
def query_places_api(
    placename: str,
    userloc: Optional[LatLonTuple] = None,
    radius: float = _PLACES_LOCBIAS_RADIUS,
    fields: Optional[str] = None,
) -> Optional[Dict]:
    """Look up a placename in Google's Places API. For details, see:
    https://developers.google.com/places/web-service/search"""

    if not fields:
        # Default fields requested from API
        fields = "place_id,opening_hours,geometry/location,formatted_address"

    # Load API key
    key = read_api_key("GoogleServerKey")
    if not key:
        # No key, can't query the API
        logging.warning("No API key for Google Places lookup")
        return None

    # Generate query string
    qdict = {
        "input": placename,
        "inputtype": "textquery",
        "fields": fields,
        "key": key,
        "language": "is",
        "region": "is",
    }
    if userloc:
        qdict["locationbias"] = "circle:{0}@{1},{2}".format(
            radius, userloc[0], userloc[1])
    qstr = urlencode(qdict)

    # Send API request
    url = _PLACES_API_URL.format(qstr)
    res = query_json_api(url)

    return res
Example #10
0
def query_place_details(place_id: str,
                        fields: Optional[str] = None) -> Optional[Dict]:
    """Look up place details by ID in Google's Place Details API. If "fields"
    parameter is omitted, *all* fields are returned. For details, see
    https://developers.google.com/places/web-service/details"""

    # Load API key
    key = read_api_key("GoogleServerKey")
    if not key:
        # No key, can't query the API
        logging.warning("No API key for Google Place Details lookup")
        return None

    # Generate query string
    qdict = {"place_id": place_id, "key": key, "language": "is"}
    if fields:
        qdict["fields"] = fields
    qstr = urlencode(qdict)

    # Send API request
    url = _PLACEDETAILS_API_URL.format(qstr)
    res = query_json_api(url)

    return res
Example #11
0
def has_google_api_key() -> bool:
    return read_api_key("GoogleServerKey") != ""
Example #12
0
def get_image_url(
    name: str,
    *,
    hints: List = [],
    size: str = "large",
    thumb: bool = False,
    enclosing_session: Optional[Session] = None,
    cache_only: bool = False,
) -> Optional[Img]:
    """ Use Google Custom Search API to obtain an image corresponding to a (person) name """
    jdoc = None
    ctype = _CTYPE + size

    with SessionContext(commit=True, session=enclosing_session) as session:
        link = (session.query(Link.content, Link.timestamp).filter(
            Link.ctype == ctype).filter(Link.key == name).one_or_none())
        if link is not None:
            # Found in cache. If the result is old, purge it
            period = timedelta(days=_CACHE_EXPIRATION_DAYS)
            expired = datetime.utcnow() - link.timestamp > period
            if expired and not cache_only:
                _purge_single(name, ctype=ctype, enclosing_session=session)
            else:
                jdoc = link.content

        if not jdoc and cache_only:
            return None

        if not jdoc:
            # Not found in cache: prepare to ask Google
            key = read_api_key("GoogleServerKey")
            if not key:
                # No API key: can't ask for an image
                logging.warning("No API key for image lookup")
                return None

            # Assemble the query parameters
            search_str = '"{0}" {1}'.format(name, " ".join(hints)).strip()
            q: Dict[str, Union[str, int]] = dict(
                q=search_str,
                num=_NUM_IMG_URLS,
                start=1,
                imgSize=size,
                # imgType = "face",   # Only images with faces
                lr="lang_is",  # Higher priority for Icelandic language pages
                gl="is",  # Higher priority for .is results
                searchType="image",
                cx=_CX,
                key=key,
            )
            if Settings.DEBUG:
                print("Sending Google image search request for '{0}'".format(
                    search_str))
            jdoc = _server_query("https://www.googleapis.com/customsearch/v1",
                                 q)
            if Settings.DEBUG:
                print("Back from Google image search for '{0}'".format(
                    search_str))
            if jdoc:
                # Store in the cache
                lnk = Link(ctype=ctype,
                           key=name,
                           content=jdoc,
                           timestamp=datetime.utcnow())
                session.add(lnk)

        if not jdoc:
            return None

        answer = json.loads(jdoc)

        if (answer and "items" in answer and answer["items"]
                and "link" in answer["items"][0]):
            blacklist = _blacklisted_urls_for_key(name,
                                                  enclosing_session=session)

            for item in answer["items"]:
                k = item["link"] if not thumb else item["image"][
                    "thumbnailLink"]
                if k and item["link"] not in blacklist:
                    image = item["image"]
                    h = image["height"] if not thumb else image[
                        "thumbnailHeight"]
                    w = image["width"] if not thumb else image["thumbnailWidth"]
                    return Img(k, w, h, image["contextLink"],
                               item["displayLink"], name)

    # No answer that makes sense
    return None