TimeCapsuleX commited on
Commit
fdbfbee
Β·
1 Parent(s): 3914cd6

Add application file

Browse files
Files changed (2) hide show
  1. __pycache__/app.cpython-311.pyc +0 -0
  2. app.py +108 -27
__pycache__/app.cpython-311.pyc CHANGED
Binary files a/__pycache__/app.cpython-311.pyc and b/__pycache__/app.cpython-311.pyc differ
 
app.py CHANGED
@@ -1,6 +1,7 @@
1
  import os
2
  import json
3
  import re
 
4
  import torch
5
  import gradio as gr
6
  import pandas as pd
@@ -25,6 +26,8 @@ QA_CHAIN = None
25
  RETRIEVER = None
26
  LLM = None
27
  PROMPT = None
 
 
28
  feedback_vector_store = None
29
  embeddings = None
30
 
@@ -42,23 +45,58 @@ def load_feedback_stats():
42
  feedback_df = pd.read_csv(FEEDBACK_FILE)
43
  if feedback_df.empty:
44
  return {}
 
 
45
  stats = feedback_df.groupby('action')['rating'].agg(['mean', 'count']).to_dict('index')
46
  return stats
47
  except pd.errors.EmptyDataError:
48
  return {}
49
 
50
- def save_feedback(action, rating, display_df):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
51
  if not action:
52
  return "Please select a recommendation from the table first.", display_df
 
 
 
 
 
 
 
53
  norm_action = normalize_action(action)
54
- new_feedback = pd.DataFrame([{'action': norm_action, 'rating': int(rating)}])
 
 
 
 
 
55
  if not os.path.exists(FEEDBACK_FILE):
56
  new_feedback.to_csv(FEEDBACK_FILE, index=False)
57
  else:
 
58
  new_feedback.to_csv(FEEDBACK_FILE, mode='a', header=False, index=False)
59
  build_feedback_db()
60
 
61
- msg = f"βœ… Rating of {rating}/10 saved for: {action}"
62
 
63
  # Update the displayed table dynamically
64
  if display_df is not None and not display_df.empty:
@@ -91,19 +129,31 @@ def build_feedback_db():
91
  feedback_vector_store = FAISS.from_texts(highly_rated_actions, embeddings)
92
  print("βœ… Feedback vector store is ready.")
93
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
94
  # --- build_rag_chain ---
95
  def build_rag_chain():
96
- global QA_CHAIN, RETRIEVER, LLM, PROMPT, embeddings
97
  try:
98
- print("Initializing local HuggingFace embedding model...")
99
- embeddings = HuggingFaceEmbeddings(
100
- model_name='all-MiniLM-L6-v2',
101
- model_kwargs={'device': DEVICE}
102
- )
103
- print("βœ… Local embedding model loaded.")
104
-
105
- build_feedback_db()
106
-
107
  print(f"Loading FMEA data from {FMEA_DATA_FILE}...")
108
  fmea_df = pd.read_csv(FMEA_DATA_FILE).fillna("")
109
  documents = []
@@ -113,11 +163,31 @@ def build_rag_chain():
113
  if "Failure_Mode" in fmea_df.columns:
114
  metadata["source"] = str(row["Failure_Mode"])
115
  documents.append(Document(page_content=page_content, metadata=metadata))
 
 
 
 
116
  print(f"βœ… Successfully loaded {len(documents)} records.")
117
 
118
- print("Creating embeddings and building main FAISS vector store...")
119
- main_vector_store = FAISS.from_documents(documents, embeddings)
120
- print("βœ… Main vector store created successfully.")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
121
 
122
  # --- UPDATED TO USE LLAMA 3.3 VIA GROQ ---
123
  llm = ChatGroq(model_name="llama-3.3-70b-versatile", temperature=0.2)
@@ -139,10 +209,11 @@ def build_rag_chain():
139
 
140
  INSTRUCTIONS:
141
  Format your entire response as a single, valid JSON object with a key "recommendations" which is a list of 3 objects.
142
- Each object must have these keys: "rank", "action", "department", "ai_score", "new_S", "new_O", "new_D".
143
 
144
  - "rank": The rank of the recommendation (1, 2, 3).
145
  - "action": The recommended action text.
 
146
  - "department": The most likely responsible department.
147
  - "ai_score": Confidence score (1-100) for this recommendation.
148
  - "new_S": Your estimated new Severity score (1-10).
@@ -153,8 +224,6 @@ def build_rag_chain():
153
  """
154
  PROMPT = PromptTemplate(template=prompt_template, input_variables=["context", "question"])
155
 
156
- # Included the token-saving "k": 2 limit
157
- RETRIEVER = main_vector_store.as_retriever(search_kwargs={"k": 2})
158
  LLM = llm
159
  QA_CHAIN = True
160
  print("βœ… RAG model is ready.")
@@ -165,7 +234,7 @@ def build_rag_chain():
165
 
166
  # --- 3. Gradio Interface Logic ---
167
  def fmea_rag_interface(mode, effect, cause, severity, occurrence, detection):
168
- if QA_CHAIN is None or RETRIEVER is None or LLM is None or PROMPT is None:
169
  return "RAG Model is not initialized.", pd.DataFrame(), ""
170
 
171
  rpn = severity * occurrence * detection
@@ -177,7 +246,10 @@ def fmea_rag_interface(mode, effect, cause, severity, occurrence, detection):
177
  f"The current scores are: Severity={severity}, Occurrence={occurrence}, Detection={detection}."
178
  )
179
 
180
- docs = RETRIEVER.invoke(query)
 
 
 
181
  context_from_history = "\n---\n".join([doc.page_content for doc in docs])
182
 
183
  context_from_feedback = ""
@@ -205,6 +277,8 @@ def fmea_rag_interface(mode, effect, cause, severity, occurrence, detection):
205
 
206
  data = json.loads(json_text)
207
  output_df = pd.DataFrame(data['recommendations'])
 
 
208
 
209
  feedback_stats = load_feedback_stats()
210
  default_stat = {'mean': 0, 'count': 0}
@@ -216,16 +290,19 @@ def fmea_rag_interface(mode, effect, cause, severity, occurrence, detection):
216
  output_df['new_O'] = output_df['new_O'].astype(int)
217
  output_df['new_D'] = output_df['new_D'].astype(int)
218
  output_df['new_RPN'] = output_df['new_S'] * output_df['new_O'] * output_df['new_D']
 
219
 
220
  rpn_change_list = [f"{int(rpn)} βž” {int(new_rpn)}" for new_rpn in output_df['new_RPN']]
221
 
222
  display_df = pd.DataFrame({
223
  "Rank": output_df['rank'],
224
  "Recommended Action": output_df['action'],
 
225
  "Department": output_df['department'],
226
  "AI Confidence": [f"{score}%" for score in output_df['ai_score']],
227
  "Avg. Feedback": [f"{avg:.2f}/10 ({int(count)})" for avg, count in zip(output_df['avg_feedback'], output_df['feedback_count'])],
228
- "Revised RPN": rpn_change_list
 
229
  })
230
 
231
  except Exception as e:
@@ -270,8 +347,8 @@ if build_rag_chain():
270
  gr.Markdown("## πŸ’‘ Top 3 AI-Generated Recommendations")
271
  rpn_output = gr.Textbox(label="Current RPN", interactive=False)
272
  recommendations_output = gr.DataFrame(
273
- headers=["Rank", "Recommended Action", "Department", "AI Confidence", "Avg. Feedback", "Revised RPN"],
274
- datatype=["number", "str", "str", "str", "str", "str"]
275
  )
276
  df_state = gr.State()
277
 
@@ -279,8 +356,12 @@ if build_rag_chain():
279
  gr.Markdown("## ⭐ Provide Feedback")
280
  gr.Markdown("Click a row in the table above to select it, then submit your rating.")
281
  selected_action_text = gr.Textbox(label="Selected for Feedback", interactive=False)
282
- rating_slider = gr.Slider(minimum=1, maximum=10, step=1, value=8, label="Your Rating (1-10)")
283
- submit_feedback_btn = gr.Button("Submit Rating")
 
 
 
 
284
  feedback_status = gr.Textbox(label="Feedback Status", interactive=False)
285
 
286
  # FIX 1: Safer update_selection function
@@ -307,7 +388,7 @@ if build_rag_chain():
307
 
308
  submit_feedback_btn.click(
309
  fn=save_feedback,
310
- inputs=[selected_action_text, rating_slider, recommendations_output],
311
  outputs=[feedback_status, recommendations_output]
312
  )
313
 
 
1
  import os
2
  import json
3
  import re
4
+ from datetime import datetime, timezone
5
  import torch
6
  import gradio as gr
7
  import pandas as pd
 
26
  RETRIEVER = None
27
  LLM = None
28
  PROMPT = None
29
+ FMEA_DF = None
30
+ DOCUMENTS = None
31
  feedback_vector_store = None
32
  embeddings = None
33
 
 
45
  feedback_df = pd.read_csv(FEEDBACK_FILE)
46
  if feedback_df.empty:
47
  return {}
48
+ if "rating" not in feedback_df.columns:
49
+ return {}
50
  stats = feedback_df.groupby('action')['rating'].agg(['mean', 'count']).to_dict('index')
51
  return stats
52
  except pd.errors.EmptyDataError:
53
  return {}
54
 
55
+ def ensure_feedback_schema():
56
+ target_cols = ["action", "rating", "feedback_type", "timestamp_utc"]
57
+ if not os.path.exists(FEEDBACK_FILE):
58
+ return
59
+ try:
60
+ existing_df = pd.read_csv(FEEDBACK_FILE)
61
+ if existing_df.empty:
62
+ pd.DataFrame(columns=target_cols).to_csv(FEEDBACK_FILE, index=False)
63
+ return
64
+ changed = False
65
+ for col in target_cols:
66
+ if col not in existing_df.columns:
67
+ existing_df[col] = ""
68
+ changed = True
69
+ if changed:
70
+ existing_df = existing_df[target_cols]
71
+ existing_df.to_csv(FEEDBACK_FILE, index=False)
72
+ except pd.errors.EmptyDataError:
73
+ pd.DataFrame(columns=target_cols).to_csv(FEEDBACK_FILE, index=False)
74
+
75
+ def save_feedback(action, feedback_choice, display_df):
76
  if not action:
77
  return "Please select a recommendation from the table first.", display_df
78
+
79
+ choice_map = {
80
+ "πŸ‘ Thumbs Up": ("thumbs_up", 10),
81
+ "πŸ‘Ž Thumbs Down": ("thumbs_down", 3)
82
+ }
83
+ feedback_type, rating = choice_map.get(feedback_choice, ("thumbs_up", 10))
84
+ timestamp_utc = datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M:%S UTC")
85
  norm_action = normalize_action(action)
86
+ new_feedback = pd.DataFrame([{
87
+ 'action': norm_action,
88
+ 'rating': int(rating),
89
+ 'feedback_type': feedback_type,
90
+ 'timestamp_utc': timestamp_utc
91
+ }])
92
  if not os.path.exists(FEEDBACK_FILE):
93
  new_feedback.to_csv(FEEDBACK_FILE, index=False)
94
  else:
95
+ ensure_feedback_schema()
96
  new_feedback.to_csv(FEEDBACK_FILE, mode='a', header=False, index=False)
97
  build_feedback_db()
98
 
99
+ msg = f"βœ… Feedback saved ({feedback_choice}) for: {action} at {timestamp_utc}"
100
 
101
  # Update the displayed table dynamically
102
  if display_df is not None and not display_df.empty:
 
129
  feedback_vector_store = FAISS.from_texts(highly_rated_actions, embeddings)
130
  print("βœ… Feedback vector store is ready.")
131
 
132
+ def keyword_retrieve_documents(search_query: str, k: int = 2):
133
+ if FMEA_DF is None or DOCUMENTS is None or FMEA_DF.empty:
134
+ return []
135
+
136
+ tokens = [tok for tok in re.findall(r"[a-z0-9]+", str(search_query).lower()) if len(tok) >= 3]
137
+ if not tokens:
138
+ return DOCUMENTS[:k]
139
+
140
+ scores = []
141
+ for idx, text in enumerate(FMEA_DF["__search_text"]):
142
+ token_hits = sum(1 for tok in tokens if tok in text)
143
+ if token_hits:
144
+ scores.append((token_hits, idx))
145
+
146
+ if not scores:
147
+ return DOCUMENTS[:k]
148
+
149
+ scores.sort(key=lambda x: x[0], reverse=True)
150
+ top_indices = [idx for _, idx in scores[:k]]
151
+ return [DOCUMENTS[idx] for idx in top_indices]
152
+
153
  # --- build_rag_chain ---
154
  def build_rag_chain():
155
+ global QA_CHAIN, RETRIEVER, LLM, PROMPT, FMEA_DF, DOCUMENTS, feedback_vector_store, embeddings
156
  try:
 
 
 
 
 
 
 
 
 
157
  print(f"Loading FMEA data from {FMEA_DATA_FILE}...")
158
  fmea_df = pd.read_csv(FMEA_DATA_FILE).fillna("")
159
  documents = []
 
163
  if "Failure_Mode" in fmea_df.columns:
164
  metadata["source"] = str(row["Failure_Mode"])
165
  documents.append(Document(page_content=page_content, metadata=metadata))
166
+ search_cols = [c for c in ["Failure_Mode", "Effect", "Cause", "Recommended_Action", "Responsible_Department"] if c in fmea_df.columns]
167
+ fmea_df["__search_text"] = fmea_df[search_cols].astype(str).agg(" ".join, axis=1).str.lower()
168
+ FMEA_DF = fmea_df
169
+ DOCUMENTS = documents
170
  print(f"βœ… Successfully loaded {len(documents)} records.")
171
 
172
+ print("Initializing local HuggingFace embedding model...")
173
+ try:
174
+ embeddings = HuggingFaceEmbeddings(
175
+ model_name='all-MiniLM-L6-v2',
176
+ model_kwargs={'device': DEVICE}
177
+ )
178
+ print("βœ… Local embedding model loaded.")
179
+
180
+ build_feedback_db()
181
+
182
+ print("Creating embeddings and building main FAISS vector store...")
183
+ main_vector_store = FAISS.from_documents(documents, embeddings)
184
+ RETRIEVER = main_vector_store.as_retriever(search_kwargs={"k": 2})
185
+ print("βœ… Main vector store created successfully.")
186
+ except Exception as embed_error:
187
+ embeddings = None
188
+ RETRIEVER = None
189
+ feedback_vector_store = None
190
+ print(f"⚠️ Embedding setup failed, using keyword retrieval fallback. Details: {embed_error}")
191
 
192
  # --- UPDATED TO USE LLAMA 3.3 VIA GROQ ---
193
  llm = ChatGroq(model_name="llama-3.3-70b-versatile", temperature=0.2)
 
209
 
210
  INSTRUCTIONS:
211
  Format your entire response as a single, valid JSON object with a key "recommendations" which is a list of 3 objects.
212
+ Each object must have these keys: "rank", "action", "action_details", "department", "ai_score", "new_S", "new_O", "new_D".
213
 
214
  - "rank": The rank of the recommendation (1, 2, 3).
215
  - "action": The recommended action text.
216
+ - "action_details": 2-3 sentences explaining why this action works and practical implementation notes.
217
  - "department": The most likely responsible department.
218
  - "ai_score": Confidence score (1-100) for this recommendation.
219
  - "new_S": Your estimated new Severity score (1-10).
 
224
  """
225
  PROMPT = PromptTemplate(template=prompt_template, input_variables=["context", "question"])
226
 
 
 
227
  LLM = llm
228
  QA_CHAIN = True
229
  print("βœ… RAG model is ready.")
 
234
 
235
  # --- 3. Gradio Interface Logic ---
236
  def fmea_rag_interface(mode, effect, cause, severity, occurrence, detection):
237
+ if QA_CHAIN is None or LLM is None or PROMPT is None:
238
  return "RAG Model is not initialized.", pd.DataFrame(), ""
239
 
240
  rpn = severity * occurrence * detection
 
246
  f"The current scores are: Severity={severity}, Occurrence={occurrence}, Detection={detection}."
247
  )
248
 
249
+ if RETRIEVER is not None:
250
+ docs = RETRIEVER.invoke(query)
251
+ else:
252
+ docs = keyword_retrieve_documents(f"{mode} {effect} {cause}", k=2)
253
  context_from_history = "\n---\n".join([doc.page_content for doc in docs])
254
 
255
  context_from_feedback = ""
 
277
 
278
  data = json.loads(json_text)
279
  output_df = pd.DataFrame(data['recommendations'])
280
+ if 'action_details' not in output_df.columns:
281
+ output_df['action_details'] = "No additional details provided."
282
 
283
  feedback_stats = load_feedback_stats()
284
  default_stat = {'mean': 0, 'count': 0}
 
290
  output_df['new_O'] = output_df['new_O'].astype(int)
291
  output_df['new_D'] = output_df['new_D'].astype(int)
292
  output_df['new_RPN'] = output_df['new_S'] * output_df['new_O'] * output_df['new_D']
293
+ output_df['generated_at'] = datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M:%S UTC")
294
 
295
  rpn_change_list = [f"{int(rpn)} βž” {int(new_rpn)}" for new_rpn in output_df['new_RPN']]
296
 
297
  display_df = pd.DataFrame({
298
  "Rank": output_df['rank'],
299
  "Recommended Action": output_df['action'],
300
+ "Action Details": output_df['action_details'],
301
  "Department": output_df['department'],
302
  "AI Confidence": [f"{score}%" for score in output_df['ai_score']],
303
  "Avg. Feedback": [f"{avg:.2f}/10 ({int(count)})" for avg, count in zip(output_df['avg_feedback'], output_df['feedback_count'])],
304
+ "Revised RPN": rpn_change_list,
305
+ "Generated At (UTC)": output_df['generated_at']
306
  })
307
 
308
  except Exception as e:
 
347
  gr.Markdown("## πŸ’‘ Top 3 AI-Generated Recommendations")
348
  rpn_output = gr.Textbox(label="Current RPN", interactive=False)
349
  recommendations_output = gr.DataFrame(
350
+ headers=["Rank", "Recommended Action", "Action Details", "Department", "AI Confidence", "Avg. Feedback", "Revised RPN", "Generated At (UTC)"],
351
+ datatype=["number", "str", "str", "str", "str", "str", "str", "str"]
352
  )
353
  df_state = gr.State()
354
 
 
356
  gr.Markdown("## ⭐ Provide Feedback")
357
  gr.Markdown("Click a row in the table above to select it, then submit your rating.")
358
  selected_action_text = gr.Textbox(label="Selected for Feedback", interactive=False)
359
+ feedback_choice = gr.Radio(
360
+ choices=["πŸ‘ Thumbs Up", "πŸ‘Ž Thumbs Down"],
361
+ value="πŸ‘ Thumbs Up",
362
+ label="Your Feedback"
363
+ )
364
+ submit_feedback_btn = gr.Button("Submit Feedback")
365
  feedback_status = gr.Textbox(label="Feedback Status", interactive=False)
366
 
367
  # FIX 1: Safer update_selection function
 
388
 
389
  submit_feedback_btn.click(
390
  fn=save_feedback,
391
+ inputs=[selected_action_text, feedback_choice, recommendations_output],
392
  outputs=[feedback_status, recommendations_output]
393
  )
394