Bhanumani12's picture
Update app.py
17483c8 verified
import os
import random
import gradio as gr
from datetime import datetime
from transformers import pipeline
from simple_salesforce import Salesforce, SalesforceLogin
from dotenv import load_dotenv
import xml.etree.ElementTree as ET
# ---------- Load Environment Variables ----------
load_dotenv()
SF_USERNAME = os.getenv("SF_USERNAME")
SF_PASSWORD = os.getenv("SF_PASSWORD")
SF_SECURITY_TOKEN = os.getenv("SF_SECURITY_TOKEN")
# ---------- Label Mapping ----------
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"
}
# ---------- Load QnA Model (no fallback) ----------
qa_pipeline = pipeline("text2text-generation", model="google/flan-t5-large")
# ---------- Logging ----------
def log_to_console(data, log_type):
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
print(f"[{timestamp}] {log_type} Log: {data}")
# ---------- Salesforce Connection ----------
try:
session_id, instance = SalesforceLogin(
username=SF_USERNAME,
password=SF_PASSWORD,
security_token=SF_SECURITY_TOKEN
)
sf = Salesforce(instance=instance, session_id=session_id)
print("βœ… Connected to Salesforce successfully")
except Exception as e:
sf = None
print(f"❌ Failed to connect to Salesforce: {e}")
# ---------- Code Analyzer ----------
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]
review_data = {
"Name": f"Review_{issue_type}",
"CodeSnippet__c": code,
"IssueType__c": issue_type,
"Suggestion__c": suggestion,
"Severity__c": severity
}
log_to_console(review_data, "Code Review")
if sf:
try:
result = sf.CodeReviewResult__c.create(review_data)
if result.get("success"):
log_to_console({"Salesforce Record ID": result["id"]}, "Salesforce Create")
else:
log_to_console(result, "Salesforce Error")
except Exception as e:
log_to_console({"Salesforce Exception": str(e)}, "Salesforce Error")
else:
log_to_console("Salesforce not connected.", "Salesforce Error")
return issue_type, suggestion, severity
# ---------- Metadata Validator ----------
def validate_metadata(metadata, admin_id=None):
if not metadata.strip():
return "No metadata provided.", "", ""
mtype = "Field"
issue = "Unknown"
recommendation = "No recommendation found."
try:
root = ET.fromstring(metadata)
description_found = any(elem.tag.endswith('description') for elem in root)
if not description_found:
issue = "Missing description"
recommendation = "Add a meaningful <description> to improve maintainability and clarity."
else:
issue = "Unused field detected"
recommendation = "Remove it to improve performance or document its purpose."
except Exception as e:
issue = "Invalid XML"
recommendation = f"Could not parse metadata XML. Error: {str(e)}"
log_data = {
"Name": f"MetadataLog_{mtype}",
"MetadataType__c": mtype,
"IssueDescription__c": issue,
"Recommendation__c": recommendation,
"Status__c": "Open"
}
if admin_id:
log_data["Admin__c"] = admin_id
log_to_console(log_data, "Metadata Validation")
if sf:
try:
result = sf.MetadataAuditLog__c.create(log_data)
if result.get("success"):
log_to_console({"Salesforce MetadataAuditLog Record ID": result["id"]}, "Salesforce Create")
else:
log_to_console(result, "Salesforce Metadata Error")
except Exception as e:
log_to_console({"Salesforce Exception": str(e)}, "Salesforce Error")
else:
log_to_console("Salesforce not connected.", "Salesforce Error")
return mtype, issue, recommendation
# ---------- Salesforce Chatbot (Improved Prompt) ----------
conversation_history = []
def salesforce_chatbot(query, history=[]):
global conversation_history
if not query.strip():
return "Please provide a valid Salesforce-related question."
salesforce_keywords = [
"apex", "soql", "trigger", "lwc", "aura", "visualforce", "salesforce", "governor limits",
"dml", "metadata", "batch apex", "queueable", "future method", "api", "sfdc", "heap", "limits"
]
if not any(keyword.lower() in query.lower() for keyword in salesforce_keywords):
return "Please ask a Salesforce-related question."
history_summary = "\n".join([f"User: {q}\nAssistant: {a}" for q, a in conversation_history[-4:]])
prompt = f"""
You are a certified Salesforce developer and architect. Your role is to answer with 100% accurate and detailed technical explanations, especially about limits, code, and platform best practices.
Your answers MUST:
- Always be at least two lines long.
- Be correct, clear, and production-safe.
- Include official Salesforce governor limits when applicable.
- Use bullet points or code snippets when needed.
- Recommend Trailhead or official docs if the answer isn't definitive.
- Follow real-world practices (bulkification, error handling, etc).
Conversation History:
{history_summary}
User: {query.strip()}
Assistant:
"""
try:
result = qa_pipeline(prompt, max_new_tokens=1024, do_sample=False, temperature=0.1, top_k=50)
output = result[0]["generated_text"].strip()
if output.startswith("Assistant:"):
output = output.replace("Assistant:", "").strip()
if len(output.split()) < 15:
output += "\n\nRefer to: https://developer.salesforce.com/docs for more."
conversation_history.append((query, output))
conversation_history = conversation_history[-6:]
log_to_console({"Question": query, "Answer": output}, "Chatbot Query")
return output
except Exception as e:
return f"⚠️ Error generating response: {str(e)}"
# ---------- 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"):
chatbot_output = gr.Chatbot(label="Conversation History", height=400)
query_input = gr.Textbox(label="Your Question", placeholder="e.g., How many DML operations are allowed in Apex?")
with gr.Row():
chatbot_button = gr.Button("Ask")
clear_button = gr.Button("Clear Chat")
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])
if __name__ == "__main__":
demo.launch()