Spaces:
Running
on
Zero
Running
on
Zero
Update app.py
Browse files
app.py
CHANGED
@@ -347,124 +347,84 @@ def extract_info(template, text):
|
|
347 |
print(f"Error in extract_info: {e}\n{trace}")
|
348 |
return f"❌ Fehler: {str(e)}", "{}"
|
349 |
@spaces.GPU
|
350 |
-
|
351 |
-
|
352 |
-
#
|
353 |
-
|
354 |
-
|
355 |
-
|
356 |
-
|
357 |
-
|
358 |
-
|
359 |
-
|
360 |
-
|
361 |
|
362 |
-
|
363 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
364 |
|
365 |
-
# Initialize geocoder and tracking variables
|
366 |
geocoder = SafeGeocoder()
|
|
|
|
|
367 |
processed_count = 0
|
368 |
-
all_lats = []
|
369 |
-
all_lons = []
|
370 |
-
hover_texts = []
|
371 |
|
372 |
-
|
|
|
|
|
373 |
for idx, row in df.iterrows():
|
374 |
if pd.isna(row[location_col]):
|
375 |
continue
|
376 |
|
377 |
location = str(row[location_col]).strip()
|
378 |
|
379 |
-
#
|
|
|
|
|
|
|
380 |
additional_info = ""
|
381 |
for col in df.columns:
|
382 |
if col != location_col and not pd.isna(row[col]):
|
383 |
additional_info += f"<br><b>{col}:</b> {row[col]}"
|
384 |
|
385 |
-
# Split location if it contains multiple comma-separated places
|
386 |
try:
|
387 |
locations = [loc.strip() for loc in location.split(',') if loc.strip()]
|
388 |
if not locations:
|
389 |
locations = [location]
|
390 |
except Exception as e:
|
391 |
-
|
|
|
392 |
locations = [location]
|
|
|
|
|
|
|
|
|
393 |
|
394 |
-
# Process each individual location
|
395 |
for loc in locations:
|
396 |
try:
|
397 |
-
#
|
|
|
|
|
|
|
398 |
point = geocoder.get_coords(loc)
|
399 |
|
400 |
-
if point:
|
401 |
-
lat, lon = point
|
402 |
-
all_lats.append(lat)
|
403 |
-
all_lons.append(lon)
|
404 |
-
|
405 |
-
# Create hover text with location name and info
|
406 |
-
hover_text = f"<b>{loc}</b>{additional_info}"
|
407 |
-
hover_texts.append(hover_text)
|
408 |
|
409 |
-
processed_count += 1
|
410 |
except Exception as e:
|
411 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
412 |
|
413 |
-
# Create Plotly map
|
414 |
-
if len(all_lats) > 0:
|
415 |
-
fig = go.Figure()
|
416 |
-
|
417 |
-
# Add scatter mapbox points
|
418 |
-
fig.add_trace(go.Scattermapbox(
|
419 |
-
lat=all_lats,
|
420 |
-
lon=all_lons,
|
421 |
-
mode='markers',
|
422 |
-
marker=go.scattermapbox.Marker(
|
423 |
-
size=10,
|
424 |
-
color='blue'
|
425 |
-
),
|
426 |
-
text=hover_texts,
|
427 |
-
hoverinfo="text"
|
428 |
-
))
|
429 |
-
|
430 |
-
# Configure map layout
|
431 |
-
fig.update_layout(
|
432 |
-
mapbox_style="open-street-map",
|
433 |
-
mapbox=dict(
|
434 |
-
center={"lat": sum(all_lats)/len(all_lats) if all_lats else 20,
|
435 |
-
"lon": sum(all_lons)/len(all_lons) if all_lons else 0},
|
436 |
-
zoom=3
|
437 |
-
),
|
438 |
-
margin={"r":0,"t":0,"l":0,"b":0},
|
439 |
-
height=600
|
440 |
-
)
|
441 |
-
|
442 |
-
return fig, processed_count
|
443 |
-
else:
|
444 |
-
# Create empty figure if no coordinates found
|
445 |
-
fig = go.Figure()
|
446 |
-
fig.update_layout(
|
447 |
-
mapbox_style="open-street-map",
|
448 |
-
mapbox=dict(
|
449 |
-
center={"lat": 20, "lon": 0},
|
450 |
-
zoom=2
|
451 |
-
),
|
452 |
-
margin={"r":0,"t":0,"l":0,"b":0},
|
453 |
-
height=600,
|
454 |
-
annotations=[
|
455 |
-
dict(
|
456 |
-
text="No locations found to display",
|
457 |
-
showarrow=False,
|
458 |
-
xref="paper",
|
459 |
-
yref="paper",
|
460 |
-
x=0.5,
|
461 |
-
y=0.5
|
462 |
-
)
|
463 |
-
]
|
464 |
-
)
|
465 |
-
return fig, 0
|
466 |
-
|
467 |
-
|
468 |
# Custom CSS for map
|
469 |
custom_css = """
|
470 |
<style>
|
@@ -588,30 +548,62 @@ h2 {
|
|
588 |
|
589 |
with gr.Blocks(css=custom_css, title="Daten Strukturieren und Analysieren") as demo:
|
590 |
gr.HTML("""
|
591 |
-
<div style="
|
592 |
-
|
593 |
-
|
594 |
-
|
595 |
-
|
|
|
|
|
|
|
|
|
596 |
|
597 |
<ol style="padding-left: 20px; margin-bottom: 0;">
|
598 |
-
<li style="margin-bottom:
|
599 |
-
<strong>Textanalyse-Tool:</strong> Findet automatisch wichtige Informationen in alten Zeitungsartikeln, wie Erdbeben-Orte oder Berichterstattungsstädte.
|
600 |
</li>
|
601 |
|
602 |
-
<li style="margin-bottom:
|
603 |
-
<strong>Fragemethode:</strong> Verwandelt leere Felder in Fragen (z.B. "Wo war das Erdbeben?") und findet Antworten im Text.
|
604 |
</li>
|
605 |
|
606 |
-
<li style="margin-bottom:
|
607 |
-
<strong>Kartenvisualisierung:</strong> Zeigt gefundene Orte automatisch auf interaktiven Karten an.
|
608 |
</li>
|
609 |
|
610 |
-
<li style="margin-bottom: 0; font-size: 1.1rem;">
|
611 |
-
<strong>Forschungshilfe:</strong> Organisiert historische Daten zu strukturierten, leicht analysierbaren Informationen.
|
612 |
</li>
|
613 |
</ol>
|
614 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
615 |
</div>
|
616 |
<div style="font-family: 'Source Sans Pro', sans-serif; max-width: 1000px; margin: 0 auto; color: #333; line-height: 1.7; font-size: 1.15rem;">
|
617 |
<p style="font-size: 1.3rem; margin-bottom: 1.8rem; color: #2c3e50; font-weight: 400; padding: 0 1rem;">
|
@@ -805,124 +797,6 @@ Die Katastrophe in <span style="background-color: #a8e6cf; font-weight: bold; pa
|
|
805 |
""")
|
806 |
|
807 |
|
808 |
-
# Instead of using folium directly with Gradio's HTML component,
|
809 |
-
# try this alternative approach using Plotly for maps
|
810 |
-
|
811 |
-
def create_map_plotly(df, location_col):
|
812 |
-
"""
|
813 |
-
Creates an interactive map using Plotly instead of Folium
|
814 |
-
which should be more stable in Gradio applications
|
815 |
-
"""
|
816 |
-
import plotly.graph_objects as go
|
817 |
-
import pandas as pd
|
818 |
-
|
819 |
-
# Track processing for debugging
|
820 |
-
print(f"Processing {len(df)} rows with location column: {location_col}")
|
821 |
-
|
822 |
-
# Initialize geocoder and tracking variables
|
823 |
-
geocoder = SafeGeocoder()
|
824 |
-
processed_count = 0
|
825 |
-
all_lats = []
|
826 |
-
all_lons = []
|
827 |
-
hover_texts = []
|
828 |
-
|
829 |
-
# Process each row
|
830 |
-
for idx, row in df.iterrows():
|
831 |
-
if pd.isna(row[location_col]):
|
832 |
-
continue
|
833 |
-
|
834 |
-
location = str(row[location_col]).strip()
|
835 |
-
|
836 |
-
# Build additional info for hover text
|
837 |
-
additional_info = ""
|
838 |
-
for col in df.columns:
|
839 |
-
if col != location_col and not pd.isna(row[col]):
|
840 |
-
additional_info += f"<br><b>{col}:</b> {row[col]}"
|
841 |
-
|
842 |
-
# Split location if it contains multiple comma-separated places
|
843 |
-
try:
|
844 |
-
locations = [loc.strip() for loc in location.split(',') if loc.strip()]
|
845 |
-
if not locations:
|
846 |
-
locations = [location]
|
847 |
-
except Exception as e:
|
848 |
-
print(f"Error splitting location '{location}': {str(e)}")
|
849 |
-
locations = [location]
|
850 |
-
|
851 |
-
# Process each individual location
|
852 |
-
for loc in locations:
|
853 |
-
try:
|
854 |
-
# Get coordinates
|
855 |
-
point = geocoder.get_coords(loc)
|
856 |
-
|
857 |
-
if point:
|
858 |
-
lat, lon = point
|
859 |
-
all_lats.append(lat)
|
860 |
-
all_lons.append(lon)
|
861 |
-
|
862 |
-
# Create hover text with location name and info
|
863 |
-
hover_text = f"<b>{loc}</b>{additional_info}"
|
864 |
-
hover_texts.append(hover_text)
|
865 |
-
|
866 |
-
processed_count += 1
|
867 |
-
except Exception as e:
|
868 |
-
print(f"Error processing location {loc}: {str(e)}")
|
869 |
-
|
870 |
-
# Create Plotly map
|
871 |
-
if len(all_lats) > 0:
|
872 |
-
fig = go.Figure()
|
873 |
-
|
874 |
-
# Add scatter mapbox points
|
875 |
-
fig.add_trace(go.Scattermapbox(
|
876 |
-
lat=all_lats,
|
877 |
-
lon=all_lons,
|
878 |
-
mode='markers',
|
879 |
-
marker=go.scattermapbox.Marker(
|
880 |
-
size=10,
|
881 |
-
color='blue'
|
882 |
-
),
|
883 |
-
text=hover_texts,
|
884 |
-
hoverinfo="text"
|
885 |
-
))
|
886 |
-
|
887 |
-
# Configure map layout
|
888 |
-
fig.update_layout(
|
889 |
-
mapbox_style="open-street-map",
|
890 |
-
mapbox=dict(
|
891 |
-
center={"lat": sum(all_lats)/len(all_lats) if all_lats else 20,
|
892 |
-
"lon": sum(all_lons)/len(all_lons) if all_lons else 0},
|
893 |
-
zoom=3
|
894 |
-
),
|
895 |
-
margin={"r":0,"t":0,"l":0,"b":0},
|
896 |
-
height=600
|
897 |
-
)
|
898 |
-
|
899 |
-
return fig, processed_count
|
900 |
-
else:
|
901 |
-
# Create empty figure if no coordinates found
|
902 |
-
fig = go.Figure()
|
903 |
-
fig.update_layout(
|
904 |
-
mapbox_style="open-street-map",
|
905 |
-
mapbox=dict(
|
906 |
-
center={"lat": 20, "lon": 0},
|
907 |
-
zoom=2
|
908 |
-
),
|
909 |
-
margin={"r":0,"t":0,"l":0,"b":0},
|
910 |
-
height=600,
|
911 |
-
annotations=[
|
912 |
-
dict(
|
913 |
-
text="No locations found to display",
|
914 |
-
showarrow=False,
|
915 |
-
xref="paper",
|
916 |
-
yref="paper",
|
917 |
-
x=0.5,
|
918 |
-
y=0.5
|
919 |
-
)
|
920 |
-
]
|
921 |
-
)
|
922 |
-
return fig, 0
|
923 |
-
|
924 |
-
# To use this in your Gradio app, modify your code to use gr.Plot instead of gr.HTML:
|
925 |
-
|
926 |
with gr.TabItem("📍 Visualisierung von strukturierten Daten"):
|
927 |
gr.HTML("""
|
928 |
<div class="info-box">
|
@@ -956,39 +830,37 @@ def create_map_plotly(df, location_col):
|
|
956 |
)
|
957 |
|
958 |
with gr.Column():
|
959 |
-
|
960 |
-
|
961 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
962 |
)
|
|
|
963 |
|
964 |
-
# Modify your process_and_map function to use the new create_map_plotly function
|
965 |
def process_and_map(file, column):
|
966 |
if file is None:
|
967 |
return None, "Hier bitte die Excel-Tabelle hochladen", None
|
968 |
|
969 |
try:
|
970 |
-
|
971 |
-
if hasattr(file, 'name'):
|
972 |
-
df = pd.read_excel(file.name)
|
973 |
-
elif isinstance(file, bytes):
|
974 |
-
df = pd.read_excel(io.BytesIO(file))
|
975 |
-
else:
|
976 |
-
df = pd.read_excel(file)
|
977 |
-
|
978 |
-
if column not in df.columns:
|
979 |
-
return None, f"Spalte '{column}' wurde in der Excel-Datei nicht gefunden.", None
|
980 |
-
|
981 |
-
# Create map using Plotly
|
982 |
-
fig, processed_count = create_map_plotly(df, column)
|
983 |
|
984 |
-
|
985 |
-
|
986 |
-
|
987 |
-
|
988 |
-
|
989 |
-
|
990 |
-
|
991 |
-
|
|
|
992 |
except Exception as e:
|
993 |
import traceback
|
994 |
trace = traceback.format_exc()
|
@@ -1000,7 +872,6 @@ def create_map_plotly(df, location_col):
|
|
1000 |
inputs=[excel_file, places_column],
|
1001 |
outputs=[map_output, stats_output, processed_file]
|
1002 |
)
|
1003 |
-
"""
|
1004 |
|
1005 |
gr.HTML("""
|
1006 |
<div style="text-align: center; margin-top: 2rem; padding-top: 1rem; border-top: 1px solid #eee; font-size: 0.9rem; color: #666;">
|
|
|
347 |
print(f"Error in extract_info: {e}\n{trace}")
|
348 |
return f"❌ Fehler: {str(e)}", "{}"
|
349 |
@spaces.GPU
|
350 |
+
@spaces.GPU
|
351 |
+
def create_map(df, location_col):
|
352 |
+
# Start a simple log to track execution
|
353 |
+
with open("map_debug.log", "w") as log:
|
354 |
+
log.write(f"Starting map creation at {time.strftime('%Y-%m-%d %H:%M:%S')}\n")
|
355 |
+
|
356 |
+
m = folium.Map(
|
357 |
+
location=[20, 0],
|
358 |
+
zoom_start=2,
|
359 |
+
control_scale=True
|
360 |
+
)
|
361 |
|
362 |
+
folium.TileLayer(
|
363 |
+
tiles=MAP_TILES["GreenMap"]["url"],
|
364 |
+
attr=MAP_TILES["GreenMap"]["attr"],
|
365 |
+
name="GreenMap",
|
366 |
+
overlay=False,
|
367 |
+
control=False
|
368 |
+
).add_to(m)
|
369 |
+
|
370 |
+
Fullscreen().add_to(m)
|
371 |
+
MeasureControl(position='topright', primary_length_unit='kilometers').add_to(m)
|
372 |
|
|
|
373 |
geocoder = SafeGeocoder()
|
374 |
+
coords = []
|
375 |
+
marker_cluster = MarkerCluster(name="Locations").add_to(m)
|
376 |
processed_count = 0
|
|
|
|
|
|
|
377 |
|
378 |
+
with open("map_debug.log", "a") as log:
|
379 |
+
log.write(f"Processing {len(df)} rows from dataframe\n")
|
380 |
+
|
381 |
for idx, row in df.iterrows():
|
382 |
if pd.isna(row[location_col]):
|
383 |
continue
|
384 |
|
385 |
location = str(row[location_col]).strip()
|
386 |
|
387 |
+
# Log the location being processed
|
388 |
+
with open("map_debug.log", "a") as log:
|
389 |
+
log.write(f"Processing location: {location}\n")
|
390 |
+
|
391 |
additional_info = ""
|
392 |
for col in df.columns:
|
393 |
if col != location_col and not pd.isna(row[col]):
|
394 |
additional_info += f"<br><b>{col}:</b> {row[col]}"
|
395 |
|
|
|
396 |
try:
|
397 |
locations = [loc.strip() for loc in location.split(',') if loc.strip()]
|
398 |
if not locations:
|
399 |
locations = [location]
|
400 |
except Exception as e:
|
401 |
+
with open("map_debug.log", "a") as log:
|
402 |
+
log.write(f"Error splitting location '{location}': {str(e)}\n")
|
403 |
locations = [location]
|
404 |
+
|
405 |
+
# Log the parsed locations
|
406 |
+
with open("map_debug.log", "a") as log:
|
407 |
+
log.write(f"Split into locations: {locations}\n")
|
408 |
|
|
|
409 |
for loc in locations:
|
410 |
try:
|
411 |
+
# Log the current location
|
412 |
+
with open("map_debug.log", "a") as log:
|
413 |
+
log.write(f"Getting coordinates for: {loc}\n")
|
414 |
+
|
415 |
point = geocoder.get_coords(loc)
|
416 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
417 |
|
|
|
418 |
except Exception as e:
|
419 |
+
# Log any errors in processing this location
|
420 |
+
with open("map_debug.log", "a") as log:
|
421 |
+
log.write(f"Error processing {loc}: {str(e)}\n")
|
422 |
+
log.write(traceback.format_exc() + "\n")
|
423 |
+
|
424 |
+
# Fit map bounds if we have coordinates
|
425 |
+
if coords:
|
426 |
+
m.fit_bounds(coords)
|
427 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
428 |
# Custom CSS for map
|
429 |
custom_css = """
|
430 |
<style>
|
|
|
548 |
|
549 |
with gr.Blocks(css=custom_css, title="Daten Strukturieren und Analysieren") as demo:
|
550 |
gr.HTML("""
|
551 |
+
<div style="font-family: 'Source Sans Pro', sans-serif; max-width: 1000px; margin: 0 auto; color: #333;">
|
552 |
+
<!-- Header Section with Improved Styling -->
|
553 |
+
<div style="text-align: center; margin-bottom: 2rem; background: linear-gradient(135deg, #2c6bb3 0%, #4e8fd1 100%); padding: 2rem; border-radius: 10px; color: white;">
|
554 |
+
<h1 style="margin: 0; font-size: 2.5rem; font-weight: 700;">Strukturierung und Visualisierung von historischen Daten</h1>
|
555 |
+
</div>
|
556 |
+
|
557 |
+
<!-- Quick Summary Box -->
|
558 |
+
<div style="background-color: #f8f9fa; padding: 1.5rem; border-radius: 8px; margin-bottom: 2rem; border-left: 5px solid #4e8fd1; box-shadow: 0 2px 10px rgba(0,0,0,0.05);">
|
559 |
+
<h3 style="color: #2c6bb3; margin-top: 0; margin-bottom: 15px; font-size: 1.4rem;">Kurz erklärt: Was macht diese Anwendung?</h3>
|
560 |
|
561 |
<ol style="padding-left: 20px; margin-bottom: 0;">
|
562 |
+
<li style="margin-bottom: 15px; font-size: 1.1rem; line-height: 1.5;">
|
563 |
+
<strong style="color: #2c6bb3;">Textanalyse-Tool:</strong> Findet automatisch wichtige Informationen in alten Zeitungsartikeln, wie Erdbeben-Orte oder Berichterstattungsstädte.
|
564 |
</li>
|
565 |
|
566 |
+
<li style="margin-bottom: 15px; font-size: 1.1rem; line-height: 1.5;">
|
567 |
+
<strong style="color: #2c6bb3;">Fragemethode:</strong> Verwandelt leere Felder in Fragen (z.B. "Wo war das Erdbeben?") und findet Antworten im Text.
|
568 |
</li>
|
569 |
|
570 |
+
<li style="margin-bottom: 15px; font-size: 1.1rem; line-height: 1.5;">
|
571 |
+
<strong style="color: #2c6bb3;">Kartenvisualisierung:</strong> Zeigt gefundene Orte automatisch auf interaktiven Karten an.
|
572 |
</li>
|
573 |
|
574 |
+
<li style="margin-bottom: 0; font-size: 1.1rem; line-height: 1.5;">
|
575 |
+
<strong style="color: #2c6bb3;">Forschungshilfe:</strong> Organisiert historische Daten zu strukturierten, leicht analysierbaren Informationen.
|
576 |
</li>
|
577 |
</ol>
|
578 |
</div>
|
579 |
+
|
580 |
+
<!-- Main Explanation Section -->
|
581 |
+
<div style="line-height: 1.7; font-size: 1.15rem; margin-bottom: 2rem;">
|
582 |
+
<p style="font-size: 1.2rem; margin-bottom: 1.5rem; color: #2c3e50; font-weight: 400; padding: 0 1rem; line-height: 1.8;">
|
583 |
+
In dieser Unterrichtseinheit befassen wir uns mit der Strukturierung unstrukturierter historischer Texte und der Visualisierung von extrahierten Daten auf Karten. Die systematische Strukturierung von Daten wird mit einem für Informationsextrahierung trainiertem Sprachmodell durchgeführt, das auf der Question-Answering-Methode basiert. Diese Methode erlaubt es, Informationen mit Hilfe einer Frage zu extrahieren, wie etwa „Wo fand das Erdbeben statt"? Dies ermöglicht die Extrahierung des Ortes, an dem ein Erdbeben stattfand, auch wenn im Text selbst noch andere Orte genannt werden.
|
584 |
+
</p>
|
585 |
+
</div>
|
586 |
+
|
587 |
+
<!-- Example Section with Improved Styling -->
|
588 |
+
<div style="line-height: 1.7; font-size: 1.15rem; background: #f8f9fa; padding: 1.5rem; border-radius: 8px; margin: 2rem 0; box-shadow: 0 2px 10px rgba(0,0,0,0.05); border: 1px solid #e8e8e8;">
|
589 |
+
<h3 style="color: #2c6bb3; margin-top: 0; margin-bottom: 15px;">Beispiel einer Textanalyse</h3>
|
590 |
+
|
591 |
+
<div style="background-color: white; padding: 1.5rem; border-radius: 6px; font-family: 'Source Sans Pro', sans-serif; line-height: 1.7;">
|
592 |
+
Die Katastrophe in <span style="background-color: #a8e6cf; font-weight: bold; padding: 2px 5px; border-radius: 3px;" title="Earthquake Location">Japan</span> — 3 Millionen Tote. Mtb. <span style="background-color: #ffdfba; font-weight: bold; padding: 2px 5px; border-radius: 3px;" title="Non-Earthquake Location">London</span>, 4. Sept. (Drahtbericht.) Zu dem Unglück in <span style="background-color: #a8e6cf; font-weight: bold; padding: 2px 5px; border-radius: 3px;" title="Earthquake Location">Japan</span> liegen noch folgende Nachrichten vor: Wie die japanische Gesandtschaft in <span style="background-color: #ffdfba; font-weight: bold; padding: 2px 5px; border-radius: 3px;" title="Non-Earthquake Location">Peking</span> meldet, sind Unterhandlungen mit <span style="background-color: #ffdfba; font-weight: bold; padding: 2px 5px; border-radius: 3px;" title="Non-Earthquake Location">China</span> über die sofortige Lieferung von Lebensmitteln ausgenommen worden. Von <span style="background-color: #ffdfba; font-weight: bold; padding: 2px 5px; border-radius: 3px;" title="Non-Earthquake Location">Peking</span> seien amerikanische, englische und italienische Schiffe mit Lebensmitteln nach <span style="background-color: #a8e6cf; font-weight: bold; padding: 2px 5px; border-radius: 3px;" title="Earthquake Location">Japan</span> abgegangen.
|
593 |
+
</div>
|
594 |
+
|
595 |
+
<!-- Legend with Improved Layout -->
|
596 |
+
<div style="display: flex; margin-top: 20px; flex-wrap: wrap; justify-content: flex-start;">
|
597 |
+
<div style="display: flex; align-items: center; margin-right: 30px; margin-bottom: 10px;">
|
598 |
+
<div style="width: 20px; height: 20px; background-color: #a8e6cf; margin-right: 10px; border-radius: 3px;"></div>
|
599 |
+
<span style="font-weight: 600;">Ort des Erdbebens: Japan</span>
|
600 |
+
</div>
|
601 |
+
<div style="display: flex; align-items: center;">
|
602 |
+
<div style="width: 20px; height: 20px; background-color: #ffdfba; margin-right: 10px; border-radius: 3px;"></div>
|
603 |
+
<span style="font-weight: 600;">Andere Orte: London, Peking, China</span>
|
604 |
+
</div>
|
605 |
+
</div>
|
606 |
+
</div>
|
607 |
</div>
|
608 |
<div style="font-family: 'Source Sans Pro', sans-serif; max-width: 1000px; margin: 0 auto; color: #333; line-height: 1.7; font-size: 1.15rem;">
|
609 |
<p style="font-size: 1.3rem; margin-bottom: 1.8rem; color: #2c3e50; font-weight: 400; padding: 0 1rem;">
|
|
|
797 |
""")
|
798 |
|
799 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
800 |
with gr.TabItem("📍 Visualisierung von strukturierten Daten"):
|
801 |
gr.HTML("""
|
802 |
<div class="info-box">
|
|
|
830 |
)
|
831 |
|
832 |
with gr.Column():
|
833 |
+
map_output = gr.HTML(
|
834 |
+
label="Interaktive Karte",
|
835 |
+
value="""
|
836 |
+
<div style="text-align:center; height:20vh; width:100%; display:flex; align-items:center; justify-content:center;
|
837 |
+
background-color:#f5f5f5; border:1px solid #e0e0e0; border-radius:8px;">
|
838 |
+
<div>
|
839 |
+
<img src="https://cdn-icons-png.flaticon.com/512/854/854878.png" width="100">
|
840 |
+
<p style="margin-top:20px; color:#666;">Your map will appear here after processing</p>
|
841 |
+
</div>
|
842 |
+
</div>
|
843 |
+
""",
|
844 |
+
elem_id="map-container"
|
845 |
)
|
846 |
+
|
847 |
|
|
|
848 |
def process_and_map(file, column):
|
849 |
if file is None:
|
850 |
return None, "Hier bitte die Excel-Tabelle hochladen", None
|
851 |
|
852 |
try:
|
853 |
+
map_html, stats, processed_path = process_excel(file, column)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
854 |
|
855 |
+
if map_html and processed_path:
|
856 |
+
responsive_html = f"""
|
857 |
+
<div style="width:100%; height:20vh; margin:0; padding:0; border:1px solid #e0e0e0; border-radius:8px; overflow:hidden;">
|
858 |
+
{map_html}
|
859 |
+
</div>
|
860 |
+
"""
|
861 |
+
return responsive_html, stats, processed_path
|
862 |
+
else:
|
863 |
+
return None, stats, None
|
864 |
except Exception as e:
|
865 |
import traceback
|
866 |
trace = traceback.format_exc()
|
|
|
872 |
inputs=[excel_file, places_column],
|
873 |
outputs=[map_output, stats_output, processed_file]
|
874 |
)
|
|
|
875 |
|
876 |
gr.HTML("""
|
877 |
<div style="text-align: center; margin-top: 2rem; padding-top: 1rem; border-top: 1px solid #eee; font-size: 0.9rem; color: #666;">
|