Spaces:
Sleeping
Sleeping
Nikhil Singh
commited on
Commit
·
e08472a
1
Parent(s):
8f1daaf
final app
Browse files- .gitignore +1 -0
- app.py +133 -4
- pyproject.toml +3 -1
.gitignore
CHANGED
|
@@ -1,3 +1,4 @@
|
|
| 1 |
__pycache__/
|
| 2 |
*.pyc
|
| 3 |
.venv/
|
|
|
|
|
|
| 1 |
__pycache__/
|
| 2 |
*.pyc
|
| 3 |
.venv/
|
| 4 |
+
.gradio/
|
app.py
CHANGED
|
@@ -1,7 +1,136 @@
|
|
| 1 |
import gradio as gr
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2 |
|
| 3 |
-
def
|
| 4 |
-
|
|
|
|
|
|
|
| 5 |
|
| 6 |
-
|
| 7 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
import gradio as gr
|
| 2 |
+
import asyncio
|
| 3 |
+
import plotly.graph_objects as go
|
| 4 |
+
import h3
|
| 5 |
+
from src.trackemdown.core import fetch_geotags
|
| 6 |
|
| 7 |
+
def create_map(results):
|
| 8 |
+
"""Create an interactive map showing the geotag locations and hexagon boundaries"""
|
| 9 |
+
if not results:
|
| 10 |
+
return go.Figure()
|
| 11 |
|
| 12 |
+
lats = [result.latitude for result in results]
|
| 13 |
+
lons = [result.longitude for result in results]
|
| 14 |
+
addresses = [result.address for result in results]
|
| 15 |
+
geotags = [result.geotag for result in results]
|
| 16 |
+
|
| 17 |
+
fig = go.Figure()
|
| 18 |
+
|
| 19 |
+
# Add hexagon boundaries for each geotag
|
| 20 |
+
colors = ['blue', 'green', 'purple', 'orange', 'brown', 'pink', 'gray', 'olive', 'cyan', 'magenta']
|
| 21 |
+
|
| 22 |
+
for i, geotag in enumerate(geotags):
|
| 23 |
+
try:
|
| 24 |
+
# Get hexagon boundary coordinates
|
| 25 |
+
boundary = h3.cell_to_boundary(geotag)
|
| 26 |
+
|
| 27 |
+
# Convert to lat/lon lists (boundary returns (lat, lon) tuples)
|
| 28 |
+
hex_lats = [coord[0] for coord in boundary] + [boundary[0][0]] # Close the polygon
|
| 29 |
+
hex_lons = [coord[1] for coord in boundary] + [boundary[0][1]]
|
| 30 |
+
|
| 31 |
+
# Add hexagon outline
|
| 32 |
+
fig.add_trace(go.Scattermap(
|
| 33 |
+
lat=hex_lats,
|
| 34 |
+
lon=hex_lons,
|
| 35 |
+
mode='lines',
|
| 36 |
+
line=dict(width=2, color=colors[i % len(colors)]),
|
| 37 |
+
name=f"H3 Hexagon {i+1}",
|
| 38 |
+
hovertemplate=f'<b>H3 Geotag: {geotag}</b><extra></extra>',
|
| 39 |
+
showlegend=True
|
| 40 |
+
))
|
| 41 |
+
|
| 42 |
+
except Exception as e:
|
| 43 |
+
print(f"Could not draw hexagon for {geotag}: {e}")
|
| 44 |
+
|
| 45 |
+
# Add location markers
|
| 46 |
+
fig.add_trace(go.Scattermap(
|
| 47 |
+
lat=lats,
|
| 48 |
+
lon=lons,
|
| 49 |
+
mode='markers',
|
| 50 |
+
marker=dict(size=8, color='red'),
|
| 51 |
+
text=[f"{addr}<br>Geotag: {geotag}" for addr, geotag in zip(addresses, geotags)],
|
| 52 |
+
hovertemplate='<b>%{text}</b><extra></extra>',
|
| 53 |
+
name="Locations",
|
| 54 |
+
showlegend=True
|
| 55 |
+
))
|
| 56 |
+
|
| 57 |
+
fig.update_layout(
|
| 58 |
+
map=dict(
|
| 59 |
+
style="open-street-map",
|
| 60 |
+
zoom=2,
|
| 61 |
+
center=dict(lat=lats[0], lon=lons[0]) if lats else dict(lat=0, lon=0)
|
| 62 |
+
),
|
| 63 |
+
height=500,
|
| 64 |
+
margin=dict(l=0, r=0, t=0, b=0),
|
| 65 |
+
legend=dict(x=0.02, y=0.98)
|
| 66 |
+
)
|
| 67 |
+
|
| 68 |
+
return fig
|
| 69 |
+
|
| 70 |
+
async def get_geotags_async(query: str, resolution: int):
|
| 71 |
+
try:
|
| 72 |
+
results = await fetch_geotags(query, resolution)
|
| 73 |
+
|
| 74 |
+
# Format results for table display
|
| 75 |
+
formatted_results = []
|
| 76 |
+
for result in results:
|
| 77 |
+
formatted_results.append([
|
| 78 |
+
result.address,
|
| 79 |
+
f"{result.latitude:.6f}",
|
| 80 |
+
f"{result.longitude:.6f}",
|
| 81 |
+
result.geotag
|
| 82 |
+
])
|
| 83 |
+
|
| 84 |
+
# Create map
|
| 85 |
+
map_fig = create_map(results)
|
| 86 |
+
|
| 87 |
+
return formatted_results, map_fig, gr.update(visible=False)
|
| 88 |
+
|
| 89 |
+
except Exception as e:
|
| 90 |
+
empty_fig = go.Figure()
|
| 91 |
+
empty_fig.update_layout(height=400, margin=dict(l=0, r=0, t=0, b=0))
|
| 92 |
+
return [], empty_fig, gr.update(value=f"Error: {str(e)}", visible=True)
|
| 93 |
+
|
| 94 |
+
def get_geotags(query: str, resolution: int):
|
| 95 |
+
loop = asyncio.new_event_loop()
|
| 96 |
+
asyncio.set_event_loop(loop)
|
| 97 |
+
try:
|
| 98 |
+
return loop.run_until_complete(get_geotags_async(query, resolution))
|
| 99 |
+
finally:
|
| 100 |
+
loop.close()
|
| 101 |
+
|
| 102 |
+
# H3 Resolution levels:
|
| 103 |
+
# 0: ~4,250 km hexagons (continent scale)
|
| 104 |
+
# 5: ~252 km hexagons (large city scale)
|
| 105 |
+
# 9: ~0.1 km hexagons (neighborhood scale)
|
| 106 |
+
# 12: ~0.01 km hexagons (building scale)
|
| 107 |
+
# 15: ~0.0005 km hexagons (room scale) - highest resolution
|
| 108 |
+
|
| 109 |
+
with gr.Blocks() as demo:
|
| 110 |
+
gr.Markdown("# TrackEmDown")
|
| 111 |
+
|
| 112 |
+
with gr.Row():
|
| 113 |
+
query_input = gr.Textbox(label="Address or Coordinates")
|
| 114 |
+
resolution_input = gr.Number(label="H3 Resolution", value=15, minimum=0, maximum=15)
|
| 115 |
+
|
| 116 |
+
search_btn = gr.Button("Generate Geotags")
|
| 117 |
+
|
| 118 |
+
results_table = gr.Dataframe(
|
| 119 |
+
headers=["Address", "Latitude", "Longitude", "H3 Geotag"],
|
| 120 |
+
datatype=["str", "str", "str", "str"],
|
| 121 |
+
interactive=False,
|
| 122 |
+
wrap=True
|
| 123 |
+
)
|
| 124 |
+
|
| 125 |
+
map_plot = gr.Plot(label="Map View")
|
| 126 |
+
|
| 127 |
+
error_output = gr.Textbox(label="Error", lines=3, interactive=False, visible=False)
|
| 128 |
+
|
| 129 |
+
search_btn.click(
|
| 130 |
+
fn=get_geotags,
|
| 131 |
+
inputs=[query_input, resolution_input],
|
| 132 |
+
outputs=[results_table, map_plot, error_output]
|
| 133 |
+
)
|
| 134 |
+
|
| 135 |
+
if __name__ == "__main__":
|
| 136 |
+
demo.launch(share=True)
|
pyproject.toml
CHANGED
|
@@ -9,7 +9,9 @@ dependencies = [
|
|
| 9 |
"uvicorn[standard]>=0.24.0",
|
| 10 |
"h3>=3.7.6",
|
| 11 |
"httpx>=0.25.2",
|
| 12 |
-
"pydantic>=2.5.0"
|
|
|
|
|
|
|
| 13 |
]
|
| 14 |
|
| 15 |
[build-system]
|
|
|
|
| 9 |
"uvicorn[standard]>=0.24.0",
|
| 10 |
"h3>=3.7.6",
|
| 11 |
"httpx>=0.25.2",
|
| 12 |
+
"pydantic>=2.5.0",
|
| 13 |
+
"gradio>=4.0.0",
|
| 14 |
+
"plotly>=5.0.0"
|
| 15 |
]
|
| 16 |
|
| 17 |
[build-system]
|