ALVHB95 commited on
Commit
76b4e6a
·
1 Parent(s): f043359
Files changed (1) hide show
  1. app.py +30 -34
app.py CHANGED
@@ -4,6 +4,7 @@
4
  - Chat tab uses Blocks + Chatbot(height=...) ✅
5
  - LLM: meta-llama/Meta-Llama-3.1-8B-Instruct ✅
6
  - RAG: e5-base-v2 + (BM25+Vector) with safe fallback + Multi-Query + reranker ✅
 
7
  - No JSON output leakage ✅
8
  =========================================================
9
  """
@@ -19,7 +20,7 @@ os.environ.setdefault("GRADIO_ANALYTICS_ENABLED", "False")
19
  os.environ.setdefault("ANONYMIZED_TELEMETRY", "false")
20
  os.environ.setdefault("CHROMA_TELEMETRY_ENABLED", "FALSE")
21
  os.environ.setdefault("USER_AGENT", "green-greta/1.0 (+contact-or-repo)")
22
- # Optional: more reproducible CPU math (silences some TF logs)
23
  # os.environ.setdefault("TF_ENABLE_ONEDNN_OPTS", "0")
24
 
25
  import gradio as gr
@@ -51,7 +52,7 @@ except ImportError:
51
 
52
  # Retrieval utilities
53
  from langchain.retrievers import ContextualCompressionRetriever, EnsembleRetriever
54
- from langchain.retrievers.document_compressors import DocumentCompressorPipeline, CrossEncoderReranker
55
  from langchain.retrievers.multi_query import MultiQueryRetriever
56
 
57
  from langchain_community.retrievers import BM25Retriever
@@ -157,26 +158,17 @@ if use_bm25:
157
  else:
158
  base_retriever = vec_retriever
159
 
160
- # Fine-grained compressor (splitter)
161
- try:
162
- from langchain_text_splitters import TokenTextSplitter
163
- splitter_for_compression = TokenTextSplitter(chunk_size=220, chunk_overlap=30) # needs tiktoken
164
- except Exception:
165
- from langchain_text_splitters import RecursiveCharacterTextSplitter as FallbackSplitter
166
- splitter_for_compression = FallbackSplitter(chunk_size=300, chunk_overlap=50)
167
-
168
- compressor_pipeline = DocumentCompressorPipeline(transformers=[splitter_for_compression])
169
-
170
  # ======================================
171
- # 3) PROMPT (NO JSON INSTRUCTIONS)
172
  # ======================================
173
  SYSTEM_TEMPLATE = (
174
- "Eres Greta, una asistente bilingüe (ES/EN) experta en reciclaje y sostenibilidad. "
175
- "Responde en el idioma del usuario, de forma directa, práctica y basada en los fragmentos. "
176
- "Si la información no está en los fragmentos, dilo claramente y sugiere pasos útiles. "
177
- "No inventes datos ni menciones la palabra 'fragmentos'.\n\n"
 
178
  "{context}\n\n"
179
- "Pregunta: {question}"
180
  )
181
  qa_prompt = ChatPromptTemplate.from_template(SYSTEM_TEMPLATE)
182
 
@@ -205,10 +197,10 @@ memory = ConversationBufferMemory(
205
  return_messages=True,
206
  )
207
 
208
- # Multi-Query to boost recall
209
  mqr = MultiQueryRetriever.from_llm(retriever=base_retriever, llm=llm, include_original=True)
210
 
211
- # Cross-encoder reranker (lighter)
212
  cross_encoder = HuggingFaceCrossEncoder(model_name="BAAI/bge-reranker-base")
213
  reranker = CrossEncoderReranker(model=cross_encoder, top_n=4)
214
 
@@ -225,16 +217,16 @@ qa_chain = ConversationalRetrievalChain.from_llm(
225
  combine_docs_chain_kwargs={"prompt": qa_prompt},
226
  get_chat_history=lambda h: h,
227
  rephrase_question=False,
228
- return_source_documents=False, # we only need the final answer
229
  )
230
 
231
- def chat_interface(question, history):
232
- """Wrap the RAG chain to return a clean text answer."""
233
  try:
234
- result = qa_chain.invoke({"question": question})
235
  answer = result.get("answer", "")
236
  if not answer:
237
- return "Lo siento, no pude generar una respuesta útil con los fragmentos disponibles."
238
  return answer
239
  except Exception as e:
240
  return (
@@ -270,9 +262,11 @@ banner_tab_content = """
270
  banner_tab = gr.Markdown(banner_tab_content)
271
 
272
  # ============================
273
- # 7) Chat tab (Blocks + Chatbot with height) OPTION A
274
  # ============================
275
 
 
 
276
  # CSS: make chat area taller and widen app a bit
277
  custom_css = """
278
  .gradio-container { max-width: 1200px !important; }
@@ -288,16 +282,18 @@ def _user_submit(user_msg, history):
288
  history = history + [[user_msg, None]]
289
  return "", history
290
 
291
- def _bot_respond(history):
292
- """Generate bot answer for the last user turn."""
293
  user_msg = history[-1][0]
294
  # Pass previous history to our RAG function (excluding the current empty bot turn)
295
- answer = chat_interface(user_msg, history[:-1])
296
  history[-1][1] = answer
297
  return history
298
 
299
  with gr.Blocks(theme=theme, css=custom_css) as chatbot_gradio_app:
300
  gr.Markdown("<h1 style='text-align:center;color:#f3efe0;'>Green Greta</h1>")
 
 
301
  chat = gr.Chatbot(label="Chatbot", height=700, elem_id="greta-chat", show_copy_button=True)
302
  with gr.Row():
303
  msg = gr.Textbox(placeholder="Type a message…", scale=9)
@@ -307,21 +303,21 @@ with gr.Blocks(theme=theme, css=custom_css) as chatbot_gradio_app:
307
  undo = gr.Button("↩︎ Undo")
308
  clear = gr.Button("🗑 Clear")
309
 
310
- # Submit via button or Enter
311
  send.click(_user_submit, [msg, chat], [msg, chat], queue=False).then(
312
- _bot_respond, [chat], [chat]
313
  )
314
  msg.submit(_user_submit, [msg, chat], [msg, chat], queue=False).then(
315
- _bot_respond, [chat], [chat]
316
  )
317
 
318
- # Utilities
319
  clear.click(lambda: [], None, chat, queue=False)
320
  undo.click(lambda h: h[:-1] if h else h, chat, chat, queue=False)
321
  retry.click(
322
  lambda h: (h[:-1] + [[h[-1][0], None]]) if h else h, # re-ask last user msg
323
  chat, chat, queue=False
324
- ).then(_bot_respond, [chat], [chat])
325
 
326
  # ============================
327
  # 8) Tabs + launch
 
4
  - Chat tab uses Blocks + Chatbot(height=...) ✅
5
  - LLM: meta-llama/Meta-Llama-3.1-8B-Instruct ✅
6
  - RAG: e5-base-v2 + (BM25+Vector) with safe fallback + Multi-Query + reranker ✅
7
+ - Language selector: Auto, English, German, French, Italian, Portuguese, Hindi, Spanish, Thai ✅
8
  - No JSON output leakage ✅
9
  =========================================================
10
  """
 
20
  os.environ.setdefault("ANONYMIZED_TELEMETRY", "false")
21
  os.environ.setdefault("CHROMA_TELEMETRY_ENABLED", "FALSE")
22
  os.environ.setdefault("USER_AGENT", "green-greta/1.0 (+contact-or-repo)")
23
+ # Optional: reproducible CPU math (silences some TF logs)
24
  # os.environ.setdefault("TF_ENABLE_ONEDNN_OPTS", "0")
25
 
26
  import gradio as gr
 
52
 
53
  # Retrieval utilities
54
  from langchain.retrievers import ContextualCompressionRetriever, EnsembleRetriever
55
+ from langchain.retrievers.document_compressors import CrossEncoderReranker
56
  from langchain.retrievers.multi_query import MultiQueryRetriever
57
 
58
  from langchain_community.retrievers import BM25Retriever
 
158
  else:
159
  base_retriever = vec_retriever
160
 
 
 
 
 
 
 
 
 
 
 
161
  # ======================================
162
+ # 3) PROMPT (with target language variable)
163
  # ======================================
164
  SYSTEM_TEMPLATE = (
165
+ "You are Greta, a bilingual recycling & sustainability assistant.\n"
166
+ "- Always answer in the *target language*: {target_language}.\n"
167
+ "- If target_language is 'Auto', detect the user's language and answer in that language.\n"
168
+ "- Be direct, practical, and base your answer only on the snippets below; if they are insufficient, say so and propose actionable next steps.\n"
169
+ "- Do not reveal or mention 'snippets' or internal tools.\n\n"
170
  "{context}\n\n"
171
+ "Question: {question}"
172
  )
173
  qa_prompt = ChatPromptTemplate.from_template(SYSTEM_TEMPLATE)
174
 
 
197
  return_messages=True,
198
  )
199
 
200
+ # Multi-Query boosts recall by generating paraphrases
201
  mqr = MultiQueryRetriever.from_llm(retriever=base_retriever, llm=llm, include_original=True)
202
 
203
+ # Cross-encoder reranker (lighter/faster than large)
204
  cross_encoder = HuggingFaceCrossEncoder(model_name="BAAI/bge-reranker-base")
205
  reranker = CrossEncoderReranker(model=cross_encoder, top_n=4)
206
 
 
217
  combine_docs_chain_kwargs={"prompt": qa_prompt},
218
  get_chat_history=lambda h: h,
219
  rephrase_question=False,
220
+ return_source_documents=False,
221
  )
222
 
223
+ def chat_interface(question: str, history, target_language: str = "Auto"):
224
+ """Wrap the RAG chain to return a clean text answer in the requested language."""
225
  try:
226
+ result = qa_chain.invoke({"question": question, "target_language": target_language})
227
  answer = result.get("answer", "")
228
  if not answer:
229
+ return "Sorry, I couldn't produce a useful answer from the available information."
230
  return answer
231
  except Exception as e:
232
  return (
 
262
  banner_tab = gr.Markdown(banner_tab_content)
263
 
264
  # ============================
265
+ # 7) Chat tab (Blocks + Chatbot with height + language selector)
266
  # ============================
267
 
268
+ SUPPORTED_LANGS = ["Auto", "English", "German", "French", "Italian", "Portuguese", "Hindi", "Spanish", "Thai"]
269
+
270
  # CSS: make chat area taller and widen app a bit
271
  custom_css = """
272
  .gradio-container { max-width: 1200px !important; }
 
282
  history = history + [[user_msg, None]]
283
  return "", history
284
 
285
+ def _bot_respond(history, target_language):
286
+ """Generate bot answer for the last user turn in the requested language."""
287
  user_msg = history[-1][0]
288
  # Pass previous history to our RAG function (excluding the current empty bot turn)
289
+ answer = chat_interface(user_msg, history[:-1], target_language=target_language or "Auto")
290
  history[-1][1] = answer
291
  return history
292
 
293
  with gr.Blocks(theme=theme, css=custom_css) as chatbot_gradio_app:
294
  gr.Markdown("<h1 style='text-align:center;color:#f3efe0;'>Green Greta</h1>")
295
+ with gr.Row():
296
+ lang_sel = gr.Dropdown(SUPPORTED_LANGS, value="Auto", label="Answer language")
297
  chat = gr.Chatbot(label="Chatbot", height=700, elem_id="greta-chat", show_copy_button=True)
298
  with gr.Row():
299
  msg = gr.Textbox(placeholder="Type a message…", scale=9)
 
303
  undo = gr.Button("↩︎ Undo")
304
  clear = gr.Button("🗑 Clear")
305
 
306
+ # Submit via button or Enter (pass language value into the responder)
307
  send.click(_user_submit, [msg, chat], [msg, chat], queue=False).then(
308
+ _bot_respond, [chat, lang_sel], [chat]
309
  )
310
  msg.submit(_user_submit, [msg, chat], [msg, chat], queue=False).then(
311
+ _bot_respond, [chat, lang_sel], [chat]
312
  )
313
 
314
+ # Utilities respect current language selection too
315
  clear.click(lambda: [], None, chat, queue=False)
316
  undo.click(lambda h: h[:-1] if h else h, chat, chat, queue=False)
317
  retry.click(
318
  lambda h: (h[:-1] + [[h[-1][0], None]]) if h else h, # re-ask last user msg
319
  chat, chat, queue=False
320
+ ).then(_bot_respond, [chat, lang_sel], [chat])
321
 
322
  # ============================
323
  # 8) Tabs + launch