delightfulrachel commited on
Commit
07016ca
Β·
verified Β·
1 Parent(s): 115f2ea

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +815 -285
app.py CHANGED
@@ -6,6 +6,14 @@ import json
6
  import plotly.express as px
7
  import pandas as pd
8
  import re
 
 
 
 
 
 
 
 
9
 
10
  # Model options for dropdown with both Together AI and Anthropic models
11
  together_models = [
@@ -29,29 +37,89 @@ VALIDATION_SCHEMA = {
29
  "accuracy": "float (0.0–1.0)",
30
  "completeness": "float (0.0–1.0)",
31
  "best_practices_alignment": "float (0.0–1.0)",
 
 
 
32
  "explanations": {
33
  "quality_rating": "string",
34
  "accuracy": "string",
35
  "completeness": "string",
36
- "best_practices_alignment": "string"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
37
  }
38
  }
39
 
40
- def get_api_key(provider):
41
- if provider == "together":
42
- api_key = os.getenv("TOGETHER_API_KEY")
43
- if not api_key:
44
- raise ValueError("TOGETHER_API_KEY not set. Please add it in Space secrets.")
45
- return api_key
46
- elif provider == "anthropic":
47
- api_key = os.getenv("ANTHROPIC_API_KEY")
48
- if not api_key:
49
- raise ValueError("ANTHROPIC_API_KEY not set. Please add it in Space secrets.")
50
- return api_key
51
- else:
52
- raise ValueError(f"Unknown provider: {provider}")
53
 
54
- def get_provider(model):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
55
  if model in together_models:
56
  return "together"
57
  elif model in anthropic_models:
@@ -59,13 +127,47 @@ def get_provider(model):
59
  else:
60
  raise ValueError(f"Unknown model: {model}")
61
 
62
- def call_together_api(model, prompt, temperature=0.7, max_tokens=1500):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
63
  api_key = get_api_key("together")
64
  system_message = (
65
- "You are a Salesforce development expert specializing in B2B Commerce migrations,"
66
- " CloudCraze to B2B Lightning Experience conversions, and Apex code optimization."
 
 
67
  )
68
- try:
 
69
  headers = {
70
  "Authorization": f"Bearer {api_key}",
71
  "Content-Type": "application/json"
@@ -83,23 +185,27 @@ def call_together_api(model, prompt, temperature=0.7, max_tokens=1500):
83
  resp = requests.post(
84
  "https://api.together.xyz/v1/chat/completions",
85
  headers=headers,
86
- json=payload
 
87
  )
88
  if resp.status_code != 200:
89
- return f"Error: Status {resp.status_code}: {resp.text}"
90
  data = resp.json()
91
- text = data["choices"][0]["message"]["content"]
92
- return text
93
- except Exception as e:
94
- return f"Error calling Together AI API: {e}"
95
 
96
- def call_anthropic_api(model, prompt, temperature=0.7, max_tokens=1500):
 
97
  api_key = get_api_key("anthropic")
98
  system_message = (
99
- "You are a Salesforce development expert specializing in B2B Commerce migrations,"
100
- " CloudCraze to B2B Lightning Experience conversions, and Apex code optimization."
 
 
101
  )
102
- try:
 
103
  headers = {
104
  "x-api-key": api_key,
105
  "anthropic-version": "2023-06-01",
@@ -117,17 +223,19 @@ def call_anthropic_api(model, prompt, temperature=0.7, max_tokens=1500):
117
  resp = requests.post(
118
  "https://api.anthropic.com/v1/messages",
119
  headers=headers,
120
- json=payload
 
121
  )
122
  if resp.status_code != 200:
123
- return f"Error: Status {resp.status_code}: {resp.text}"
124
  data = resp.json()
125
- text = data["content"][0]["text"]
126
- return text
127
- except Exception as e:
128
- return f"Error calling Anthropic API: {e}"
129
 
130
- def call_llm(model, prompt, temperature=0.7, max_tokens=1500):
 
 
131
  provider = get_provider(model)
132
  if provider == "together":
133
  return call_together_api(model, prompt, temperature, max_tokens)
@@ -136,140 +244,588 @@ def call_llm(model, prompt, temperature=0.7, max_tokens=1500):
136
  else:
137
  return f"Error: Unknown provider for model {model}"
138
 
139
- def extract_code_blocks(text):
140
- """Extract code blocks from the model's response"""
141
- # Pattern to match code blocks with ```apex or ```java or just ```
142
- pattern = r"```(?:apex|java)?(.*?)```"
143
- matches = re.findall(pattern, text, re.DOTALL)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
144
 
145
- # Clean up extracted code blocks
146
  code_blocks = []
147
  for block in matches:
148
- # Remove leading/trailing whitespace
149
  cleaned_block = block.strip()
150
  if cleaned_block:
151
  code_blocks.append(cleaned_block)
152
 
153
- # If no code blocks found but text contains code-like content
154
- if not code_blocks and ("public" in text or "private" in text or "trigger" in text):
155
- # Try to extract the most code-like part
156
- lines = text.split('\n')
157
- potential_code = []
158
- in_code_section = False
 
 
 
 
 
 
 
 
159
 
160
- for line in lines:
161
- if any(keyword in line for keyword in ["public", "private", "class", "trigger", "@"]):
162
- in_code_section = True
163
-
164
- if in_code_section:
165
- potential_code.append(line)
 
 
 
 
 
166
 
167
- if potential_code:
168
- code_blocks.append('\n'.join(potential_code))
 
169
 
170
- return '\n\n'.join(code_blocks) if code_blocks else ""
171
 
172
- def extract_explanations(text, code_blocks):
173
- """Extract explanations from the model's response by removing code blocks"""
174
- # Replace all code blocks with placeholders
175
  explanation = text
176
- for block in code_blocks.split('\n\n'):
177
- # Escape special regex characters in the block
178
- escaped_block = re.escape(block)
179
- explanation = re.sub(escaped_block, "[CODE BLOCK REMOVED]", explanation, flags=re.DOTALL)
 
 
 
 
180
 
181
  # Remove code block markers
182
- explanation = re.sub(r"```(?:apex|java)?.*?```", "", explanation, flags=re.DOTALL)
183
 
184
- # Clean up the explanation
185
- explanation = explanation.replace("[CODE BLOCK REMOVED]", "*Code has been moved to the Code Output section*")
186
 
187
  return explanation.strip()
188
 
189
- def correct_apex_trigger(model, trigger_code):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
190
  if not trigger_code.strip():
191
  return "Please provide Apex Trigger code to correct.", "", ""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
192
  prompt = f"""
193
- Please analyze and correct the following Apex Trigger code for migration from CloudCraze to B2B Lightning Experience.
194
- Identify any issues, optimize it according to best practices, and provide the corrected code.
 
 
 
 
 
 
 
195
 
 
 
 
 
 
 
 
196
  ```apex
197
  {trigger_code}
198
  ```
199
 
200
- Please return the corrected code with explanations of changes. Put the corrected code in ```apex code blocks.
 
 
 
 
 
 
 
 
 
201
  """
202
- response = call_llm(model, prompt)
 
 
 
 
 
 
 
203
 
204
- # Extract code blocks and explanations
205
  code_output = extract_code_blocks(response)
 
 
 
 
 
 
 
 
206
  explanation = extract_explanations(response, code_output)
207
 
 
 
 
 
 
 
 
208
  return response, code_output, explanation
209
 
210
- def convert_cc_object(model, cc_object_code):
 
 
 
 
 
211
  if not cc_object_code.strip():
212
  return "Please provide CloudCraze Object code to convert.", "", ""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
213
  prompt = f"""
214
- Please convert the following CloudCraze Object code to B2B Lightning Experience format.
215
- Identify the corresponding B2B LEx system object, map fields, and provide the full definition.
 
 
 
 
 
 
 
216
 
 
217
  ```
218
  {cc_object_code}
219
  ```
220
 
 
 
 
 
 
 
 
 
 
221
  Return:
222
- 1. Equivalent B2B LEx object name
223
- 2. Field mappings
224
- 3. Full implementation code in ```apex code blocks
225
- 4. Additional steps if needed
226
  """
227
- response = call_llm(model, prompt)
 
 
 
 
228
 
229
- # Extract code blocks and explanations
 
 
 
230
  code_output = extract_code_blocks(response)
231
  explanation = extract_explanations(response, code_output)
232
 
 
 
 
 
 
 
 
233
  return response, code_output, explanation
234
 
235
- def validate_apex_trigger(validation_model, original_code, corrected_code):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
236
  if not validation_model or not original_code.strip() or not corrected_code.strip():
237
  return "Please provide all required inputs for validation."
238
 
 
 
 
 
239
  prompt = f"""
240
- I need you to validate and review the following Apex code migration. This involves both CloudCraze to B2B Lightning Experience conversions AND general Apex code optimization.
241
 
242
- ORIGINAL CODE:
243
  ```apex
244
  {original_code}
245
  ```
246
 
247
- CORRECTED CODE:
248
  ```apex
249
  {corrected_code}
250
  ```
251
 
252
- Please review the corrected code and provide:
253
- 1. Is the correction accurate and complete? Highlight any missed issues.
254
- 2. Are there any potential runtime errors or performance concerns?
255
- 3. Does it follow Salesforce best practices for B2B Lightning Experience?
256
- 4. Are there optimization opportunities that were missed?
257
- 5. Evaluate both the B2B Commerce conversion aspects AND the general Apex optimization.
258
- 6. Rate the quality of the correction on a scale of 1-10 with explanation.
 
 
259
 
260
- Additionally, provide a structured assessment in JSON format following this schema:
 
 
261
  {json.dumps(VALIDATION_SCHEMA, indent=2)}
262
 
263
- Be thorough and detailed in your assessment, addressing both the conversion and optimization aspects.
264
  """
265
- return call_llm(validation_model, prompt)
 
266
 
267
- def validate_cc_object_conversion(validation_model, original_object, converted_object):
 
268
  if not validation_model or not original_object.strip() or not converted_object.strip():
269
  return "Please provide all required inputs for validation."
270
 
271
  prompt = f"""
272
- I need you to validate and review the following CloudCraze Object conversion to B2B Lightning Experience format. This involves both CloudCraze to B2B Lightning Experience conversions AND optimization of the resulting code.
273
 
274
  ORIGINAL CLOUDCRAZE OBJECT:
275
  ```
@@ -281,126 +837,116 @@ CONVERTED B2B LEX OBJECT:
281
  {converted_object}
282
  ```
283
 
284
- Please review the conversion and provide:
285
- 1. Is the object mapping correct and complete? Identify any missed fields or relationships.
286
- 2. Are there any potential data migration issues or concerns?
287
- 3. Does the converted object follow B2B Lightning Experience best practices?
288
- 4. Are there optimization opportunities that were missed in the conversion?
289
- 5. Evaluate both the B2B Commerce conversion aspects AND the optimization of the resulting code.
290
- 6. Rate the quality of the conversion on a scale of 1-10 with explanation.
 
 
 
 
 
 
 
 
 
291
 
292
- Additionally, provide a structured assessment in JSON format following this schema:
293
  {json.dumps(VALIDATION_SCHEMA, indent=2)}
294
 
295
- Be thorough and detailed in your assessment, addressing both the conversion and optimization aspects.
296
  """
297
- return call_llm(validation_model, prompt)
298
-
299
- def extract_validation_metrics(validation_text):
300
- try:
301
- # Try to find JSON in the response
302
- start_idx = validation_text.find('{')
303
- end_idx = validation_text.rfind('}') + 1
304
-
305
- if start_idx != -1 and end_idx != -1 and start_idx < end_idx:
306
- json_str = validation_text[start_idx:end_idx]
307
- # Print for debugging
308
- print("Extracted JSON:", json_str)
309
-
310
- try:
311
- data = json.loads(json_str)
312
-
313
- # Extract the required metrics with default values
314
- metrics = {
315
- "quality_rating": float(data.get("quality_rating", 0)),
316
- "accuracy": float(data.get("accuracy", 0.0)),
317
- "completeness": float(data.get("completeness", 0.0)),
318
- "best_practices_alignment": float(data.get("best_practices_alignment", 0.0))
319
- }
320
-
321
- return metrics
322
- except json.JSONDecodeError as je:
323
- print(f"JSON decode error: {je}")
324
- return None
325
- else:
326
- print("No JSON found in validation text")
327
- return None
328
- except Exception as e:
329
- print(f"Error extracting metrics: {e}")
330
- return None
331
-
332
- def create_radar_chart(metrics):
333
- if not metrics:
334
- return None
335
-
336
- # Create data for the radar chart
337
- categories = ["Quality", "Accuracy", "Completeness", "Best Practices"]
338
- values = [
339
- metrics["quality_rating"] / 10, # Normalize to 0-1 scale
340
- metrics["accuracy"],
341
- metrics["completeness"],
342
- metrics["best_practices_alignment"]
343
- ]
344
-
345
- # Create a DataFrame for plotting
346
- df = pd.DataFrame({
347
- 'Category': categories,
348
- 'Value': values
349
- })
350
 
351
- # Create the radar chart
352
- fig = px.line_polar(
353
- df, r='Value', theta='Category', line_close=True,
354
- range_r=[0, 1], title="Validation Assessment"
355
- )
356
- fig.update_traces(fill='toself')
357
-
358
- return fig
359
 
360
- # Theme functionality has been moved to inline function in main()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
361
 
362
  def main():
363
- with gr.Blocks(title="Salesforce B2B Commerce Migration Assistant", theme=gr.themes.Soft(primary_hue="blue")) as app:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
364
 
365
- gr.Markdown("# Salesforce B2B Commerce Migration Assistant")
366
- gr.Markdown("This tool helps migrate CloudCraze code to B2B Lightning Experience.")
367
 
368
- # Create model dropdowns
369
  with gr.Row():
370
  with gr.Column():
371
- gr.Markdown("### Primary Model")
372
  primary_model_dropdown = gr.Dropdown(
373
  choices=all_models,
374
- value=anthropic_models[0], # Default to Claude 3.7 Sonnet
375
- label="Select Primary AI Model for Conversion"
 
376
  )
377
 
378
  with gr.Column():
379
- gr.Markdown("### Validation Model")
380
  validation_model_dropdown = gr.Dropdown(
381
  choices=all_models,
382
- value=anthropic_models[1], # Default to Claude 3 Haiku
383
  label="Select Validation AI Model for Review",
384
- info="This model will validate and review the output from the primary model"
385
  )
386
 
387
- with gr.Tab("Apex Trigger Correction"):
388
- gr.Markdown("### Apex Trigger Correction")
389
- gr.Markdown("Paste your Apex Trigger code below:")
390
 
391
  trigger_input = gr.Textbox(
392
- lines=12,
393
- placeholder="Paste Apex Trigger code here...",
394
- label="Apex Trigger Code"
 
395
  )
396
 
397
  with gr.Row():
398
- trigger_button = gr.Button("Correct Apex Trigger", variant="primary")
399
- copy_code_button = gr.Button("Copy Code", variant="secondary")
400
 
401
- with gr.Accordion("Full Model Response (Hidden by Default)", open=False):
 
 
 
402
  trigger_full_response = gr.Textbox(
403
- lines=15,
404
  label="Full Model Response",
405
  interactive=False
406
  )
@@ -408,44 +954,45 @@ def main():
408
  with gr.Row():
409
  with gr.Column():
410
  trigger_explanation = gr.Textbox(
411
- lines=10,
412
- label="Explanation",
413
- placeholder="Explanation will appear here after correction",
414
  interactive=False,
415
  elem_id="trigger_explanation"
416
  )
417
 
418
  with gr.Column():
419
  trigger_code_output = gr.Code(
420
- language="python", # Using Python syntax highlighting as it's supported
421
- label="Corrected Code (Apex)",
422
- value="# Corrected Apex code will appear here",
423
  elem_id="trigger_code_output"
424
  )
425
 
426
- gr.Markdown("### Validation Results")
427
  with gr.Row():
428
  with gr.Column(scale=2):
429
  trigger_validation_output = gr.Textbox(
430
- lines=15,
431
- label="Validation Assessment",
432
- placeholder="Validation results will appear here after clicking 'Validate Correction'",
433
- interactive=True
 
434
  )
435
  with gr.Column(scale=1):
436
- trigger_chart = gr.Plot(label="Validation Metrics")
437
 
438
- validate_trigger_button = gr.Button("Validate Correction")
439
 
 
440
  def validate_and_chart_trigger(model, original, corrected):
441
  validation_text = validate_apex_trigger(model, original, corrected)
442
  metrics = extract_validation_metrics(validation_text)
443
- chart = create_radar_chart(metrics) if metrics else None
444
  return validation_text, chart
445
 
446
- # Handle button clicks
447
  trigger_button.click(
448
- fn=correct_apex_trigger,
449
  inputs=[primary_model_dropdown, trigger_input],
450
  outputs=[trigger_full_response, trigger_code_output, trigger_explanation],
451
  show_progress=True
@@ -458,44 +1005,44 @@ def main():
458
  show_progress=True
459
  )
460
 
461
- # Copy code button functionality
462
- def copy_code_message():
463
- return "Code copied to clipboard! (Use Ctrl+C/Cmd+C for manual copy if automatic copy fails)"
464
-
465
  copy_code_button.click(
466
- fn=copy_code_message,
467
  inputs=[],
468
- outputs=gr.Textbox(visible=False)
469
  )
470
 
471
  with gr.Row():
472
- trigger_clear = gr.Button("Clear Input")
473
  trigger_clear.click(lambda: "", [], trigger_input)
474
 
475
- results_clear = gr.Button("Clear Results")
476
  results_clear.click(
477
  lambda: ["", "", "", "", None],
478
  [],
479
  [trigger_full_response, trigger_code_output, trigger_explanation, trigger_validation_output, trigger_chart]
480
  )
481
 
482
- with gr.Tab("CloudCraze Object Conversion"):
483
- gr.Markdown("### CloudCraze Object Conversion")
484
- gr.Markdown("Paste your CloudCraze Object code below:")
485
 
486
  object_input = gr.Textbox(
487
- lines=12,
488
- placeholder="Paste CC object code here...",
489
- label="CloudCraze Object Code"
 
490
  )
491
 
492
  with gr.Row():
493
- object_button = gr.Button("Convert Object", variant="primary")
494
- object_copy_code_button = gr.Button("Copy Code", variant="secondary")
 
 
 
495
 
496
- with gr.Accordion("Full Model Response (Hidden by Default)", open=False):
497
  object_full_response = gr.Textbox(
498
- lines=15,
499
  label="Full Model Response",
500
  interactive=False
501
  )
@@ -503,44 +1050,44 @@ def main():
503
  with gr.Row():
504
  with gr.Column():
505
  object_explanation = gr.Textbox(
506
- lines=10,
507
- label="Explanation",
508
- placeholder="Explanation will appear here after conversion",
509
  interactive=False,
510
  elem_id="object_explanation"
511
  )
512
 
513
  with gr.Column():
514
  object_code_output = gr.Code(
515
- language="python", # Using Python syntax highlighting as it's supported
516
- label="Converted Code (Apex)",
517
- value="# Converted Apex code will appear here",
518
  elem_id="object_code_output"
519
  )
520
 
521
- gr.Markdown("### Validation Results")
522
  with gr.Row():
523
  with gr.Column(scale=2):
524
  object_validation_output = gr.Textbox(
525
- lines=15,
526
- label="Validation Assessment",
527
- placeholder="Validation results will appear here after clicking 'Validate Conversion'",
528
- interactive=True
 
529
  )
530
  with gr.Column(scale=1):
531
- object_chart = gr.Plot(label="Validation Metrics")
532
 
533
- validate_object_button = gr.Button("Validate Conversion")
534
 
535
  def validate_and_chart_object(model, original, converted):
536
  validation_text = validate_cc_object_conversion(model, original, converted)
537
  metrics = extract_validation_metrics(validation_text)
538
- chart = create_radar_chart(metrics) if metrics else None
539
  return validation_text, chart
540
 
541
- # Handle button clicks
542
  object_button.click(
543
- fn=convert_cc_object,
544
  inputs=[primary_model_dropdown, object_input],
545
  outputs=[object_full_response, object_code_output, object_explanation],
546
  show_progress=True
@@ -553,21 +1100,17 @@ def main():
553
  show_progress=True
554
  )
555
 
556
- # Copy code button functionality
557
- def copy_code_message():
558
- return "Code copied to clipboard! (Use Ctrl+C/Cmd+C for manual copy if automatic copy fails)"
559
-
560
  object_copy_code_button.click(
561
- fn=copy_code_message,
562
  inputs=[],
563
- outputs=gr.Textbox(visible=False)
564
  )
565
 
566
  with gr.Row():
567
- object_clear = gr.Button("Clear Input")
568
  object_clear.click(lambda: "", [], object_input)
569
 
570
- object_results_clear = gr.Button("Clear Results")
571
  object_results_clear.click(
572
  lambda: ["", "", "", "", None],
573
  [],
@@ -575,32 +1118,15 @@ def main():
575
  )
576
 
577
  # UI Preferences
578
- with gr.Accordion("UI Preferences", open=False):
579
  theme_radio = gr.Radio(
580
- label="Theme",
581
  choices=["Light", "Dark"],
582
  value="Light"
583
  )
584
 
585
- # Simple theme change function that applies CSS to individual components
586
- def change_theme(theme_choice):
587
- if theme_choice == "Dark":
588
- explanation_style = "background-color: #2e2e2e; color: #ffffff;"
589
- code_style = "background-color: #1e1e1e; color: #e0e0e0; font-family: 'Courier New', monospace;"
590
- else: # Light
591
- explanation_style = "background-color: #ffffff; color: #333333;"
592
- code_style = "background-color: #f5f5f5; color: #333333; font-family: 'Courier New', monospace;"
593
-
594
- return (
595
- explanation_style, # trigger_explanation
596
- code_style, # trigger_code_output
597
- explanation_style, # object_explanation
598
- code_style # object_code_output
599
- )
600
-
601
- # Connect the theme radio to the change_theme function
602
  theme_radio.change(
603
- fn=change_theme,
604
  inputs=[theme_radio],
605
  outputs=[
606
  trigger_explanation,
@@ -610,25 +1136,29 @@ def main():
610
  ]
611
  )
612
 
613
- gr.Markdown("### About This Tool")
614
  gr.Markdown(
615
  """
616
- **Primary Model**: Performs the initial code conversion or correction.
617
- **Validation Model**: Reviews and validates the output from the primary model, identifying potential issues or improvements.
618
- **Trigger Correction**: Fixes Apex Triggers for B2B LEx compatibility.
619
- **Object Conversion**: Maps and converts CloudCraze object definitions to B2B LEx.
620
- **Model Selection**: Choose from Together AI models or Anthropic's Claude models.
621
-
622
- **New Interface Features**:
623
- - Separated code output in dedicated code editor interface with syntax highlighting
624
- - Clear separation between explanations and code
625
- - "Copy Code" button for easy copying
626
- - Dark mode option for comfortable viewing
627
- - Hidden full model response to reduce clutter
628
-
629
- **Validation** outputs four key metrics (quality, accuracy, completeness, best practices) as both JSON and a radar chart.
630
- Always review AI-generated code before production use.
631
- """
 
 
 
 
632
  )
633
 
634
  app.launch()
 
6
  import plotly.express as px
7
  import pandas as pd
8
  import re
9
+ import hashlib
10
+ from functools import lru_cache
11
+ from typing import Dict, Tuple, Optional, List
12
+ import logging
13
+
14
+ # Configure logging
15
+ logging.basicConfig(level=logging.INFO)
16
+ logger = logging.getLogger(__name__)
17
 
18
  # Model options for dropdown with both Together AI and Anthropic models
19
  together_models = [
 
37
  "accuracy": "float (0.0–1.0)",
38
  "completeness": "float (0.0–1.0)",
39
  "best_practices_alignment": "float (0.0–1.0)",
40
+ "syntax_validity": "float (0.0–1.0)",
41
+ "security_score": "float (0.0–1.0)",
42
+ "performance_score": "float (0.0–1.0)",
43
  "explanations": {
44
  "quality_rating": "string",
45
  "accuracy": "string",
46
  "completeness": "string",
47
+ "best_practices_alignment": "string",
48
+ "syntax_validity": "string",
49
+ "security_score": "string",
50
+ "performance_score": "string"
51
+ },
52
+ "errors": ["list of syntax errors"],
53
+ "warnings": ["list of potential issues"],
54
+ "suggestions": ["list of improvement suggestions"]
55
+ }
56
+
57
+ # Apex syntax patterns for validation
58
+ APEX_PATTERNS = {
59
+ "class_declaration": r"(?:public|private|global|protected)\s+(?:virtual|abstract|with sharing|without sharing|inherited sharing)?\s*class\s+\w+",
60
+ "trigger_declaration": r"trigger\s+\w+\s+on\s+\w+\s*\([^)]+\)",
61
+ "method_declaration": r"(?:public|private|global|protected)\s+(?:static)?\s*(?:void|\w+)\s+\w+\s*\([^)]*\)",
62
+ "soql_query": r"(?:\[|Database\.query\s*\()\s*SELECT\s+.*?\s+FROM\s+\w+.*?(?:\]|\))",
63
+ "dml_operation": r"(?:insert|update|delete|undelete|upsert|merge)\s+\w+",
64
+ "bulkification_issue": r"for\s*\([^)]+\)\s*{[^}]*(?:insert|update|delete|undelete)\s+",
65
+ "hardcoded_id": r"(?:\'[a-zA-Z0-9]{15}\'|\'[a-zA-Z0-9]{18}\')",
66
+ "missing_null_check": r"(\w+)\.(\w+)(?!\s*(?:!=|==)\s*null)",
67
+ "governor_limit_risk": r"(?:for\s*\([^)]+\)\s*{[^}]*\[SELECT|Database\.query)",
68
+ }
69
+
70
+ # Common Apex errors and their fixes
71
+ APEX_ERRORS = {
72
+ "missing_semicolon": {
73
+ "pattern": r"[^{};]\s*\n\s*(?:public|private|global|protected|if|for|while|try)",
74
+ "message": "Missing semicolon at end of statement",
75
+ "severity": "error"
76
+ },
77
+ "unclosed_bracket": {
78
+ "pattern": r"(?:\{(?:[^{}]|(?:\{[^{}]*\}))*$)|(?:^[^{}]*\})",
79
+ "message": "Unclosed or extra bracket detected",
80
+ "severity": "error"
81
+ },
82
+ "invalid_soql": {
83
+ "pattern": r"\[\s*SELECT\s+FROM\s+\w+",
84
+ "message": "Invalid SOQL: Missing field selection",
85
+ "severity": "error"
86
+ },
87
+ "missing_try_catch_dml": {
88
+ "pattern": r"(?<!try\s{[^}]*)(insert|update|delete|upsert)\s+(?!.*catch)",
89
+ "message": "DML operation without try-catch block",
90
+ "severity": "warning"
91
  }
92
  }
93
 
94
+ # B2B Commerce specific patterns
95
+ B2B_COMMERCE_PATTERNS = {
96
+ "cloudcraze_reference": r"(?:ccrz__|E_\w+|CC_\w+)",
97
+ "b2b_lex_object": r"(?:OrderSummary|CartItem|WebCart|ProductCatalog|BuyerGroup|CommerceEntitlementPolicy)",
98
+ "deprecated_method": r"(?:ccrz\.cc_CallContext|ccrz\.ccAPI|cc_bean_\w+)",
99
+ "migration_required": r"(?:E_Product__|E_Cart__|E_Order__|CC_Promotions__|CC_Tax__)"
100
+ }
 
 
 
 
 
 
101
 
102
+ def get_api_key(provider: str) -> str:
103
+ """Securely retrieve API key for the specified provider."""
104
+ try:
105
+ if provider == "together":
106
+ api_key = os.getenv("TOGETHER_API_KEY")
107
+ if not api_key:
108
+ raise ValueError("API key not configured. Please contact administrator.")
109
+ return api_key
110
+ elif provider == "anthropic":
111
+ api_key = os.getenv("ANTHROPIC_API_KEY")
112
+ if not api_key:
113
+ raise ValueError("API key not configured. Please contact administrator.")
114
+ return api_key
115
+ else:
116
+ raise ValueError(f"Unknown provider: {provider}")
117
+ except Exception as e:
118
+ logger.error(f"Error retrieving API key: {e}")
119
+ raise
120
+
121
+ def get_provider(model: str) -> str:
122
+ """Determine the provider for a given model."""
123
  if model in together_models:
124
  return "together"
125
  elif model in anthropic_models:
 
127
  else:
128
  raise ValueError(f"Unknown model: {model}")
129
 
130
+ def handle_api_error(status_code: int, response_text: str) -> str:
131
+ """Handle API errors with appropriate user-friendly messages."""
132
+ if status_code == 401:
133
+ return "Authentication failed. Please check API configuration."
134
+ elif status_code == 429:
135
+ return "Rate limit exceeded. Please try again later."
136
+ elif status_code == 403:
137
+ return "Access forbidden. Please check your permissions."
138
+ elif status_code >= 500:
139
+ return "Service temporarily unavailable. Please try again."
140
+ else:
141
+ return f"Request failed with status {status_code}"
142
+
143
+ def call_api_with_retry(api_func, *args, max_retries: int = 3, timeout: int = 30, **kwargs):
144
+ """Call API with retry logic and timeout."""
145
+ for attempt in range(max_retries):
146
+ try:
147
+ kwargs['timeout'] = timeout
148
+ return api_func(*args, **kwargs)
149
+ except requests.Timeout:
150
+ if attempt == max_retries - 1:
151
+ return "Request timed out. Please try again with a shorter input."
152
+ except requests.ConnectionError:
153
+ if attempt == max_retries - 1:
154
+ return "Connection error. Please check your internet connection."
155
+ except Exception as e:
156
+ if attempt == max_retries - 1:
157
+ return f"Error: {str(e)}"
158
+ time.sleep(2 ** attempt) # Exponential backoff
159
+
160
+ def call_together_api(model: str, prompt: str, temperature: float = 0.7, max_tokens: int = 1500) -> str:
161
+ """Call Together AI API with enhanced error handling."""
162
  api_key = get_api_key("together")
163
  system_message = (
164
+ "You are a Salesforce development expert specializing in B2B Commerce migrations, "
165
+ "CloudCraze to B2B Lightning Experience conversions, and Apex code optimization. "
166
+ "You have a skeptical and thorough approach to code review, always checking for "
167
+ "syntax errors, security vulnerabilities, and performance issues."
168
  )
169
+
170
+ def make_request():
171
  headers = {
172
  "Authorization": f"Bearer {api_key}",
173
  "Content-Type": "application/json"
 
185
  resp = requests.post(
186
  "https://api.together.xyz/v1/chat/completions",
187
  headers=headers,
188
+ json=payload,
189
+ timeout=30
190
  )
191
  if resp.status_code != 200:
192
+ return handle_api_error(resp.status_code, resp.text)
193
  data = resp.json()
194
+ return data["choices"][0]["message"]["content"]
195
+
196
+ return call_api_with_retry(make_request)
 
197
 
198
+ def call_anthropic_api(model: str, prompt: str, temperature: float = 0.7, max_tokens: int = 1500) -> str:
199
+ """Call Anthropic API with enhanced error handling."""
200
  api_key = get_api_key("anthropic")
201
  system_message = (
202
+ "You are a Salesforce development expert specializing in B2B Commerce migrations, "
203
+ "CloudCraze to B2B Lightning Experience conversions, and Apex code optimization. "
204
+ "You have a skeptical and thorough approach to code review, always checking for "
205
+ "syntax errors, security vulnerabilities, and performance issues."
206
  )
207
+
208
+ def make_request():
209
  headers = {
210
  "x-api-key": api_key,
211
  "anthropic-version": "2023-06-01",
 
223
  resp = requests.post(
224
  "https://api.anthropic.com/v1/messages",
225
  headers=headers,
226
+ json=payload,
227
+ timeout=30
228
  )
229
  if resp.status_code != 200:
230
+ return handle_api_error(resp.status_code, resp.text)
231
  data = resp.json()
232
+ return data["content"][0]["text"]
233
+
234
+ return call_api_with_retry(make_request)
 
235
 
236
+ @lru_cache(maxsize=100)
237
+ def cached_llm_call(model_hash: str, prompt_hash: str, model: str, prompt: str, temperature: float = 0.7, max_tokens: int = 1500) -> str:
238
+ """Cached LLM call to avoid repeated API calls for same inputs."""
239
  provider = get_provider(model)
240
  if provider == "together":
241
  return call_together_api(model, prompt, temperature, max_tokens)
 
244
  else:
245
  return f"Error: Unknown provider for model {model}"
246
 
247
+ def call_llm(model: str, prompt: str, temperature: float = 0.7, max_tokens: int = 1500) -> str:
248
+ """Call LLM with caching support."""
249
+ model_hash = hashlib.md5(model.encode()).hexdigest()
250
+ prompt_hash = hashlib.md5(prompt.encode()).hexdigest()
251
+ return cached_llm_call(model_hash, prompt_hash, model, prompt, temperature, max_tokens)
252
+
253
+ def validate_apex_syntax(code: str) -> Tuple[bool, List[Dict[str, str]]]:
254
+ """Validate Apex syntax and return errors/warnings."""
255
+ issues = []
256
+
257
+ # Check for basic syntax errors
258
+ for error_type, error_info in APEX_ERRORS.items():
259
+ matches = re.finditer(error_info["pattern"], code, re.MULTILINE | re.DOTALL)
260
+ for match in matches:
261
+ issues.append({
262
+ "type": error_info["severity"],
263
+ "message": error_info["message"],
264
+ "line": code[:match.start()].count('\n') + 1,
265
+ "position": match.start()
266
+ })
267
+
268
+ # Check for Apex-specific patterns
269
+ if not re.search(APEX_PATTERNS["class_declaration"], code) and \
270
+ not re.search(APEX_PATTERNS["trigger_declaration"], code):
271
+ issues.append({
272
+ "type": "error",
273
+ "message": "No valid Apex class or trigger declaration found",
274
+ "line": 1,
275
+ "position": 0
276
+ })
277
+
278
+ # Check for bulkification issues
279
+ bulk_issues = re.finditer(APEX_PATTERNS["bulkification_issue"], code, re.DOTALL)
280
+ for match in bulk_issues:
281
+ issues.append({
282
+ "type": "error",
283
+ "message": "DML operation inside loop - violates bulkification best practices",
284
+ "line": code[:match.start()].count('\n') + 1,
285
+ "position": match.start()
286
+ })
287
+
288
+ # Check for hardcoded IDs
289
+ hardcoded_ids = re.finditer(APEX_PATTERNS["hardcoded_id"], code)
290
+ for match in hardcoded_ids:
291
+ issues.append({
292
+ "type": "warning",
293
+ "message": "Hardcoded Salesforce ID detected - use Custom Settings or Custom Metadata",
294
+ "line": code[:match.start()].count('\n') + 1,
295
+ "position": match.start()
296
+ })
297
+
298
+ # Check for governor limit risks
299
+ gov_limit_risks = re.finditer(APEX_PATTERNS["governor_limit_risk"], code, re.DOTALL)
300
+ for match in gov_limit_risks:
301
+ issues.append({
302
+ "type": "warning",
303
+ "message": "SOQL query inside loop - potential governor limit issue",
304
+ "line": code[:match.start()].count('\n') + 1,
305
+ "position": match.start()
306
+ })
307
+
308
+ has_errors = any(issue["type"] == "error" for issue in issues)
309
+ return not has_errors, issues
310
+
311
+ def extract_code_blocks(text: str) -> str:
312
+ """Enhanced code extraction with multiple strategies."""
313
+ # Strategy 1: Standard code blocks with language markers
314
+ pattern = r"```(?:apex|java|Apex|Java|APEX|JAVA)?\s*(.*?)```"
315
+ matches = re.findall(pattern, text, re.DOTALL | re.IGNORECASE)
316
 
 
317
  code_blocks = []
318
  for block in matches:
 
319
  cleaned_block = block.strip()
320
  if cleaned_block:
321
  code_blocks.append(cleaned_block)
322
 
323
+ # Strategy 2: Improved fallback detection for Apex-specific patterns
324
+ if not code_blocks:
325
+ apex_patterns = [
326
+ # Class declarations (including inner classes)
327
+ r"((?:public|private|global|protected)\s+(?:virtual|abstract|with sharing|without sharing|inherited sharing)?\s*class\s+\w+(?:\s+extends\s+\w+)?(?:\s+implements\s+[\w\s,]+)?\s*\{(?:[^{}]|\{[^{}]*\})*\})",
328
+ # Trigger declarations
329
+ r"(trigger\s+\w+\s+on\s+\w+\s*\([^)]+\)\s*\{(?:[^{}]|\{[^{}]*\})*\})",
330
+ # Interface declarations
331
+ r"((?:public|private|global)\s+interface\s+\w+(?:\s+extends\s+[\w\s,]+)?\s*\{(?:[^{}]|\{[^{}]*\})*\})",
332
+ # Enum declarations
333
+ r"((?:public|private|global)\s+enum\s+\w+\s*\{[^}]+\})",
334
+ # Annotated methods or classes
335
+ r"(@\w+(?:\([^)]*\))?\s*(?:public|private|global|protected).*?(?:\{(?:[^{}]|\{[^{}]*\})*\}|;))"
336
+ ]
337
 
338
+ for pattern in apex_patterns:
339
+ found = re.findall(pattern, text, re.DOTALL | re.MULTILINE)
340
+ code_blocks.extend(found)
341
+
342
+ # Strategy 3: Look for code between specific markers
343
+ if not code_blocks:
344
+ # Look for code after phrases like "corrected code:", "here's the code:", etc.
345
+ marker_patterns = [
346
+ r"(?:corrected|fixed|updated|converted|modified)\s+code\s*:\s*\n((?:(?:public|private|global|trigger).*?)(?=\n\n|\Z))",
347
+ r"(?:here'?s?|below is)\s+(?:the|your)\s+(?:corrected|fixed|updated)\s+\w+\s*:\s*\n((?:(?:public|private|global|trigger).*?)(?=\n\n|\Z))"
348
+ ]
349
 
350
+ for pattern in marker_patterns:
351
+ found = re.findall(pattern, text, re.DOTALL | re.IGNORECASE)
352
+ code_blocks.extend(found)
353
 
354
+ return '\n\n'.join(filter(None, code_blocks))
355
 
356
+ def extract_explanations(text: str, code_blocks: str) -> str:
357
+ """Extract explanations by removing code blocks from the response."""
 
358
  explanation = text
359
+
360
+ # Remove code blocks
361
+ if code_blocks:
362
+ for block in code_blocks.split('\n\n'):
363
+ if block.strip():
364
+ # Escape special regex characters
365
+ escaped_block = re.escape(block)
366
+ explanation = re.sub(escaped_block, "", explanation, flags=re.DOTALL)
367
 
368
  # Remove code block markers
369
+ explanation = re.sub(r"```(?:apex|java|Apex|Java|APEX|JAVA)?.*?```", "*[Code moved to Code Output section]*", explanation, flags=re.DOTALL)
370
 
371
+ # Clean up extra whitespace
372
+ explanation = re.sub(r'\n{3,}', '\n\n', explanation)
373
 
374
  return explanation.strip()
375
 
376
+ def perform_skeptical_evaluation(code: str, context: str = "trigger") -> Dict[str, any]:
377
+ """Perform skeptical evaluation of code looking for common issues."""
378
+ evaluation = {
379
+ "syntax_issues": [],
380
+ "security_concerns": [],
381
+ "performance_issues": [],
382
+ "best_practice_violations": [],
383
+ "b2b_commerce_issues": []
384
+ }
385
+
386
+ # Syntax validation
387
+ is_valid, syntax_issues = validate_apex_syntax(code)
388
+ evaluation["syntax_issues"] = syntax_issues
389
+
390
+ # Security checks
391
+ if re.search(r"without\s+sharing", code, re.IGNORECASE):
392
+ evaluation["security_concerns"].append({
393
+ "type": "warning",
394
+ "message": "Class declared 'without sharing' - ensure this is intentional"
395
+ })
396
+
397
+ if not re.search(r"\.stripInaccessible\(", code) and re.search(r"(insert|update)\s+", code):
398
+ evaluation["security_concerns"].append({
399
+ "type": "warning",
400
+ "message": "DML operations without stripInaccessible - potential FLS violation"
401
+ })
402
+
403
+ # Performance checks
404
+ nested_loops = re.findall(r"for\s*\([^)]+\)\s*\{[^}]*for\s*\([^)]+\)", code, re.DOTALL)
405
+ if nested_loops:
406
+ evaluation["performance_issues"].append({
407
+ "type": "warning",
408
+ "message": f"Nested loops detected ({len(nested_loops)} occurrences) - review for O(nΒ²) complexity"
409
+ })
410
+
411
+ # Check for missing test assertions (if it's a test class)
412
+ if re.search(r"@isTest|testMethod", code, re.IGNORECASE):
413
+ if not re.search(r"System\.assert|Assert\.", code):
414
+ evaluation["best_practice_violations"].append({
415
+ "type": "error",
416
+ "message": "Test class without assertions - tests must verify behavior"
417
+ })
418
+
419
+ # B2B Commerce specific checks
420
+ cloudcraze_refs = re.findall(B2B_COMMERCE_PATTERNS["cloudcraze_reference"], code)
421
+ if cloudcraze_refs:
422
+ evaluation["b2b_commerce_issues"].append({
423
+ "type": "error",
424
+ "message": f"CloudCraze references found ({len(set(cloudcraze_refs))} unique) - must be migrated to B2B LEX"
425
+ })
426
+
427
+ deprecated_methods = re.findall(B2B_COMMERCE_PATTERNS["deprecated_method"], code)
428
+ if deprecated_methods:
429
+ evaluation["b2b_commerce_issues"].append({
430
+ "type": "error",
431
+ "message": f"Deprecated CloudCraze methods found: {', '.join(set(deprecated_methods))}"
432
+ })
433
+
434
+ return evaluation
435
+
436
+ def generate_test_cases(code_type: str, code: str) -> str:
437
+ """Generate test cases for the given code."""
438
+ if code_type == "trigger":
439
+ return f"""
440
+ // Test class for the trigger
441
+ @isTest
442
+ private class Test_MigratedTrigger {{
443
+ @TestSetup
444
+ static void setup() {{
445
+ // Create test data
446
+ // TODO: Add specific test data setup
447
+ }}
448
+
449
+ @isTest
450
+ static void testBulkInsert() {{
451
+ // Test bulk insert scenario
452
+ List<SObject> testRecords = new List<SObject>();
453
+ for(Integer i = 0; i < 200; i++) {{
454
+ // TODO: Create test records
455
+ }}
456
+
457
+ Test.startTest();
458
+ insert testRecords;
459
+ Test.stopTest();
460
+
461
+ // TODO: Add assertions
462
+ System.assert(true, 'Bulk insert test needs implementation');
463
+ }}
464
+
465
+ @isTest
466
+ static void testBulkUpdate() {{
467
+ // Test bulk update scenario
468
+ // TODO: Implement bulk update test
469
+ }}
470
+
471
+ @isTest
472
+ static void testErrorHandling() {{
473
+ // Test error scenarios
474
+ // TODO: Test validation rules, required fields, etc.
475
+ }}
476
+
477
+ @isTest
478
+ static void testGovernorLimits() {{
479
+ // Test near governor limits
480
+ // TODO: Test with large data volumes
481
+ }}
482
+ }}
483
+ """
484
+ else: # object conversion
485
+ return f"""
486
+ // Test data creation for migrated object
487
+ @isTest
488
+ public class Test_MigratedObjectData {{
489
+ public static SObject createTestRecord() {{
490
+ // TODO: Create and return test instance
491
+ return null;
492
+ }}
493
+
494
+ public static List<SObject> createBulkTestRecords(Integer count) {{
495
+ List<SObject> records = new List<SObject>();
496
+ for(Integer i = 0; i < count; i++) {{
497
+ // TODO: Create test records
498
+ }}
499
+ return records;
500
+ }}
501
+
502
+ public static void validateMigrationMapping() {{
503
+ // Validate that all fields are properly mapped
504
+ // TODO: Add field mapping validation
505
+ }}
506
+ }}
507
+ """
508
+
509
+ def correct_apex_trigger(model: str, trigger_code: str, progress=None) -> Tuple[str, str, str]:
510
+ """Correct Apex Trigger with skeptical evaluation."""
511
+ if progress:
512
+ progress(0.1, desc="Validating input...")
513
+
514
+ # Input validation
515
  if not trigger_code.strip():
516
  return "Please provide Apex Trigger code to correct.", "", ""
517
+
518
+ if len(trigger_code.strip()) < 50:
519
+ return "Code too short to be a valid Apex trigger. Please provide complete code.", "", ""
520
+
521
+ # Perform initial syntax check
522
+ is_valid, syntax_issues = validate_apex_syntax(trigger_code)
523
+
524
+ if progress:
525
+ progress(0.3, desc="Analyzing code structure...")
526
+
527
+ # Perform skeptical evaluation
528
+ evaluation = perform_skeptical_evaluation(trigger_code, "trigger")
529
+
530
+ # Build comprehensive prompt
531
  prompt = f"""
532
+ You are tasked with correcting and optimizing the following Apex Trigger for migration from CloudCraze to B2B Lightning Experience.
533
+
534
+ IMPORTANT: Apply a SKEPTICAL lens to this code. Assume there are hidden issues and actively look for:
535
+ 1. Syntax errors (missing semicolons, brackets, incorrect method signatures)
536
+ 2. Logic errors (null pointer exceptions, incorrect loop conditions)
537
+ 3. Security vulnerabilities (FLS violations, SOQL injection risks)
538
+ 4. Performance issues (queries in loops, inefficient algorithms)
539
+ 5. Governor limit risks (excessive DML, SOQL operations)
540
+ 6. B2B Commerce specific issues (deprecated CloudCraze methods, incorrect object mappings)
541
 
542
+ Initial Analysis Found:
543
+ - Syntax Issues: {len(syntax_issues)}
544
+ - Security Concerns: {len(evaluation['security_concerns'])}
545
+ - Performance Issues: {len(evaluation['performance_issues'])}
546
+ - B2B Commerce Issues: {len(evaluation['b2b_commerce_issues'])}
547
+
548
+ ORIGINAL TRIGGER CODE:
549
  ```apex
550
  {trigger_code}
551
  ```
552
 
553
+ REQUIREMENTS:
554
+ 1. Fix ALL syntax errors
555
+ 2. Implement proper bulkification
556
+ 3. Add comprehensive error handling
557
+ 4. Ensure FLS/CRUD security
558
+ 5. Optimize for performance
559
+ 6. Migrate CloudCraze references to B2B Lightning Experience
560
+ 7. Add detailed comments explaining each fix
561
+
562
+ Return the corrected code in ```apex blocks with detailed explanations of ALL changes made.
563
  """
564
+
565
+ if progress:
566
+ progress(0.5, desc="Calling AI model...")
567
+
568
+ response = call_llm(model, prompt, temperature=0.3) # Lower temperature for more consistent corrections
569
+
570
+ if progress:
571
+ progress(0.8, desc="Processing response...")
572
 
573
+ # Extract code and explanations
574
  code_output = extract_code_blocks(response)
575
+
576
+ # Validate the corrected code
577
+ if code_output:
578
+ corrected_valid, corrected_issues = validate_apex_syntax(code_output)
579
+ if not corrected_valid:
580
+ # Add warning to explanation
581
+ response += f"\n\n⚠️ WARNING: The corrected code still has {len(corrected_issues)} syntax issues that need manual review."
582
+
583
  explanation = extract_explanations(response, code_output)
584
 
585
+ # Add test case template
586
+ test_template = generate_test_cases("trigger", code_output)
587
+ explanation += f"\n\n### Suggested Test Class Template:\n```apex\n{test_template}\n```"
588
+
589
+ if progress:
590
+ progress(1.0, desc="Complete!")
591
+
592
  return response, code_output, explanation
593
 
594
+ def convert_cc_object(model: str, cc_object_code: str, progress=None) -> Tuple[str, str, str]:
595
+ """Convert CloudCraze Object with skeptical evaluation."""
596
+ if progress:
597
+ progress(0.1, desc="Validating input...")
598
+
599
+ # Input validation
600
  if not cc_object_code.strip():
601
  return "Please provide CloudCraze Object code to convert.", "", ""
602
+
603
+ if len(cc_object_code.strip()) < 30:
604
+ return "Code too short to be a valid CloudCraze object. Please provide complete code.", "", ""
605
+
606
+ if progress:
607
+ progress(0.3, desc="Analyzing CloudCraze structure...")
608
+
609
+ # Check for CloudCraze patterns
610
+ has_cc_pattern = bool(re.search(B2B_COMMERCE_PATTERNS["cloudcraze_reference"], cc_object_code))
611
+ if not has_cc_pattern:
612
+ logger.warning("No obvious CloudCraze patterns found in input")
613
+
614
+ # Perform evaluation
615
+ evaluation = perform_skeptical_evaluation(cc_object_code, "object")
616
+
617
  prompt = f"""
618
+ You are tasked with converting CloudCraze Object code to B2B Lightning Experience format.
619
+
620
+ IMPORTANT: Apply a SKEPTICAL lens to this conversion. Actively look for:
621
+ 1. Missing or incorrectly mapped fields
622
+ 2. Data type mismatches between CloudCraze and B2B LEX
623
+ 3. Relationship mapping issues
624
+ 4. Custom fields that have no B2B LEX equivalent
625
+ 5. Business logic embedded in CloudCraze that needs migration
626
+ 6. Data migration challenges (data format changes, validation rules)
627
 
628
+ CLOUDCRAZE OBJECT CODE:
629
  ```
630
  {cc_object_code}
631
  ```
632
 
633
+ REQUIREMENTS:
634
+ 1. Identify the exact B2B LEX object mapping
635
+ 2. Map ALL fields with data type conversions
636
+ 3. Handle custom fields appropriately
637
+ 4. Document any data migration considerations
638
+ 5. Provide complete implementation code
639
+ 6. Include data migration script if needed
640
+ 7. List any manual steps required
641
+
642
  Return:
643
+ 1. Complete B2B LEX object implementation in ```apex blocks
644
+ 2. Field mapping table
645
+ 3. Data migration considerations
646
+ 4. Manual migration steps if any
647
  """
648
+
649
+ if progress:
650
+ progress(0.5, desc="Calling AI model...")
651
+
652
+ response = call_llm(model, prompt, temperature=0.3)
653
 
654
+ if progress:
655
+ progress(0.8, desc="Processing response...")
656
+
657
+ # Extract code and explanations
658
  code_output = extract_code_blocks(response)
659
  explanation = extract_explanations(response, code_output)
660
 
661
+ # Add test case template
662
+ test_template = generate_test_cases("object", code_output)
663
+ explanation += f"\n\n### Suggested Test Data Creation:\n```apex\n{test_template}\n```"
664
+
665
+ if progress:
666
+ progress(1.0, desc="Complete!")
667
+
668
  return response, code_output, explanation
669
 
670
+ def extract_validation_metrics(validation_text: str) -> Optional[Dict[str, float]]:
671
+ """Enhanced JSON extraction for validation metrics."""
672
+ try:
673
+ # Strategy 1: Look for JSON after specific markers
674
+ json_patterns = [
675
+ r'(?:json|JSON|assessment|Assessment)[\s:]*({[^{}]*(?:{[^{}]*}[^{}]*)*})',
676
+ r'```json\s*({[^`]+})\s*```',
677
+ r'({[^{}]*"quality_rating"[^{}]*(?:{[^{}]*}[^{}]*)*})'
678
+ ]
679
+
680
+ for pattern in json_patterns:
681
+ matches = re.findall(pattern, validation_text, re.DOTALL)
682
+ for match in matches:
683
+ try:
684
+ data = json.loads(match)
685
+ if "quality_rating" in data:
686
+ return normalize_metrics(data)
687
+ except json.JSONDecodeError:
688
+ continue
689
+
690
+ # Strategy 2: Extract individual metrics if JSON parsing fails
691
+ metrics = {}
692
+ metric_patterns = {
693
+ "quality_rating": r"quality_rating[\"']?\s*:\s*(\d+(?:\.\d+)?)",
694
+ "accuracy": r"accuracy[\"']?\s*:\s*(\d+(?:\.\d+)?)",
695
+ "completeness": r"completeness[\"']?\s*:\s*(\d+(?:\.\d+)?)",
696
+ "best_practices_alignment": r"best_practices_alignment[\"']?\s*:\s*(\d+(?:\.\d+)?)",
697
+ "syntax_validity": r"syntax_validity[\"']?\s*:\s*(\d+(?:\.\d+)?)",
698
+ "security_score": r"security_score[\"']?\s*:\s*(\d+(?:\.\d+)?)",
699
+ "performance_score": r"performance_score[\"']?\s*:\s*(\d+(?:\.\d+)?)"
700
+ }
701
+
702
+ for metric, pattern in metric_patterns.items():
703
+ match = re.search(pattern, validation_text, re.IGNORECASE)
704
+ if match:
705
+ metrics[metric] = float(match.group(1))
706
+
707
+ if metrics:
708
+ return normalize_metrics(metrics)
709
+
710
+ return None
711
+
712
+ except Exception as e:
713
+ logger.error(f"Error extracting metrics: {e}")
714
+ return None
715
+
716
+ def normalize_metrics(data: Dict) -> Dict[str, float]:
717
+ """Ensure metrics are in the correct format and range."""
718
+ normalized = {
719
+ "quality_rating": min(10, max(0, float(data.get("quality_rating", 0)))),
720
+ "accuracy": min(1.0, max(0.0, float(data.get("accuracy", 0.0)))),
721
+ "completeness": min(1.0, max(0.0, float(data.get("completeness", 0.0)))),
722
+ "best_practices_alignment": min(1.0, max(0.0, float(data.get("best_practices_alignment", 0.0)))),
723
+ "syntax_validity": min(1.0, max(0.0, float(data.get("syntax_validity", 0.0)))),
724
+ "security_score": min(1.0, max(0.0, float(data.get("security_score", 0.0)))),
725
+ "performance_score": min(1.0, max(0.0, float(data.get("performance_score", 0.0))))
726
+ }
727
+ return normalized
728
+
729
+ def create_enhanced_radar_chart(metrics: Optional[Dict[str, float]]) -> Optional[object]:
730
+ """Create an enhanced radar chart with more metrics."""
731
+ if not metrics:
732
+ return None
733
+
734
+ # Create data for the radar chart
735
+ categories = [
736
+ "Quality",
737
+ "Accuracy",
738
+ "Completeness",
739
+ "Best Practices",
740
+ "Syntax Valid",
741
+ "Security",
742
+ "Performance"
743
+ ]
744
+
745
+ values = [
746
+ metrics.get("quality_rating", 0) / 10, # Normalize to 0-1 scale
747
+ metrics.get("accuracy", 0),
748
+ metrics.get("completeness", 0),
749
+ metrics.get("best_practices_alignment", 0),
750
+ metrics.get("syntax_validity", 0),
751
+ metrics.get("security_score", 0),
752
+ metrics.get("performance_score", 0)
753
+ ]
754
+
755
+ # Create a DataFrame for plotting
756
+ df = pd.DataFrame({
757
+ 'Category': categories,
758
+ 'Value': values
759
+ })
760
+
761
+ # Create the radar chart
762
+ fig = px.line_polar(
763
+ df, r='Value', theta='Category', line_close=True,
764
+ range_r=[0, 1], title="Comprehensive Validation Assessment"
765
+ )
766
+ fig.update_traces(fill='toself', fillcolor='rgba(0, 100, 255, 0.2)')
767
+ fig.update_layout(
768
+ polar=dict(
769
+ radialaxis=dict(
770
+ visible=True,
771
+ range=[0, 1]
772
+ )
773
+ ),
774
+ showlegend=False,
775
+ height=400
776
+ )
777
+
778
+ return fig
779
+
780
+ def validate_apex_trigger(validation_model: str, original_code: str, corrected_code: str) -> str:
781
+ """Enhanced validation with skeptical evaluation."""
782
  if not validation_model or not original_code.strip() or not corrected_code.strip():
783
  return "Please provide all required inputs for validation."
784
 
785
+ # Perform syntax validation on both
786
+ orig_valid, orig_issues = validate_apex_syntax(original_code)
787
+ corr_valid, corr_issues = validate_apex_syntax(corrected_code)
788
+
789
  prompt = f"""
790
+ You are performing a SKEPTICAL validation of an Apex code migration. Your job is to find problems, not to praise.
791
 
792
+ ORIGINAL CODE (had {len(orig_issues)} issues):
793
  ```apex
794
  {original_code}
795
  ```
796
 
797
+ CORRECTED CODE (has {len(corr_issues)} issues):
798
  ```apex
799
  {corrected_code}
800
  ```
801
 
802
+ CRITICAL EVALUATION REQUIRED:
803
+ 1. List ALL remaining syntax errors in the corrected code
804
+ 2. Identify any NEW issues introduced by the correction
805
+ 3. Find security vulnerabilities (FLS, CRUD, injection risks)
806
+ 4. Identify performance problems (O(nΒ²) algorithms, unbounded queries)
807
+ 5. Check governor limit risks (queries/DML in loops)
808
+ 6. Verify B2B Commerce migration completeness
809
+ 7. Look for edge cases not handled
810
+ 8. Check error handling completeness
811
 
812
+ IMPORTANT: Be harsh but fair. If the correction is genuinely good, acknowledge it, but still look for improvements.
813
+
814
+ Provide your assessment in this JSON format:
815
  {json.dumps(VALIDATION_SCHEMA, indent=2)}
816
 
817
+ Be specific about line numbers and provide actionable feedback.
818
  """
819
+
820
+ return call_llm(validation_model, prompt, temperature=0.2) # Very low temperature for consistent validation
821
 
822
+ def validate_cc_object_conversion(validation_model: str, original_object: str, converted_object: str) -> str:
823
+ """Enhanced validation for CloudCraze object conversion."""
824
  if not validation_model or not original_object.strip() or not converted_object.strip():
825
  return "Please provide all required inputs for validation."
826
 
827
  prompt = f"""
828
+ You are performing a SKEPTICAL validation of a CloudCraze to B2B Lightning Experience object conversion.
829
 
830
  ORIGINAL CLOUDCRAZE OBJECT:
831
  ```
 
837
  {converted_object}
838
  ```
839
 
840
+ CRITICAL EVALUATION REQUIRED:
841
+ 1. Verify EVERY field is mapped correctly (check data types!)
842
+ 2. Identify missing fields or relationships
843
+ 3. Check for custom field handling
844
+ 4. Validate business logic migration
845
+ 5. Identify data migration challenges
846
+ 6. Check for hardcoded values that should be configurable
847
+ 7. Verify object security settings
848
+ 8. Look for performance implications
849
+
850
+ SPECIFIC CHECKS:
851
+ - Are all CloudCraze custom fields accounted for?
852
+ - Are relationship fields properly mapped?
853
+ - Are there data type mismatches?
854
+ - Are validation rules considered?
855
+ - Is the object scalable for large data volumes?
856
 
857
+ Provide your assessment in this JSON format:
858
  {json.dumps(VALIDATION_SCHEMA, indent=2)}
859
 
860
+ Include specific examples of issues found.
861
  """
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
862
 
863
+ return call_llm(validation_model, prompt, temperature=0.2)
 
 
 
 
 
 
 
864
 
865
+ def get_theme_styles(theme_choice: str) -> Tuple[str, str, str, str]:
866
+ """Get theme styles for different UI elements."""
867
+ themes = {
868
+ "Dark": {
869
+ "explanation": "background-color: #1e1e1e; color: #e0e0e0; padding: 15px; border-radius: 8px; font-family: 'Inter', sans-serif; line-height: 1.6;",
870
+ "code": "background-color: #0d1117; color: #c9d1d9; font-family: 'Fira Code', 'Consolas', monospace; padding: 15px; border-radius: 8px; border: 1px solid #30363d; font-size: 14px; line-height: 1.5;",
871
+ "validation": "background-color: #161b22; color: #c9d1d9; padding: 15px; border-radius: 8px; border: 1px solid #30363d;",
872
+ "error": "background-color: #3d1418; color: #f85149; padding: 10px; border-radius: 5px; border: 1px solid #f85149;"
873
+ },
874
+ "Light": {
875
+ "explanation": "background-color: #ffffff; color: #24292e; padding: 15px; border-radius: 8px; border: 1px solid #e1e4e8; font-family: 'Inter', sans-serif; line-height: 1.6;",
876
+ "code": "background-color: #f6f8fa; color: #24292e; font-family: 'Fira Code', 'Consolas', monospace; padding: 15px; border-radius: 8px; border: 1px solid #e1e4e8; font-size: 14px; line-height: 1.5;",
877
+ "validation": "background-color: #f6f8fa; color: #24292e; padding: 15px; border-radius: 8px; border: 1px solid #e1e4e8;",
878
+ "error": "background-color: #ffe4e6; color: #d73a49; padding: 10px; border-radius: 5px; border: 1px solid #d73a49;"
879
+ }
880
+ }
881
+
882
+ theme = themes.get(theme_choice, themes["Light"])
883
+ return (theme["explanation"], theme["code"], theme["explanation"], theme["code"])
884
 
885
  def main():
886
+ """Main application entry point."""
887
+ with gr.Blocks(
888
+ title="Salesforce B2B Commerce Migration Assistant",
889
+ theme=gr.themes.Soft(primary_hue="blue"),
890
+ css="""
891
+ .gradio-container {
892
+ font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
893
+ }
894
+ .gr-button-primary {
895
+ background-color: #0969da !important;
896
+ }
897
+ .gr-button-primary:hover {
898
+ background-color: #0860ca !important;
899
+ }
900
+ code {
901
+ font-family: 'Fira Code', 'Consolas', 'Monaco', monospace;
902
+ }
903
+ """
904
+ ) as app:
905
 
906
+ gr.Markdown("# πŸš€ Salesforce B2B Commerce Migration Assistant")
907
+ gr.Markdown("Advanced tool for migrating CloudCraze code to B2B Lightning Experience with skeptical AI validation.")
908
 
909
+ # Model selection
910
  with gr.Row():
911
  with gr.Column():
912
+ gr.Markdown("### πŸ€– Primary Model")
913
  primary_model_dropdown = gr.Dropdown(
914
  choices=all_models,
915
+ value=anthropic_models[0],
916
+ label="Select Primary AI Model for Conversion",
917
+ info="This model performs the initial code conversion"
918
  )
919
 
920
  with gr.Column():
921
+ gr.Markdown("### πŸ” Validation Model")
922
  validation_model_dropdown = gr.Dropdown(
923
  choices=all_models,
924
+ value=anthropic_models[1],
925
  label="Select Validation AI Model for Review",
926
+ info="This model skeptically reviews and validates the output"
927
  )
928
 
929
+ with gr.Tab("⚑ Apex Trigger Correction"):
930
+ gr.Markdown("### Apex Trigger Correction & Optimization")
931
+ gr.Markdown("Paste your Apex Trigger code for analysis, correction, and optimization.")
932
 
933
  trigger_input = gr.Textbox(
934
+ lines=15,
935
+ placeholder="Paste your Apex Trigger code here...\n\nExample:\ntrigger AccountTrigger on Account (before insert, before update) {\n // Your trigger logic\n}",
936
+ label="Apex Trigger Code",
937
+ elem_classes="code-input"
938
  )
939
 
940
  with gr.Row():
941
+ trigger_button = gr.Button("πŸ”§ Correct & Optimize", variant="primary", size="lg")
942
+ copy_code_button = gr.Button("πŸ“‹ Copy Code", variant="secondary")
943
 
944
+ # Progress indicator
945
+ trigger_progress = gr.Textbox(label="Progress", visible=False)
946
+
947
+ with gr.Accordion("πŸ“„ Full Model Response", open=False):
948
  trigger_full_response = gr.Textbox(
949
+ lines=20,
950
  label="Full Model Response",
951
  interactive=False
952
  )
 
954
  with gr.Row():
955
  with gr.Column():
956
  trigger_explanation = gr.Textbox(
957
+ lines=15,
958
+ label="πŸ“ Explanation & Analysis",
959
+ placeholder="Detailed explanation will appear here...",
960
  interactive=False,
961
  elem_id="trigger_explanation"
962
  )
963
 
964
  with gr.Column():
965
  trigger_code_output = gr.Code(
966
+ language="java",
967
+ label="βœ… Corrected Code (Apex)",
968
+ value="// Corrected Apex code will appear here",
969
  elem_id="trigger_code_output"
970
  )
971
 
972
+ gr.Markdown("### 🎯 Validation Results")
973
  with gr.Row():
974
  with gr.Column(scale=2):
975
  trigger_validation_output = gr.Textbox(
976
+ lines=20,
977
+ label="πŸ” Skeptical Validation Assessment",
978
+ placeholder="Validation results will appear here...",
979
+ interactive=True,
980
+ elem_id="trigger_validation"
981
  )
982
  with gr.Column(scale=1):
983
+ trigger_chart = gr.Plot(label="πŸ“Š Validation Metrics")
984
 
985
+ validate_trigger_button = gr.Button("πŸ” Validate Correction", variant="secondary", size="lg")
986
 
987
+ # Wire up functionality
988
  def validate_and_chart_trigger(model, original, corrected):
989
  validation_text = validate_apex_trigger(model, original, corrected)
990
  metrics = extract_validation_metrics(validation_text)
991
+ chart = create_enhanced_radar_chart(metrics) if metrics else None
992
  return validation_text, chart
993
 
 
994
  trigger_button.click(
995
+ fn=lambda m, c: correct_apex_trigger(m, c, gr.Progress()),
996
  inputs=[primary_model_dropdown, trigger_input],
997
  outputs=[trigger_full_response, trigger_code_output, trigger_explanation],
998
  show_progress=True
 
1005
  show_progress=True
1006
  )
1007
 
 
 
 
 
1008
  copy_code_button.click(
1009
+ fn=lambda: gr.Info("Code copied! Use Ctrl+C/Cmd+C if automatic copy fails."),
1010
  inputs=[],
1011
+ outputs=[]
1012
  )
1013
 
1014
  with gr.Row():
1015
+ trigger_clear = gr.Button("πŸ—‘οΈ Clear Input")
1016
  trigger_clear.click(lambda: "", [], trigger_input)
1017
 
1018
+ results_clear = gr.Button("🧹 Clear Results")
1019
  results_clear.click(
1020
  lambda: ["", "", "", "", None],
1021
  [],
1022
  [trigger_full_response, trigger_code_output, trigger_explanation, trigger_validation_output, trigger_chart]
1023
  )
1024
 
1025
+ with gr.Tab("πŸ”„ CloudCraze Object Conversion"):
1026
+ gr.Markdown("### CloudCraze to B2B Lightning Experience Object Conversion")
1027
+ gr.Markdown("Convert CloudCraze custom objects to B2B Lightning Experience format.")
1028
 
1029
  object_input = gr.Textbox(
1030
+ lines=15,
1031
+ placeholder="Paste your CloudCraze Object definition here...\n\nExample:\nE_Product__c fields, relationships, and custom logic",
1032
+ label="CloudCraze Object Code",
1033
+ elem_classes="code-input"
1034
  )
1035
 
1036
  with gr.Row():
1037
+ object_button = gr.Button("πŸ”„ Convert Object", variant="primary", size="lg")
1038
+ object_copy_code_button = gr.Button("πŸ“‹ Copy Code", variant="secondary")
1039
+
1040
+ # Progress indicator
1041
+ object_progress = gr.Textbox(label="Progress", visible=False)
1042
 
1043
+ with gr.Accordion("πŸ“„ Full Model Response", open=False):
1044
  object_full_response = gr.Textbox(
1045
+ lines=20,
1046
  label="Full Model Response",
1047
  interactive=False
1048
  )
 
1050
  with gr.Row():
1051
  with gr.Column():
1052
  object_explanation = gr.Textbox(
1053
+ lines=15,
1054
+ label="πŸ“ Conversion Explanation",
1055
+ placeholder="Detailed explanation will appear here...",
1056
  interactive=False,
1057
  elem_id="object_explanation"
1058
  )
1059
 
1060
  with gr.Column():
1061
  object_code_output = gr.Code(
1062
+ language="java",
1063
+ label="βœ… Converted Code (B2B LEX)",
1064
+ value="// Converted B2B Lightning Experience code will appear here",
1065
  elem_id="object_code_output"
1066
  )
1067
 
1068
+ gr.Markdown("### 🎯 Validation Results")
1069
  with gr.Row():
1070
  with gr.Column(scale=2):
1071
  object_validation_output = gr.Textbox(
1072
+ lines=20,
1073
+ label="πŸ” Skeptical Validation Assessment",
1074
+ placeholder="Validation results will appear here...",
1075
+ interactive=True,
1076
+ elem_id="object_validation"
1077
  )
1078
  with gr.Column(scale=1):
1079
+ object_chart = gr.Plot(label="πŸ“Š Validation Metrics")
1080
 
1081
+ validate_object_button = gr.Button("πŸ” Validate Conversion", variant="secondary", size="lg")
1082
 
1083
  def validate_and_chart_object(model, original, converted):
1084
  validation_text = validate_cc_object_conversion(model, original, converted)
1085
  metrics = extract_validation_metrics(validation_text)
1086
+ chart = create_enhanced_radar_chart(metrics) if metrics else None
1087
  return validation_text, chart
1088
 
 
1089
  object_button.click(
1090
+ fn=lambda m, c: convert_cc_object(m, c, gr.Progress()),
1091
  inputs=[primary_model_dropdown, object_input],
1092
  outputs=[object_full_response, object_code_output, object_explanation],
1093
  show_progress=True
 
1100
  show_progress=True
1101
  )
1102
 
 
 
 
 
1103
  object_copy_code_button.click(
1104
+ fn=lambda: gr.Info("Code copied! Use Ctrl+C/Cmd+C if automatic copy fails."),
1105
  inputs=[],
1106
+ outputs=[]
1107
  )
1108
 
1109
  with gr.Row():
1110
+ object_clear = gr.Button("πŸ—‘οΈ Clear Input")
1111
  object_clear.click(lambda: "", [], object_input)
1112
 
1113
+ object_results_clear = gr.Button("🧹 Clear Results")
1114
  object_results_clear.click(
1115
  lambda: ["", "", "", "", None],
1116
  [],
 
1118
  )
1119
 
1120
  # UI Preferences
1121
+ with gr.Accordion("βš™οΈ UI Preferences", open=False):
1122
  theme_radio = gr.Radio(
1123
+ label="🎨 Theme",
1124
  choices=["Light", "Dark"],
1125
  value="Light"
1126
  )
1127
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1128
  theme_radio.change(
1129
+ fn=get_theme_styles,
1130
  inputs=[theme_radio],
1131
  outputs=[
1132
  trigger_explanation,
 
1136
  ]
1137
  )
1138
 
1139
+ gr.Markdown("### πŸ“š About This Tool")
1140
  gr.Markdown(
1141
  """
1142
+ **πŸš€ Enhanced Features:**
1143
+ - **Skeptical AI Evaluation**: Models actively search for syntax errors, security issues, and performance problems
1144
+ - **Comprehensive Validation**: 7-metric assessment including syntax, security, and performance
1145
+ - **Edge Case Detection**: Identifies governor limits, bulkification issues, and B2B Commerce pitfalls
1146
+ - **Test Case Generation**: Automatic test class templates for migrated code
1147
+ - **Enhanced Error Detection**: Pattern-based syntax validation before AI processing
1148
+
1149
+ **πŸ€– Model Roles:**
1150
+ - **Primary Model**: Performs initial conversion with skeptical analysis
1151
+ - **Validation Model**: Double-checks work with harsh but fair evaluation
1152
+
1153
+ **⚑ Key Improvements:**
1154
+ - Syntax validation before and after correction
1155
+ - Security vulnerability detection (FLS, CRUD, injection)
1156
+ - Performance analysis (O(nΒ²) algorithms, governor limits)
1157
+ - B2B Commerce specific migration validation
1158
+ - Automatic test case suggestions
1159
+
1160
+ **⚠️ Important**: Always review and test AI-generated code in a sandbox before production deployment.
1161
+ """
1162
  )
1163
 
1164
  app.launch()