TuristGreta / app.py
AlessandroArgiolas02's picture
Update app.py
db97180 verified
# app.py
import gradio as gr
import requests
import google.generativeai as genai
import json
import os
import re
# Configurazione da variabili d'ambiente
GEMINI_KEY = os.getenv("GEMINI")
UNSPLASH_KEY = os.getenv("UNSPLASH_ACCESS")
WEATHER_KEY = os.getenv("OPENWEATHER")
# Inizializzazione Gemini
genai.configure(api_key=GEMINI_KEY)
model = genai.GenerativeModel('gemini-pro')
CSS = """
body { font-family: 'Arial', sans-serif; background: #f5f7fa; margin: 0; }
.travel-container { max-width: 1200px; margin: 0 auto; padding: 20px; }
.header { text-align: center; color: #2d3436; margin-bottom: 30px; }
.section { background: white; padding: 20px; border-radius: 15px; margin-bottom: 20px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }
.card { border: 1px solid #e0e0e0; padding: 15px; margin: 10px 0; border-radius: 8px; transition: transform 0.2s; }
.card:hover { transform: translateY(-3px); }
.gallery { display: flex; flex-wrap: wrap; gap: 10px; margin: 15px 0; }
.gallery img { width: 30%; flex-grow: 1; border-radius: 8px; height: 200px; object-fit: cover; }
.weather-widget { background: #e3f2fd !important; padding: 15px !important; }
.price-tag { color: #2e7d32; font-weight: bold; }
.reasons-list { padding-left: 20px; color: #666; }
.loading { text-align: center; padding: 30px; color: #555; }
.error { background: #ffebee; color: #d32f2f; padding: 20px; border-radius: 8px; }
"""
def get_weather(city):
try:
url = "http://api.openweathermap.org/data/2.5/weather"
params = {
"q": city,
"appid": WEATHER_KEY,
"units": "metric",
"lang": "it"
}
response = requests.get(url, params=params, timeout=10)
data = response.json()
return f"""
<div class='section weather-widget'>
<h3>⛅ Meteo Attuale</h3>
<p>🌡️ Temperatura: {data['main']['temp']}°C</p>
<p>☁️ Condizioni: {data['weather'][0]['description'].capitalize()}</p>
<p>💧 Umidità: {data['main']['humidity']}%</p>
<p>🌬️ Vento: {data['wind']['speed']} m/s</p>
</div>
"""
except Exception as e:
print(f"Errore meteo: {str(e)}")
return ""
def get_city_photos(city):
try:
url = "https://api.unsplash.com/search/photos"
headers = {"Authorization": f"Client-ID {UNSPLASH_KEY}"}
params = {"query": f"{city} city", "per_page": 3}
response = requests.get(url, headers=headers, params=params, timeout=10)
photos = [img['urls']['regular'] for img in response.json()['results']]
return f"""
<div class='section'>
<h3>📸 Foto di {city.capitalize()}</h3>
<div class='gallery'>
{"".join([f"<img src='{photo}'>" for photo in photos])}
</div>
</div>
"""
except Exception as e:
print(f"Errore foto: {str(e)}")
return ""
def generate_recommendations(city, category):
prompt = f"""
GENERA SOLO JSON VALIDO. Niente testo prima o dopo.
Genera 5 consigli per {category} a {city} in formato JSON con struttura:
{{
"recommendations": [
{{
"name": "Nome",
"description": "Descrizione (max 40 parole)",
"price_range": "€/€€/€€€",
"address": "Zona",
"reasons": ["motivo1", "motivo2", "motivo3"],
"tip": "Consiglio pratico"
}}
]
}}
"""
try:
response = model.generate_content(prompt)
return response.text
except Exception as e:
print(f"Errore Gemini: {str(e)}")
return None
def parse_response(response):
try:
# Pulizia e validazione JSON
json_str = re.sub(r'[\x00-\x1F]+', '', response) # Rimuove caratteri non stampabili
json_str = re.search(r'\{.*\}', json_str, re.DOTALL).group()
data = json.loads(json_str)
# Validazione struttura
if not isinstance(data.get('recommendations', []), list):
return []
return data['recommendations'][:5] # Limita a 5 risultati
except Exception as e:
print(f"Errore parsing: {str(e)}")
return []
with gr.Blocks(css=CSS) as app:
gr.Markdown("# 🌍 Travel Assistant Pro")
city_input = gr.Textbox(label="Inserisci città", placeholder="Es: Roma, Parigi...")
search_btn = gr.Button("Cerca")
output = gr.HTML()
@search_btn.click(inputs=city_input, outputs=output)
def search(city):
if not city.strip():
return "<div class='error'>🚨 Inserisci una città valida</div>"
yield "<div class='loading'>🔍 Ricerca in corso... ⏳</div>"
try:
# Dati base
weather = get_weather(city)
photos = get_city_photos(city)
# Genera raccomandazioni
sections = []
for cat in ["mangiare", "visitare", "dormire"]:
response = generate_recommendations(city, cat)
items = parse_response(response) if response else []
cards = []
for item in items:
cards.append(f"""
<div class='card'>
<h3>{item.get('name', '')}</h3>
<p>📍 {item.get('address', 'Indirizzo non disponibile')}</p>
<p class='price-tag'>💰 {item.get('price_range', '€')}</p>
<p>{item.get('description', '')}</p>
<div class='reasons-list'>
{"".join([f"<p>✔️ {r}</p>" for r in item.get('reasons', [])])}
</div>
<p>💡 {item.get('tip', '')}</p>
</div>
""")
sections.append(f"""
<div class='section'>
<h2>🌟 {cat.capitalize()}</h2>
{"".join(cards) if cards else '<p class="error">Nessun risultato trovato</p>'}
</div>
""")
# Costruisci output
content = f"""
<div class='travel-container'>
<h1 class='header'>{city.capitalize()}</h1>
{weather}
{photos}
{"".join(sections)}
</div>
"""
yield content
except Exception as e:
error_msg = f"""
<div class='error'>
<h3>❌ Errore grave</h3>
<p>{str(e)}</p>
<p>Prova a ricaricare la pagina o riprova più tardi</p>
</div>
"""
yield error_msg
app.launch()