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
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
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
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
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.")
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
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
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)
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
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
def has_google_api_key() -> bool: return read_api_key("GoogleServerKey") != ""
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