import gradio as gr import google.generativeai as genai import os import re GEMINI_KEY = os.getenv("GEMINI") genai.configure(api_key=GEMINI_KEY) model = genai.GenerativeModel('gemini-pro') CSS = """ :root { --primary: #2A5C82; --secondary: #5BA4E6; --accent: #FF7F50; --background: #F8F9FA; --text: #2C3E50; } body { background: var(--background); font-family: 'Segoe UI', system-ui, sans-serif; min-height: 100vh; margin: 0; padding: 20px; } .gradio-container { max-width: 800px; margin: 0 auto; background: white; border-radius: 20px; box-shadow: 0 10px 30px rgba(0,0,0,0.1); overflow: hidden; } .header { background: var(--primary); padding: 40px 20px; text-align: center; color: white; } .header h1 { margin: 0; font-size: 2.2em; font-weight: 700; display: flex; align-items: center; justify-content: center; gap: 10px; color:#fff; } .header h1 svg{ color:#fff; } .header h1 p { color: #fff; } .chat-container { padding: 20px; height: 60vh; overflow-y: auto; } .msg-user { background: var(--secondary); color: white; padding: 15px 20px; border-radius: 15px 15px 0 15px; margin: 10px 0 10px 30%; position: relative; animation: slideIn 0.3s ease; } .msg-bot { background: white; padding: 20px; border-radius: 15px 15px 15px 0; margin: 10px 30% 10px 0; border: 1px solid #E0E0E0; position: relative; animation: fadeIn 0.5s ease; } .msg-bot::before { content: "โœˆ๏ธ"; position: absolute; left: -35px; top: 15px; font-size: 1.5em; } .card { background: white; padding: 20px; border-radius: 12px; margin: 15px 0; border-left: 4px solid var(--accent); box-shadow: 0 3px 10px rgba(0,0,0,0.05); transition: transform 0.2s; } .card:hover { transform: translateY(-3px); } .price { color: var(--primary); font-weight: 600; margin: 8px 0; } .link { color: var(--secondary) !important; text-decoration: none; font-weight: 500; display: inline-flex; align-items: center; gap: 5px; } .link:hover { text-decoration: underline; } .controls { padding: 20px; background: #F8FAFD; border-top: 1px solid #E0E0E0; } input[type="text"] { border: 2px solid var(--secondary) !important; border-radius: 12px !important; padding: 15px !important; font-size: 1em; } button { background: var(--primary) !important; color: white !important; border: none !important; padding: 12px 25px !important; border-radius: 10px !important; transition: all 0.2s !important; } button:hover { transform: translateY(-2px); box-shadow: 0 5px 15px rgba(42,92,130,0.2) !important; } @keyframes slideIn { from { transform: translateX(20px); opacity: 0; } to { transform: translateX(0); opacity: 1; } } @keyframes fadeIn { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } } @media (max-width: 600px) { .gradio-container { border-radius: 0; } .msg-user, .msg-bot { margin-left: 10%; margin-right: 10%; } } """ class ChatManager: def __init__(self): self.context = {"city": None} def extract_city(self, text): cities = re.findall(r'\b(?:a|in|su|per)\s+([A-Z][a-z]+(?:\s+[A-Z][a-z]+)*)\b', text, re.IGNORECASE) return cities[0] if cities else self.context["city"] def format_response(self, response): structured = [] current_item = {} lines = response.split('\n') for line in lines: if line.startswith('- **'): parts = re.split(r'\*\*:?|\*', line) if len(parts) > 2: key = parts[1].strip().lower() value = parts[2].strip() current_item[key] = value elif line.strip() == '' and current_item: structured.append(current_item) current_item = {} if current_item: structured.append(current_item) html = "" for item in structured: html += f"""

๐Ÿ“ {item.get('nome', '')}

{item.get('descrizione', '')}

{f"
๐Ÿ’ฐ {item.get('prezzo', '')}
" if item.get('prezzo') else ''} {f" Maggiori info" if 'link' in item else ''}
""" return html if html else response chat_manager = ChatManager() def respond(message, chat_history): chat_history.append((message, "")) city = chat_manager.extract_city(message) if city: chat_manager.context["city"] = city if not chat_manager.context["city"]: bot_response = "๐ŸŒ Per favore dimmi prima di quale cittร  vuoi informazioni!" chat_history[-1] = (message, bot_response) return "", chat_history prompt = f""" Sei un assistente turistico esperto di {chat_manager.context["city"]}. Fornisci informazioni strutturate in italiano con: - Nome luogo - Breve descrizione (max 30 parole) - Prezzo (se applicabile) - Link ufficiale (se disponibile) Richiesta: {message} """ try: response = model.generate_content(prompt).text bot_response = chat_manager.format_response(response) except Exception as e: bot_response = f"โš ๏ธ Errore: {str(e)}" chat_history[-1] = (message, bot_response) return "", chat_history def reset_context(chat_history): chat_manager.context = {"city": None} new_history = chat_history + [[None, "๐Ÿ”„ Contesto resettato! Di quale cittร  vuoi parlare ora?"]] return new_history with gr.Blocks(css=CSS) as app: with gr.Column(): gr.HTML("""

Travel Assistant AI

La tua guida personale per scoprire il mondo

""") chatbot = gr.Chatbot( label="Chat", elem_classes="chat-container", show_label=False, avatar_images=( None, "https://i.ibb.co/8XJp0dN/bot-avatar.png" # Sostituisci con il tuo URL ), value=[[None, "Ciao sono la tua guida turistica, come posso aiutarti? ๐ŸŒ"]] ) with gr.Row(elem_classes="controls"): msg = gr.Textbox( label="", placeholder="Scrivi qui la tua richiesta...", show_label=False, container=False ) with gr.Column(min_width=100): send_btn = gr.Button("Invia โž”", variant="primary") reset_btn = gr.Button("Nuova Ricerca", variant="secondary") send_btn.click( respond, [msg, chatbot], [msg, chatbot] ) reset_btn.click( reset_context, [chatbot], [chatbot] ) msg.submit( respond, [msg, chatbot], [msg, chatbot] ) app.launch()