Spaces:
Sleeping
Sleeping
import random | |
import gradio as gr | |
from datetime import datetime | |
from transformers import pipeline | |
# ---------- Label Mapping (Unchanged) ---------- | |
label_to_issue_type = { | |
"LABEL_0": "Performance", | |
"LABEL_1": "Error", | |
"LABEL_2": "Security", | |
"LABEL_3": "Best Practice" | |
} | |
suggestions = { | |
"Performance": "Consider optimizing loops and database access. Use collections to reduce SOQL queries.", | |
"Error": "Add proper error handling and null checks. Use try-catch blocks effectively.", | |
"Security": "Avoid dynamic SOQL. Use binding variables to prevent SOQL injection.", | |
"Best Practice": "Refactor for readability and use bulk-safe patterns, such as processing records in batches." | |
} | |
severities = { | |
"Performance": "Medium", | |
"Error": "High", | |
"Security": "High", | |
"Best Practice": "Low" | |
} | |
# ---------- Mock Salesforce Knowledge Base ---------- | |
salesforce_knowledge_base = { | |
"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).", | |
"governor limits dml": "The governor limit for DML statements is 150 per synchronous or asynchronous transaction.", | |
"bulkify apex trigger": """ | |
To bulkify an Apex trigger, ensure it handles multiple records to stay within governor limits: | |
- Use collections (e.g., Lists, Sets, Maps) to process records. | |
- Perform SOQL queries outside loops. | |
- Execute DML operations in bulk. | |
Example: | |
```apex | |
trigger AccountTrigger on Account (before insert) { | |
Set<String> accountNames = new Set<String>(); | |
for (Account acc : Trigger.new) { | |
accountNames.add(acc.Name); | |
} | |
List<Account> existingAccounts = [SELECT Name FROM Account WHERE Name IN :accountNames]; | |
// Process records | |
} | |
```""", | |
"soql injection": """ | |
To prevent SOQL injection: | |
- Use bind variables (e.g., `:variable`) instead of dynamic SOQL. | |
- Escape single quotes with `String.escapeSingleQuotes()`. | |
Example: | |
```apex | |
String userInput = 'Test'; | |
List<Account> accounts = [SELECT Name FROM Account WHERE Name = :userInput]; | |
```""", | |
"lwc best practices": """ | |
LWC best practices include: | |
- Use `@api` decorators for public properties. | |
- Leverage `@wire` for efficient data retrieval. | |
- Avoid hardcoding IDs; use dynamic queries. | |
- Follow SLDS for consistent UI. | |
Example: | |
```javascript | |
import { LightningElement, api } from 'lwc'; | |
export default class MyComponent extends LightningElement { | |
@api recordId; | |
} | |
```""", | |
"batch apex": """ | |
Batch Apex processes records in chunks to handle large data volumes: | |
- Implement `Database.Batchable<SObject>`. | |
- Use `start`, `execute`, and `finish` methods. | |
Example: | |
```apex | |
global class MyBatch implements Database.Batchable<SObject> { | |
global Database.QueryLocator start(Database.BatchableContext bc) { | |
return Database.getQueryLocator('SELECT Id FROM Account'); | |
} | |
global void execute(Database.BatchableContext bc, List<SObject> scope) { | |
// Process records | |
} | |
global void finish(Database.BatchableContext bc) {} | |
} | |
```""", | |
} | |
# ---------- Load QnA Model ---------- | |
try: | |
qa_pipeline = pipeline("text2text-generation", model="google/flan-t5-large") | |
except Exception as e: | |
print(f"Model loading error: {e}. Falling back to flan-t5-base.") | |
qa_pipeline = pipeline("text2text-generation", model="google/flan-t5-base") | |
# ---------- Local Logging (Unchanged) ---------- | |
def log_to_console(data, log_type): | |
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") | |
print(f"[{timestamp}] {log_type} Log: {data}") | |
# ---------- Code Analyzer (Unchanged) ---------- | |
def analyze_code(code): | |
if not code.strip(): | |
return "No code provided.", "", "" | |
label = random.choice(list(label_to_issue_type.keys())) | |
issue_type = label_to_issue_type[label] | |
suggestion = suggestions[issue_type] | |
severity = severities[issue_type] | |
log_data = { | |
"Name": f"Review_{issue_type}", | |
"CodeSnippet": code, | |
"IssueType": issue_type, | |
"Suggestion": suggestion, | |
"Severity": severity | |
} | |
log_to_console(log_data, "Code Review") | |
return issue_type, suggestion, severity | |
# ---------- Metadata Validator (Unchanged) ---------- | |
def validate_metadata(metadata): | |
if not metadata.strip(): | |
return "No metadata provided.", "", "" | |
mtype = "Field" | |
issue = "Unused field detected" | |
recommendation = "Remove it to improve performance or document its purpose." | |
log_data = { | |
"Name": f"MetadataLog_{mtype}", | |
"MetadataType": mtype, | |
"IssueDescription": issue, | |
"Recommendation": recommendation, | |
"Status": "Open" | |
} | |
log_to_console(log_data, "Metadata Validation") | |
return mtype, issue, recommendation | |
# ---------- Advanced Salesforce Chatbot ---------- | |
conversation_history = [] | |
def salesforce_chatbot(query, history=[]): | |
global conversation_history | |
if not query.strip(): | |
return "Please provide a valid Salesforce-related question." | |
# Expanded Salesforce keywords | |
salesforce_keywords = [ | |
"apex", "soql", "sosl", "trigger", "lwc", "aura", "visualforce", "salesforce", | |
"governor limits", "bulkification", "dml", "query", "metadata", "flow", | |
"process builder", "sobject", "schema", "lightning", "custom object", | |
"validation rule", "workflow", "platform event", "batch apex", "queueable", | |
"future method", "lightning web component", "api", "rest", "soap", "integration", | |
"trigger", "profile", "permission set", "sharing rule", "field", "record type", | |
"crm", "sfdc", "force.com" | |
] | |
# Check if query is Salesforce-related | |
if not any(keyword.lower() in query.lower() for keyword in salesforce_keywords): | |
return "Please ask a Salesforce-related question (e.g., about Apex, SOQL, LWC, or Salesforce platform features)." | |
# Check knowledge base for exact matches | |
query_key = query.lower().strip() | |
for kb_key, kb_answer in salesforce_knowledge_base.items(): | |
if kb_key in query_key: | |
# Store in conversation history | |
conversation_history.append((query, kb_answer)) | |
conversation_history = conversation_history[-6:] # Keep last 6 exchanges | |
log_to_console({"Question": query, "Answer": kb_answer}, "Chatbot Query") | |
return kb_answer | |
# Build conversation context | |
history_summary = "\n".join([f"User: {q}\nAssistant: {a}" for q, a in conversation_history[-4:]]) | |
prompt = f""" | |
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: | |
- Provide concise, accurate answers with no speculation. | |
- Include code snippets in ```apex``` or ```javascript``` blocks for technical questions. | |
- Reference governor limits or best practices explicitly. | |
- If the question is ambiguous, ask for clarification within the response. | |
- Use bullet points for lists or steps. | |
- Leverage conversation history for context. | |
- If unsure, admit limitations and suggest checking Salesforce documentation or Trailhead. | |
Conversation History: | |
{history_summary} | |
Question: {query.strip()} | |
Answer: | |
""" | |
try: | |
# Generate response with strict parameters | |
result = qa_pipeline(prompt, max_new_tokens=1024, do_sample=False, temperature=0.1, top_k=50) | |
output = result[0]["generated_text"].strip() | |
# Clean up response | |
if output.startswith("Answer:"): | |
output = output[7:].strip() | |
# Validate response quality | |
if len(output) < 20 or output.lower() in ["unknown", "i don't know", "not sure"]: | |
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." | |
# Store in conversation history | |
conversation_history.append((query, output)) | |
conversation_history = conversation_history[-6:] # Keep last 6 exchanges | |
# Log question and answer | |
log_to_console({"Question": query, "Answer": output}, "Chatbot Query") | |
return output | |
except Exception as e: | |
error_msg = f"⚠️ Error generating response: {str(e)}. Please try rephrasing your question or check Salesforce documentation at https://developer.salesforce.com/docs." | |
log_to_console({"Question": query, "Error": error_msg}, "Chatbot Error") | |
return error_msg | |
# ---------- Gradio UI ---------- | |
with gr.Blocks(theme=gr.themes.Soft()) as demo: | |
gr.Markdown("# 🤖 Advanced Salesforce AI Code Review & Chatbot") | |
with gr.Tab("Code Review"): | |
code_input = gr.Textbox(label="Apex / LWC Code", lines=8, placeholder="Enter your Apex or LWC code here") | |
issue_type = gr.Textbox(label="Issue Type") | |
suggestion = gr.Textbox(label="AI Suggestion") | |
severity = gr.Textbox(label="Severity") | |
code_button = gr.Button("Analyze Code") | |
code_button.click(analyze_code, inputs=code_input, outputs=[issue_type, suggestion, severity]) | |
with gr.Tab("Metadata Validation"): | |
metadata_input = gr.Textbox(label="Metadata XML", lines=8, placeholder="Enter your metadata XML here") | |
mtype = gr.Textbox(label="Type") | |
issue = gr.Textbox(label="Issue") | |
recommendation = gr.Textbox(label="Recommendation") | |
metadata_button = gr.Button("Validate Metadata") | |
metadata_button.click(validate_metadata, inputs=metadata_input, outputs=[mtype, issue, recommendation]) | |
with gr.Tab("Salesforce Chatbot"): | |
gr.Markdown("### Ask a Salesforce Question\nGet expert answers on Apex, SOQL, LWC, and more!") | |
chatbot_output = gr.Chatbot(label="Conversation History", height=400) | |
query_input = gr.Textbox(label="Your Question", placeholder="e.g., How do I bulkify an Apex trigger?") | |
with gr.Row(): | |
chatbot_button = gr.Button("Ask") | |
clear_button = gr.Button("Clear Chat") | |
# State to manage chat history | |
chat_state = gr.State(value=[]) | |
def update_chatbot(query, chat_history): | |
if not query.strip(): | |
return chat_history, "Please enter a valid question." | |
response = salesforce_chatbot(query, chat_history) | |
chat_history.append((query, response)) | |
return chat_history, "" | |
def clear_chat(): | |
global conversation_history | |
conversation_history = [] | |
return [], "" | |
chatbot_button.click( | |
fn=update_chatbot, | |
inputs=[query_input, chat_state], | |
outputs=[chatbot_output, query_input] | |
) | |
clear_button.click( | |
fn=clear_chat, | |
inputs=None, | |
outputs=[chatbot_output, query_input] | |
) | |
# ---------- Start UI ---------- | |
if __name__ == "__main__": | |
demo.launch() |