File size: 36,908 Bytes
78e8dd4
 
 
d4295d6
78e8dd4
 
 
d4295d6
 
 
 
 
 
 
 
 
 
 
 
 
78e8dd4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
d4295d6
0cfa3a6
 
 
 
 
 
 
 
 
 
 
78e8dd4
 
d4295d6
a9fc8a6
78e8dd4
 
d4295d6
a9fc8a6
78e8dd4
 
d4295d6
a9fc8a6
78e8dd4
 
d4295d6
a9fc8a6
78e8dd4
 
 
d4295d6
a9fc8a6
78e8dd4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
a9fc8a6
78e8dd4
 
 
 
 
 
 
 
 
a9fc8a6
 
78e8dd4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
"""
Gradio Interface Module
Creates the main Gradio web interface for the RAG system
Compatible with Gradio 4.x and 6.x
"""
import gradio as gr
from typing import Optional

# Gradio 6.0 compatibility: TabItem was renamed to Tab
# Use Tab for Gradio 6.0, fallback to TabItem for older versions
try:
    # Try to use Tab (Gradio 6.0+)
    if hasattr(gr, 'Tab'):
        Tab = gr.Tab
    else:
        # Fallback to TabItem (Gradio 4.x)
        Tab = gr.TabItem
except AttributeError:
    # If neither exists, use Tab (shouldn't happen)
    Tab = gr.Tab if hasattr(gr, 'Tab') else gr.TabItem
from .rag_query import RAGQueryEngine
from .question_generator import QuestionGenerator
from .knowledge_graph import KnowledgeGraphGenerator
from .config import Config

# Import cold start onboarding functions if available
try:
    from modules.cold_start_onboarding import check_and_show_onboarding
    COLD_START_AVAILABLE = True
except ImportError:
    COLD_START_AVAILABLE = False
    def check_and_show_onboarding(user_profiling, user_id):
        """Fallback function if module not available"""
        if not user_profiling:
            return False
        return user_profiling.is_cold_start(user_id)


class GradioInterfaceBuilder:
    """Builds the Gradio interface for the RAG system"""
    
    def __init__(self, rag_engine: RAGQueryEngine, question_generator: QuestionGenerator,
                 knowledge_graph: KnowledgeGraphGenerator, config: Config,
                 user_profiling=None, adaptive_engine=None, proactive_engine=None, enhanced_rag_engine=None):
        self.rag_engine = rag_engine
        self.question_generator = question_generator
        self.knowledge_graph = knowledge_graph
        self.config = config
        self.user_profiling = user_profiling
        self.adaptive_engine = adaptive_engine
        self.proactive_engine = proactive_engine
        self.enhanced_rag_engine = enhanced_rag_engine  # Enhanced RAG engine (scenario feature)
    
    def create_interface(self):
        """Create the main Gradio interface"""
        with gr.Blocks(title="Mercedes E-class ADAS Manual Interface") as demo:
            gr.Markdown("# πŸš— Mercedes E-class ADAS Manual Interface")
            gr.Markdown("Ask questions, explore knowledge maps, and test your understanding!")
            
            # Create tabs with proper order: Setup -> Ask Questions -> Knowledge Map -> Test -> Personalized Learning
            # Ask Questions is set as default selected tab
            # Gradio 6.0 compatibility: Use Tab (which is gr.Tab for 6.0, gr.TabItem for 4.x)
            # Note: In Gradio 6.0, selected parameter might be deprecated, try both ways
            def create_tabs():
                """Create tabs with compatibility for Gradio 4.x and 6.x"""
                try:
                    # Try with selected parameter (Gradio 4.x style)
                    return gr.Tabs(selected=1 if self.user_profiling else 0)
                except (TypeError, ValueError):
                    # If selected parameter not supported, create without it (Gradio 6.0+)
                    return gr.Tabs()
            
            with create_tabs():
                # Tab 1: Setup (Cold Start/Onboarding) - only shown if user_profiling is available
                if self.user_profiling:
                    with Tab("Setup"):
                        self._create_onboarding_tab()
                
                # Tab 2: Ask Questions (Default selected tab)
                with Tab("Ask Questions"):
                    self._create_qa_tab()
                
                # Tab 3: Knowledge Map
                with Tab("Knowledge Map"):
                    self._create_knowledge_map_tab()
                
                # Tab 4: Test Your Knowledge
                with Tab("Test Your Knowledge"):
                    self._create_test_tab()
                
                # Tab 5: Personalized Learning Path (if available)
                if self.adaptive_engine:
                    with Tab("Personalized Learning"):
                        self._create_learning_path_tab()
        
        return demo
    
    def _create_qa_tab(self):
        """Create the Q&A tab"""
        gr.Markdown("Ask questions about your car's advanced driver assistance systems")
        
        # User ID input (if user profiling is available)
        user_id_input = None
        if self.user_profiling:
            with gr.Row():
                user_id_input = gr.Textbox(
                    label="User ID",
                    placeholder="Enter your user ID (e.g., default_user)",
                    value="default_user",
                    scale=3
                )
                load_suggestions_btn = gr.Button("πŸ’‘ Get Suggestions", variant="secondary", scale=1)
        
        # Prompt suggestions area
        suggestions_container = gr.Column(visible=False)
        suggestions_display = None
        refresh_suggestions_btn = None
        cancel_suggestions_btn = None
        regenerate_suggestions_btn = None
        if self.proactive_engine:
            with suggestions_container:
                gr.Markdown("### πŸ’‘ Suggested Questions for You:")
                suggestions_display = gr.HTML()
                with gr.Row():
                    refresh_suggestions_btn = gr.Button("πŸ”„ Refresh Suggestions", variant="secondary", size="sm")
                    cancel_suggestions_btn = gr.Button("⏹️ Stop", variant="stop", size="sm")
                    regenerate_suggestions_btn = gr.Button("πŸ”„ Regenerate", variant="secondary", size="sm")
        
        with gr.Row():
            query_input = gr.Textbox(
                lines=2,
                placeholder="Enter your question here...",
                label="Your Question"
            )
        
        with gr.Row():
            submit_btn = gr.Button("Get Answer", variant="primary")
            cancel_answer_btn = gr.Button("⏹️ Stop", variant="stop")
            regenerate_answer_btn = gr.Button("πŸ”„ Regenerate", variant="secondary")
        
        with gr.Column():
            answer_output = gr.Markdown(label="Answer")
            footnotes_output = gr.Markdown(label="Sources")
            
            # Scenario contextualization area (collapsible)
            scenarios_container = gr.Column(visible=False)
            with scenarios_container:
                scenarios_header = gr.Markdown("### 🎯 Related Scenarios")
                scenarios_display = gr.HTML()
            
            # Follow-up questions area
            followup_container = gr.Column(visible=False)
            cancel_followup_btn = None
            regenerate_followup_btn = None
            if self.proactive_engine:
                with followup_container:
                    gr.Markdown("### πŸ’‘ Want to learn more? Try these questions:")
                    followup_questions_display = gr.HTML()
                    with gr.Row():
                        cancel_followup_btn = gr.Button("⏹️ Stop", variant="stop", size="sm")
                        regenerate_followup_btn = gr.Button("πŸ”„ Regenerate", variant="secondary", size="sm")
            else:
                followup_questions_display = gr.HTML()
        
        def process_query(query, user_id="default_user"):
            """Process query and generate follow-up questions"""
            # Use enhanced RAG engine if available, otherwise use standard
            if self.enhanced_rag_engine:
                try:
                    enhanced_answer = self.enhanced_rag_engine.query(query, user_id=user_id)
                    answer = enhanced_answer.answer
                    footnotes = enhanced_answer.sources
                    scenarios_html = enhanced_answer.scenarios_html
                    show_scenarios = enhanced_answer.scenario_count > 0
                except Exception as e:
                    print(f"⚠️ Error in enhanced RAG engine: {e}, falling back to standard")
                    answer, footnotes = self.rag_engine.query(query)
                    scenarios_html = ""
                    show_scenarios = False
            else:
                answer, footnotes = self.rag_engine.query(query)
                scenarios_html = ""
                show_scenarios = False
            
            # Update user profile with question
            if self.user_profiling and user_id:
                try:
                    self.user_profiling.update_from_question(user_id, query)
                except Exception as e:
                    print(f"Error updating user profile: {e}")
            
            # Generate follow-up questions
            followup_html = ""
            followup_visible = False
            if self.proactive_engine and user_id:
                try:
                    followup_questions = self.proactive_engine.get_follow_up_questions(
                        user_id, answer, max_questions=5
                    )
                    if followup_questions:
                        followup_visible = True
                        followup_html = "<div style='margin-top: 15px;'>"
                        for i, q_data in enumerate(followup_questions, 1):
                            question = q_data.get("question", "")
                            bloom_level = q_data.get("bloom_level", "")
                            # Escape quotes for JavaScript
                            question_escaped = question.replace("'", "\\'").replace('"', '\\"')
                            followup_html += f"""
                            <div style='margin: 10px 0; padding: 12px; background-color: #f5f5f5; border-radius: 5px; border-left: 3px solid #4CAF50; display: flex; justify-content: space-between; align-items: center;'>
                                <div style='flex: 1;'>
                                    <div style='font-weight: 500; margin-bottom: 4px;'>{question}</div>
                                    <small style='color: #666;'>Bloom Level: {bloom_level.title()}</small>
                                </div>
                                <button onclick="document.querySelector('textarea[label=\\'Your Question\\']').value='{question_escaped}'; this.style.backgroundColor='#4CAF50'; this.style.color='white';" 
                                        style='margin-left: 15px; padding: 8px 16px; background-color: #2196F3; color: white; border: none; border-radius: 3px; cursor: pointer; white-space: nowrap;'>
                                    Use
                                </button>
                            </div>
                            """
                        followup_html += "</div>"
                except Exception as e:
                    print(f"Error generating follow-up questions: {e}")
            
            # Prepare return values
            outputs = [answer, footnotes]
            
            # Add scenarios output
            if self.enhanced_rag_engine:
                outputs.append(gr.update(visible=show_scenarios))
                outputs.append(scenarios_html if scenarios_html else "")
            
            # Add follow-up questions output
            if self.proactive_engine:
                outputs.append(gr.update(visible=followup_visible))
                outputs.append(followup_html)
            
            return tuple(outputs)
        
        def load_suggestions(user_id="default_user"):
            """Load prompt suggestions"""
            if not self.proactive_engine or not user_id:
                return gr.update(visible=False), ""
            
            try:
                suggestions = self.proactive_engine.get_prompt_suggestions(user_id, max_suggestions=5)
                if not suggestions:
                    return gr.update(visible=False), ""
                
                suggestions_html = "<div style='margin-top: 10px;'>"
                for i, suggestion in enumerate(suggestions, 1):
                    question = suggestion.get("question", "")
                    reason = suggestion.get("reason", "")
                    priority = suggestion.get("priority", "low")
                    priority_color = {"high": "#f44336", "medium": "#ff9800", "low": "#4CAF50"}.get(priority, "#666")
                    
                    # Escape quotes for JavaScript
                    question_escaped = question.replace("'", "\\'").replace('"', '\\"')
                    suggestions_html += f"""
                    <div style='margin: 10px 0; padding: 12px; background-color: #f9f9f9; border-radius: 5px; border-left: 4px solid {priority_color};'>
                        <div style='display: flex; justify-content: space-between; align-items: start;'>
                            <div style='flex: 1;'>
                                <strong style='color: #333;'>{i}. {question}</strong>
                                <br><small style='color: #666;'>{reason}</small>
                            </div>
                            <button onclick="document.querySelector('textarea[label=\\'Your Question\\']').value='{question_escaped}'; this.style.backgroundColor='#4CAF50'; this.style.color='white';" 
                                    style='margin-left: 10px; padding: 8px 15px; background-color: #2196F3; color: white; border: none; border-radius: 3px; cursor: pointer; white-space: nowrap;'>
                                Use
                            </button>
                        </div>
                    </div>
                    """
                suggestions_html += "</div>"
                
                return gr.update(visible=True), suggestions_html
            except Exception as e:
                print(f"Error loading suggestions: {e}")
                return gr.update(visible=False), ""
        
        # Set up event handlers
        if self.proactive_engine and user_id_input and suggestions_display:
            # Suggestions event handlers
            suggestions_event = load_suggestions_btn.click(
                load_suggestions,
                inputs=[user_id_input],
                outputs=[suggestions_container, suggestions_display]
            )
            if refresh_suggestions_btn:
                refresh_suggestions_btn.click(
                    load_suggestions,
                    inputs=[user_id_input],
                    outputs=[suggestions_container, suggestions_display]
                )
            if regenerate_suggestions_btn:
                regenerate_suggestions_btn.click(
                    load_suggestions,
                    inputs=[user_id_input],
                    outputs=[suggestions_container, suggestions_display]
                )
            if cancel_suggestions_btn:
                cancel_suggestions_btn.click(fn=None, cancels=suggestions_event)
            
            # Build outputs list for query
            outputs_list = [answer_output, footnotes_output]
            if self.enhanced_rag_engine:
                outputs_list.extend([scenarios_container, scenarios_display])
            outputs_list.extend([followup_container, followup_questions_display])
            
            # Query event handlers
            query_event = submit_btn.click(
                process_query,
                inputs=[query_input, user_id_input],
                outputs=outputs_list
            )
            regenerate_answer_btn.click(
                process_query,
                inputs=[query_input, user_id_input],
                outputs=outputs_list
            )
            if cancel_answer_btn:
                cancel_answer_btn.click(fn=None, cancels=query_event)
            
            # Follow-up questions event handlers (regenerate only, cancel is handled by query cancel)
            if self.proactive_engine and regenerate_followup_btn:
                def regenerate_followup(query, user_id, answer_text):
                    """Regenerate follow-up questions based on the current answer"""
                    if not self.proactive_engine or not user_id or not answer_text:
                        return gr.update(visible=False), ""
                    
                    try:
                        followup_questions = self.proactive_engine.get_follow_up_questions(
                            user_id, answer_text, max_questions=5
                        )
                        if followup_questions:
                            followup_html = "<div style='margin-top: 15px;'>"
                            for i, q_data in enumerate(followup_questions, 1):
                                question = q_data.get("question", "")
                                bloom_level = q_data.get("bloom_level", "")
                                question_escaped = question.replace("'", "\\'").replace('"', '\\"')
                                followup_html += f"""
                                <div style='margin: 10px 0; padding: 12px; background-color: #f5f5f5; border-radius: 5px; border-left: 3px solid #4CAF50; display: flex; justify-content: space-between; align-items: center;'>
                                    <div style='flex: 1;'>
                                        <div style='font-weight: 500; margin-bottom: 4px;'>{question}</div>
                                        <small style='color: #666;'>Bloom Level: {bloom_level.title()}</small>
                                    </div>
                                    <button onclick="document.querySelector('textarea[label=\\'Your Question\\']').value='{question_escaped}'; this.style.backgroundColor='#4CAF50'; this.style.color='white';" 
                                            style='margin-left: 15px; padding: 8px 16px; background-color: #2196F3; color: white; border: none; border-radius: 3px; cursor: pointer; white-space: nowrap;'>
                                        Use
                                    </button>
                                </div>
                                """
                            followup_html += "</div>"
                            return gr.update(visible=True), followup_html
                        else:
                            return gr.update(visible=False), ""
                    except Exception as e:
                        print(f"Error regenerating follow-up questions: {e}")
                        return gr.update(visible=False), ""
                
                followup_event = regenerate_followup_btn.click(
                    regenerate_followup,
                    inputs=[query_input, user_id_input, answer_output],
                    outputs=[followup_container, followup_questions_display]
                )
                if cancel_followup_btn:
                    cancel_followup_btn.click(fn=None, cancels=followup_event)
        else:
            # Build outputs list (must match process_query return values)
            outputs_list = [answer_output, footnotes_output]
            if self.enhanced_rag_engine:
                outputs_list.extend([scenarios_container, scenarios_display])
            if self.proactive_engine:
                outputs_list.extend([followup_container, followup_questions_display])
            
            query_event = submit_btn.click(
                process_query,
                inputs=[query_input],
                outputs=outputs_list
            )
            regenerate_answer_btn.click(
                process_query,
                inputs=[query_input],
                outputs=outputs_list
            )
            if cancel_answer_btn:
                cancel_answer_btn.click(fn=None, cancels=query_event)
    
    def _create_knowledge_map_tab(self):
        """Create the knowledge map tab"""
        gr.Markdown("## πŸ“Š Car Manual Knowledge Map")
        gr.Markdown("This visualization shows how different concepts in the car manual are related.")
        
        knowledge_map_img = gr.Image(
            value=str(self.config.output_dir / "knowledge_graph.png"),
            label="Knowledge Graph"
        )
        
        gr.Markdown("## πŸ”₯ Document Similarity Heatmap")
        gr.Markdown("This heatmap shows how similar different ADAS features are to each other.")
        
        similarity_heatmap_img = gr.Image(
            value=str(self.config.output_dir / "similarity_heatmap.png"),
            label="Similarity Heatmap"
        )
        
        with gr.Row():
            refresh_btn = gr.Button("πŸ”„ Refresh Visualizations", variant="secondary")
        
        def refresh_images():
            graph_path, heatmap_path = self.knowledge_graph.generate_visualizations()
            return graph_path, heatmap_path
        
        refresh_btn.click(
            refresh_images,
            inputs=[],
            outputs=[knowledge_map_img, similarity_heatmap_img]
        )
    
    def _create_test_tab(self):
        """Create the test tab"""
        gr.Markdown("## πŸ“ Test Your Understanding of Mercedes E-class ADAS")
        gr.Markdown("Select a topic to test your knowledge with multiple-choice questions based on Bloom's taxonomy levels.")
        
        topic_files = self.rag_engine.get_files_from_vector_store()
        
        with gr.Row():
            test_questions = gr.State(None)
            current_level_idx = gr.State(0)
            selected_topic = gr.State(None)
            test_results = gr.State([])
            
            topic_dropdown = gr.Dropdown(
                label="Select a Topic",
                choices=topic_files,
                value=topic_files[0] if topic_files else None,
                interactive=True
            )
            
            start_test_btn = gr.Button("Start Test", variant="primary")
        
        # Progress indicator
        with gr.Column(visible=False) as progress_container:
            progress_html = gr.HTML()
        
        # Test container
        with gr.Column(visible=False) as test_container:
            taxonomy_level = gr.Markdown("Level: Remember")
            level_description = gr.Markdown()
            question_display = gr.Markdown()
            
            option_radio = gr.Radio(
                choices=["A", "B", "C", "D"],
                label="Select your answer",
                interactive=True
            )
            
            submit_answer_btn = gr.Button("Submit Answer", variant="primary")
            feedback_display = gr.Markdown(visible=False)
            next_question_btn = gr.Button("Next Question", visible=False)
            show_summary_btn = gr.Button("Show Summary", visible=False)
        
        # Summary container
        with gr.Column(visible=False) as summary_container:
            summary_topic = gr.Markdown()
            summary_results = gr.HTML()
            summary_recommendation = gr.Markdown()
            restart_btn = gr.Button("Start Another Test")
        
        # Connect handlers (simplified - full implementation would include all handlers)
        # This is a placeholder structure - full implementation would be quite long
        
    def _create_onboarding_tab(self):
        """Create onboarding tab for cold start"""
        gr.Markdown("## 🎯 Welcome! Let's Get Started")
        gr.Markdown("Complete your profile to get a personalized learning experience.")
        
        if not self.user_profiling:
            gr.Markdown("⚠️ Personalized Learning System not initialized.")
            return
        
        user_id_input = gr.Textbox(
            label="User ID",
            placeholder="Enter your user ID",
            value="default_user"
        )
        
        with gr.Accordion("πŸ“‹ Step 1: Background Information", open=True):
            background_input = gr.Radio(
                label="What's your experience with ADAS systems?",
                choices=[
                    ("Beginner - I'm new to ADAS systems", "beginner"),
                    ("Intermediate - I know some basics", "intermediate"),
                    ("Experienced - I have good knowledge", "experienced")
                ],
                value="beginner"
            )
        
        with gr.Accordion("🎨 Step 2: Learning Preferences", open=True):
            learning_style_input = gr.Radio(
                label="How do you prefer to learn?",
                choices=[
                    ("Visual - I like diagrams and illustrations", "visual"),
                    ("Textual - I prefer reading and explanations", "textual"),
                    ("Practical - I learn by doing", "practical"),
                    ("Mixed - I like a combination", "mixed")
                ],
                value="mixed"
            )
            
            learning_pace_input = gr.Radio(
                label="What's your preferred learning pace?",
                choices=[
                    ("Slow - I like to take my time", "slow"),
                    ("Medium - Normal pace is fine", "medium"),
                    ("Fast - I want to learn quickly", "fast")
                ],
                value="medium"
            )
        
        with gr.Accordion("🎯 Step 3: Learning Goals", open=True):
            learning_goals_input = gr.CheckboxGroup(
                label="What are your learning goals?",
                choices=[
                    "Understand basic ADAS functions",
                    "Learn how to operate ADAS features",
                    "Master advanced ADAS capabilities",
                    "Troubleshoot ADAS issues",
                    "Prepare for certification",
                    "General knowledge improvement"
                ],
                value=["Understand basic ADAS functions"]
            )
        
        with gr.Accordion("πŸ“Š Step 4: Initial Knowledge Assessment", open=True):
            gr.Markdown("Rate your familiarity with each topic (0 = No knowledge, 1 = Expert)")
            
            knowledge_sliders = {}
            for topic in self.config.available_topics:
                display_name = topic.replace("Function of ", "").replace(" Assist", "")
                knowledge_sliders[topic] = gr.Slider(
                    label=display_name,
                    minimum=0.0,
                    maximum=1.0,
                    value=0.0,
                    step=0.1
                )
        
        submit_btn = gr.Button("Complete Setup", variant="primary")
        output_result = gr.JSON(label="Setup Result")
        
        def submit_onboarding(user_id, background, learning_style, learning_pace,
                             learning_goals, *knowledge_values):
            """Submit cold start data"""
            if not self.user_profiling:
                return {"status": "error", "message": "System not initialized"}
            
            # Convert knowledge_values tuple to dictionary
            knowledge_survey = {}
            for i, topic in enumerate(self.config.available_topics):
                if i < len(knowledge_values):
                    knowledge_survey[topic] = knowledge_values[i]
                else:
                    knowledge_survey[topic] = 0.0
            
            # Handle tuple values from Radio components
            if isinstance(background, tuple):
                background = background[1] if len(background) > 1 else background[0]
            if isinstance(learning_style, tuple):
                learning_style = learning_style[1] if len(learning_style) > 1 else learning_style[0]
            if isinstance(learning_pace, tuple):
                learning_pace = learning_pace[1] if len(learning_pace) > 1 else learning_pace[0]
            
            onboarding_data = {
                'learning_style': learning_style,
                'learning_pace': learning_pace,
                'background_experience': background,
                'learning_goals': learning_goals if learning_goals else [],
                'initial_knowledge_survey': knowledge_survey,
                'initial_assessment_completed': True
            }
            
            try:
                profile = self.user_profiling.complete_onboarding(user_id, onboarding_data)
                return {
                    "status": "success",
                    "message": f"Onboarding completed for {user_id}",
                    "profile_summary": self.user_profiling.get_profile_summary(user_id)
                }
            except Exception as e:
                import traceback
                error_details = traceback.format_exc()
                return {"status": "error", "message": f"Error: {str(e)}\nDetails: {error_details}"}
        
        inputs = [user_id_input, background_input, learning_style_input,
                 learning_pace_input, learning_goals_input] + list(knowledge_sliders.values())
        submit_btn.click(submit_onboarding, inputs=inputs, outputs=output_result)
    
    def _create_learning_path_tab(self):
        """Create personalized learning path tab"""
        gr.Markdown("## πŸ—ΊοΈ Your Personalized Learning Journey")
        gr.Markdown("Get a customized learning path based on your knowledge profile.")
        
        if not self.adaptive_engine or not self.user_profiling:
            gr.Markdown("⚠️ Personalized Learning System not initialized.")
            return
        
        # User ID input
        with gr.Row():
            user_id_input = gr.Textbox(
                label="User ID",
                placeholder="Enter your user ID",
                value="default_user"
            )
            load_profile_btn = gr.Button("Load My Profile", variant="primary")
        
        # User profile display
        with gr.Column(visible=False) as profile_container:
            profile_summary = gr.Markdown()
            
            with gr.Row():
                with gr.Column():
                    gr.Markdown("### πŸ“Š Knowledge Profile")
                    knowledge_level_display = gr.JSON()
                
                with gr.Column():
                    gr.Markdown("### πŸ“ˆ Learning Statistics")
                    learning_stats = gr.JSON()
        
        # Learning path generation
        with gr.Row():
            focus_areas_input = gr.CheckboxGroup(
                label="Focus Areas (Optional)",
                choices=self.config.available_topics,
                value=[],
                interactive=True
            )
            generate_path_btn = gr.Button("Generate Learning Path", variant="primary")
        
        # Learning path display
        with gr.Column(visible=False) as path_container:
            gr.Markdown("### πŸ—ΊοΈ Your Learning Path")
            path_progress = gr.HTML()
            path_visualization = gr.HTML()
            
            with gr.Row():
                with gr.Column():
                    current_node_info = gr.Markdown()
                    recommendations_display = gr.JSON()
        
        def check_and_show_onboarding_wrapper(user_id):
            """Check if user needs onboarding"""
            if not user_id:
                return False
            return check_and_show_onboarding(self.user_profiling, user_id)
        
        def load_user_profile(user_id):
            """Load the user profile"""
            if not self.user_profiling or not user_id:
                return (gr.update(visible=False), "", {}, {}, [])
            
            if check_and_show_onboarding_wrapper(user_id):
                return (
                    gr.update(visible=False),
                    f"## ⚠️ Onboarding Required\n\nPlease complete onboarding first.",
                    {},
                    {},
                    self.config.available_topics
                )
            
            profile = self.user_profiling.get_or_create_profile(user_id)
            summary = self.user_profiling.get_profile_summary(user_id)
            
            summary_text = f"""
### πŸ‘€ User Profile: {user_id}

**Learning Style:** {summary['learning_style'].title()}  
**Learning Pace:** {summary['learning_pace'].title()}  
**Overall Progress:** {summary['overall_progress']:.1%}  
**Total Questions:** {summary['total_questions']}  
**Total Tests:** {summary['total_tests']}

**Strong Areas:** {', '.join(summary['strong_areas']) if summary['strong_areas'] else 'None'}  
**Weak Areas:** {', '.join(summary['weak_areas']) if summary['weak_areas'] else 'None'}
"""
            
            knowledge_data = summary['knowledge_level'] or {"No topics learned yet": 0.0}
            stats_data = {
                "Total Questions": summary['total_questions'],
                "Total Tests": summary['total_tests'],
                "Preferred Topics": summary['preferred_topics'][:5] if summary['preferred_topics'] else [],
                "Overall Progress": f"{summary['overall_progress']:.1%}"
            }
            
            return (
                gr.update(visible=True),
                summary_text,
                knowledge_data,
                stats_data,
                self.config.available_topics
            )
        
        def generate_learning_path(user_id, focus_areas):
            """Generate learning paths"""
            if not self.adaptive_engine or not user_id:
                return (gr.update(visible=False), "⚠️ System not initialized.", "", "", {})
            
            if check_and_show_onboarding_wrapper(user_id):
                return (gr.update(visible=False), "⚠️ Please complete onboarding first.", "", "", {})
            
            path = self.adaptive_engine.create_or_update_path(user_id, focus_areas if focus_areas else None)
            
            progress_html = f"""
            <div style="width:100%; background-color:#f0f0f0; border-radius:5px; overflow:hidden; margin:20px 0;">
                <div style="width:{path.completion_percentage*100}%; background-color:#4CAF50; height:30px; border-radius:5px; display:flex; align-items:center; justify-content:center; color:white; font-weight:bold;">
                    {path.completion_percentage*100:.1f}% Complete
                </div>
            </div>
            <p><strong>Total Nodes:</strong> {len(path.nodes)} | <strong>Completed:</strong> {sum(1 for n in path.nodes if n.status == 'completed')} | <strong>Estimated Time:</strong> {path.estimated_total_time} minutes</p>
            """
            
            path_html = "<div style='margin:20px 0;'><h4>Learning Path:</h4><div style='display:flex; flex-direction:column; gap:10px;'>"
            for i, node in enumerate(path.nodes):
                status_color = {"completed": "#4CAF50", "in_progress": "#2196F3", "pending": "#9E9E9E", "skipped": "#FF9800"}.get(node.status, "#9E9E9E")
                is_current = i == path.current_node_index
                highlight = "border: 3px solid #FF5722; padding: 10px;" if is_current else "padding: 10px;"
                path_html += f"""
                <div style='{highlight} background-color:white; border-left: 5px solid {status_color}; border-radius:5px; margin:5px 0;'>
                    <div style='display:flex; justify-content:space-between; align-items:center;'>
                        <div><strong>{node.topic}</strong> - {node.bloom_level.title()} ({node.content_type})<br><small>Difficulty: {node.difficulty:.2f} | Time: {node.estimated_time} min</small></div>
                        <div style='color:{status_color}; font-weight:bold;'>{node.status.title()}</div>
                    </div>
                </div>
                """
            path_html += "</div></div>"
            
            if path.current_node_index < len(path.nodes):
                current_node = path.nodes[path.current_node_index]
                current_node_info_text = f"""
### Current Learning Node

**Topic:** {current_node.topic}  
**Bloom Level:** {current_node.bloom_level.title()}  
**Content Type:** {current_node.content_type.title()}  
**Difficulty:** {current_node.difficulty:.2f}  
**Estimated Time:** {current_node.estimated_time} minutes
"""
            else:
                current_node_info_text = "### Learning Path Complete! πŸŽ‰"
            
            recommendations = self.adaptive_engine.get_recommendations(user_id)
            
            return (
                gr.update(visible=True),
                progress_html,
                path_html,
                current_node_info_text,
                recommendations
            )
        
        load_profile_btn.click(
            load_user_profile,
            inputs=[user_id_input],
            outputs=[profile_container, profile_summary, knowledge_level_display, learning_stats, focus_areas_input]
        )
        
        generate_path_btn.click(
            generate_learning_path,
            inputs=[user_id_input, focus_areas_input],
            outputs=[path_container, path_progress, path_visualization, current_node_info, recommendations_display]
        )