Prathamesh1420 commited on
Commit
04771f5
Β·
verified Β·
1 Parent(s): 3d7d1bb

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +199 -102
app.py CHANGED
@@ -3,7 +3,7 @@ import mauve
3
  from sacrebleu import corpus_bleu
4
  from rouge_score import rouge_scorer
5
  from bert_score import score
6
- from transformers import GPT2LMHeadModel, GPT2Tokenizer, pipeline, AutoTokenizer
7
  import re
8
  from mauve import compute_mauve
9
  import os
@@ -54,7 +54,6 @@ class RAGEvaluator:
54
  tokenizer = GPT2Tokenizer.from_pretrained('gpt2')
55
  return model, tokenizer
56
 
57
- # BLEU, ROUGE
58
  def evaluate_bleu_rouge(self, candidates, references):
59
  try:
60
  bleu_score = corpus_bleu(candidates, [references]).score
@@ -68,7 +67,6 @@ class RAGEvaluator:
68
  print(f"BLEU/ROUGE evaluation failed: {e}")
69
  return 0, 0, 0, 0
70
 
71
- # BERT Score
72
  def evaluate_bert_score(self, candidates, references):
73
  try:
74
  P, R, F1 = score(candidates, references, lang="en", model_type='bert-base-multilingual-cased')
@@ -77,7 +75,6 @@ class RAGEvaluator:
77
  print(f"BERT score evaluation failed: {e}")
78
  return 0, 0, 0
79
 
80
- # Perplexity
81
  def evaluate_perplexity(self, text):
82
  try:
83
  encodings = self.gpt2_tokenizer(text, return_tensors='pt')
@@ -99,9 +96,8 @@ class RAGEvaluator:
99
  return ppl.item()
100
  except Exception as e:
101
  print(f"Perplexity evaluation failed: {e}")
102
- return 1000.0 # High perplexity indicates error
103
 
104
- # Diversity
105
  def evaluate_diversity(self, texts):
106
  try:
107
  all_tokens = []
@@ -116,7 +112,6 @@ class RAGEvaluator:
116
  print(f"Diversity evaluation failed: {e}")
117
  return 0
118
 
119
- # Racial bias
120
  def evaluate_racial_bias(self, text):
121
  try:
122
  results = self.bias_pipeline([text], candidate_labels=["hate speech", "not hate speech"])
@@ -126,7 +121,6 @@ class RAGEvaluator:
126
  print(f"Bias evaluation failed: {e}")
127
  return 0
128
 
129
- # METEOR
130
  def evaluate_meteor(self, candidates, references):
131
  try:
132
  meteor_scores = []
@@ -146,7 +140,6 @@ class RAGEvaluator:
146
  print(f"METEOR evaluation failed: {e}")
147
  return 0
148
 
149
- # CHRF
150
  def evaluate_chrf(self, candidates, references):
151
  try:
152
  chrf_scores = []
@@ -169,7 +162,6 @@ class RAGEvaluator:
169
  print(f"CHRF evaluation failed: {e}")
170
  return 0
171
 
172
- # Readability
173
  def evaluate_readability(self, text):
174
  try:
175
  words = re.findall(r'\b\w+\b', text.lower())
@@ -185,7 +177,6 @@ class RAGEvaluator:
185
  print(f"Readability evaluation failed: {e}")
186
  return 0, 0
187
 
188
- # MAUVE
189
  def evaluate_mauve(self, reference_texts, generated_texts):
190
  try:
191
  out = compute_mauve(
@@ -276,16 +267,98 @@ def get_retrieved_context(query: str, top_k=3):
276
  if mlflow.active_run():
277
  mlflow.log_metric("retrieved_chunks", len(results['matches']))
278
 
279
- return "\n".join([m['metadata']['text'] for m in results['matches']])
 
280
  except Exception as e:
281
  print(f"Context retrieval failed: {e}")
282
  return f"Context retrieval error: {str(e)}"
283
 
284
- # ------------------ Custom LLM ------------------
285
- class LitServeLLM(LLM):
286
- endpoint_url: str
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
287
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
288
  def _call(self, prompt: str, stop: Optional[List[str]] = None) -> str:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
289
  try:
290
  payload = {"prompt": prompt}
291
  start_time = time.time()
@@ -298,43 +371,52 @@ class LitServeLLM(LLM):
298
  data = response.json()
299
  if mlflow.active_run():
300
  mlflow.log_metric("response_tokens", len(data.get("response", "").split()))
301
- return data.get("response", "").strip()
302
  else:
303
  if mlflow.active_run():
304
  mlflow.log_metric("request_errors", 1)
305
- error_msg = f"Request failed with status {response.status_code}"
306
- print(f"LLM Error: {error_msg}")
307
- return f"I apologize, but I'm currently experiencing technical difficulties. Error: {error_msg}"
308
 
309
- except requests.exceptions.Timeout:
310
- error_msg = "Request timeout - service unavailable"
311
- print(f"LLM Timeout: {error_msg}")
312
- return f"I apologize, but the service is currently unavailable. Please try again later."
313
  except Exception as e:
314
- error_msg = f"Connection error: {str(e)}"
315
- print(f"LLM Connection Error: {error_msg}")
316
- return f"I apologize, but I'm having trouble connecting to the service. Please try again later."
 
 
 
 
 
 
 
 
 
 
317
 
318
  @property
319
  def _identifying_params(self) -> Mapping[str, Any]:
320
- return {"endpoint_url": self.endpoint_url}
321
 
322
  @property
323
  def _llm_type(self) -> str:
324
- return "litserve_llm"
325
 
326
- # Initialize model with fallback
327
  try:
328
- model = LitServeLLM(endpoint_url="https://8001-01k2h9d9mervcmgfn66ybkpwvq.cloudspaces.litng.ai/predict")
 
 
 
 
329
  except Exception as e:
330
- print(f"Model initialization failed: {e}")
331
  model = None
332
 
 
333
  prompt = PromptTemplate(
334
  input_variables=["context", "question"],
335
  template="""
336
- You are a smart assistant. Based on the provided context, answer the question in 1–2 lines only.
337
- If the context has more details, summarize it concisely.
338
 
339
  Context:
340
  {context}
@@ -345,63 +427,71 @@ Answer:
345
  """
346
  )
347
 
348
- # Initialize chain with error handling
349
  try:
350
  if model:
351
  llm_chain = LLMChain(llm=model, prompt=prompt)
 
352
  else:
353
  llm_chain = None
354
- print("LLM chain not initialized due to model failure")
355
  except Exception as e:
356
  print(f"LLM chain initialization failed: {e}")
357
  llm_chain = None
358
 
359
  # ------------------ RAG Pipeline ------------------
360
  def get_rag_response(question):
361
- """Get the complete RAG response with error handling"""
362
  try:
363
- # Get context
 
 
 
364
  retrieved_context = get_retrieved_context(question)
365
 
366
- # If LLM chain is not available, return fallback response
367
- if not llm_chain:
368
- fallback_response = "I'm currently experiencing technical difficulties. Please try again later or contact support."
 
 
 
 
 
 
 
 
 
 
 
 
 
369
  return fallback_response, retrieved_context
370
-
371
- # Get response from LLM
372
- result = llm_chain.invoke({
373
- "context": retrieved_context,
374
- "question": question
375
- })
376
-
377
- full_response = result["text"].strip()
378
-
379
- if "Answer:" in full_response:
380
- full_response = full_response.split("Answer:", 1)[-1].strip()
381
-
382
- return full_response, retrieved_context
383
-
384
  except Exception as e:
385
- error_msg = f"Error generating response: {str(e)}"
386
- print(f"RAG pipeline error: {error_msg}")
387
- return f"I apologize, but I encountered an error while processing your request. Please try again. Error: {str(e)}", "Error retrieving context"
 
 
 
 
388
 
389
  def rag_pipeline_stream(question):
390
  """Streaming version of RAG pipeline"""
391
  try:
392
  full_response, _ = get_rag_response(question)
393
 
394
- # Stream word by word
395
  words = full_response.split()
396
  current_text = ""
397
  for word in words:
398
  current_text += word + " "
399
  yield current_text
400
- time.sleep(0.05) # Adjust speed as needed
401
 
402
  except Exception as e:
403
  error_msg = f"Error in streaming: {str(e)}"
404
- print(f"Streaming error: {error_msg}")
405
  yield "I apologize, but I encountered an error while generating the response."
406
 
407
  # ------------------ Gradio UI ------------------
@@ -409,6 +499,8 @@ with gr.Blocks(theme=gr.themes.Soft(), title="Maintenance AI Assistant") as demo
409
  gr.Markdown("""
410
  # πŸ›  Maintenance AI Assistant
411
  *Your intelligent companion for maintenance queries and troubleshooting*
 
 
412
  """)
413
 
414
  usage_counter = gr.State(value=0)
@@ -420,10 +512,14 @@ with gr.Blocks(theme=gr.themes.Soft(), title="Maintenance AI Assistant") as demo
420
  gr.Markdown("### πŸ’¬ Chat Interface")
421
  question_input = gr.Textbox(
422
  label="Ask your maintenance question",
423
- placeholder="e.g., How do I troubleshoot a leaking valve?",
424
- lines=2
425
  )
426
- ask_button = gr.Button("Get Answer πŸš€", variant="primary")
 
 
 
 
427
 
428
  feedback = gr.Radio(
429
  ["Helpful", "Not Helpful"],
@@ -431,21 +527,22 @@ with gr.Blocks(theme=gr.themes.Soft(), title="Maintenance AI Assistant") as demo
431
  info="Your feedback helps improve the system"
432
  )
433
 
434
- gr.Markdown("### πŸ“Š Evaluation Metrics")
435
- metrics_output = gr.JSON(label="Quality Metrics", visible=False)
436
-
437
  with gr.Column(scale=1):
438
  gr.Markdown("### πŸ€– AI Response")
439
  answer_output = gr.Textbox(
440
  label="Response",
441
- lines=6,
442
  interactive=False,
443
- show_copy_button=True
 
444
  )
445
 
446
- with gr.Row():
447
- clear_btn = gr.Button("Clear Chat πŸ—‘οΈ")
448
- evaluate_btn = gr.Button("Show Metrics πŸ“ˆ", variant="secondary")
 
 
 
449
 
450
  def track_usage(question, count, session_start, feedback_value=None):
451
  """Track usage and get response"""
@@ -455,8 +552,9 @@ with gr.Blocks(theme=gr.themes.Soft(), title="Maintenance AI Assistant") as demo
455
  count += 1
456
 
457
  try:
458
- with mlflow.start_run(run_name=f"User-Interaction-{count}", nested=True) if mlflow_tracking_uri else dummy_context():
459
- if mlflow_tracking_uri:
 
460
  mlflow.log_param("question", question)
461
  mlflow.log_param("session_start", session_start)
462
  mlflow.log_param("user_feedback", feedback_value or "No feedback")
@@ -465,36 +563,38 @@ with gr.Blocks(theme=gr.themes.Soft(), title="Maintenance AI Assistant") as demo
465
  mlflow.log_metric("helpful_responses", 1 if feedback_value == "Helpful" else 0)
466
 
467
  mlflow.log_metric("total_queries", count)
468
-
469
- # Get response and context
470
- response, context = get_rag_response(question)
471
-
472
- if mlflow_tracking_uri:
473
  mlflow.log_metric("response_length", len(response))
474
  mlflow.log_metric("response_tokens", len(response.split()))
475
-
 
 
 
 
 
476
  return response, count, session_start, response
477
 
478
  except Exception as e:
479
  print(f"Tracking error: {e}")
480
- error_msg = f"System error: {str(e)}"
481
- return error_msg, count, session_start, error_msg
482
 
483
  def evaluate_response(question, response):
484
  """Evaluate the response and return metrics"""
485
- if not question or not response or "error" in response.lower() or "apologize" in response.lower():
486
- return gr.update(value={"info": "Evaluation skipped due to error response"}, visible=True)
 
 
 
 
487
 
488
  try:
489
  context = get_retrieved_context(question)
490
  metrics = evaluator.evaluate_all(question, response, context)
491
 
492
- # Log metrics to MLflow if available
493
- if mlflow_tracking_uri and mlflow.active_run():
494
- for metric_name, metric_value in metrics.items():
495
- if isinstance(metric_value, (int, float)):
496
- mlflow.log_metric(metric_name, metric_value)
497
-
498
  return gr.update(value=metrics, visible=True)
499
  except Exception as e:
500
  print(f"Evaluation error: {e}")
@@ -504,16 +604,9 @@ with gr.Blocks(theme=gr.themes.Soft(), title="Maintenance AI Assistant") as demo
504
  """Clear the chat interface"""
505
  return "", "", gr.update(visible=False)
506
 
507
- # Dummy context manager for when MLflow is not available
508
- class dummy_context:
509
- def __enter__(self):
510
- return self
511
- def __exit__(self, *args):
512
- pass
513
-
514
  # Main interaction flow
515
  ask_button.click(
516
- fn=lambda: ("", gr.update(visible=False)), # Clear previous metrics
517
  outputs=[answer_output, metrics_output]
518
  ).then(
519
  fn=rag_pipeline_stream,
@@ -538,14 +631,13 @@ with gr.Blocks(theme=gr.themes.Soft(), title="Maintenance AI Assistant") as demo
538
  outputs=[question_input, answer_output, metrics_output]
539
  )
540
 
541
- # Feedback handling
542
  def handle_feedback(feedback_val):
543
  try:
544
  if mlflow_tracking_uri and mlflow.active_run():
545
  mlflow.log_metric("user_feedback_score", 1 if feedback_val == "Helpful" else 0)
546
  except:
547
- pass
548
- return
549
 
550
  feedback.change(
551
  fn=handle_feedback,
@@ -554,9 +646,14 @@ with gr.Blocks(theme=gr.themes.Soft(), title="Maintenance AI Assistant") as demo
554
  )
555
 
556
  if __name__ == "__main__":
 
 
 
 
557
  demo.launch(
558
  server_name="0.0.0.0",
559
  server_port=7860,
560
- share=False, # Disable sharing to avoid the warning
561
- show_error=True
 
562
  )
 
3
  from sacrebleu import corpus_bleu
4
  from rouge_score import rouge_scorer
5
  from bert_score import score
6
+ from transformers import GPT2LMHeadModel, GPT2Tokenizer, pipeline, AutoTokenizer, AutoModelForCausalLM
7
  import re
8
  from mauve import compute_mauve
9
  import os
 
54
  tokenizer = GPT2Tokenizer.from_pretrained('gpt2')
55
  return model, tokenizer
56
 
 
57
  def evaluate_bleu_rouge(self, candidates, references):
58
  try:
59
  bleu_score = corpus_bleu(candidates, [references]).score
 
67
  print(f"BLEU/ROUGE evaluation failed: {e}")
68
  return 0, 0, 0, 0
69
 
 
70
  def evaluate_bert_score(self, candidates, references):
71
  try:
72
  P, R, F1 = score(candidates, references, lang="en", model_type='bert-base-multilingual-cased')
 
75
  print(f"BERT score evaluation failed: {e}")
76
  return 0, 0, 0
77
 
 
78
  def evaluate_perplexity(self, text):
79
  try:
80
  encodings = self.gpt2_tokenizer(text, return_tensors='pt')
 
96
  return ppl.item()
97
  except Exception as e:
98
  print(f"Perplexity evaluation failed: {e}")
99
+ return 1000.0
100
 
 
101
  def evaluate_diversity(self, texts):
102
  try:
103
  all_tokens = []
 
112
  print(f"Diversity evaluation failed: {e}")
113
  return 0
114
 
 
115
  def evaluate_racial_bias(self, text):
116
  try:
117
  results = self.bias_pipeline([text], candidate_labels=["hate speech", "not hate speech"])
 
121
  print(f"Bias evaluation failed: {e}")
122
  return 0
123
 
 
124
  def evaluate_meteor(self, candidates, references):
125
  try:
126
  meteor_scores = []
 
140
  print(f"METEOR evaluation failed: {e}")
141
  return 0
142
 
 
143
  def evaluate_chrf(self, candidates, references):
144
  try:
145
  chrf_scores = []
 
162
  print(f"CHRF evaluation failed: {e}")
163
  return 0
164
 
 
165
  def evaluate_readability(self, text):
166
  try:
167
  words = re.findall(r'\b\w+\b', text.lower())
 
177
  print(f"Readability evaluation failed: {e}")
178
  return 0, 0
179
 
 
180
  def evaluate_mauve(self, reference_texts, generated_texts):
181
  try:
182
  out = compute_mauve(
 
267
  if mlflow.active_run():
268
  mlflow.log_metric("retrieved_chunks", len(results['matches']))
269
 
270
+ context_texts = [m['metadata']['text'] for m in results['matches']]
271
+ return "\n".join(context_texts) if context_texts else "No relevant context found."
272
  except Exception as e:
273
  print(f"Context retrieval failed: {e}")
274
  return f"Context retrieval error: {str(e)}"
275
 
276
+ # ------------------ Fallback LLM Models ------------------
277
+ class FallbackLLM:
278
+ def __init__(self):
279
+ self.models_loaded = False
280
+ self.pipeline = None
281
+ self.load_fallback_models()
282
+
283
+ def load_fallback_models(self):
284
+ """Load local models as fallback"""
285
+ try:
286
+ # Use a smaller model for fallback
287
+ self.pipeline = pipeline(
288
+ "text-generation",
289
+ model="microsoft/DialoGPT-small",
290
+ tokenizer="microsoft/DialoGPT-small",
291
+ max_length=150,
292
+ do_sample=True,
293
+ temperature=0.7
294
+ )
295
+ self.models_loaded = True
296
+ print("Fallback model loaded successfully")
297
+ except Exception as e:
298
+ print(f"Fallback model loading failed: {e}")
299
+ self.models_loaded = False
300
+
301
+ def generate_response(self, context, question):
302
+ if not self.models_loaded:
303
+ return "I'm currently experiencing technical difficulties. Please try again later."
304
+
305
+ try:
306
+ prompt = f"""
307
+ Based on the following context, please provide a concise answer to the question.
308
 
309
+ Context: {context}
310
+
311
+ Question: {question}
312
+
313
+ Answer: """
314
+
315
+ response = self.pipeline(
316
+ prompt,
317
+ max_new_tokens=100,
318
+ num_return_sequences=1,
319
+ pad_token_id=50256
320
+ )
321
+
322
+ if response and len(response) > 0:
323
+ full_response = response[0]['generated_text']
324
+ # Extract only the answer part
325
+ if "Answer:" in full_response:
326
+ answer = full_response.split("Answer:")[-1].strip()
327
+ return answer
328
+ return full_response.strip()
329
+ else:
330
+ return "I couldn't generate a response at the moment. Please try again."
331
+
332
+ except Exception as e:
333
+ print(f"Fallback model generation failed: {e}")
334
+ return "I'm having trouble generating a response. Please try again later."
335
+
336
+ # Initialize fallback LLM
337
+ fallback_llm = FallbackLLM()
338
+
339
+ # ------------------ Custom LLM with Fallback ------------------
340
+ class RobustLitServeLLM(LLM):
341
+ endpoint_url: str
342
+ use_fallback: bool = True
343
+
344
  def _call(self, prompt: str, stop: Optional[List[str]] = None) -> str:
345
+ # Try the primary endpoint first
346
+ primary_success, primary_response = self._try_primary_endpoint(prompt)
347
+
348
+ if primary_success:
349
+ return primary_response
350
+
351
+ # If primary fails and fallback is enabled, use fallback
352
+ if self.use_fallback:
353
+ print("Using fallback LLM due to primary endpoint failure")
354
+ # Extract context and question from prompt
355
+ context, question = self._extract_context_question(prompt)
356
+ return fallback_llm.generate_response(context, question)
357
+ else:
358
+ return "I apologize, but the AI service is currently unavailable. Please try again later."
359
+
360
+ def _try_primary_endpoint(self, prompt: str):
361
+ """Try to get response from primary endpoint"""
362
  try:
363
  payload = {"prompt": prompt}
364
  start_time = time.time()
 
371
  data = response.json()
372
  if mlflow.active_run():
373
  mlflow.log_metric("response_tokens", len(data.get("response", "").split()))
374
+ return True, data.get("response", "").strip()
375
  else:
376
  if mlflow.active_run():
377
  mlflow.log_metric("request_errors", 1)
378
+ print(f"Primary endpoint failed with status: {response.status_code}")
379
+ return False, ""
 
380
 
 
 
 
 
381
  except Exception as e:
382
+ print(f"Primary endpoint error: {e}")
383
+ return False, ""
384
+
385
+ def _extract_context_question(self, prompt: str):
386
+ """Extract context and question from the prompt template"""
387
+ try:
388
+ if "Context:" in prompt and "Question:" in prompt:
389
+ context_part = prompt.split("Context:")[1].split("Question:")[0].strip()
390
+ question_part = prompt.split("Question:")[1].split("Answer:")[0].strip()
391
+ return context_part, question_part
392
+ return "", prompt
393
+ except:
394
+ return "", prompt
395
 
396
  @property
397
  def _identifying_params(self) -> Mapping[str, Any]:
398
+ return {"endpoint_url": self.endpoint_url, "use_fallback": self.use_fallback}
399
 
400
  @property
401
  def _llm_type(self) -> str:
402
+ return "robust_litserve_llm"
403
 
404
+ # Initialize the robust model
405
  try:
406
+ model = RobustLitServeLLM(
407
+ endpoint_url="https://8001-01k2h9d9mervcmgfn66ybkpwvq.cloudspaces.litng.ai/predict",
408
+ use_fallback=True
409
+ )
410
+ print("Robust LLM initialized successfully")
411
  except Exception as e:
412
+ print(f"Robust LLM initialization failed: {e}")
413
  model = None
414
 
415
+ # ------------------ Prompt Template ------------------
416
  prompt = PromptTemplate(
417
  input_variables=["context", "question"],
418
  template="""
419
+ You are a smart maintenance assistant. Based on the provided context, answer the question concisely in 1-2 lines.
 
420
 
421
  Context:
422
  {context}
 
427
  """
428
  )
429
 
430
+ # Initialize LLM chain
431
  try:
432
  if model:
433
  llm_chain = LLMChain(llm=model, prompt=prompt)
434
+ print("LLM chain initialized successfully")
435
  else:
436
  llm_chain = None
437
+ print("LLM chain not initialized - no model available")
438
  except Exception as e:
439
  print(f"LLM chain initialization failed: {e}")
440
  llm_chain = None
441
 
442
  # ------------------ RAG Pipeline ------------------
443
  def get_rag_response(question):
444
+ """Get the complete RAG response with robust error handling"""
445
  try:
446
+ if not question.strip():
447
+ return "Please enter a valid question.", ""
448
+
449
+ # Get context from Pinecone
450
  retrieved_context = get_retrieved_context(question)
451
 
452
+ # If we have an LLM chain, use it
453
+ if llm_chain:
454
+ result = llm_chain.invoke({
455
+ "context": retrieved_context,
456
+ "question": question
457
+ })
458
+ full_response = result["text"].strip()
459
+
460
+ # Clean up the response
461
+ if "Answer:" in full_response:
462
+ full_response = full_response.split("Answer:")[-1].strip()
463
+
464
+ return full_response, retrieved_context
465
+ else:
466
+ # Use direct fallback
467
+ fallback_response = fallback_llm.generate_response(retrieved_context, question)
468
  return fallback_response, retrieved_context
469
+
 
 
 
 
 
 
 
 
 
 
 
 
 
470
  except Exception as e:
471
+ error_msg = f"Error in RAG pipeline: {str(e)}"
472
+ print(error_msg)
473
+ # Final fallback - simple response based on context
474
+ if "context" in locals() and retrieved_context:
475
+ return f"Based on available information: I found relevant maintenance data, but encountered an issue processing it. Context available: {len(retrieved_context)} characters.", retrieved_context
476
+ else:
477
+ return "I apologize, but I'm experiencing technical difficulties. Please try again later or contact support.", "No context retrieved"
478
 
479
  def rag_pipeline_stream(question):
480
  """Streaming version of RAG pipeline"""
481
  try:
482
  full_response, _ = get_rag_response(question)
483
 
484
+ # Stream word by word for better UX
485
  words = full_response.split()
486
  current_text = ""
487
  for word in words:
488
  current_text += word + " "
489
  yield current_text
490
+ time.sleep(0.03) # Faster streaming
491
 
492
  except Exception as e:
493
  error_msg = f"Error in streaming: {str(e)}"
494
+ print(error_msg)
495
  yield "I apologize, but I encountered an error while generating the response."
496
 
497
  # ------------------ Gradio UI ------------------
 
499
  gr.Markdown("""
500
  # πŸ›  Maintenance AI Assistant
501
  *Your intelligent companion for maintenance queries and troubleshooting*
502
+
503
+ **Note**: This system uses multiple fallback mechanisms to ensure reliability.
504
  """)
505
 
506
  usage_counter = gr.State(value=0)
 
512
  gr.Markdown("### πŸ’¬ Chat Interface")
513
  question_input = gr.Textbox(
514
  label="Ask your maintenance question",
515
+ placeholder="e.g., How do I troubleshoot a leaking valve? What's the maintenance schedule for pumps?",
516
+ lines=3
517
  )
518
+ ask_button = gr.Button("Get Answer πŸš€", variant="primary", size="lg")
519
+
520
+ with gr.Row():
521
+ clear_btn = gr.Button("Clear Chat πŸ—‘οΈ")
522
+ evaluate_btn = gr.Button("Show Metrics πŸ“ˆ", variant="secondary")
523
 
524
  feedback = gr.Radio(
525
  ["Helpful", "Not Helpful"],
 
527
  info="Your feedback helps improve the system"
528
  )
529
 
 
 
 
530
  with gr.Column(scale=1):
531
  gr.Markdown("### πŸ€– AI Response")
532
  answer_output = gr.Textbox(
533
  label="Response",
534
+ lines=8,
535
  interactive=False,
536
+ show_copy_button=True,
537
+ autoscroll=True
538
  )
539
 
540
+ gr.Markdown("### πŸ“Š Evaluation Metrics")
541
+ metrics_output = gr.JSON(
542
+ label="Quality Metrics",
543
+ visible=False,
544
+ show_label=True
545
+ )
546
 
547
  def track_usage(question, count, session_start, feedback_value=None):
548
  """Track usage and get response"""
 
552
  count += 1
553
 
554
  try:
555
+ # Only use MLflow if properly configured
556
+ if mlflow_tracking_uri:
557
+ with mlflow.start_run(run_name=f"User-Interaction-{count}", nested=True):
558
  mlflow.log_param("question", question)
559
  mlflow.log_param("session_start", session_start)
560
  mlflow.log_param("user_feedback", feedback_value or "No feedback")
 
563
  mlflow.log_metric("helpful_responses", 1 if feedback_value == "Helpful" else 0)
564
 
565
  mlflow.log_metric("total_queries", count)
566
+
567
+ # Get response and context
568
+ response, context = get_rag_response(question)
569
+
 
570
  mlflow.log_metric("response_length", len(response))
571
  mlflow.log_metric("response_tokens", len(response.split()))
572
+ mlflow.log_metric("context_length", len(context))
573
+
574
+ return response, count, session_start, response
575
+ else:
576
+ # Without MLflow
577
+ response, context = get_rag_response(question)
578
  return response, count, session_start, response
579
 
580
  except Exception as e:
581
  print(f"Tracking error: {e}")
582
+ error_response = f"I encountered a system error. Please try again. Error: {str(e)}"
583
+ return error_response, count, session_start, error_response
584
 
585
  def evaluate_response(question, response):
586
  """Evaluate the response and return metrics"""
587
+ if not question or not response:
588
+ return gr.update(value={"info": "No question or response to evaluate"}, visible=True)
589
+
590
+ # Skip evaluation for error responses
591
+ if any(error_word in response.lower() for error_word in ["error", "apologize", "unavailable", "technical"]):
592
+ return gr.update(value={"info": "Evaluation skipped for error response"}, visible=True)
593
 
594
  try:
595
  context = get_retrieved_context(question)
596
  metrics = evaluator.evaluate_all(question, response, context)
597
 
 
 
 
 
 
 
598
  return gr.update(value=metrics, visible=True)
599
  except Exception as e:
600
  print(f"Evaluation error: {e}")
 
604
  """Clear the chat interface"""
605
  return "", "", gr.update(visible=False)
606
 
 
 
 
 
 
 
 
607
  # Main interaction flow
608
  ask_button.click(
609
+ fn=lambda: ("", gr.update(visible=False)), # Clear previous metrics and response
610
  outputs=[answer_output, metrics_output]
611
  ).then(
612
  fn=rag_pipeline_stream,
 
631
  outputs=[question_input, answer_output, metrics_output]
632
  )
633
 
634
+ # Handle feedback
635
  def handle_feedback(feedback_val):
636
  try:
637
  if mlflow_tracking_uri and mlflow.active_run():
638
  mlflow.log_metric("user_feedback_score", 1 if feedback_val == "Helpful" else 0)
639
  except:
640
+ pass # Silently fail if feedback logging doesn't work
 
641
 
642
  feedback.change(
643
  fn=handle_feedback,
 
646
  )
647
 
648
  if __name__ == "__main__":
649
+ print("πŸš€ Starting Maintenance AI Assistant...")
650
+ print("βœ… System initialized with fallback mechanisms")
651
+ print("🌐 Web interface available at http://0.0.0.0:7860")
652
+
653
  demo.launch(
654
  server_name="0.0.0.0",
655
  server_port=7860,
656
+ share=False,
657
+ show_error=True,
658
+ debug=False
659
  )