neerajkalyank commited on
Commit
2ee69ab
·
verified ·
1 Parent(s): f03fd62

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +142 -23
app.py CHANGED
@@ -1,9 +1,9 @@
1
  import random
2
  import gradio as gr
3
- from transformers import pipeline
4
  from datetime import datetime
 
5
 
6
- # ---------- Label Mapping ----------
7
  label_to_issue_type = {
8
  "LABEL_0": "Performance",
9
  "LABEL_1": "Error",
@@ -25,26 +25,88 @@ severities = {
25
  "Best Practice": "Low"
26
  }
27
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
28
  # ---------- Load QnA Model ----------
29
- qa_pipeline = pipeline("text2text-generation", model="google/flan-t5-base")
 
 
 
 
30
 
31
- # ---------- Local Logging (Replacement for Salesforce Logging) ----------
32
  def log_to_console(data, log_type):
33
  timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
34
  print(f"[{timestamp}] {log_type} Log: {data}")
35
 
36
- # ---------- Code Analyzer ----------
37
  def analyze_code(code):
38
  if not code.strip():
39
  return "No code provided.", "", ""
40
 
41
- # Simulate classification (replace with actual analysis for production)
42
  label = random.choice(list(label_to_issue_type.keys()))
43
  issue_type = label_to_issue_type[label]
44
  suggestion = suggestions[issue_type]
45
  severity = severities[issue_type]
46
 
47
- # Log to console instead of Salesforce
48
  log_data = {
49
  "Name": f"Review_{issue_type}",
50
  "CodeSnippet": code,
@@ -56,7 +118,7 @@ def analyze_code(code):
56
 
57
  return issue_type, suggestion, severity
58
 
59
- # ---------- Metadata Validator ----------
60
  def validate_metadata(metadata):
61
  if not metadata.strip():
62
  return "No metadata provided.", "", ""
@@ -65,7 +127,6 @@ def validate_metadata(metadata):
65
  issue = "Unused field detected"
66
  recommendation = "Remove it to improve performance or document its purpose."
67
 
68
- # Log to console instead of Salesforce
69
  log_data = {
70
  "Name": f"MetadataLog_{mtype}",
71
  "MetadataType": mtype,
@@ -83,23 +144,44 @@ conversation_history = []
83
  def salesforce_chatbot(query, history=[]):
84
  global conversation_history
85
  if not query.strip():
86
- return "No question provided."
87
 
88
- # Expanded Salesforce-related keywords
89
  salesforce_keywords = [
90
  "apex", "soql", "sosl", "trigger", "lwc", "aura", "visualforce", "salesforce",
91
  "governor limits", "bulkification", "dml", "query", "metadata", "flow",
92
  "process builder", "sobject", "schema", "lightning", "custom object",
93
  "validation rule", "workflow", "platform event", "batch apex", "queueable",
94
- "future method", "lightning web component", "api", "rest", "soap"
 
 
95
  ]
 
 
96
  if not any(keyword.lower() in query.lower() for keyword in salesforce_keywords):
97
- return "Please ask a Salesforce-related question."
 
 
 
 
 
 
 
 
 
 
98
 
99
  # Build conversation context
100
- history_summary = "\n".join([f"Q: {q} A: {a}" for q, a in conversation_history[-3:]]) # Last 3 exchanges
101
  prompt = f"""
102
- You are an expert Salesforce developer with deep knowledge of Apex, SOQL, LWC, and Salesforce platform features. Answer the following Salesforce-related question accurately, concisely, and based strictly on Salesforce best practices and official documentation (e.g., governor limits: 100 SOQL queries, 150 DML statements per transaction). Provide code examples where relevant, use correct terminology, and address the question directly. If the question builds on prior context, consider the conversation history.
 
 
 
 
 
 
 
103
 
104
  Conversation History:
105
  {history_summary}
@@ -109,24 +191,33 @@ Answer:
109
  """
110
 
111
  try:
112
- result = qa_pipeline(prompt, max_new_tokens=512, do_sample=False)
 
113
  output = result[0]["generated_text"].strip()
114
 
 
 
 
 
 
 
 
 
115
  # Store in conversation history
116
  conversation_history.append((query, output))
117
- conversation_history = conversation_history[-5:] # Keep last 5 exchanges
118
 
119
  # Log question and answer
120
  log_to_console({"Question": query, "Answer": output}, "Chatbot Query")
121
 
122
  return output
123
  except Exception as e:
124
- error_msg = f"⚠️ AI Response Error: {str(e)}"
125
  log_to_console({"Question": query, "Error": error_msg}, "Chatbot Error")
126
  return error_msg
127
 
128
  # ---------- Gradio UI ----------
129
- with gr.Blocks() as demo:
130
  gr.Markdown("# 🤖 Advanced Salesforce AI Code Review & Chatbot")
131
 
132
  with gr.Tab("Code Review"):
@@ -146,10 +237,38 @@ with gr.Blocks() as demo:
146
  metadata_button.click(validate_metadata, inputs=metadata_input, outputs=[mtype, issue, recommendation])
147
 
148
  with gr.Tab("Salesforce Chatbot"):
149
- query_input = gr.Textbox(label="Ask a Salesforce question", lines=2, placeholder="e.g., How do I bulkify an Apex trigger?")
150
- response_output = gr.Textbox(label="AI Response", lines=8)
151
- chatbot_button = gr.Button("Ask")
152
- chatbot_button.click(salesforce_chatbot, inputs=query_input, outputs=response_output)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
153
 
154
  # ---------- Start UI ----------
155
  if __name__ == "__main__":
 
1
  import random
2
  import gradio as gr
 
3
  from datetime import datetime
4
+ from transformers import pipeline
5
 
6
+ # ---------- Label Mapping (Unchanged) ----------
7
  label_to_issue_type = {
8
  "LABEL_0": "Performance",
9
  "LABEL_1": "Error",
 
25
  "Best Practice": "Low"
26
  }
27
 
28
+ # ---------- Mock Salesforce Knowledge Base ----------
29
+ salesforce_knowledge_base = {
30
+ "governor limits soql": "In Salesforce, the governor limit for SOQL queries is 100 per synchronous transaction and 200 per asynchronous transaction (e.g., Batch Apex, Queueable).",
31
+ "governor limits dml": "The governor limit for DML statements is 150 per synchronous or asynchronous transaction.",
32
+ "bulkify apex trigger": """
33
+ To bulkify an Apex trigger, ensure it handles multiple records to stay within governor limits:
34
+ - Use collections (e.g., Lists, Sets, Maps) to process records.
35
+ - Perform SOQL queries outside loops.
36
+ - Execute DML operations in bulk.
37
+ Example:
38
+ ```apex
39
+ trigger AccountTrigger on Account (before insert) {
40
+ Set<String> accountNames = new Set<String>();
41
+ for (Account acc : Trigger.new) {
42
+ accountNames.add(acc.Name);
43
+ }
44
+ List<Account> existingAccounts = [SELECT Name FROM Account WHERE Name IN :accountNames];
45
+ // Process records
46
+ }
47
+ ```""",
48
+ "soql injection": """
49
+ To prevent SOQL injection:
50
+ - Use bind variables (e.g., `:variable`) instead of dynamic SOQL.
51
+ - Escape single quotes with `String.escapeSingleQuotes()`.
52
+ Example:
53
+ ```apex
54
+ String userInput = 'Test';
55
+ List<Account> accounts = [SELECT Name FROM Account WHERE Name = :userInput];
56
+ ```""",
57
+ "lwc best practices": """
58
+ LWC best practices include:
59
+ - Use `@api` decorators for public properties.
60
+ - Leverage `@wire` for efficient data retrieval.
61
+ - Avoid hardcoding IDs; use dynamic queries.
62
+ - Follow SLDS for consistent UI.
63
+ Example:
64
+ ```javascript
65
+ import { LightningElement, api } from 'lwc';
66
+ export default class MyComponent extends LightningElement {
67
+ @api recordId;
68
+ }
69
+ ```""",
70
+ "batch apex": """
71
+ Batch Apex processes records in chunks to handle large data volumes:
72
+ - Implement `Database.Batchable<SObject>`.
73
+ - Use `start`, `execute`, and `finish` methods.
74
+ Example:
75
+ ```apex
76
+ global class MyBatch implements Database.Batchable<SObject> {
77
+ global Database.QueryLocator start(Database.BatchableContext bc) {
78
+ return Database.getQueryLocator('SELECT Id FROM Account');
79
+ }
80
+ global void execute(Database.BatchableContext bc, List<SObject> scope) {
81
+ // Process records
82
+ }
83
+ global void finish(Database.BatchableContext bc) {}
84
+ }
85
+ ```""",
86
+ }
87
+
88
  # ---------- Load QnA Model ----------
89
+ try:
90
+ qa_pipeline = pipeline("text2text-generation", model="google/flan-t5-large")
91
+ except Exception as e:
92
+ print(f"Model loading error: {e}. Falling back to flan-t5-base.")
93
+ qa_pipeline = pipeline("text2text-generation", model="google/flan-t5-base")
94
 
95
+ # ---------- Local Logging (Unchanged) ----------
96
  def log_to_console(data, log_type):
97
  timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
98
  print(f"[{timestamp}] {log_type} Log: {data}")
99
 
100
+ # ---------- Code Analyzer (Unchanged) ----------
101
  def analyze_code(code):
102
  if not code.strip():
103
  return "No code provided.", "", ""
104
 
 
105
  label = random.choice(list(label_to_issue_type.keys()))
106
  issue_type = label_to_issue_type[label]
107
  suggestion = suggestions[issue_type]
108
  severity = severities[issue_type]
109
 
 
110
  log_data = {
111
  "Name": f"Review_{issue_type}",
112
  "CodeSnippet": code,
 
118
 
119
  return issue_type, suggestion, severity
120
 
121
+ # ---------- Metadata Validator (Unchanged) ----------
122
  def validate_metadata(metadata):
123
  if not metadata.strip():
124
  return "No metadata provided.", "", ""
 
127
  issue = "Unused field detected"
128
  recommendation = "Remove it to improve performance or document its purpose."
129
 
 
130
  log_data = {
131
  "Name": f"MetadataLog_{mtype}",
132
  "MetadataType": mtype,
 
144
  def salesforce_chatbot(query, history=[]):
145
  global conversation_history
146
  if not query.strip():
147
+ return "Please provide a valid Salesforce-related question."
148
 
149
+ # Expanded Salesforce keywords
150
  salesforce_keywords = [
151
  "apex", "soql", "sosl", "trigger", "lwc", "aura", "visualforce", "salesforce",
152
  "governor limits", "bulkification", "dml", "query", "metadata", "flow",
153
  "process builder", "sobject", "schema", "lightning", "custom object",
154
  "validation rule", "workflow", "platform event", "batch apex", "queueable",
155
+ "future method", "lightning web component", "api", "rest", "soap", "integration",
156
+ "trigger", "profile", "permission set", "sharing rule", "field", "record type",
157
+ "crm", "sfdc", "force.com"
158
  ]
159
+
160
+ # Check if query is Salesforce-related
161
  if not any(keyword.lower() in query.lower() for keyword in salesforce_keywords):
162
+ return "Please ask a Salesforce-related question (e.g., about Apex, SOQL, LWC, or Salesforce platform features)."
163
+
164
+ # Check knowledge base for exact matches
165
+ query_key = query.lower().strip()
166
+ for kb_key, kb_answer in salesforce_knowledge_base.items():
167
+ if kb_key in query_key:
168
+ # Store in conversation history
169
+ conversation_history.append((query, kb_answer))
170
+ conversation_history = conversation_history[-6:] # Keep last 6 exchanges
171
+ log_to_console({"Question": query, "Answer": kb_answer}, "Chatbot Query")
172
+ return kb_answer
173
 
174
  # Build conversation context
175
+ history_summary = "\n".join([f"User: {q}\nAssistant: {a}" for q, a in conversation_history[-4:]])
176
  prompt = f"""
177
+ You are an expert Salesforce developer with deep knowledge of Apex, SOQL, SOSL, LWC, Aura, Visualforce, and Salesforce platform features. Your role is to provide 100% accurate answers based strictly on Salesforce official documentation and best practices (e.g., governor limits: 100 SOQL queries, 150 DML statements per transaction). Follow these guidelines:
178
+ - Provide concise, accurate answers with no speculation.
179
+ - Include code snippets in ```apex``` or ```javascript``` blocks for technical questions.
180
+ - Reference governor limits or best practices explicitly.
181
+ - If the question is ambiguous, ask for clarification within the response.
182
+ - Use bullet points for lists or steps.
183
+ - Leverage conversation history for context.
184
+ - If unsure, admit limitations and suggest checking Salesforce documentation or Trailhead.
185
 
186
  Conversation History:
187
  {history_summary}
 
191
  """
192
 
193
  try:
194
+ # Generate response with strict parameters
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
 
198
+ # Clean up response
199
+ if output.startswith("Answer:"):
200
+ output = output[7:].strip()
201
+
202
+ # Validate response quality
203
+ if len(output) < 20 or output.lower() in ["unknown", "i don't know", "not sure"]:
204
+ output = f"I'm sorry, I couldn't find a precise answer for '{query}'. Please clarify or refer to Salesforce documentation at https://developer.salesforce.com/docs."
205
+
206
  # Store in conversation history
207
  conversation_history.append((query, output))
208
+ conversation_history = conversation_history[-6:] # Keep last 6 exchanges
209
 
210
  # Log question and answer
211
  log_to_console({"Question": query, "Answer": output}, "Chatbot Query")
212
 
213
  return output
214
  except Exception as e:
215
+ error_msg = f"⚠️ Error generating response: {str(e)}. Please try rephrasing your question or check Salesforce documentation at https://developer.salesforce.com/docs."
216
  log_to_console({"Question": query, "Error": error_msg}, "Chatbot Error")
217
  return error_msg
218
 
219
  # ---------- Gradio UI ----------
220
+ with gr.Blocks(theme=gr.themes.Soft()) as demo:
221
  gr.Markdown("# 🤖 Advanced Salesforce AI Code Review & Chatbot")
222
 
223
  with gr.Tab("Code Review"):
 
237
  metadata_button.click(validate_metadata, inputs=metadata_input, outputs=[mtype, issue, recommendation])
238
 
239
  with gr.Tab("Salesforce Chatbot"):
240
+ gr.Markdown("### Ask a Salesforce Question\nGet expert answers on Apex, SOQL, LWC, and more!")
241
+ chatbot_output = gr.Chatbot(label="Conversation History", height=400)
242
+ query_input = gr.Textbox(label="Your Question", placeholder="e.g., How do I bulkify an Apex trigger?")
243
+ with gr.Row():
244
+ chatbot_button = gr.Button("Ask")
245
+ clear_button = gr.Button("Clear Chat")
246
+
247
+ # State to manage chat history
248
+ chat_state = gr.State(value=[])
249
+
250
+ def update_chatbot(query, chat_history):
251
+ if not query.strip():
252
+ return chat_history, "Please enter a valid question."
253
+ response = salesforce_chatbot(query, chat_history)
254
+ chat_history.append((query, response))
255
+ return chat_history, ""
256
+
257
+ def clear_chat():
258
+ global conversation_history
259
+ conversation_history = []
260
+ return [], ""
261
+
262
+ chatbot_button.click(
263
+ fn=update_chatbot,
264
+ inputs=[query_input, chat_state],
265
+ outputs=[chatbot_output, query_input]
266
+ )
267
+ clear_button.click(
268
+ fn=clear_chat,
269
+ inputs=None,
270
+ outputs=[chatbot_output, query_input]
271
+ )
272
 
273
  # ---------- Start UI ----------
274
  if __name__ == "__main__":