ninooo96 commited on
Commit
13e0cf8
·
1 Parent(s): 153e89d

added language es, fr, de, ru on the UI

Browse files
Files changed (2) hide show
  1. app.py +89 -22
  2. lang.yaml +180 -0
app.py CHANGED
@@ -6,8 +6,28 @@ from sentence_transformers import SentenceTransformer
6
  from deep_translator import GoogleTranslator
7
  from langdetect import detect, DetectorFactory
8
  import time
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9
 
10
- # Evita risultati random nel rilevamento lingua
11
  DetectorFactory.seed = 0
12
 
13
  # --- SETUP DATABASE & AI ---
@@ -76,16 +96,15 @@ details[open] summary::before { content: "✅ "; }
76
  LOADING_HTML = """
77
  <div style="display: flex; justify-content: center; align-items: center; height: 100px; width: 100%; flex-direction: column;">
78
  <div style="border: 4px solid #374151; border-top: 4px solid #3b82f6; border-radius: 50%; width: 30px; height: 30px; animation: spin 1s linear infinite;"></div>
79
- <p style="margin-top: 10px; color: #9ca3af; font-size: 0.9em;">Ricerca in corso...</p>
80
- </div>
81
  <style>@keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }</style>
82
  """
83
 
84
  # --- LOGICA ---
85
 
86
  def render_results(ids, scores, ui_lang="it"):
87
- if not ids: return "Nessun risultato trovato."
88
- if not TURSO_URL: return "Errore: Database non configurato."
89
 
90
  conn = get_turso_conn()
91
  placeholders = ", ".join(["?"] * len(ids))
@@ -113,9 +132,9 @@ def render_results(ids, scores, ui_lang="it"):
113
  show_btn = True
114
  translated_text = translator.translate(summary)
115
  except:
116
- translated_text = "Traduzione non disponibile."
117
 
118
- btn_label = "Traduci in Italiano" if ui_lang == 'it' else "Translate to English"
119
  translate_block = ""
120
  if show_btn:
121
  translate_block = f"""<details><summary>{btn_label}</summary><p style="margin-top: 10px; color: #e5e7eb; border-left: 2px solid #fbbf24; padding-left: 10px; font-style: italic;">{translated_text}</p></details>"""
@@ -131,10 +150,40 @@ def render_results(ids, scores, ui_lang="it"):
131
  html += "</div>"
132
  return html
133
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
134
  def search_logic(query, max_res, lang_pref):
 
135
  yield gr.update(visible=True), gr.update(visible=False)
136
  if not query:
137
- yield gr.update(visible=False), "Inserisci del testo."
138
  return
139
  try:
140
  q_emb = GoogleTranslator(source='auto', target='en').translate(query) if lang_pref == "it" else query
@@ -147,6 +196,7 @@ def search_logic(query, max_res, lang_pref):
147
  yield gr.update(visible=False), f"Errore: {e}"
148
 
149
  def find_logic(title):
 
150
  yield gr.update(visible=True), gr.update(visible=False), [], gr.update(visible=False)
151
  conn = get_turso_conn()
152
  rows = conn.execute(f"SELECT id, title, author, year FROM books WHERE title LIKE '%{title}%' LIMIT 10").fetchall()
@@ -174,39 +224,56 @@ def clean_tab2(): return gr.update(value=""), gr.update(visible=False), gr.updat
174
 
175
  # --- UI ---
176
  with gr.Blocks(theme=gr.themes.Ocean(), css=GLOBAL_CSS, js=JS_FORCE_DARK) as demo:
177
- gr.Markdown("# 📚 AI Book Finder")
178
  books_state = gr.State([])
179
 
180
  with gr.Row():
181
- lang_selector = gr.Radio(choices=["it", "en"], value="it", label="Lingua / Language")
182
- num_results = gr.Slider(1, 10, value=5, step=1, label="Risultati", show_reset_button=False)
183
 
184
  with gr.Tabs() as tabs:
185
- with gr.Tab("🔎 Ricerca Trama") as t1:
186
  with gr.Row():
187
- txt_in = gr.Textbox(placeholder="Descrivi...", show_label=False, scale=4)
188
- btn_search = gr.Button("Cerca", variant="primary", scale=1)
189
 
190
- with gr.Tab("📖 Cerca Titolo") as t2:
191
  with gr.Row():
192
- txt_tit = gr.Textbox(placeholder="Titolo...", show_label=False, scale=4)
193
- btn_find = gr.Button("Trova", scale=1)
194
- loader_list = gr.HTML(value=LOADING_HTML, visible=False)
195
 
196
  # --- CORREZIONE TABELLA QUI SOTTO ---
197
  dataset = gr.Dataset(
198
  elem_id="book_cards",
199
  components=[gr.Textbox(visible=False), gr.Textbox(visible=False), gr.Textbox(visible=False)],
200
- headers=["Titolo", "Autore", "Anno"],
201
- label="Risultati:",
202
  samples=[],
203
  type="index"
204
  )
205
 
206
- loader = gr.HTML(value=LOADING_HTML, visible=False)
207
- results = gr.HTML(label="Risultati", visible=True)
208
 
209
  # EVENTI
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
210
  btn_search.click(search_logic, [txt_in, num_results, lang_selector], [loader, results])
211
  txt_in.submit(search_logic, [txt_in, num_results, lang_selector], [loader, results])
212
 
 
6
  from deep_translator import GoogleTranslator
7
  from langdetect import detect, DetectorFactory
8
  import time
9
+ import yaml
10
+
11
+ # --- CARICAMENTO ETICHETTE I18N ---
12
+ def load_labels(filepath="lang.yaml"):
13
+ """Carica tutte le etichette dal file YAML."""
14
+ try:
15
+ with open(filepath, 'r', encoding='utf-8') as f:
16
+ return yaml.safe_load(f)
17
+ except FileNotFoundError:
18
+ print("Errore: Il file 'lang.yaml' non è stato trovato.")
19
+ return {}
20
+ except Exception as e:
21
+ print(f"Errore durante la lettura di 'lang.yaml': {e}")
22
+ return {}
23
+
24
+ ALL_LABELS = load_labels()
25
+ DEFAULT_LANG = "it"
26
+
27
+ def L(key, lang_code=DEFAULT_LANG):
28
+ """Funzione helper per ottenere una label per la lingua specificata."""
29
+ return ALL_LABELS.get(lang_code, ALL_LABELS[DEFAULT_LANG]).get(key, f"MISSING_KEY:{key}")
30
 
 
31
  DetectorFactory.seed = 0
32
 
33
  # --- SETUP DATABASE & AI ---
 
96
  LOADING_HTML = """
97
  <div style="display: flex; justify-content: center; align-items: center; height: 100px; width: 100%; flex-direction: column;">
98
  <div style="border: 4px solid #374151; border-top: 4px solid #3b82f6; border-radius: 50%; width: 30px; height: 30px; animation: spin 1s linear infinite;"></div>
99
+ <p style="margin-top: 10px; color: #9ca3af; font-size: 0.9em;">{}</p> </div>
 
100
  <style>@keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }</style>
101
  """
102
 
103
  # --- LOGICA ---
104
 
105
  def render_results(ids, scores, ui_lang="it"):
106
+ if not ids: return L("error_no_results", ui_lang)
107
+ if not TURSO_URL: return L("error_db_not_configured", ui_lang)
108
 
109
  conn = get_turso_conn()
110
  placeholders = ", ".join(["?"] * len(ids))
 
132
  show_btn = True
133
  translated_text = translator.translate(summary)
134
  except:
135
+ L("translation_not_available", ui_lang)
136
 
137
+ btn_label = L("translation_button_label", ui_lang)
138
  translate_block = ""
139
  if show_btn:
140
  translate_block = f"""<details><summary>{btn_label}</summary><p style="margin-top: 10px; color: #e5e7eb; border-left: 2px solid #fbbf24; padding-left: 10px; font-style: italic;">{translated_text}</p></details>"""
 
150
  html += "</div>"
151
  return html
152
 
153
+ # --- FUNZIONE DI AGGIORNAMENTO UI ---
154
+ def update_ui_labels(new_lang):
155
+ """Aggiorna tutti i componenti Gradio in base alla lingua selezionata."""
156
+
157
+ # Aggiorna il titolo del blocco (gr.Markdown)
158
+ title_update = gr.Markdown.update(value=f"## {L('app_title', new_lang)}")
159
+
160
+ # Aggiornamenti dei componenti
161
+ return [
162
+ title_update,
163
+ gr.Radio.update(label=L("language_label", new_lang)),
164
+ gr.Slider.update(label=L("results_label", new_lang)),
165
+ gr.Tab.update(label=L("plot_search_tab", new_lang)),
166
+ gr.Textbox.update(placeholder=L("plot_search_placeholder", new_lang)),
167
+ gr.Button.update(value=L("plot_search_button", new_lang)),
168
+ gr.Tab.update(label=L("title_search_tab", new_lang)),
169
+ gr.Textbox.update(placeholder=L("title_search_placeholder", new_lang)),
170
+ gr.Button.update(value=L("title_search_button", new_lang)),
171
+ gr.Dataset.update(
172
+ label=L("dataset_label", new_lang),
173
+ headers=[
174
+ L("dataset_header_title", new_lang),
175
+ L("dataset_header_author", new_lang),
176
+ L("dataset_header_year", new_lang)
177
+ ]
178
+ ),
179
+ gr.HTML.update(label=L("results_label", new_lang))
180
+ ]
181
+
182
  def search_logic(query, max_res, lang_pref):
183
+ loading_html_dynamic = LOADING_HTML.format(L("search_loading_message", lang_pref))
184
  yield gr.update(visible=True), gr.update(visible=False)
185
  if not query:
186
+ yield gr.update(visible=False), L("error_no_query", lang_pref)
187
  return
188
  try:
189
  q_emb = GoogleTranslator(source='auto', target='en').translate(query) if lang_pref == "it" else query
 
196
  yield gr.update(visible=False), f"Errore: {e}"
197
 
198
  def find_logic(title):
199
+ loading_html_dynamic = LOADING_HTML.format(L("search_loading_message", "en"))
200
  yield gr.update(visible=True), gr.update(visible=False), [], gr.update(visible=False)
201
  conn = get_turso_conn()
202
  rows = conn.execute(f"SELECT id, title, author, year FROM books WHERE title LIKE '%{title}%' LIMIT 10").fetchall()
 
224
 
225
  # --- UI ---
226
  with gr.Blocks(theme=gr.themes.Ocean(), css=GLOBAL_CSS, js=JS_FORCE_DARK) as demo:
227
+ app_title_md = gr.Markdown(f"# {L('app_title')}")
228
  books_state = gr.State([])
229
 
230
  with gr.Row():
231
+ lang_selector = gr.Radio(choices=["it", "en", "es", "fr", "de", "ru"],value=DEFAULT_LANG, label=L("language_label"))
232
+ num_results = gr.Slider(1, 10, value=5, step=1, label=L("results_label"), show_reset_button=False)
233
 
234
  with gr.Tabs() as tabs:
235
+ with gr.Tab(L("plot_search_tab")) as t1:
236
  with gr.Row():
237
+ txt_in = gr.Textbox(placeholder=L("plot_search_placeholder"), show_label=False, scale=4)
238
+ btn_search = gr.Button(L("plot_search_button"), variant="primary", scale=1)
239
 
240
+ with gr.Tab(L("title_search_tab")) as t2:
241
  with gr.Row():
242
+ txt_tit = gr.Textbox(placeholder=L("title_search_placeholder"), show_label=False, scale=4)
243
+ btn_find = gr.Button(L("title_search_button"), scale=1)
244
+ loader_list = gr.HTML(value=LOADING_HTML.format(L("search_loading_message")), visible=False)
245
 
246
  # --- CORREZIONE TABELLA QUI SOTTO ---
247
  dataset = gr.Dataset(
248
  elem_id="book_cards",
249
  components=[gr.Textbox(visible=False), gr.Textbox(visible=False), gr.Textbox(visible=False)],
250
+ headers=[L("dataset_header_title"), L("dataset_header_author"), L("dataset_header_year")],
251
+ label=L("dataset_label"),
252
  samples=[],
253
  type="index"
254
  )
255
 
256
+ loader = gr.HTML(value=LOADING_HTML.format(L("search_loading_message")), visible=False)
257
+ results = gr.HTML(label=L("results_label"), visible=True)
258
 
259
  # EVENTI
260
+ # Elenco dei componenti da aggiornare in ordine
261
+ components_to_update = [
262
+ app_title_md,
263
+ lang_selector, num_results,
264
+ t1, txt_in, btn_search,
265
+ t2, txt_tit, btn_find,
266
+ dataset,
267
+ results
268
+ ]
269
+
270
+ # Evento di cambio lingua:
271
+ lang_selector.change(
272
+ fn=update_ui_labels,
273
+ inputs=[lang_selector],
274
+ outputs=components_to_update
275
+ )
276
+
277
  btn_search.click(search_logic, [txt_in, num_results, lang_selector], [loader, results])
278
  txt_in.submit(search_logic, [txt_in, num_results, lang_selector], [loader, results])
279
 
lang.yaml ADDED
@@ -0,0 +1,180 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # lang.yaml
2
+ # --- ITALIANO (it) ---
3
+ it:
4
+ app_title: "📚 AI Book Finder"
5
+ language_label: "Lingua / Language"
6
+ results_label: "Risultati"
7
+ search_loading_message: "Ricerca in corso..."
8
+
9
+ # Ricerca Trama (Tab 1)
10
+ plot_search_tab: "🔎 Ricerca Trama"
11
+ plot_search_placeholder: "Descrivi la trama che stai cercando..."
12
+ plot_search_button: "Cerca"
13
+
14
+ # Cerca Titolo (Tab 2)
15
+ title_search_tab: "📖 Cerca Titolo"
16
+ title_search_placeholder: "Titolo..."
17
+ title_search_button: "Trova"
18
+
19
+ # Dataset/Tabella
20
+ dataset_label: "Risultati:"
21
+ dataset_header_title: "Titolo"
22
+ dataset_header_author: "Autore"
23
+ dataset_header_year: "Anno"
24
+
25
+ # Errori e messaggi di fallback
26
+ error_no_query: "Inserisci del testo."
27
+ error_db_not_configured: "Errore: Database non configurato."
28
+ error_no_results: "Nessun risultato trovato."
29
+ translation_button_label: "Traduci in Italiano"
30
+ translation_not_available: "Traduzione non disponibile."
31
+
32
+ # --- INGLESE (en) ---
33
+ en:
34
+ app_title: "📚 AI Book Finder"
35
+ language_label: "Language / Lingua"
36
+ results_label: "Results"
37
+ search_loading_message: "Searching..."
38
+
39
+ # Plot Search (Tab 1)
40
+ plot_search_tab: "🔎 Search Plot"
41
+ plot_search_placeholder: "Describe the plot you are looking for..."
42
+ plot_search_button: "Search"
43
+
44
+ # Title Search (Tab 2)
45
+ title_search_tab: "📖 Search Title"
46
+ title_search_placeholder: "Title..."
47
+ title_search_button: "Find"
48
+
49
+ # Dataset/Table
50
+ dataset_label: "Results:"
51
+ dataset_header_title: "Title"
52
+ dataset_header_author: "Author"
53
+ dataset_header_year: "Year"
54
+
55
+ # Errors and fallback messages
56
+ error_no_query: "Please enter some text."
57
+ error_db_not_configured: "Error: Database not configured."
58
+ error_no_results: "No results found."
59
+ translation_button_label: "Translate to English"
60
+ translation_not_available: "Translation not available."
61
+
62
+ # --- FRANCESE (fr) ---
63
+ fr:
64
+ app_title: "📚 AI Book Finder"
65
+ language_label: "Langue / Language"
66
+ results_label: "Résultats"
67
+ search_loading_message: "Recherche en cours..."
68
+
69
+ # Plot Search (Tab 1)
70
+ plot_search_tab: "🔎 Recherche par intrigue"
71
+ plot_search_placeholder: "Décrivez l'intrigue que vous cherchez..."
72
+ plot_search_button: "Rechercher"
73
+
74
+ # Title Search (Tab 2)
75
+ title_search_tab: "📖 Recherche par titre"
76
+ title_search_placeholder: "Titre..."
77
+ title_search_button: "Trouver"
78
+
79
+ # Dataset/Table
80
+ dataset_label: "Résultats :"
81
+ dataset_header_title: "Titre"
82
+ dataset_header_author: "Auteur"
83
+ dataset_header_year: "Année"
84
+
85
+ # Errors and fallback messages
86
+ error_no_query: "Veuillez saisir du texte."
87
+ error_db_not_configured: "Erreur : Base de données non configurée."
88
+ error_no_results: "Aucun résultat trouvé."
89
+ translation_button_label: "Traduire en français"
90
+ translation_not_available: "Traduction non disponible."
91
+
92
+ # --- SPAGNOLO (es) ---
93
+ es:
94
+ app_title: "📚 AI Book Finder"
95
+ language_label: "Idioma / Language"
96
+ results_label: "Resultados"
97
+ search_loading_message: "Buscando..."
98
+
99
+ # Plot Search (Tab 1)
100
+ plot_search_tab: "🔎 Buscar por trama"
101
+ plot_search_placeholder: "Describe la trama que buscas..."
102
+ plot_search_button: "Buscar"
103
+
104
+ # Title Search (Tab 2)
105
+ title_search_tab: "📖 Buscar por título"
106
+ title_search_placeholder: "Título..."
107
+ title_search_button: "Encontrar"
108
+
109
+ # Dataset/Table
110
+ dataset_label: "Resultados:"
111
+ dataset_header_title: "Título"
112
+ dataset_header_author: "Autor"
113
+ dataset_header_year: "Año"
114
+
115
+ # Errors and fallback messages
116
+ error_no_query: "Por favor, introduce texto."
117
+ error_db_not_configured: "Error: Base de datos no configurada."
118
+ error_no_results: "No se encontraron resultados."
119
+ translation_button_label: "Traducir al español"
120
+ translation_not_available: "Traducción no disponible."
121
+
122
+ # --- TEDESCO (de) ---
123
+ de:
124
+ app_title: "📚 AI Book Finder"
125
+ language_label: "Sprache / Language"
126
+ results_label: "Ergebnisse"
127
+ search_loading_message: "Suche läuft..."
128
+
129
+ # Plot Search (Tab 1)
130
+ plot_search_tab: "🔎 Suche nach Handlung"
131
+ plot_search_placeholder: "Beschreiben Sie die Handlung..."
132
+ plot_search_button: "Suchen"
133
+
134
+ # Title Search (Tab 2)
135
+ title_search_tab: "📖 Suche nach Titel"
136
+ title_search_placeholder: "Titel..."
137
+ title_search_button: "Finden"
138
+
139
+ # Dataset/Table
140
+ dataset_label: "Ergebnisse:"
141
+ dataset_header_title: "Titel"
142
+ dataset_header_author: "Autor"
143
+ dataset_header_year: "Jahr"
144
+
145
+ # Errors and fallback messages
146
+ error_no_query: "Bitte geben Sie Text ein."
147
+ error_db_not_configured: "Fehler: Datenbank nicht konfiguriert."
148
+ error_no_results: "Keine Ergebnisse gefunden."
149
+ translation_button_label: "Auf Deutsch übersetzen"
150
+ translation_not_available: "Übersetzung nicht verfügbar."
151
+
152
+ # --- RUSSO (ru) ---
153
+ ru:
154
+ app_title: "📚 AI Book Finder"
155
+ language_label: "Язык / Language"
156
+ results_label: "Результаты"
157
+ search_loading_message: "Поиск..."
158
+
159
+ # Plot Search (Tab 1)
160
+ plot_search_tab: "🔎 Поиск п�� сюжету"
161
+ plot_search_placeholder: "Опишите сюжет, который вы ищете..."
162
+ plot_search_button: "Поиск"
163
+
164
+ # Title Search (Tab 2)
165
+ title_search_tab: "📖 Поиск по названию"
166
+ title_search_placeholder: "Название..."
167
+ title_search_button: "Найти"
168
+
169
+ # Dataset/Table
170
+ dataset_label: "Результаты:"
171
+ dataset_header_title: "Название"
172
+ dataset_header_author: "Автор"
173
+ dataset_header_year: "Год"
174
+
175
+ # Errors and fallback messages
176
+ error_no_query: "Пожалуйста, введите текст."
177
+ error_db_not_configured: "Ошибка: База данных не настроена."
178
+ error_no_results: "Результаты не найдены."
179
+ translation_button_label: "Перевести на русский"
180
+ translation_not_available: "Перевод недоступен."