"""Internationalization (i18n) of the bot's user-facing messages. The Vetrina core works internally in English (the FAISS indexes and the product catalog are English, and the Router translates any input language to English). This module controls only the language of the messages shown back to the user. Two locales ship out of the box: "en" (default) and "it". The active locale is chosen by RESPONSE_LANG in utils/config.py (env var RESPONSE_LANG). To add a language, add an entry to MESSAGES and to GREETING_PROMPTS with the same keys; everything else picks it up automatically. """ from utils.config import RESPONSE_LANG # --- Static user-facing messages, keyed by locale --- MESSAGES = { "en": { # Search Agent "search_catalog_unavailable": "Sorry, the product catalog is unavailable.", "search_no_results": "I couldn't find any products matching your request.", "search_results": "Here's what I found for you!", "unknown_product": "Unknown product", # Recommender Agent "recommender_offline": "The recommendation system is offline.", "recommender_no_data": "I don't have enough data to make recommendations.", "recommender_results": "Here are some products recommended for you!", "recommender_error": "Error while computing the recommendations: {error}", # Visual Agent "visual_no_image": "No image was provided for the visual search.", "visual_offline": "The visual search system is offline.", "visual_no_results": "I couldn't find products visually similar to this image.", "visual_results": "Here are the most visually similar products!", "visual_image_not_found": "Image not found: {path}", "visual_error": "Error during the visual search: {error}", # Greeting fallback + default node "greeting_fallback": "Hi! I'm your fashion assistant. I can search for products or give you recommendations.", "default_out_of_scope": "For help with orders or returns, please contact human support.", # Web API errors "api_empty_message": "Empty message", "api_no_image": "No image sent", "api_system_error": "System error: {error}", }, "it": { # Search Agent "search_catalog_unavailable": "Errore: il catalogo prodotti non è disponibile.", "search_no_results": "Non ho trovato prodotti che corrispondono alla tua richiesta.", "search_results": "Ecco cosa ho trovato per te!", "unknown_product": "Prodotto sconosciuto", # Recommender Agent "recommender_offline": "Il sistema di raccomandazione è offline.", "recommender_no_data": "Non ho abbastanza dati per fare raccomandazioni.", "recommender_results": "Ecco alcuni prodotti consigliati per te!", "recommender_error": "Errore nel calcolo dei consigli: {error}", # Visual Agent "visual_no_image": "Nessuna immagine fornita per la ricerca visiva.", "visual_offline": "Il sistema di ricerca visiva è offline.", "visual_no_results": "Non ho trovato prodotti visivamente simili a questa immagine.", "visual_results": "Ecco i prodotti più simili visivamente!", "visual_image_not_found": "Immagine non trovata: {path}", "visual_error": "Errore nella ricerca visiva: {error}", # Greeting fallback + default node "greeting_fallback": "Ciao! Sono il tuo assistente fashion. Posso cercare prodotti o darti consigli.", "default_out_of_scope": "Per assistenza su ordini o resi, contatta il supporto umano.", # Web API errors "api_empty_message": "Messaggio vuoto", "api_no_image": "Nessuna immagine inviata", "api_system_error": "Errore di sistema: {error}", }, } # --- Greeting-node LLM prompts, keyed by locale --- # The greeting node uses a higher-temperature LLM for varied replies; the prompt # tells it which language to answer in. GREETING_PROMPTS = { "en": { "greeting": """You are a fashion assistant for an e-commerce store. The user is greeting you. Reply with a short, natural greeting (1-2 sentences). Vary the tone and structure every time. Mention that you can help with product search, recommendations, or visual search from an image. Reply in English. Do not use emoji. Do not list the features mechanically.""", "thanks": """You are a fashion assistant for an e-commerce store. The user is thanking you. Reply briefly (1-2 sentences) in a natural and varied way. Ask if they need anything else. Reply in English. Do not use emoji.""", "goodbye": """You are a fashion assistant for an e-commerce store. The user is saying goodbye. Say goodbye briefly (1-2 sentences) in a friendly way. Remind them you're available whenever needed. Reply in English. Do not use emoji.""", }, "it": { "greeting": """Sei un assistente fashion per un e-commerce. L'utente ti sta salutando. Rispondi con un saluto breve e naturale (1-2 frasi). Varia il tono e la struttura ogni volta. Menziona che puoi aiutare con ricerca prodotti, consigli o ricerca visiva da immagine. Rispondi in italiano. Non usare emoji. Non elencare le funzionalità in modo meccanico.""", "thanks": """Sei un assistente fashion per un e-commerce. L'utente ti sta ringraziando. Rispondi brevemente (1-2 frasi) in modo naturale e vario. Chiedi se serve altro aiuto. Rispondi in italiano. Non usare emoji.""", "goodbye": """Sei un assistente fashion per un e-commerce. L'utente si sta congedando. Saluta brevemente (1-2 frasi) in modo cordiale. Ricorda che sei disponibile quando serve. Rispondi in italiano. Non usare emoji.""", }, } def _active_lang(): """Returns the active locale, falling back to English if unknown.""" return RESPONSE_LANG if RESPONSE_LANG in MESSAGES else "en" def t(key, **kwargs): """Returns the localized message for `key`, formatted with `kwargs`. Falls back to the English string if the key is missing in the active locale. """ lang = _active_lang() template = MESSAGES[lang].get(key) or MESSAGES["en"].get(key, key) return template.format(**kwargs) if kwargs else template def greeting_prompt(greeting_type): """Returns the greeting-node LLM prompt for the given type in the active locale.""" prompts = GREETING_PROMPTS.get(_active_lang(), GREETING_PROMPTS["en"]) return prompts.get(greeting_type, prompts["greeting"])