CineAI commited on
Commit
8f12571
·
verified ·
1 Parent(s): 15b4974

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +25 -49
app.py CHANGED
@@ -3,7 +3,6 @@ import os
3
  import subprocess
4
  import pandas as pd
5
  from PIL import Image
6
- import io
7
  import folium
8
 
9
  # --- Setup: Clone the repository for helper classes ---
@@ -13,7 +12,7 @@ if not os.path.exists(REPO_DIR):
13
  try:
14
  print(f"Cloning repository into ./{REPO_DIR}...")
15
  subprocess.run(
16
- ["git", "clone", "https://github.com/ioscbasotcstw/TheAmateur.git"],
17
  check=True,
18
  capture_output=True,
19
  text=True
@@ -21,15 +20,13 @@ if not os.path.exists(REPO_DIR):
21
  print("Repository cloned successfully.")
22
  except subprocess.CalledProcessError as e:
23
  print(f"Error cloning repository: {e.stderr}")
24
- # Exit if cloning fails, as the app cannot run without it.
25
- exit()
26
 
27
  # Now that the repo is cloned, we can import the necessary modules
28
  try:
29
  from TheAmateur.src.rainbolt_parody import RainboltParody
30
  from TheAmateur.src.map_gen import MapGenerator
31
  from TheAmateur.src.geo_info import GeoInfo
32
- from TheAmateur.src.utils import prepare_csv as original_prepare_csv
33
  except ImportError as e:
34
  print(f"Failed to import from the cloned repository: {e}")
35
  exit()
@@ -45,14 +42,10 @@ You will follow a strict, three-stage analytical process.
45
 
46
  ## STAGE 1: OBSERVATION & CLUE EXTRACTION
47
  Internally, create a structured list of all visual evidence. Do not output this list.
48
- - **Road & Infrastructure:**
49
- - Road Lines, Bollards, Poles, Signage (Language, Script, Style)
50
- - **Environment & Nature:**
51
- - Sun Position & Climate, Vegetation & Trees, Soil & Topography
52
- - **Human & Cultural Markers:**
53
- - Architecture Style, Vehicle Models & License Plates
54
- - **Meta Clues:**
55
- - Google Car Generation/Antenna, Image Quality/Season
56
 
57
  ## STAGE 2: DEDUCTION & SYNTHESIS
58
  Internally, reason through the clues from Stage 1.
@@ -88,7 +81,8 @@ def handle_error(message, e=None):
88
 
89
  def pinpoint_location(api_key, uploaded_image):
90
  """
91
- Takes an API key and an uploaded image, returns location data and a map.
 
92
  """
93
  if not api_key:
94
  handle_error("Google AI API Key is required.")
@@ -97,11 +91,14 @@ def pinpoint_location(api_key, uploaded_image):
97
 
98
  try:
99
  rp = RainboltParody(title="Location Analysis", api_key=api_key)
100
- # The 'get_info' method in the original code expects a PIL image
101
  response, _, _ = rp.get_info(SYSTEM_PROMPT=SYSTEM_PROMPT, img=uploaded_image)
102
 
103
  # Prepare outputs for Gradio
104
- info_df = pd.DataFrame([response])
 
 
 
105
  reasoning = response.get('reasoning', 'No reasoning provided.')
106
  coords_str = response.get('coordinates', '0,0')
107
  lat, lon = map(float, coords_str.split(','))
@@ -128,13 +125,11 @@ def calculate_error_distance(prediction_state, url, manual_coords_str):
128
  handle_error("Please provide either a Google Maps URL or manual coordinates for the actual location.")
129
 
130
  try:
131
- # Determine the source of the actual coordinates
132
  if url:
133
  gi = GeoInfo(response=prediction_state, url=url)
134
  else:
135
  gi = GeoInfo(response=prediction_state, coordinates=manual_coords_str)
136
 
137
- # Calculate error and bearing
138
  error_km, lat_actual, lon_actual, _, _ = gi.calculate_error()
139
  bearing = gi.calculate_bearing()
140
  direction = gi.get_direction(angle=bearing)
@@ -142,7 +137,6 @@ def calculate_error_distance(prediction_state, url, manual_coords_str):
142
  info_text = gi.combine_info(error=error_km, direction=direction)
143
  actual_coords = f"{lat_actual},{lon_actual}"
144
 
145
- # Generate map with both points and a line
146
  mgk = MapGenerator()
147
  map_with_line = mgk.get_map(
148
  location1=prediction_state['coordinates'],
@@ -151,7 +145,6 @@ def calculate_error_distance(prediction_state, url, manual_coords_str):
151
  direction=direction
152
  )
153
 
154
- # Convert folium map to HTML for display in Gradio
155
  map_html = map_with_line._repr_html_()
156
 
157
  return info_text, gr.HTML(value=map_html, visible=True), error_km, direction, url if url else ""
@@ -162,7 +155,8 @@ def calculate_error_distance(prediction_state, url, manual_coords_str):
162
 
163
  def save_and_download(prediction_state, error_km, direction, original_url, filename):
164
  """
165
- Saves the combined results to a CSV file and provides a download link.
 
166
  """
167
  if not prediction_state:
168
  handle_error("No prediction data to save.")
@@ -172,34 +166,30 @@ def save_and_download(prediction_state, error_km, direction, original_url, filen
172
  filename += '.csv'
173
 
174
  try:
175
- # Re-using the logic from the original notebook's prepare_csv
176
- # but adapting it for Gradio by removing the colab-specific download part.
177
-
178
- file_exists = os.path.exists(filename)
179
-
180
  data_to_add = prediction_state.copy()
181
- data_to_add['error'] = error_km if error_km is not None else 'N/A'
182
  data_to_add['direction'] = direction if direction else 'N/A'
183
  data_to_add['actual_location_url'] = original_url if original_url else 'N/A'
184
-
185
  new_df = pd.DataFrame([data_to_add])
186
 
187
- if file_exists:
 
188
  existing_df = pd.read_csv(filename)
189
  final_df = pd.concat([existing_df, new_df], ignore_index=True)
190
  else:
191
  final_df = new_df
192
 
 
193
  final_df.to_csv(filename, index=False)
194
 
195
  # Return the updated DataFrame for display and the file path for download
196
- return gr.DataFrame(value=final_df, visible=True), gr.File(value=filename, visible=True)
197
 
198
  except Exception as e:
199
  handle_error("Failed to save data to CSV", e)
200
 
201
  # --- Gradio UI ---
202
-
203
  with gr.Blocks(theme=gr.themes.Soft(), title="GeoGuessr AI") as app:
204
  gr.Markdown("# GeoGuessr AI 🔎")
205
  gr.Markdown("Pinpoint the location of any Google Street View image.")
@@ -212,27 +202,18 @@ with gr.Blocks(theme=gr.themes.Soft(), title="GeoGuessr AI") as app:
212
 
213
  with gr.Row():
214
  with gr.Column(scale=1):
215
- # --- STEP 1: Input and Prediction ---
216
  gr.Markdown("## 1. Pinpoint Location")
217
- api_key_input = gr.Textbox(
218
- label="Google AI API Key",
219
- placeholder="Enter your API key here...",
220
- type="password",
221
- interactive=True
222
- )
223
  image_input = gr.Image(type="pil", label="Upload Street View Image")
224
  pinpoint_btn = gr.Button("Pinpoint Location", variant="primary")
225
-
226
- # --- STEP 2: Prediction Output ---
227
  gr.Markdown("### Prediction Results")
228
  info_output_df = gr.DataFrame(label="Location Information", headers=["Attribute", "Value"])
229
  reasoning_output = gr.Textbox(label="AI Reasoning", lines=5, interactive=False)
230
 
231
  with gr.Column(scale=2):
232
- # --- Map Display ---
233
  gr.Markdown("### Map View")
234
  map_output_single = gr.Map(label="Predicted Location", interactive=False)
235
- # This HTML component will be used for the two-point map later
236
  map_output_comparison = gr.HTML(visible=False)
237
 
238
  with gr.Accordion("2. Calculate Error (Optional)", open=False, visible=False) as error_accordion:
@@ -250,29 +231,24 @@ with gr.Blocks(theme=gr.themes.Soft(), title="GeoGuessr AI") as app:
250
  download_file = gr.File(label="Download CSV", visible=False)
251
 
252
  # --- Event Handlers ---
253
-
254
- # Pinpoint button click event
255
  pinpoint_btn.click(
256
  fn=pinpoint_location,
257
  inputs=[api_key_input, image_input],
258
  outputs=[info_output_df, reasoning_output, map_output_single, prediction_state, error_accordion, save_accordion]
259
  )
260
-
261
- # Calculate distance button click event
262
  calculate_btn.click(
263
  fn=calculate_error_distance,
264
  inputs=[prediction_state, url_input, manual_coords_input],
265
  outputs=[distance_output, map_output_comparison, error_state, direction_state, url_state]
266
  )
267
-
268
- # Save to CSV button click event
269
  save_btn.click(
270
  fn=save_and_download,
271
  inputs=[prediction_state, error_state, direction_state, url_state, filename_input],
272
  outputs=[csv_preview_df, download_file]
273
  )
274
 
275
- # # --- Example Images ---
276
  # gr.Examples(
277
  # examples=[
278
  # [os.path.join(REPO_DIR, "examples/example_1.png")],
 
3
  import subprocess
4
  import pandas as pd
5
  from PIL import Image
 
6
  import folium
7
 
8
  # --- Setup: Clone the repository for helper classes ---
 
12
  try:
13
  print(f"Cloning repository into ./{REPO_DIR}...")
14
  subprocess.run(
15
+ ["git", "clone", "https://github.com/OrlovVladislav/TheAmateur.git"],
16
  check=True,
17
  capture_output=True,
18
  text=True
 
20
  print("Repository cloned successfully.")
21
  except subprocess.CalledProcessError as e:
22
  print(f"Error cloning repository: {e.stderr}")
23
+ exit() # Exit if cloning fails, as the app cannot run without it.
 
24
 
25
  # Now that the repo is cloned, we can import the necessary modules
26
  try:
27
  from TheAmateur.src.rainbolt_parody import RainboltParody
28
  from TheAmateur.src.map_gen import MapGenerator
29
  from TheAmateur.src.geo_info import GeoInfo
 
30
  except ImportError as e:
31
  print(f"Failed to import from the cloned repository: {e}")
32
  exit()
 
42
 
43
  ## STAGE 1: OBSERVATION & CLUE EXTRACTION
44
  Internally, create a structured list of all visual evidence. Do not output this list.
45
+ - **Road & Infrastructure:** Road Lines, Bollards, Poles, Signage (Language, Script, Style)
46
+ - **Environment & Nature:** Sun Position & Climate, Vegetation & Trees, Soil & Topography
47
+ - **Human & Cultural Markers:** Architecture Style, Vehicle Models & License Plates
48
+ - **Meta Clues:** Google Car Generation/Antenna, Image Quality/Season
 
 
 
 
49
 
50
  ## STAGE 2: DEDUCTION & SYNTHESIS
51
  Internally, reason through the clues from Stage 1.
 
81
 
82
  def pinpoint_location(api_key, uploaded_image):
83
  """
84
+ Takes an API key and an uploaded image, returns location data.
85
+ The `gr.Image(type="pil")` component handles the upload, replacing the need for a custom upload function.
86
  """
87
  if not api_key:
88
  handle_error("Google AI API Key is required.")
 
91
 
92
  try:
93
  rp = RainboltParody(title="Location Analysis", api_key=api_key)
94
+ # 'uploaded_image' is already a PIL Image object, thanks to `type="pil"`.
95
  response, _, _ = rp.get_info(SYSTEM_PROMPT=SYSTEM_PROMPT, img=uploaded_image)
96
 
97
  # Prepare outputs for Gradio
98
+ # Convert the dictionary to a list of lists for the DataFrame
99
+ info_data = [[key, value] for key, value in response.items()]
100
+ info_df = pd.DataFrame(info_data, columns=["Attribute", "Value"])
101
+
102
  reasoning = response.get('reasoning', 'No reasoning provided.')
103
  coords_str = response.get('coordinates', '0,0')
104
  lat, lon = map(float, coords_str.split(','))
 
125
  handle_error("Please provide either a Google Maps URL or manual coordinates for the actual location.")
126
 
127
  try:
 
128
  if url:
129
  gi = GeoInfo(response=prediction_state, url=url)
130
  else:
131
  gi = GeoInfo(response=prediction_state, coordinates=manual_coords_str)
132
 
 
133
  error_km, lat_actual, lon_actual, _, _ = gi.calculate_error()
134
  bearing = gi.calculate_bearing()
135
  direction = gi.get_direction(angle=bearing)
 
137
  info_text = gi.combine_info(error=error_km, direction=direction)
138
  actual_coords = f"{lat_actual},{lon_actual}"
139
 
 
140
  mgk = MapGenerator()
141
  map_with_line = mgk.get_map(
142
  location1=prediction_state['coordinates'],
 
145
  direction=direction
146
  )
147
 
 
148
  map_html = map_with_line._repr_html_()
149
 
150
  return info_text, gr.HTML(value=map_html, visible=True), error_km, direction, url if url else ""
 
155
 
156
  def save_and_download(prediction_state, error_km, direction, original_url, filename):
157
  """
158
+ Saves the combined results to a CSV file and provides it for download.
159
+ This function replaces the Colab-specific `prepare_csv`.
160
  """
161
  if not prediction_state:
162
  handle_error("No prediction data to save.")
 
166
  filename += '.csv'
167
 
168
  try:
169
+ # Prepare the new row of data
 
 
 
 
170
  data_to_add = prediction_state.copy()
171
+ data_to_add['error'] = f"{error_km:.2f}" if error_km is not None else 'N/A'
172
  data_to_add['direction'] = direction if direction else 'N/A'
173
  data_to_add['actual_location_url'] = original_url if original_url else 'N/A'
 
174
  new_df = pd.DataFrame([data_to_add])
175
 
176
+ # Check if file exists to append or create new
177
+ if os.path.exists(filename):
178
  existing_df = pd.read_csv(filename)
179
  final_df = pd.concat([existing_df, new_df], ignore_index=True)
180
  else:
181
  final_df = new_df
182
 
183
+ # Save the final dataframe to the CSV file
184
  final_df.to_csv(filename, index=False)
185
 
186
  # Return the updated DataFrame for display and the file path for download
187
+ return gr.DataFrame(value=final_df, visible=True), gr.File(value=filename, label="Download CSV", visible=True)
188
 
189
  except Exception as e:
190
  handle_error("Failed to save data to CSV", e)
191
 
192
  # --- Gradio UI ---
 
193
  with gr.Blocks(theme=gr.themes.Soft(), title="GeoGuessr AI") as app:
194
  gr.Markdown("# GeoGuessr AI 🔎")
195
  gr.Markdown("Pinpoint the location of any Google Street View image.")
 
202
 
203
  with gr.Row():
204
  with gr.Column(scale=1):
 
205
  gr.Markdown("## 1. Pinpoint Location")
206
+ api_key_input = gr.Textbox(label="Google AI API Key", placeholder="Enter your API key here...", type="password")
 
 
 
 
 
207
  image_input = gr.Image(type="pil", label="Upload Street View Image")
208
  pinpoint_btn = gr.Button("Pinpoint Location", variant="primary")
209
+
 
210
  gr.Markdown("### Prediction Results")
211
  info_output_df = gr.DataFrame(label="Location Information", headers=["Attribute", "Value"])
212
  reasoning_output = gr.Textbox(label="AI Reasoning", lines=5, interactive=False)
213
 
214
  with gr.Column(scale=2):
 
215
  gr.Markdown("### Map View")
216
  map_output_single = gr.Map(label="Predicted Location", interactive=False)
 
217
  map_output_comparison = gr.HTML(visible=False)
218
 
219
  with gr.Accordion("2. Calculate Error (Optional)", open=False, visible=False) as error_accordion:
 
231
  download_file = gr.File(label="Download CSV", visible=False)
232
 
233
  # --- Event Handlers ---
 
 
234
  pinpoint_btn.click(
235
  fn=pinpoint_location,
236
  inputs=[api_key_input, image_input],
237
  outputs=[info_output_df, reasoning_output, map_output_single, prediction_state, error_accordion, save_accordion]
238
  )
239
+
 
240
  calculate_btn.click(
241
  fn=calculate_error_distance,
242
  inputs=[prediction_state, url_input, manual_coords_input],
243
  outputs=[distance_output, map_output_comparison, error_state, direction_state, url_state]
244
  )
245
+
 
246
  save_btn.click(
247
  fn=save_and_download,
248
  inputs=[prediction_state, error_state, direction_state, url_state, filename_input],
249
  outputs=[csv_preview_df, download_file]
250
  )
251
 
 
252
  # gr.Examples(
253
  # examples=[
254
  # [os.path.join(REPO_DIR, "examples/example_1.png")],