Bhanumani12 commited on
Commit
cda8f2c
·
verified ·
1 Parent(s): 2992416

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +85 -29
app.py CHANGED
@@ -1,11 +1,12 @@
1
  import os
2
  import random
 
3
  import gradio as gr
4
  from datetime import datetime
5
  from transformers import pipeline
6
  from simple_salesforce import Salesforce, SalesforceLogin
7
  from dotenv import load_dotenv
8
- import xml.etree.ElementTree as ET # NEW: for parsing metadata
9
 
10
  # ---------- Load Environment Variables ----------
11
  load_dotenv()
@@ -35,7 +36,7 @@ severities = {
35
  "Best Practice": "Low"
36
  }
37
 
38
- # ---------- Knowledge Base ----------
39
  salesforce_knowledge_base = {
40
  "governor limits soql": "In Salesforce, the governor limit for SOQL queries is 100 per synchronous transaction and 200 per asynchronous transaction.",
41
  "governor limits dml": "The governor limit for DML statements is 150 per transaction.",
@@ -104,7 +105,22 @@ def analyze_code(code):
104
 
105
  return issue_type, suggestion, severity
106
 
107
- # ---------- Metadata Validator (Updated with dynamic XML parsing) ----------
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
108
  def validate_metadata(metadata, admin_id=None):
109
  if not metadata.strip():
110
  return "No metadata provided.", "", ""
@@ -113,22 +129,54 @@ def validate_metadata(metadata, admin_id=None):
113
  issue = "Unknown"
114
  recommendation = "No recommendation found."
115
 
116
- try:
117
- root = ET.fromstring(metadata)
118
- # Detect missing <description> tag
119
- description_found = any(elem.tag.endswith('description') for elem in root)
120
 
121
- if not description_found:
122
- issue = "Missing description"
123
- recommendation = "Add a meaningful <description> to improve maintainability and clarity."
124
- else:
125
- issue = "Unused field detected"
126
- recommendation = "Remove it to improve performance or document its purpose."
127
 
128
- except Exception as e:
129
- issue = "Invalid XML"
130
- recommendation = f"Could not parse metadata XML. Error: {str(e)}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
131
 
 
132
  log_data = {
133
  "Name": f"MetadataLog_{mtype}",
134
  "MetadataType__c": mtype,
@@ -156,7 +204,7 @@ def validate_metadata(metadata, admin_id=None):
156
 
157
  return mtype, issue, recommendation
158
 
159
- # ---------- Salesforce Chatbot ----------
160
  conversation_history = []
161
 
162
  def salesforce_chatbot(query, history=[]):
@@ -166,11 +214,11 @@ def salesforce_chatbot(query, history=[]):
166
 
167
  salesforce_keywords = [
168
  "apex", "soql", "trigger", "lwc", "aura", "visualforce", "salesforce", "governor limits",
169
- "dml", "metadata", "batch apex", "queueable", "future method", "api", "sfdc"
170
  ]
171
 
172
  if not any(keyword.lower() in query.lower() for keyword in salesforce_keywords):
173
- return "Please ask a Salesforce-related question."
174
 
175
  query_key = query.lower().strip()
176
  for kb_key, kb_answer in salesforce_knowledge_base.items():
@@ -181,23 +229,31 @@ def salesforce_chatbot(query, history=[]):
181
  return kb_answer
182
 
183
  history_summary = "\n".join([f"User: {q}\nAssistant: {a}" for q, a in conversation_history[-4:]])
184
- prompt = f"""
185
- You are an expert Salesforce developer...
186
 
 
 
 
 
 
 
 
 
 
187
  Conversation History:
188
  {history_summary}
189
-
190
- Question: {query.strip()}
191
- Answer:
192
  """
193
 
194
  try:
195
  result = qa_pipeline(prompt, max_new_tokens=1024, do_sample=False, temperature=0.1, top_k=50)
196
  output = result[0]["generated_text"].strip()
197
- if output.startswith("Answer:"):
198
- output = output[7:].strip()
 
199
  if len(output) < 20:
200
- output = f"I'm sorry, I couldn't find a precise answer for '{query}'. Please refer to Salesforce docs."
 
201
  conversation_history.append((query, output))
202
  conversation_history = conversation_history[-6:]
203
  log_to_console({"Question": query, "Answer": output}, "Chatbot Query")
@@ -226,8 +282,8 @@ with gr.Blocks(theme=gr.themes.Soft()) as demo:
226
  metadata_button.click(validate_metadata, inputs=metadata_input, outputs=[mtype, issue, recommendation])
227
 
228
  with gr.Tab("Salesforce Chatbot"):
229
- chatbot_output = gr.Chatbot(label="Conversation History", height=400)
230
- query_input = gr.Textbox(label="Your Question", placeholder="e.g., How do I bulkify an Apex trigger?")
231
  with gr.Row():
232
  chatbot_button = gr.Button("Ask")
233
  clear_button = gr.Button("Clear Chat")
 
1
  import os
2
  import random
3
+ import re
4
  import gradio as gr
5
  from datetime import datetime
6
  from transformers import pipeline
7
  from simple_salesforce import Salesforce, SalesforceLogin
8
  from dotenv import load_dotenv
9
+ import xml.etree.ElementTree as ET
10
 
11
  # ---------- Load Environment Variables ----------
12
  load_dotenv()
 
36
  "Best Practice": "Low"
37
  }
38
 
39
+ # ---------- Mock Knowledge Base ----------
40
  salesforce_knowledge_base = {
41
  "governor limits soql": "In Salesforce, the governor limit for SOQL queries is 100 per synchronous transaction and 200 per asynchronous transaction.",
42
  "governor limits dml": "The governor limit for DML statements is 150 per transaction.",
 
105
 
106
  return issue_type, suggestion, severity
107
 
108
+ # ---------- Helpers for Metadata XML ----------
109
+ def _strip_code_fences(text: str) -> str:
110
+ # Remove ```xml ... ``` or plain ``` ... ```
111
+ t = re.sub(r'^\s*```(?:xml)?\s*', '', text, flags=re.IGNORECASE)
112
+ t = re.sub(r'\s*```\s*$', '', t)
113
+ return t
114
+
115
+ def _escape_bare_ampersands(text: str) -> str:
116
+ # Replace & that aren't valid entities with &amp;
117
+ return re.sub(
118
+ r'&(?!amp;|lt;|gt;|apos;|quot;|#\d+;|#x[0-9a-fA-F]+;)',
119
+ '&amp;',
120
+ text
121
+ )
122
+
123
+ # ---------- Metadata Validator ----------
124
  def validate_metadata(metadata, admin_id=None):
125
  if not metadata.strip():
126
  return "No metadata provided.", "", ""
 
129
  issue = "Unknown"
130
  recommendation = "No recommendation found."
131
 
132
+ # Preview to logs for debugging
133
+ preview = metadata[:100].replace("\n", "\\n")
134
+ log_to_console({"preview": preview}, "Metadata Input Preview")
 
135
 
136
+ # Clean typical paste artefacts
137
+ cleaned = _strip_code_fences(metadata).lstrip("\ufeff").strip()
 
 
 
 
138
 
139
+ # Quick non-XML guard
140
+ if "<" not in cleaned or ">" not in cleaned:
141
+ issue = "Invalid Input (Not XML)"
142
+ recommendation = (
143
+ "Please paste Salesforce metadata XML (starts with '<'). Example:\n"
144
+ "<CustomField xmlns=\"http://soap.sforce.com/2006/04/metadata\">...</CustomField>"
145
+ )
146
+ else:
147
+ # If leading junk before first '<', cut it
148
+ if cleaned and not cleaned.lstrip().startswith("<"):
149
+ idx = cleaned.find("<")
150
+ if idx != -1:
151
+ cleaned = cleaned[idx:].strip()
152
+
153
+ # Escape stray ampersands
154
+ cleaned = _escape_bare_ampersands(cleaned)
155
+
156
+ # Try to parse
157
+ try:
158
+ root = ET.fromstring(cleaned)
159
+ # Find <description> regardless of namespace
160
+ has_description = any(
161
+ elem.tag.split('}')[-1].lower() == "description"
162
+ for elem in root.iter()
163
+ )
164
+
165
+ if not has_description:
166
+ issue = "Missing description"
167
+ recommendation = "Add a meaningful <description> to improve maintainability and clarity."
168
+ else:
169
+ issue = "Unused field detected"
170
+ recommendation = "Remove it to improve performance or document its purpose."
171
+
172
+ except ET.ParseError as pe:
173
+ issue = "Invalid XML"
174
+ recommendation = f"Could not parse metadata XML. Error: {pe}."
175
+ except Exception as e:
176
+ issue = "Validation Error"
177
+ recommendation = f"Unexpected error while validating metadata: {str(e)}"
178
 
179
+ # Log to Salesforce
180
  log_data = {
181
  "Name": f"MetadataLog_{mtype}",
182
  "MetadataType__c": mtype,
 
204
 
205
  return mtype, issue, recommendation
206
 
207
+ # ---------- Salesforce Chatbot (Updated Prompt) ----------
208
  conversation_history = []
209
 
210
  def salesforce_chatbot(query, history=[]):
 
214
 
215
  salesforce_keywords = [
216
  "apex", "soql", "trigger", "lwc", "aura", "visualforce", "salesforce", "governor limits",
217
+ "dml", "metadata", "batch apex", "queueable", "future method", "api", "sfdc", "heap", "limits"
218
  ]
219
 
220
  if not any(keyword.lower() in query.lower() for keyword in salesforce_keywords):
221
+ return "Please ask a Salesforce-related question (e.g., Apex, SOQL, LWC, limits, etc)."
222
 
223
  query_key = query.lower().strip()
224
  for kb_key, kb_answer in salesforce_knowledge_base.items():
 
229
  return kb_answer
230
 
231
  history_summary = "\n".join([f"User: {q}\nAssistant: {a}" for q, a in conversation_history[-4:]])
 
 
232
 
233
+ prompt = f"""
234
+ You are an expert Salesforce developer and certified architect. You provide 100% accurate, clear, and practical answers for topics like Apex, SOQL, LWC, governor limits, triggers, metadata, and more.
235
+ When answering:
236
+ - ALWAYS give at least 2 lines of explanation.
237
+ - Be clear, concise, and technically correct.
238
+ - Mention official Salesforce limits if applicable.
239
+ - Use bullet points or code snippets when helpful.
240
+ - Avoid speculation — if unknown, say so and suggest Trailhead or official docs.
241
+ - Examples must be realistic and follow best practices.
242
  Conversation History:
243
  {history_summary}
244
+ User: {query.strip()}
245
+ Assistant:
 
246
  """
247
 
248
  try:
249
  result = qa_pipeline(prompt, max_new_tokens=1024, do_sample=False, temperature=0.1, top_k=50)
250
  output = result[0]["generated_text"].strip()
251
+ if output.startswith("Assistant:"):
252
+ output = output.replace("Assistant:", "").strip()
253
+
254
  if len(output) < 20:
255
+ output = f"I'm sorry, I couldn't generate a detailed answer for '{query}'. You can also check https://developer.salesforce.com/docs."
256
+
257
  conversation_history.append((query, output))
258
  conversation_history = conversation_history[-6:]
259
  log_to_console({"Question": query, "Answer": output}, "Chatbot Query")
 
282
  metadata_button.click(validate_metadata, inputs=metadata_input, outputs=[mtype, issue, recommendation])
283
 
284
  with gr.Tab("Salesforce Chatbot"):
285
+ chatbot_output = gr.Chatbot(label="Conversation History", height=400, type="messages")
286
+ query_input = gr.Textbox(label="Your Question", placeholder="e.g., What is heap size in Apex?")
287
  with gr.Row():
288
  chatbot_button = gr.Button("Ask")
289
  clear_button = gr.Button("Clear Chat")