Nihal2000 commited on
Commit
426a800
Β·
verified Β·
1 Parent(s): 85edf4d

Update ui/gradio_interface.py

Browse files
Files changed (1) hide show
  1. ui/gradio_interface.py +152 -249
ui/gradio_interface.py CHANGED
@@ -36,18 +36,14 @@ class DebugGenieUI:
36
  # Validate inputs
37
  if not error_text and screenshot is None:
38
  return (
39
- [{"role": "assistant", "content": "⚠️ **Please provide either an error message or a screenshot to begin analysis.**"}],
40
- "",
41
- "",
42
  None,
43
- {},
44
- gr.update(visible=False),
45
- gr.update(visible=False),
46
- gr.update(visible=False),
47
- "⚠️ Waiting for input..."
48
  )
49
 
50
- progress(0.1, desc="πŸ” Analyzing error...")
51
 
52
  # Build context
53
  context = {
@@ -59,33 +55,29 @@ class DebugGenieUI:
59
  if screenshot is not None:
60
  context['type'] = 'ide'
61
 
62
- progress(0.3, desc="πŸ€– Running AI agents...")
63
 
64
  # Run backend analysis
65
  result = await self.backend.analyze(context)
66
 
67
- progress(0.7, desc="πŸ“Š Generating insights...")
68
 
69
- # Build main response
70
- response_parts = [f"## 🎯 Root Cause\n\n{result.root_cause}\n\n---\n"]
 
 
 
 
 
71
 
72
  # Generate solutions HTML
73
- solutions_html = self._generate_modern_solutions(result.solutions)
74
 
75
  # Generate visualization
76
  mock_trace = self.visualizer.generate_mock_trace()
77
  viz_html = self.visualizer.generate_flow(mock_trace)
78
 
79
- # Build metrics
80
- analysis_json = {
81
- "execution_time": f"{result.execution_time:.2f}s",
82
- "confidence": f"{result.confidence_score:.1%}",
83
- "agents_used": list(result.agent_metrics.keys()),
84
- "solutions_found": len(result.solutions)
85
- }
86
-
87
- # Voice explanation
88
- progress(0.9, desc="πŸŽ™οΈ Generating explanation...")
89
  voice_audio = None
90
  if self.voice_explainer and result.solutions:
91
  try:
@@ -111,134 +103,63 @@ class DebugGenieUI:
111
  except Exception as e:
112
  logger.warning(f"Voice generation failed: {e}")
113
 
114
- progress(1.0, desc="βœ… Complete!")
115
-
116
- chat_history = [{"role": "assistant", "content": "".join(response_parts)}]
117
 
118
  return (
119
- chat_history,
120
  solutions_html,
121
  viz_html,
122
  voice_audio,
123
- analysis_json,
124
- gr.update(visible=True),
125
- gr.update(visible=True),
126
- gr.update(visible=True),
127
- f"βœ… Analysis complete β€’ {result.execution_time:.1f}s β€’ {len(result.solutions)} solutions"
128
  )
129
 
130
  except Exception as e:
131
  logger.error(f"Analysis failed: {e}")
132
  return (
133
- [{"role": "assistant", "content": f"## ❌ Analysis Failed\n\n{str(e)}\n\nPlease check your input and try again."}],
134
  "",
135
  "",
136
  None,
137
- {"error": str(e)},
138
- gr.update(visible=False),
139
- gr.update(visible=False),
140
- gr.update(visible=False),
141
- f"❌ Error: {str(e)}"
142
  )
143
 
144
- def _generate_modern_solutions(self, solutions: List[Dict]) -> str:
145
- """Generate modern, card-based solutions UI."""
146
  if not solutions:
147
- return "<div style='text-align: center; padding: 40px; color: #666;'>No solutions found.</div>"
148
 
149
- html = """
150
- <style>
151
- .solutions-grid {
152
- display: grid;
153
- gap: 20px;
154
- margin-top: 10px;
155
- }
156
- .solution-card {
157
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
158
- border-radius: 16px;
159
- padding: 24px;
160
- color: white;
161
- box-shadow: 0 10px 30px rgba(0,0,0,0.15);
162
- transition: transform 0.2s, box-shadow 0.2s;
163
- cursor: pointer;
164
- }
165
- .solution-card:hover {
166
- transform: translateY(-4px);
167
- box-shadow: 0 15px 40px rgba(0,0,0,0.25);
168
- }
169
- .solution-card.high-confidence {
170
- background: linear-gradient(135deg, #11998e 0%, #38ef7d 100%);
171
- }
172
- .solution-card.medium-confidence {
173
- background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
174
- }
175
- .solution-card.low-confidence {
176
- background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
177
- }
178
- .solution-header {
179
- display: flex;
180
- justify-content: space-between;
181
- align-items: flex-start;
182
- margin-bottom: 16px;
183
- }
184
- .solution-rank {
185
- background: rgba(255,255,255,0.3);
186
- border-radius: 50%;
187
- width: 36px;
188
- height: 36px;
189
- display: flex;
190
- align-items: center;
191
- justify-content: center;
192
- font-weight: bold;
193
- font-size: 18px;
194
- }
195
- .solution-confidence {
196
- background: rgba(255,255,255,0.25);
197
- padding: 6px 14px;
198
- border-radius: 20px;
199
- font-size: 13px;
200
- font-weight: 600;
201
- backdrop-filter: blur(10px);
202
- }
203
- .solution-title {
204
- font-size: 20px;
205
- font-weight: 700;
206
- margin-bottom: 12px;
207
- line-height: 1.3;
208
- }
209
- .solution-description {
210
- font-size: 15px;
211
- line-height: 1.6;
212
- opacity: 0.95;
213
- }
214
- </style>
215
- <div class="solutions-grid">
216
- """
217
 
218
  for idx, sol in enumerate(solutions[:5], 1):
219
  title = sol.get('title', f'Solution {idx}')
220
  desc = sol.get('description', 'No description available')
221
  prob = sol.get('probability', 0.5)
222
 
223
- # Determine confidence class
224
  if prob > 0.7:
225
- conf_class = "high-confidence"
226
- conf_label = "High Confidence"
227
  elif prob > 0.4:
228
- conf_class = "medium-confidence"
229
- conf_label = "Medium Confidence"
230
  else:
231
- conf_class = "low-confidence"
232
- conf_label = "Low Confidence"
233
 
234
  html += f"""
235
- <div class="solution-card {conf_class}">
236
- <div class="solution-header">
237
- <div class="solution-rank">#{idx}</div>
238
- <div class="solution-confidence">{prob:.0%} β€’ {conf_label}</div>
 
 
 
239
  </div>
240
- <div class="solution-title">{title}</div>
241
- <div class="solution-description">{desc}</div>
242
  </div>
243
  """
244
 
@@ -246,101 +167,84 @@ class DebugGenieUI:
246
  return html
247
 
248
  def create_interface(backend: DebugBackend):
249
- """Create the main Gradio interface with modern UX."""
250
  ui = DebugGenieUI(backend)
251
 
252
- with gr.Blocks() as demo:
253
 
254
- # Hero Section
255
- with gr.Row():
256
- gr.Markdown(
257
- """
258
- # πŸ§žβ€β™‚οΈ DebugGenie
259
- ### Your AI-Powered Debugging Assistant
260
- Upload an error, get instant solutions powered by multi-agent AI
261
- """,
262
- elem_classes="hero-section"
263
- )
264
 
265
- # Main Content Area
266
- with gr.Row(equal_height=True):
267
- # Left Panel - Input Section
268
- with gr.Column(scale=2, min_width=400):
269
- gr.Markdown("### πŸ“‹ Error Details")
270
-
271
- with gr.Group():
272
- error_input = gr.Code(
273
- label="Error Message or Stack Trace",
274
- language="python",
275
- lines=12,
276
- placeholder="Paste your error message, stack trace, or exception here...\n\nExample:\nTraceback (most recent call last):\n File 'app.py', line 42\n ValueError: invalid literal for int()",
277
- show_label=False
278
- )
279
-
280
- with gr.Accordion("🎨 Additional Context (Optional)", open=False):
281
- screenshot_input = gr.Image(
282
- label="Screenshot",
283
- type="pil",
284
- sources=["upload", "clipboard"],
285
- height=200
286
- )
287
-
288
- codebase_files = gr.File(
289
- label="Related Code Files",
290
- file_count="multiple",
291
- file_types=[".py", ".js", ".java", ".cpp", ".ts", ".jsx", ".tsx"]
292
- )
293
-
294
- analyze_btn = gr.Button(
295
- "πŸ” Analyze Error",
296
- variant="primary",
297
- size="lg",
298
- scale=1
299
  )
300
 
301
- status_text = gr.Markdown(
302
- "πŸ’‘ Ready to debug β€’ Paste an error to get started",
303
- elem_classes="status-bar"
304
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
305
 
306
- # Right Panel - Results Section
307
- with gr.Column(scale=3, min_width=600):
308
- gr.Markdown("### 🎯 Analysis Results")
309
-
310
- # Main Analysis Display
311
- with gr.Group():
312
- chatbot = gr.Chatbot(
313
- height=400,
314
- type="messages",
315
- show_copy_button=False,
316
- avatar_images=(None, "🧞"),
317
- bubble_full_width=False,
318
- render_markdown=True
319
- )
320
-
321
- # Collapsible Sections
322
- with gr.Group() as solutions_group:
323
- with gr.Accordion("πŸ’‘ Recommended Solutions", open=True, visible=False) as solutions_accordion:
324
- solutions_html = gr.HTML()
325
-
326
- with gr.Group() as viz_group:
327
- with gr.Accordion("πŸ“Š Error Flow Visualization", open=False, visible=False) as viz_accordion:
328
- viz_3d = gr.HTML()
329
-
330
- with gr.Group() as details_group:
331
- with gr.Accordion("πŸ”¬ Technical Details", open=False, visible=False) as details_accordion:
332
- with gr.Row():
333
- with gr.Column(scale=1):
334
- analysis_details = gr.JSON(label="Metrics")
335
- with gr.Column(scale=1):
336
- voice_output = gr.Audio(
337
- label="πŸŽ™οΈ Voice Explanation",
338
- autoplay=False,
339
- show_download_button=False
340
- )
341
 
342
- # Quick Start Examples
343
- gr.Markdown("### πŸ“š Quick Start Examples")
344
  gr.Examples(
345
  examples=[
346
  [
@@ -360,31 +264,26 @@ json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)""",
360
  ],
361
  [
362
  """AttributeError: 'list' object has no attribute 'keys'
363
- File "data_processor.py", line 28, in parse_config
364
  for key in config.keys():""",
365
  None,
366
  None
367
  ]
368
  ],
369
  inputs=[error_input, screenshot_input, codebase_files],
370
- label=None,
371
- examples_per_page=3
372
  )
373
 
374
- # Event handlers
375
  analyze_btn.click(
376
  fn=ui.handle_analyze,
377
  inputs=[error_input, screenshot_input, codebase_files],
378
  outputs=[
379
- chatbot,
380
- solutions_html,
381
- viz_3d,
382
  voice_output,
383
- analysis_details,
384
- solutions_accordion,
385
- viz_accordion,
386
- details_accordion,
387
- status_text
388
  ]
389
  )
390
 
@@ -401,47 +300,51 @@ if __name__ == "__main__":
401
  show_error=True,
402
  theme=gr.themes.Soft(
403
  primary_hue="indigo",
404
- secondary_hue="purple",
405
- neutral_hue="slate",
406
- radius_size="lg",
407
- font=["Inter", "system-ui", "sans-serif"]
408
  ),
409
  css="""
410
- .hero-section {
 
411
  text-align: center;
412
- padding: 20px 0;
 
 
 
 
 
 
 
413
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
414
  -webkit-background-clip: text;
415
  -webkit-text-fill-color: transparent;
416
- background-clip: text;
417
  }
418
- .status-bar {
419
- text-align: center;
420
- padding: 12px;
421
- background: #f8fafc;
422
- border-radius: 8px;
423
- margin-top: 16px;
424
- font-weight: 500;
425
  }
 
 
426
  .gradio-container {
427
- max-width: 1400px !important;
428
- margin: auto;
429
  }
430
- button {
431
- border-radius: 12px !important;
432
- font-weight: 600 !important;
433
- transition: all 0.2s !important;
 
 
434
  }
435
- button:hover {
 
436
  transform: translateY(-2px);
437
- box-shadow: 0 8px 20px rgba(0,0,0,0.15) !important;
438
- }
439
- .gr-group {
440
- border-radius: 12px !important;
441
- border: 1px solid #e2e8f0 !important;
442
  }
443
- .gr-accordion {
444
- border-radius: 12px !important;
 
 
445
  }
446
  """
447
  )
 
36
  # Validate inputs
37
  if not error_text and screenshot is None:
38
  return (
39
+ "<div style='padding: 20px; text-align: center; color: #666;'>⚠️ Please provide an error message or screenshot</div>",
40
+ "<div style='padding: 20px; text-align: center; color: #999;'>Solutions will appear here after analysis</div>",
41
+ "<div style='padding: 20px; text-align: center; color: #999;'>Visualization will appear here</div>",
42
  None,
43
+ None
 
 
 
 
44
  )
45
 
46
+ progress(0.2, desc="Analyzing error...")
47
 
48
  # Build context
49
  context = {
 
55
  if screenshot is not None:
56
  context['type'] = 'ide'
57
 
58
+ progress(0.5, desc="Running AI analysis...")
59
 
60
  # Run backend analysis
61
  result = await self.backend.analyze(context)
62
 
63
+ progress(0.8, desc="Generating results...")
64
 
65
+ # Build root cause display
66
+ root_cause_html = f"""
67
+ <div style='background: #f8f9fa; border-left: 4px solid #4f46e5; padding: 20px; border-radius: 8px; margin-bottom: 20px;'>
68
+ <h3 style='margin: 0 0 10px 0; color: #1e293b;'>🎯 Root Cause</h3>
69
+ <p style='margin: 0; color: #475569; line-height: 1.6;'>{result.root_cause}</p>
70
+ </div>
71
+ """
72
 
73
  # Generate solutions HTML
74
+ solutions_html = self._generate_solutions_html(result.solutions)
75
 
76
  # Generate visualization
77
  mock_trace = self.visualizer.generate_mock_trace()
78
  viz_html = self.visualizer.generate_flow(mock_trace)
79
 
80
+ # Generate voice explanation
 
 
 
 
 
 
 
 
 
81
  voice_audio = None
82
  if self.voice_explainer and result.solutions:
83
  try:
 
103
  except Exception as e:
104
  logger.warning(f"Voice generation failed: {e}")
105
 
106
+ progress(1.0, desc="Complete!")
 
 
107
 
108
  return (
109
+ root_cause_html,
110
  solutions_html,
111
  viz_html,
112
  voice_audio,
113
+ {
114
+ "execution_time": f"{result.execution_time:.2f}s",
115
+ "confidence": f"{result.confidence_score:.1%}",
116
+ "solutions_found": len(result.solutions)
117
+ }
118
  )
119
 
120
  except Exception as e:
121
  logger.error(f"Analysis failed: {e}")
122
  return (
123
+ f"<div style='padding: 20px; background: #fee; border-radius: 8px; color: #c00;'>❌ Analysis failed: {str(e)}</div>",
124
  "",
125
  "",
126
  None,
127
+ {"error": str(e)}
 
 
 
 
128
  )
129
 
130
+ def _generate_solutions_html(self, solutions: List[Dict]) -> str:
131
+ """Generate clean, readable solutions display."""
132
  if not solutions:
133
+ return "<div style='padding: 20px; text-align: center; color: #999;'>No solutions found</div>"
134
 
135
+ html = "<div style='display: flex; flex-direction: column; gap: 16px;'>"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
136
 
137
  for idx, sol in enumerate(solutions[:5], 1):
138
  title = sol.get('title', f'Solution {idx}')
139
  desc = sol.get('description', 'No description available')
140
  prob = sol.get('probability', 0.5)
141
 
142
+ # Color based on confidence
143
  if prob > 0.7:
144
+ bg_color = "#10b981"
145
+ badge_text = "High Confidence"
146
  elif prob > 0.4:
147
+ bg_color = "#f59e0b"
148
+ badge_text = "Medium Confidence"
149
  else:
150
+ bg_color = "#6366f1"
151
+ badge_text = "Low Confidence"
152
 
153
  html += f"""
154
+ <div style='border: 1px solid #e2e8f0; border-radius: 12px; padding: 20px; background: white;'>
155
+ <div style='display: flex; justify-content: space-between; align-items: start; margin-bottom: 12px;'>
156
+ <div style='display: flex; align-items: center; gap: 12px;'>
157
+ <span style='display: inline-flex; align-items: center; justify-content: center; width: 32px; height: 32px; background: {bg_color}; color: white; border-radius: 50%; font-weight: bold; font-size: 16px;'>{idx}</span>
158
+ <h4 style='margin: 0; color: #1e293b; font-size: 18px;'>{title}</h4>
159
+ </div>
160
+ <span style='background: {bg_color}20; color: {bg_color}; padding: 4px 12px; border-radius: 12px; font-size: 13px; font-weight: 600;'>{prob:.0%} β€’ {badge_text}</span>
161
  </div>
162
+ <p style='margin: 0; color: #64748b; line-height: 1.6;'>{desc}</p>
 
163
  </div>
164
  """
165
 
 
167
  return html
168
 
169
  def create_interface(backend: DebugBackend):
170
+ """Create the main Gradio interface with clean, simple design."""
171
  ui = DebugGenieUI(backend)
172
 
173
+ with gr.Blocks(title="DebugGenie - AI Debugging Assistant") as demo:
174
 
175
+ # Header
176
+ gr.Markdown(
177
+ """
178
+ # 🧞 DebugGenie
179
+ ### AI-Powered Debugging Assistant
180
+ Paste your error message below and get instant solutions from multiple AI agents.
181
+ """,
182
+ elem_classes="header"
183
+ )
 
184
 
185
+ # Main input section
186
+ gr.Markdown("## πŸ“‹ Enter Your Error")
187
+
188
+ error_input = gr.Code(
189
+ label="Error Message or Stack Trace",
190
+ language="python",
191
+ lines=10,
192
+ placeholder="Paste your error message, stack trace, or exception here...",
193
+ show_label=False
194
+ )
195
+
196
+ # Optional inputs in accordion
197
+ with gr.Accordion("βž• Add Screenshot or Files (Optional)", open=False):
198
+ with gr.Row():
199
+ screenshot_input = gr.Image(
200
+ label="Screenshot",
201
+ type="pil",
202
+ sources=["upload", "clipboard"]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
203
  )
204
 
205
+ codebase_files = gr.File(
206
+ label="Related Code Files",
207
+ file_count="multiple"
208
  )
209
+
210
+ # Analyze button
211
+ analyze_btn = gr.Button(
212
+ "πŸ” Analyze Error",
213
+ variant="primary",
214
+ size="lg"
215
+ )
216
+
217
+ # Results section
218
+ gr.Markdown("## 🎯 Analysis Results")
219
+
220
+ root_cause_display = gr.HTML(
221
+ label="Root Cause",
222
+ value="<div style='padding: 20px; text-align: center; color: #999;'>Results will appear here after analysis</div>"
223
+ )
224
+
225
+ # Solutions in accordion
226
+ with gr.Accordion("πŸ’‘ Recommended Solutions", open=True):
227
+ solutions_display = gr.HTML(
228
+ value="<div style='padding: 20px; text-align: center; color: #999;'>Solutions will appear here</div>"
229
+ )
230
+
231
+ # Additional details in tabs
232
+ with gr.Tabs():
233
+ with gr.Tab("πŸ“Š Error Visualization"):
234
+ viz_display = gr.HTML()
235
 
236
+ with gr.Tab("πŸŽ™οΈ Voice Explanation"):
237
+ voice_output = gr.Audio(
238
+ label="AI-Generated Explanation",
239
+ autoplay=False
240
+ )
241
+
242
+ with gr.Tab("πŸ“ˆ Technical Details"):
243
+ analysis_json = gr.JSON(label="Analysis Metrics")
244
+
245
+ # Examples section
246
+ gr.Markdown("### πŸ“š Try These Examples")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
247
 
 
 
248
  gr.Examples(
249
  examples=[
250
  [
 
264
  ],
265
  [
266
  """AttributeError: 'list' object has no attribute 'keys'
267
+ File "data_processor.py", line 28
268
  for key in config.keys():""",
269
  None,
270
  None
271
  ]
272
  ],
273
  inputs=[error_input, screenshot_input, codebase_files],
274
+ label=None
 
275
  )
276
 
277
+ # Event handler
278
  analyze_btn.click(
279
  fn=ui.handle_analyze,
280
  inputs=[error_input, screenshot_input, codebase_files],
281
  outputs=[
282
+ root_cause_display,
283
+ solutions_display,
284
+ viz_display,
285
  voice_output,
286
+ analysis_json
 
 
 
 
287
  ]
288
  )
289
 
 
300
  show_error=True,
301
  theme=gr.themes.Soft(
302
  primary_hue="indigo",
303
+ radius_size="lg"
 
 
 
304
  ),
305
  css="""
306
+ /* Clean, minimal styling */
307
+ .header {
308
  text-align: center;
309
+ padding: 24px 0;
310
+ margin-bottom: 32px;
311
+ }
312
+
313
+ .header h1 {
314
+ font-size: 2.5rem;
315
+ font-weight: 700;
316
+ margin-bottom: 8px;
317
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
318
  -webkit-background-clip: text;
319
  -webkit-text-fill-color: transparent;
 
320
  }
321
+
322
+ .header h3 {
323
+ color: #64748b;
324
+ font-weight: 400;
 
 
 
325
  }
326
+
327
+ /* Container spacing */
328
  .gradio-container {
329
+ max-width: 1200px;
330
+ margin: 0 auto;
331
  }
332
+
333
+ /* Button styling */
334
+ button.primary {
335
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
336
+ border: none;
337
+ font-weight: 600;
338
  }
339
+
340
+ button.primary:hover {
341
  transform: translateY(-2px);
342
+ box-shadow: 0 8px 16px rgba(102, 126, 234, 0.3);
 
 
 
 
343
  }
344
+
345
+ /* Smooth transitions */
346
+ * {
347
+ transition: all 0.2s ease;
348
  }
349
  """
350
  )