From fa5d2f5f8282c1f149d910b7d54703b51a8a4702 Mon Sep 17 00:00:00 2001 From: = Date: Wed, 8 Nov 2023 23:12:27 -0500 Subject: [PATCH] working on databaseagent, still some problems --- docker-compose.yml | 2 + flask_app/agents/database_agent.py | 142 ++++++++---------- flask_app/agents/map_info_agent.py | 20 ++- flask_app/agents/marshall_agent.py | 23 +-- flask_app/agents/navigation_agent.py | 11 +- flask_app/agents/style_agent.py | 8 +- flask_app/app.py | 27 ++-- flask_app/templates/index.html | 1 - settings/clip.geojson | 8 - ...echtenstein-latest.osm.pbf:Zone.Identifier | 4 + 10 files changed, 103 insertions(+), 143 deletions(-) delete mode 100644 settings/clip.geojson create mode 100644 settings/liechtenstein-latest.osm.pbf:Zone.Identifier diff --git a/docker-compose.yml b/docker-compose.yml index 2586363..53f466f 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -34,6 +34,8 @@ services: - settings-data:/home/settings healthcheck: test: "pg_isready -d ${POSTGRES_DBNAME}" + ports: + - "${POSTGRES_PORT}:5432" imposm: image: kartoza/docker-osm:imposm-latest diff --git a/flask_app/agents/database_agent.py b/flask_app/agents/database_agent.py index f16a641..1deba18 100644 --- a/flask_app/agents/database_agent.py +++ b/flask_app/agents/database_agent.py @@ -1,4 +1,3 @@ -import openai import json import logging import os @@ -16,10 +15,11 @@ class DatabaseAgent: def get_table_from_database(self, query): return {"name": "get_table_from_database", "query": query} - def __init__(self, model_version="gpt-3.5-turbo-0613", schema=None): + def __init__(self, client, schema=None): self.model_version = model_version + self.client = client self.schema = schema - self.function_descriptions = self.get_function_descriptions() + self.tools = self.get_function_descriptions() self.messages = [ { "role": "system", @@ -27,12 +27,7 @@ class DatabaseAgent: When responding with sql queries, you must use the 'osm' schema desgignation. - Favor SQL queries that return polygons first, then lines, then points. - - An example prompt from the user is: - - 'add buildings to the map - Ensure the query is restricted to the following bbox: 30, 50, 31, 51' + An example prompt from the user is: "Add buildings to the map. Ensure the query is restricted to the following bbox: 30, 50, 31, 51" You would respond with: 'SELECT ST_AsGeoJSON(geometry) FROM osm.osm_buildings WHERE ST_Intersects(geometry, ST_MakeEnvelope(30, 50, 31, 51, 4326))'. @@ -50,92 +45,77 @@ class DatabaseAgent: } def listen(self, message, bbox): - logger.info(f"In DatabaseAgent.listen()...message is: {message}") - logger.info(f"In DatabaseAgent.listen()...bbox is: {bbox}") - data = {'message': message} - response = requests.get("http://localhost:5000/get_table_name", json=data) """Listen to a message from the user.""" - map_context = f"Ensure the query is restricted to the following bbox: {bbox}" - table_name_context = "" + #data = {'message': message} + table_names = [table['table_name'] for table in self.schema] + prefixed_message = f"Choose the most likely table the following text is referring to from this list:\m {table_names}.\n" + final_message = prefixed_message + message + + # use openai to choose the most likely table name from the schema + response = self.client.chat.completions.create( + model=self.model_version, + messages=[ + {"role": "system", "content": "You are a helpful assistant that chooses a table name from a list. Only respond with the table name."}, + {"role": "user", "content": final_message}, + ], + temperature=0, + max_tokens=32, + frequency_penalty=0, + presence_penalty=0, + ) + table_name = response.choices[0].message.content + logger.info(f"table_name in DatabaseAgent is: {table_name}") + map_context = f"Ensure the query is restricted to the following bbox: {bbox}" + db = Database( + database=os.getenv("POSTGRES_DBNAME"), + user=os.getenv("POSTGRES_USER"), + password=os.getenv("POSTGRES_PASS"), + host=os.getenv("POSTGRES_HOST"), + port=os.getenv("POSTGRES_PORT") + ) + column_names = db.get_column_names(table_name) + logger.info(f"column_names in DatabaseAgent is: {column_names}") + db.close() + table_name_context = f"Generate your query using the following table name: {table_name} and the appropriate column names: {column_names}" - # attempt to get the tablename from the user message - # we do this to avoid sending the entire schema to openai - if response.status_code == 200: - logger.info(f"Response from /get_table_name route: {response}") - response_data = response.json() - logger.info(f"Response message from /get_table_name route: {response_data}") - table_name = response_data.get('choices', [{}])[0].get('message', {}).get('content', '') - if table_name: - logger.info(f"Table name: {table_name}") - db = Database( - database=os.getenv("POSTGRES_DBNAME"), - user=os.getenv("POSTGRES_USER"), - password=os.getenv("POSTGRES_PASS"), - host=os.getenv("POSTGRES_HOST"), - port=os.getenv("POSTGRES_PORT") - ) - column_names = db.get_column_names(table_name) - db.close() - table_name_context = f"Generate your query using the following table name: {table_name} and the appropriate column names: {column_names}" - - #remove the last item in self.messages - if len(self.messages) > 1: - self.messages.pop() self.messages.append({ "role": "user", "content": message + "\n" + map_context + "\n" + table_name_context, }) - # self.messages.append({ - # "role": "user", - # "content": map_context, - # }) - logger.info(f"DatabaseAgent self.messages: {self.messages}") - logger.info(f"DatabaseAgent self.function_descriptions: {self.function_descriptions}") + # this will be the function gpt will call if it # determines that the user wants to call a function function_response = None try: - response = openai.ChatCompletion.create( + logger.info("Calling OpenAI API in DatabaseAgent...") + response = self.client.chat.completions.create( model=self.model_version, messages=self.messages, - functions=self.function_descriptions, - function_call="auto", - temperature=0, - max_tokens=256, - top_p=1, - frequency_penalty=0, - presence_penalty=0 + tools=self.tools, + tool_choice="auto", ) + response_message = response.choices[0].message + logger.info(f"response_message in DatabaseAgent is: {response_message}") + tool_calls = response_message.tool_calls - response_message = response["choices"][0]["message"] - - logger.info(f"Response from OpenAI in DatabaseAgent: {response_message}") - - if response_message.get("function_call"): - function_name = response_message["function_call"]["name"] - function_name = function_name.strip() - logger.info(f"Function name: {function_name}") - function_to_call = self.available_functions[function_name] - logger.info(f"Function to call: {function_to_call}") - function_args = json.loads(response_message["function_call"]["arguments"]) - logger.info(f"Function args: {function_args}") - # determine the function to call - function_response = function_to_call(**function_args) - - ### This is blowing up my context window - # self.messages.append(response_message) - # self.messages.append({ - # "role": "function", - # "name": function_name, - # "content": function_response, - # }) - + if tool_calls: + self.messages.append(response_message) + for tool_call in tool_calls: + function_name = tool_call.function.name + function_to_call = self.available_functions[function_name] + function_args = json.loads(tool_call.function.arguments) + function_response = function_to_call(**function_args) + self.messages.append( + { + "tool_call_id": tool_call.id, + "role": "tool", + "name": function_name, + "content": json.dumps(function_response), + } + ) + logger.info("Sucessful StyleAgent task completion.") return {"response": function_response} - elif response_message.get("content"): - return {"response": response_message["content"]} - else: - return {"response": "I'm sorry, I don't understand."} except Exception as e: return {"error": "Failed to get response from OpenAI in NavigationAgent: " + str(e)}, 500 @@ -145,13 +125,13 @@ class DatabaseAgent: return [ { "name": "get_geojson_from_database", - "description": """Retrieve geojson sptatial data using PostGIS SQL.""", + "description": """Retrieve geojson spatial data using PostGIS SQL.""", "parameters": { "type": "object", "properties": { "query": { "type": "string", - "description": f"""SQL query to get geojson from the database. + "description": """SQL query to get geojson from the database. The query shall be returned in string format as a single command.""" }, }, diff --git a/flask_app/agents/map_info_agent.py b/flask_app/agents/map_info_agent.py index f80bfaa..818a3b6 100644 --- a/flask_app/agents/map_info_agent.py +++ b/flask_app/agents/map_info_agent.py @@ -10,8 +10,8 @@ class MapInfoAgent: def select_layer_name(self, layer_name): return {"name": "select_layer_name", "layer_name": layer_name} - def __init__(self, openai, model_version="gpt-3.5-turbo-0613"): - self.openai = openai + def __init__(self, client, model_version): + self.client = client self.model_version = model_version self.tools = map_info_function_descriptions self.messages = [ @@ -49,7 +49,7 @@ class MapInfoAgent: function_response = None try: - response = self.openai.chat.completions.create( + response = self.client.chat.completions.create( model=self.model_version, messages=self.messages, tools=self.tools, @@ -80,25 +80,23 @@ class MapInfoAgent: # what they meant. In general, it's pretty good at this unless there are multiple layers with similar names, in which case # it just chooses one. if function_name == "select_layer_name": - logger.info(f"Sending layer name retrieval request to OpenAI...") - prompt = f"Please select a layer name from the following list that is closest to the text '{function_response['layer_name']}': {str(layer_names)}\n Only state the layer name in your response." - logger.info(f"Prompt to OpenAI: {prompt}") + + prompt = f"""Please select a layer name from the following list that is closest to the + text '{function_response['layer_name']}': {str(layer_names)}\n + Only state the layer name in your response.""" + messages = [ { "role": "user", "content": prompt, }, ] - second_response = self.openai.chat.completions.create( + second_response = self.client.chat.completions.create( model=self.model_version, messages=messages, ) - logger.info(f"Second response from OpenAI in MapInfoAgent: {second_response}") second_response_message = second_response.choices[0].message.content - logger.info(f"Second response message from OpenAI in MapInfoAgent: {second_response_message}") - logger.info(f"Function Response bofore setting the layer name: {function_response}") function_response['layer_name'] = second_response_message - logger.info(f"Function response after call to select a layername: {function_response}") return {"response": function_response} elif response_message.get("content"): return {"response": response_message["content"]} diff --git a/flask_app/agents/marshall_agent.py b/flask_app/agents/marshall_agent.py index 455872c..79d0c3c 100644 --- a/flask_app/agents/marshall_agent.py +++ b/flask_app/agents/marshall_agent.py @@ -1,14 +1,13 @@ import json -#import openai import logging logger = logging.getLogger(__name__) class MarshallAgent: """A Marshall agent that has function descriptions for choosing the appropriate agent for a specified task.""" - def __init__(self, openai, model_version="gpt-3.5-turbo-0613"): + def __init__(self, client, model_version): self.model_version = model_version - self.openai = openai + self.client = client self.tools = [ { "type": "function", @@ -31,7 +30,7 @@ class MarshallAgent: self.system_message = """You are a helpful assistant that decides which agent to use for a specified task. For tasks related to adding layers and other geospatial data to the map, use the DatabaseAgent. - Examples include 'add buildings to the map' and 'get landuse polygons within this extent'. + Examples include 'add buildings to the map', 'show industrial buildings', and 'get landuse polygons within this extent'. For tasks that ask to change the style of a map, such as opacity, color, or line width, you will use the StyleAgent. Examples StyleAgent prompts include 'change color to green', 'opacity 45%' @@ -52,18 +51,14 @@ class MarshallAgent: self.available_functions = { "choose_agent": self.choose_agent, } - self.logger = logging.getLogger(__name__) + def choose_agent(self, agent_name): return {"name": "choose_agent", "agent_name": agent_name} def listen(self, message): - self.logger.info(f"In MarshallAgent.listen()...message is: {message}") + logger.info(f"In MarshallAgent.listen()...message is: {message}") """Listen to a message from the user.""" - - # # Remove the last item in self.messages. Our agent has no memory - # if len(self.messages) > 1: - # self.messages.pop() self.messages.append({ "role": "user", @@ -75,7 +70,7 @@ class MarshallAgent: function_response = None try: - response = self.openai.chat.completions.create( + response = self.client.chat.completions.create( model=self.model_version, messages=self.messages, tools=self.tools, @@ -100,11 +95,7 @@ class MarshallAgent: "content": json.dumps(function_response), } ) - # second_response = self.openai.chat.completions.create( - # model=self.model_version, - # messages=self.messages, - # ) - logger.info(f"Sucessful MarallAgent task completion: {function_response}") + logger.info(f"Sucessful MarshallAgent task completion: {function_response}") return {"response": function_response} except Exception as e: diff --git a/flask_app/agents/navigation_agent.py b/flask_app/agents/navigation_agent.py index 80c93c9..8ded914 100644 --- a/flask_app/agents/navigation_agent.py +++ b/flask_app/agents/navigation_agent.py @@ -1,6 +1,6 @@ import logging from .function_descriptions.navigation_function_descriptions import navigation_function_descriptions -#import openai +#import client import json logger = logging.getLogger(__name__) @@ -20,8 +20,8 @@ class NavigationAgent: def zoom_out(self, zoom_levels=1): return {"name": "zoom_out", "zoom_levels": zoom_levels} - def __init__(self, openai, model_version="gpt-3.5-turbo-0613"): - self.openai = openai + def __init__(self, client, model_version): + self.client = client self.model_version = model_version self.messages = [ { @@ -42,7 +42,6 @@ class NavigationAgent: "zoom_out": self.zoom_out, } self.tools = navigation_function_descriptions - logger.info(f"self.tools in NavigationAgent is: {self.tools}") def listen(self, message): logging.info(f"In NavigationAgent...message is: {message}") @@ -61,15 +60,13 @@ class NavigationAgent: try: logger.info("Calling OpenAI API in NavigationAgent...") - response = self.openai.chat.completions.create( + response = self.client.chat.completions.create( model=self.model_version, messages=self.messages, tools=self.tools, tool_choice="auto", ) - logger.info(f"response in NavigationAgent is: {response}") response_message = response.choices[0].message - logger.info(f"response_message in NavigationAgent is: {response_message}") tool_calls = response_message.tool_calls if tool_calls: diff --git a/flask_app/agents/style_agent.py b/flask_app/agents/style_agent.py index 563bb7e..a0b4de9 100644 --- a/flask_app/agents/style_agent.py +++ b/flask_app/agents/style_agent.py @@ -19,8 +19,8 @@ class StyleAgent: def set_visibility(self, layer_name, visibility): return {"name": "set_visibility", "layer_name": layer_name, "visibility": visibility} - def __init__(self, openai, model_version="gpt-3.5-turbo-0613"): - self.openai = openai + def __init__(self, client, model_version): + self.client = client self.model_version = model_version self.tools = style_function_descriptions @@ -57,15 +57,13 @@ class StyleAgent: try: logger.info("Calling OpenAI API in StyleAgent...") - response = self.openai.chat.completions.create( + response = self.client.chat.completions.create( model=self.model_version, messages=self.messages, tools=self.tools, tool_choice="auto", ) - logger.info(f"response in StyleAgent is: {response}") response_message = response.choices[0].message - logger.info(f"response_message in StyleAgent is: {response_message}") tool_calls = response_message.tool_calls if tool_calls: diff --git a/flask_app/app.py b/flask_app/app.py index 7720b17..185767e 100644 --- a/flask_app/app.py +++ b/flask_app/app.py @@ -22,14 +22,14 @@ load_dotenv() app = Flask(__name__) CORS(app) -openai = OpenAI(api_key=os.getenv("OPENAI_API_KEY")) +client = OpenAI(api_key=os.getenv("OPENAI_API_KEY")) model_version = os.getenv("OPENAI_MODEL_VERSION") UPLOAD_FOLDER = 'uploads/audio' -navigation_agent = NavigationAgent(openai, model_version=model_version) -marshall_agent = MarshallAgent(openai, model_version=model_version) -style_agent = StyleAgent(openai, model_version=model_version) -map_info_agent = MapInfoAgent(openai, model_version=model_version) +navigation_agent = NavigationAgent(client, model_version=model_version) +marshall_agent = MarshallAgent(client, model_version=model_version) +style_agent = StyleAgent(client, model_version=model_version) +map_info_agent = MapInfoAgent(client, model_version=model_version) def get_database_schema(): db = Database( @@ -44,15 +44,12 @@ def get_database_schema(): return schema schema = get_database_schema() -database_agent = DatabaseAgent(model_version=model_version, schema=schema) +database_agent = DatabaseAgent(client, model_version=model_version, schema=schema) @app.route('/get_query', methods=['POST']) def get_query(): - logging.info(f"Received request in /get_query route...: {request}") message = request.json.get('message', '') bbox = request.json.get('bbox', '') - logging.info(f"Received message in /get_query route...: {message}") - logging.info(f"Received bbox in /get_query route...: {bbox}") return jsonify(database_agent.listen(message, bbox)) @app.route('/get_table_name', methods=['GET']) @@ -62,17 +59,16 @@ def get_table_name(): prefixed_message = f"Choose the most likely table the following text is referring to from this list:\m {table_names}.\n" final_message = prefixed_message + message logging.info(f"Received message in /get_table_name route...: {final_message}") - response = openai.ChatCompletion.create( + response = client.chat.completions.create( model=model_version, messages=[ {"role": "system", "content": "You are a helpful assistant that chooses a table name from a list. Only respond with the table name."}, {"role": "user", "content": final_message}, ], temperature=0, - max_tokens=256, - top_p=1, + max_tokens=32, frequency_penalty=0, - presence_penalty=0 + presence_penalty=0, ) logging.info(f"Response from OpenAI in /get_table_name route: {response}") #response_message = response["choices"][0]["message"] @@ -163,7 +159,10 @@ def upload_audio(): audio_file = request.files['audio'] audio_file.save(os.path.join(UPLOAD_FOLDER, "user_audio.webm")) audio_file=open(os.path.join(UPLOAD_FOLDER, "user_audio.webm"), 'rb') - transcript = openai.audio.transcribe("whisper-1", audio_file) + transcript = client.audio.transcriptions.create( + model="whisper-1", + file = audio_file + ) logging.info(f"Received transcript: {transcript}") message = transcript['text'] #delete the audio diff --git a/flask_app/templates/index.html b/flask_app/templates/index.html index 1903e56..cbdc937 100644 --- a/flask_app/templates/index.html +++ b/flask_app/templates/index.html @@ -270,7 +270,6 @@ .then(response => response.json()) .then(data => { response_data = data.response; - console.log(response_data); chatbox.value += databaseResponseAgent.handleResponse(userMessage, response_data); return; }) diff --git a/settings/clip.geojson b/settings/clip.geojson deleted file mode 100644 index 4e0762e..0000000 --- a/settings/clip.geojson +++ /dev/null @@ -1,8 +0,0 @@ -{ -"type": "FeatureCollection", -"name": "clip", -"crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:OGC:1.3:CRS84" } }, -"features": [ -{ "type": "Feature", "properties": { "ADMIN": "Ukraine", "ISO_A3": "UKR", "ISO_A2": "UA" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ 21.132923158713862, 48.417709891882616 ], [ 21.143896771748455, 48.671108296153747 ], [ 21.226825891952078, 48.979995925090556 ], [ 21.403032688513559, 49.246904094942089 ], [ 21.480375719376543, 49.311544679771927 ], [ 21.657247074388945, 49.562804175378275 ], [ 21.664504279159214, 49.74464855788208 ], [ 21.825566944679174, 50.109541300091443 ], [ 21.999848894953661, 50.316668522166928 ], [ 22.41382379833718, 50.683159539885736 ], [ 22.725737943227237, 50.916907988968674 ], [ 22.672485774335058, 51.033184518861589 ], [ 22.606883441517635, 51.553315548711751 ], [ 22.602574799941813, 51.732936285842307 ], [ 22.687858209979584, 52.027182633511188 ], [ 22.870312192177639, 52.294953737383842 ], [ 23.060564470381568, 52.455979616418851 ], [ 23.289157339698502, 52.569627222561436 ], [ 23.468490374575904, 52.616084320570693 ], [ 23.731634626488386, 52.643917393918649 ], [ 23.828844889056921, 52.716281919043297 ], [ 24.165062761409658, 52.854203296839835 ], [ 24.342175736974021, 52.878830351695377 ], [ 24.702024725871148, 52.885358493253236 ], [ 24.939339636798451, 52.929011179067906 ], [ 25.16560832184237, 52.949593558074348 ], [ 25.440367737880116, 52.920614358383027 ], [ 25.884539846959864, 52.921687095710368 ], [ 26.187136469077203, 52.89545040433611 ], [ 26.332459865665765, 52.852928622149683 ], [ 26.433997523979532, 52.850264895241679 ], [ 26.964113904728165, 52.75644851748558 ], [ 27.133921737221858, 52.762135680197211 ], [ 27.287365895629268, 52.74743486316811 ], [ 27.491444535958049, 52.697060327476841 ], [ 27.703732599431074, 52.599845217188587 ], [ 27.750035951303794, 52.609886577891608 ], [ 27.881312202370427, 52.595127916121854 ], [ 28.2709761788287, 52.650314262239441 ], [ 28.554760558693332, 52.597071466748083 ], [ 28.620480353985045, 52.563256208701652 ], [ 28.701963621171412, 52.552437145605175 ], [ 28.824068570148938, 52.601787836033623 ], [ 29.032928696236961, 52.630137595414531 ], [ 29.235500202267019, 52.619624918537262 ], [ 29.487682279661062, 52.556519715599954 ], [ 29.601829675623229, 52.488586047687754 ], [ 29.748903569605105, 52.489248786274409 ], [ 29.848203749988727, 52.467641081936193 ], [ 29.91640713906494, 52.474427010027192 ], [ 30.056810137220232, 52.62659496776142 ], [ 30.37466583213639, 52.898374652779914 ], [ 30.739087950051989, 53.050453781345617 ], [ 31.103023333296385, 53.078103040705713 ], [ 31.379979385092529, 53.117486965817086 ], [ 31.752613586009705, 53.101509735305612 ], [ 31.892600324742688, 53.209009114629382 ], [ 32.226427038405852, 53.313473563835188 ], [ 32.592102947851579, 53.314184469651721 ], [ 32.773145943686337, 53.279512399471052 ], [ 33.076174274851169, 53.361683070199859 ], [ 33.561408890131062, 53.346699612114186 ], [ 33.799447458069622, 53.359850852218969 ], [ 34.01620285885403, 53.33184890437235 ], [ 34.248313552081939, 53.25051284251051 ], [ 34.597660959185298, 53.015797168330458 ], [ 34.74773115884576, 52.892226931780577 ], [ 34.838157313336801, 52.793256496532848 ], [ 34.937924865816314, 52.644237260833698 ], [ 35.214639876100968, 52.37705514408016 ], [ 35.319714559170578, 52.177044934100955 ], [ 35.698099687932171, 51.992713461111776 ], [ 35.738375794675079, 51.949899395426563 ], [ 35.932667830536992, 51.846719093847106 ], [ 36.140247574643091, 51.644880261185513 ], [ 36.282882080507413, 51.395301134168854 ], [ 36.433804544336695, 51.365798521575108 ], [ 36.592177126201499, 51.288728859287652 ], [ 36.938210396311199, 51.340980756545378 ], [ 37.062677948377029, 51.39067690779234 ], [ 37.327081406041415, 51.427966925743675 ], [ 37.741655643674733, 51.37707573877082 ], [ 38.071601316122589, 51.196345270807747 ], [ 38.225205857646401, 51.059894038651336 ], [ 38.401595201131322, 51.055328510214082 ], [ 38.672064069332407, 50.988684346885314 ], [ 38.74156516225797, 50.948793080841433 ], [ 38.869247323358515, 50.944014009229562 ], [ 39.096466844970351, 50.854653543938539 ], [ 39.293540005128186, 50.864063366204725 ], [ 39.643976115508885, 50.746331710204764 ], [ 39.706920715280205, 50.704374005209388 ], [ 39.929482729613596, 50.652239167822991 ], [ 40.005726473939163, 50.606913200918804 ], [ 40.28986418458534, 50.575249746569618 ], [ 40.693069712815117, 50.40691771433292 ], [ 40.920022288105976, 50.193806117384334 ], [ 41.064064386886791, 49.938767318390269 ], [ 41.12803108958957, 49.652933142409069 ], [ 41.150669755332352, 49.20065821438024 ], [ 41.080004400778712, 48.900070602248256 ], [ 41.049384082498086, 48.845989613024265 ], [ 40.996899748589826, 48.520131122287118 ], [ 40.968874993979476, 48.465946792804239 ], [ 40.982395713666698, 48.420156993382747 ], [ 40.984567850800723, 48.141755529316015 ], [ 40.921080377490682, 47.887242727356131 ], [ 40.805329896549665, 47.67381697510541 ], [ 40.74247700705854, 47.603458320322545 ], [ 40.593739258632318, 47.282224758654131 ], [ 40.291668682980387, 46.986046038904071 ], [ 39.867771103853386, 46.825007561976236 ], [ 39.417086031167351, 46.822935819987073 ], [ 39.261121008399705, 46.839966495221915 ], [ 39.176321924985523, 46.790916895127509 ], [ 39.130842040421705, 46.722313954813806 ], [ 39.107303093957995, 46.64856660498301 ], [ 38.914491000606539, 46.387005840724129 ], [ 38.754853094122879, 46.260035747464627 ], [ 38.456455919924721, 46.088305877136236 ], [ 38.115432668946134, 46.026380262286374 ], [ 37.894233053300226, 46.059535174510067 ], [ 37.849264126093566, 46.024711889714986 ], [ 37.632494830239594, 45.92768243668074 ], [ 37.476170342569624, 45.899702831295286 ], [ 37.520180181240704, 45.832520865554947 ], [ 37.59392088241043, 45.646047733758166 ], [ 37.638348951246293, 45.347259810529088 ], [ 37.591529675136236, 45.048837238070895 ], [ 37.457735222962242, 44.778010502065214 ], [ 37.375205783383635, 44.694864144358235 ], [ 37.223729471879835, 44.438861860216122 ], [ 37.016244482826096, 44.249934437179945 ], [ 36.690339010115892, 44.099262349111854 ], [ 36.527452792311912, 44.067552263672724 ], [ 36.397592650171745, 44.022587113234913 ], [ 36.106345837363428, 44.019952124796298 ], [ 35.948829848575485, 43.998986837605422 ], [ 35.733391026818794, 44.02470393015134 ], [ 35.678147582792285, 44.006973594468285 ], [ 35.582675517048038, 43.928816482103279 ], [ 35.284601681031063, 43.814752023954689 ], [ 34.976729590267453, 43.800901923833393 ], [ 34.874312494535403, 43.70574688496432 ], [ 34.764368651434246, 43.659346269396529 ], [ 34.547183820218883, 43.529404004496214 ], [ 34.279220628214276, 43.436046603721984 ], [ 34.034465287408693, 43.385736344728564 ], [ 33.819375947556736, 43.388080386846269 ], [ 33.539292863731184, 43.416283798795803 ], [ 33.326069295578634, 43.477457998712872 ], [ 32.929463962333898, 43.67158542883562 ], [ 32.702267706679464, 43.828888739533689 ], [ 32.526797981572912, 44.042366714301572 ], [ 32.489110886249335, 44.146838363004861 ], [ 32.476677538239613, 44.141232028022308 ], [ 32.415314243256375, 44.3406961621099 ], [ 32.339879074773478, 44.352057272053763 ], [ 32.083179363485556, 44.437585450428408 ], [ 31.811833739582124, 44.627435322089724 ], [ 31.590353385690392, 44.949856815682949 ], [ 31.524641226265452, 45.118718659364092 ], [ 31.511208633105841, 45.248019372739861 ], [ 31.321671966482857, 45.296794578085212 ], [ 31.165719503355255, 45.364749598391377 ], [ 31.051639558379257, 45.250286313773316 ], [ 30.835815718812359, 45.076927454776836 ], [ 30.695341920336691, 44.985262965844775 ], [ 30.656737511052569, 44.862653713505708 ], [ 30.5092073162558, 44.61128681483396 ], [ 30.295461591460779, 44.413137272173678 ], [ 30.066169699485172, 44.289223362129441 ], [ 29.849041033460576, 44.228920337622256 ], [ 29.526149391276327, 44.224632064500774 ], [ 29.213046248866604, 44.321058483349923 ], [ 29.137157913439978, 44.307329999414137 ], [ 29.070313096107292, 44.27455788512308 ], [ 28.841139314038887, 44.234876187252574 ], [ 28.553133144017487, 44.239346222265333 ], [ 28.226334971011049, 44.311186765643754 ], [ 27.93902286707754, 44.402272386798813 ], [ 27.711037090511958, 44.537687838086157 ], [ 27.359606189549172, 44.91902001629019 ], [ 27.240622625470824, 45.17794629287431 ], [ 27.199499644838287, 45.4599193513221 ], [ 27.239576429781554, 45.742043006011166 ], [ 27.332806843972783, 45.964297838402835 ], [ 27.413363212093326, 46.088030323278723 ], [ 27.546883562413335, 46.23535626230354 ], [ 27.805600742481648, 46.40642768072879 ], [ 27.906693343329511, 46.495588458923578 ], [ 27.942706522356623, 46.556493387808963 ], [ 27.948924673718771, 46.648183811272432 ], [ 28.039264125349721, 46.896107021522802 ], [ 28.193679222451333, 47.11433560674898 ], [ 28.052840599968984, 47.160549926939126 ], [ 27.740962131853625, 47.320726545636276 ], [ 27.637222900526638, 47.34747907210383 ], [ 27.538175356325571, 47.416499068426397 ], [ 27.13815347849912, 47.362658579641199 ], [ 27.069526774607205, 47.331735546558136 ], [ 26.88685335463407, 47.295345852358821 ], [ 26.701365611136165, 47.144090788797563 ], [ 26.422810366186404, 47.023566033518676 ], [ 25.656108833440051, 46.924829639824338 ], [ 25.361468987759267, 46.783372037981685 ], [ 25.015928167157472, 46.717205808829128 ], [ 24.740838903356909, 46.722265574281543 ], [ 24.47754061426518, 46.802101125548731 ], [ 24.305033115470621, 46.912612483004843 ], [ 24.183120696010896, 46.897937094460545 ], [ 23.557382635005407, 46.98272796447543 ], [ 23.500590223231175, 46.97212768703681 ], [ 23.209940704446879, 47.00742017295552 ], [ 23.082352474343452, 46.967924688529273 ], [ 22.731751267274184, 46.957431765081267 ], [ 22.362300466714224, 47.088705009789905 ], [ 22.290460849104523, 47.15339764825351 ], [ 22.248776971223492, 47.162818780916822 ], [ 22.00058343053615, 47.300729706999469 ], [ 21.951309390547308, 47.349858225567559 ], [ 21.804379863074885, 47.409709270627637 ], [ 21.640031139662831, 47.546368095039277 ], [ 21.486629510611735, 47.64163909072915 ], [ 21.293369284992306, 47.861393248027397 ], [ 21.172002493534755, 48.127685392837634 ], [ 21.132923158713862, 48.417709891882616 ] ] ] ] } } -] -} diff --git a/settings/liechtenstein-latest.osm.pbf:Zone.Identifier b/settings/liechtenstein-latest.osm.pbf:Zone.Identifier new file mode 100644 index 0000000..4f52817 --- /dev/null +++ b/settings/liechtenstein-latest.osm.pbf:Zone.Identifier @@ -0,0 +1,4 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=https://download.geofabrik.de/europe.html +HostUrl=https://download.geofabrik.de/europe/liechtenstein-latest.osm.pbf