Update app.py
Browse files
app.py
CHANGED
|
@@ -3,123 +3,111 @@ import google.generativeai as genai
|
|
| 3 |
import os
|
| 4 |
import re
|
| 5 |
|
| 6 |
-
# Configurazione API
|
| 7 |
GEMINI_KEY = os.getenv("GEMINI")
|
| 8 |
genai.configure(api_key=GEMINI_KEY)
|
| 9 |
model = genai.GenerativeModel('gemini-pro')
|
| 10 |
|
| 11 |
CSS = """
|
| 12 |
-
body {
|
| 13 |
-
.
|
| 14 |
-
.
|
| 15 |
-
#
|
| 16 |
-
|
| 17 |
-
.
|
| 18 |
-
.
|
|
|
|
|
|
|
| 19 |
"""
|
| 20 |
|
| 21 |
-
def
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 25 |
|
| 26 |
-
def generate_response(
|
| 27 |
-
|
| 28 |
-
|
| 29 |
-
|
| 30 |
-
|
| 31 |
-
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
|
| 36 |
-
|
| 37 |
-
|
| 38 |
-
|
| 39 |
-
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
|
| 45 |
-
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
|
| 49 |
-
Città: {current_city}
|
| 50 |
-
|
| 51 |
-
Genera una risposta ben formattata in Markdown con:
|
| 52 |
-
1. Cose da vedere (monumenti principali)
|
| 53 |
-
2. Dove mangiare (3 ristoranti tipici)
|
| 54 |
-
3. Dove dormire (3 opzioni alloggio)
|
| 55 |
-
4. Cose da fare (attività uniche)
|
| 56 |
-
5. Itinerari per 1, 2 e 3 giorni
|
| 57 |
-
|
| 58 |
-
Struttura:
|
| 59 |
-
# {current_city} 🏙️
|
| 60 |
-
## 🏛️ Da Vedere
|
| 61 |
-
- [Luogo 1]
|
| 62 |
-
- [Luogo 2]
|
| 63 |
-
|
| 64 |
-
## 🍝 Dove Mangiare
|
| 65 |
-
1. **Ristorante 1** - Specialità...
|
| 66 |
-
|
| 67 |
-
## 🛌 Dove Dormire
|
| 68 |
-
- Hotel 1 ★★★
|
| 69 |
-
|
| 70 |
-
## 🎡 Cose da Fare
|
| 71 |
-
- Attività 1
|
| 72 |
-
|
| 73 |
-
## 📅 Itinerari
|
| 74 |
-
**1 Giorno**:
|
| 75 |
-
- Mattina: ...
|
| 76 |
-
"""
|
| 77 |
-
|
| 78 |
-
try:
|
| 79 |
response = model.generate_content(prompt).text
|
| 80 |
-
|
| 81 |
-
|
| 82 |
-
|
| 83 |
-
|
| 84 |
-
|
| 85 |
-
|
| 86 |
-
|
| 87 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 88 |
|
| 89 |
-
with gr.Blocks(css=CSS) as
|
| 90 |
-
|
| 91 |
-
label="Chat Turistica",
|
| 92 |
-
bubble_full_width=False,
|
| 93 |
-
show_label=False,
|
| 94 |
-
avatar_images=(
|
| 95 |
-
"https://i.imgur.com/7kQEsHU.png",
|
| 96 |
-
"https://i.imgur.com/7W7QEs2.png"
|
| 97 |
-
)
|
| 98 |
-
)
|
| 99 |
-
msg = gr.Textbox(label="Scrivi qui...")
|
| 100 |
-
clear = gr.ClearButton([msg, chatbot])
|
| 101 |
|
| 102 |
-
|
| 103 |
-
|
| 104 |
-
|
| 105 |
|
| 106 |
-
|
| 107 |
-
history += [[message, None]]
|
| 108 |
-
bot_message = generate_response(history, message)
|
| 109 |
-
history[-1][1] = bot_message
|
| 110 |
-
return history
|
| 111 |
|
| 112 |
-
|
| 113 |
-
|
| 114 |
-
|
| 115 |
-
|
| 116 |
-
queue=False
|
| 117 |
-
).then(
|
| 118 |
-
lambda: "",
|
| 119 |
-
None,
|
| 120 |
-
[msg]
|
| 121 |
)
|
| 122 |
-
|
| 123 |
-
demo.load(init_message, None, [chatbot])
|
| 124 |
|
| 125 |
-
|
|
|
|
| 3 |
import os
|
| 4 |
import re
|
| 5 |
|
|
|
|
| 6 |
GEMINI_KEY = os.getenv("GEMINI")
|
| 7 |
genai.configure(api_key=GEMINI_KEY)
|
| 8 |
model = genai.GenerativeModel('gemini-pro')
|
| 9 |
|
| 10 |
CSS = """
|
| 11 |
+
body { font-family: Arial, sans-serif; max-width: 800px; margin: 0 auto; padding: 20px; }
|
| 12 |
+
.header { text-align: center; margin-bottom: 30px; }
|
| 13 |
+
.input-section { display: flex; gap: 10px; margin-bottom: 20px; }
|
| 14 |
+
#question { flex-grow: 1; padding: 10px; }
|
| 15 |
+
.category { margin: 25px 0; border-bottom: 2px solid #eee; padding-bottom: 20px; }
|
| 16 |
+
.category-title { color: #2c3e50; font-size: 1.4em; margin-bottom: 15px; }
|
| 17 |
+
.item-card { background: white; padding: 15px; border-radius: 8px; margin: 10px 0; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }
|
| 18 |
+
.item-card h3 { margin: 0 0 8px 0; color: #3498db; }
|
| 19 |
+
.link { color: #2980b9; text-decoration: underline; }
|
| 20 |
"""
|
| 21 |
|
| 22 |
+
def parse_response(response):
|
| 23 |
+
categories = {}
|
| 24 |
+
current_category = None
|
| 25 |
+
|
| 26 |
+
# Dividi in categorie
|
| 27 |
+
lines = response.split('\n')
|
| 28 |
+
for line in lines:
|
| 29 |
+
if line.startswith('## '):
|
| 30 |
+
current_category = line.replace('## ', '').strip()
|
| 31 |
+
categories[current_category] = []
|
| 32 |
+
elif line.startswith('- **') or line.startswith('1. **'):
|
| 33 |
+
parts = re.split(r'\*\*|\*', line)
|
| 34 |
+
name = parts[1].strip()
|
| 35 |
+
desc = parts[-1].strip()
|
| 36 |
+
|
| 37 |
+
# Estrai link
|
| 38 |
+
links = re.findall(r'(https?://\S+)', desc)
|
| 39 |
+
desc = re.sub(r'(https?://\S+)', '', desc).strip()
|
| 40 |
+
|
| 41 |
+
categories[current_category].append({
|
| 42 |
+
"name": name,
|
| 43 |
+
"description": desc,
|
| 44 |
+
"links": links
|
| 45 |
+
})
|
| 46 |
+
|
| 47 |
+
return categories
|
| 48 |
|
| 49 |
+
def generate_response(question):
|
| 50 |
+
# Controlla se è una richiesta specifica
|
| 51 |
+
specific_query = re.search(r'\b(dove|cosa|come|quale|quando)\b', question, re.IGNORECASE)
|
| 52 |
+
|
| 53 |
+
if specific_query:
|
| 54 |
+
# Modalità risposta libera
|
| 55 |
+
response = model.generate_content(f"Rispondi in italiano in formato testo semplice: {question}").text
|
| 56 |
+
return f"<div class='free-response'>{response}</div>"
|
| 57 |
+
else:
|
| 58 |
+
# Modalità strutturata
|
| 59 |
+
city = re.search(r'\b(a|in|per|su)\s+([A-Za-z\s]+)', question, re.IGNORECASE)
|
| 60 |
+
city = city.group(2).strip() if city else question
|
| 61 |
+
|
| 62 |
+
prompt = f"""
|
| 63 |
+
Genera una guida turistica per {city} in italiano con:
|
| 64 |
+
- 3-5 luoghi da vedere con breve descrizione e sito ufficiale se disponibile
|
| 65 |
+
- 3 ristoranti tipici con specialità e eventuale sito web
|
| 66 |
+
- 3 opzioni alloggio con range prezzi
|
| 67 |
+
- 2-3 attività caratteristiche
|
| 68 |
+
- Formatta in markdown con categorie ##
|
| 69 |
+
- Includi link dove appropriato
|
| 70 |
+
"""
|
| 71 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 72 |
response = model.generate_content(prompt).text
|
| 73 |
+
categories = parse_response(response)
|
| 74 |
+
|
| 75 |
+
html_output = ""
|
| 76 |
+
for category, items in categories.items():
|
| 77 |
+
section = f"""
|
| 78 |
+
<div class='category'>
|
| 79 |
+
<div class='category-title'>{category}</div>
|
| 80 |
+
"""
|
| 81 |
+
|
| 82 |
+
for item in items:
|
| 83 |
+
links = "".join([f"<a href='{link}' class='link' target='_blank'>Sito ufficiale</a>" for link in item['links']])
|
| 84 |
+
|
| 85 |
+
section += f"""
|
| 86 |
+
<div class='item-card'>
|
| 87 |
+
<h3>{item['name']}</h3>
|
| 88 |
+
<p>{item['description']}</p>
|
| 89 |
+
{links}
|
| 90 |
+
</div>
|
| 91 |
+
"""
|
| 92 |
+
|
| 93 |
+
section += "</div>"
|
| 94 |
+
html_output += section
|
| 95 |
+
|
| 96 |
+
return html_output
|
| 97 |
|
| 98 |
+
with gr.Blocks(css=CSS) as app:
|
| 99 |
+
gr.HTML("<div class='header'><h1>🌍 Guida Turistica Digitale</h1><p>Chiedimi informazioni su qualsiasi destinazione!</p></div>")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 100 |
|
| 101 |
+
with gr.Row(equal_height=True, variant="panel"):
|
| 102 |
+
question = gr.Textbox(placeholder="Es: Cosa visitare a Roma?", elem_id="question")
|
| 103 |
+
submit_btn = gr.Button("Cerca", variant="primary")
|
| 104 |
|
| 105 |
+
output = gr.HTML()
|
|
|
|
|
|
|
|
|
|
|
|
|
| 106 |
|
| 107 |
+
submit_btn.click(
|
| 108 |
+
fn=generate_response,
|
| 109 |
+
inputs=question,
|
| 110 |
+
outputs=output
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 111 |
)
|
|
|
|
|
|
|
| 112 |
|
| 113 |
+
app.launch()
|