Spaces:
Paused
Paused
| import os | |
| import gradio as gr | |
| from google import genai | |
| from google.genai import types | |
| from urllib.parse import quote | |
| def search_with_maps(user_query): | |
| try: | |
| # Setup client with provided API key | |
| # Note: This is the Gemini API Key (AI Studio) | |
| client = genai.Client(api_key=os.environ.get("GEMINI_API_KEY")) | |
| # Configure the Google Maps tool | |
| config = types.GenerateContentConfig( | |
| tools=[types.Tool(google_maps=types.GoogleMaps())] | |
| ) | |
| # Generate content | |
| response = client.models.generate_content( | |
| model='gemini-2.5-flash', | |
| contents=f"antworte immer auf deutsch: {user_query}", | |
| config=config | |
| ) | |
| # Get the text response | |
| response_text = response.text | |
| # Extract grounding metadata (Maps sources) | |
| map_html = "" | |
| locations = [] | |
| # Check if we have valid grounding metadata | |
| if (response.candidates[0].grounding_metadata and | |
| response.candidates[0].grounding_metadata.grounding_chunks): | |
| metadata = response.candidates[0].grounding_metadata | |
| # Collect all locations | |
| for chunk in metadata.grounding_chunks: | |
| if chunk.maps: | |
| locations.append({ | |
| 'title': chunk.maps.title, | |
| 'uri': chunk.maps.uri | |
| }) | |
| if locations: | |
| # 1. Create the link for the Button (Opens in new tab) | |
| # "maps/search" is perfect for the external link | |
| location_names = [loc['title'] for loc in locations] | |
| search_terms = " ".join(location_names) # Removing '|' often helps generic search | |
| # External link URL | |
| maps_external_url = f"https://www.google.com/maps/search/{quote(search_terms)}" | |
| # 2. Create the URL for the Iframe (Embedding) | |
| # Standard maps/search URLs get blocked by X-Frame-Options. | |
| # OPTION A: Use Google Maps Embed API (Best for production) | |
| # Requires a Google Cloud API Key with 'Maps Embed API' enabled. | |
| maps_api_key = os.environ.get("GOOGLE_MAPS_API_KEY") | |
| if maps_api_key: | |
| # Search mode with API Key | |
| embed_src = f"https://www.google.com/maps/embed/v1/search?key={maps_api_key}&q={quote(search_terms)}" | |
| else: | |
| # OPTION B: Legacy embedding (Free/No Key) | |
| # We use maps.google.com with output=embed. | |
| # Note: We prioritize the first location found for the embed preview | |
| # because the legacy embed doesn't handle list searches well. | |
| primary_location = locations[1]['title'] | |
| embed_src = f"https://maps.google.com/maps?q={quote(primary_location)}&t=&z=13&ie=UTF8&iwloc=&output=embed" | |
| # Create HTML with embedded map and location list src="{embed_src}" | |
| map_html = f""" | |
| <div style="width: 100%; display: flex; flex-direction: column; gap: 10px;"> | |
| <iframe | |
| src="{embed_src}" | |
| width="100%" | |
| height="450" | |
| style="border:0; border-radius: 8px; box-shadow: 0 2px 8px rgba(0,0,0,0.1);" | |
| allowfullscreen="" | |
| loading="lazy" | |
| referrerpolicy="no-referrer-when-downgrade"> | |
| </iframe> | |
| <a href="{maps_external_url}" target="_blank" | |
| style="display: block; text-align: center; padding: 12px; background: #4a90e2; color: white; | |
| text-decoration: none; border-radius: 6px; font-weight: bold; | |
| transition: background 0.3s;"> | |
| 🗺️ Alle {len(locations)} Orte in Google Maps öffnen | |
| </a> | |
| <div style="font-size: 0.9em; color: #666; background: #f5f5f5; padding: 10px; border-radius: 6px;"> | |
| <strong>Gefundene Orte:</strong><br> | |
| {", ".join(location_names)} | |
| </div> | |
| </div> | |
| """ | |
| else: | |
| map_html = """ | |
| <div style="padding: 20px; background: #fff3cd; border: 1px solid #ffc107; border-radius: 5px;"> | |
| <p style="margin: 0; color: #856404;">⚠️ Keine spezifischen Orte gefunden.</p> | |
| </div> | |
| """ | |
| else: | |
| map_html = """ | |
| <div style="padding: 20px; background: #f8f9fa; border: 1px solid #ddd; border-radius: 5px;"> | |
| <p style="margin: 0; color: #666;">ℹ️ Keine Kartendaten verfügbar.</p> | |
| </div> | |
| """ | |
| return response_text, map_html | |
| except Exception as e: | |
| import traceback | |
| traceback.print_exc() # Print full error to console for debugging | |
| error_msg = f"❌ Error: {str(e)}" | |
| error_html = f""" | |
| <div style="padding: 20px; background: #f8d7da; border: 1px solid #f5c6cb; border-radius: 5px;"> | |
| <p style="margin: 0; color: #721c24;"><strong>Systemfehler:</strong> {str(e)}</p> | |
| </div> | |
| """ | |
| return error_msg, error_html | |
| # Create Gradio interface | |
| with gr.Blocks(title="Gemini Maps Search", theme=gr.themes.Soft()) as demo: | |
| gr.Markdown("# 🗺️ Gemini Maps Search") | |
| with gr.Row(): | |
| sources_output = gr.HTML(label="📍 Karte") | |
| with gr.Row(): | |
| response_output = gr.Markdown(label="🤖 Antwort") | |
| with gr.Row(): | |
| query_input = gr.Textbox( | |
| label="Suchanfrage", | |
| placeholder="z.B. Zeige mir die besten Restaurants in Berlin Mitte", | |
| lines=2 | |
| ) | |
| with gr.Row(): | |
| search_btn = gr.Button("🔍 Suchen", variant="primary") | |
| # Set up the event handler | |
| search_btn.click( | |
| fn=search_with_maps, | |
| inputs=query_input, | |
| outputs=[response_output, sources_output] | |
| ) | |
| query_input.submit( | |
| fn=search_with_maps, | |
| inputs=query_input, | |
| outputs=[response_output, sources_output] | |
| ) | |
| if __name__ == "__main__": | |
| demo.launch() |