File size: 34,892 Bytes
43ceeff
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
import streamlit as st
import json
import base64
import os
import time
import uuid
from backend import VirtualInterviewer
import pandas as pd

# Set page configuration
st.set_page_config(
    page_title="Virtual Interviewer",
    page_icon="🎯",
    layout="wide",
    initial_sidebar_state="expanded"
)

# Default job description and key topics for Solution Architect
DEFAULT_JOB_DESCRIPTION = """

Job Title: Enterprise Solution Architect



Job Description:

We are seeking an experienced Enterprise Solution Architect to design and implement innovative technology solutions that address complex business challenges. The ideal candidate will have a strong background in cloud architecture, enterprise integration, and modern application development.



Responsibilities:

- Design scalable, secure, and resilient enterprise solutions using cloud-native technologies

- Create architectural blueprints and technical roadmaps aligned with business objectives

- Evaluate and recommend appropriate technologies and frameworks for various business needs

- Lead technical discussions with stakeholders and development teams

- Ensure solutions adhere to architectural standards, best practices, and compliance requirements

- Mentor junior architects and developers on architectural principles and patterns



Requirements:

- 8+ years of experience in IT with at least 5 years in solution architecture

- Strong knowledge of Azure cloud services and architecture patterns

- Experience with Java enterprise applications and microservices architecture

- Familiarity with GraphQL API design and implementation

- Experience integrating with Salesforce and other enterprise systems

- Knowledge of Generative AI technologies and their practical applications

- Excellent communication and presentation skills

- Ability to translate business requirements into technical solutions

"""

DEFAULT_KEY_TOPICS = "Azure, GraphQL, Java, Salesforce, Generative AI, Cloud Architecture, Microservices, API Design"

# Custom CSS for styling
st.markdown("""

<style>

    .main-header {

        font-size: 2.5rem;

        color: #4527A0;

        font-weight: 700;

        margin-bottom: 0;

    }

    .sub-header {

        font-size: 1.1rem;

        color: #5E35B1;

        font-style: italic;

        margin-top: 0;

    }

    .section-header {

        font-size: 1.5rem;

        color: #3949AB;

        font-weight: 600;

        border-bottom: 2px solid #3949AB;

        padding-bottom: 0.3rem;

        margin-top: 1rem;

    }

    .question-header {

        font-size: 1.3rem;

        color: #1E88E5;

        font-weight: 600;

    }

    .question-number {

        font-size: 1rem;

        color: #0D47A1;

        font-weight: 500;

    }

    .success-text {

        color: #2E7D32;

        font-weight: 500;

    }

    .warning-text {

        color: #FF6F00;

        font-weight: 500;

    }

    .score-header {

        font-size: 1.4rem;

        color: #00897B;

        font-weight: 600;

    }

    .score-value {

        font-size: 1.8rem;

        color: #00695C;

        font-weight: 700;

    }

    .feedback-text {

        color: #455A64;

        font-style: italic;

    }

    .ideal-answer-header {

        color: #7B1FA2;

        font-weight: 600;

    }

    .user-answer-header {

        color: #0277BD;

        font-weight: 600;

    }

    .footer {

        text-align: center;

        color: #78909C;

        font-size: 0.8rem;

        margin-top: 2rem;

    }

    .stButton>button {

        background-color: #3949AB;

        color: white;

        font-weight: 500;

    }

    .stButton>button:hover {

        background-color: #303F9F;

        color: white;

    }

    .submit-button>button {

        background-color: #00897B;

        color: white;

    }

    .submit-button>button:hover {

        background-color: #00796B;

    }

    .score-button>button {

        background-color: #7B1FA2;

        color: white;

    }

    .score-button>button:hover {

        background-color: #6A1B9A;

    }

    .stExpander {

        border: 1px solid #E0E0E0;

        border-radius: 5px;

        margin-bottom: 1rem;

    }

    /* Voice selection styling */

    div[data-testid="stRadio"] > div {

        background-color: #E8EAF6;

        padding: 1rem;

        border-radius: 5px;

        margin-bottom: 1rem;

    }

    div[data-testid="stRadio"] label {

        font-weight: 500;

        color: #3949AB;

    }

    .audio-player {

        margin-top: 0.5rem;

        margin-bottom: 1rem;

    }

    /* Score table styling */

    .score-table {

        width: 100%;

        border-collapse: collapse;

        margin-bottom: 2rem;

        font-size: 1.1rem;

        box-shadow: 0 4px 8px rgba(0,0,0,0.1);

        border-radius: 5px;

        overflow: hidden;

    }

    .score-table th {

        background-color: #3949AB;

        color: white;

        font-weight: 600;

        text-align: left;

        padding: 0.75rem 1rem;

        border: none;

    }

    .score-table td {

        padding: 0.75rem 1rem;

        border-bottom: 1px solid #E0E0E0;

        vertical-align: middle;

    }

    .score-table tr:last-child {

        font-weight: bold;

        background-color: #E8EAF6;

    }

    .score-table tr:last-child td {

        border-top: 2px solid #3949AB;

        border-bottom: none;

        color: #3949AB;

    }

    .score-table tr:nth-child(even):not(:last-child) {

        background-color: #F5F5F5;

    }

    .score-table tr:hover:not(:last-child) {

        background-color: #EDE7F6;

    }

    /* Make the table responsive */

    @media screen and (max-width: 600px) {

        .score-table {

            font-size: 0.9rem;

        }

        .score-table th, .score-table td {

            padding: 0.5rem;

        }

    }

</style>

""", unsafe_allow_html=True)

# Function to create an HTML audio player
def get_audio_player_html(audio_path, autoplay=True, player_id=None):
    if not audio_path or not os.path.exists(audio_path):
        return ""
    
    # Generate a unique ID for this audio player if not provided
    if player_id is None:
        player_id = str(uuid.uuid4())
    
    # Read the audio file
    with open(audio_path, 'rb') as f:
        audio_bytes = f.read()
    
    audio_base64 = base64.b64encode(audio_bytes).decode()
    
    autoplay_attr = "autoplay" if autoplay else ""
    
    # Create HTML with JavaScript to ensure autoplay works
    html = f"""

    <div class="audio-player" id="audio-container-{player_id}">

        <audio id="audio-{player_id}" controls {autoplay_attr}>

            <source src="data:audio/mp3;base64,{audio_base64}" type="audio/mp3">

            Your browser does not support the audio element.

        </audio>

    </div>

    <script>

        // Force play the audio after a short delay

        setTimeout(function() {{

            const audioElement = document.getElementById('audio-{player_id}');

            if (audioElement) {{

                audioElement.play().catch(e => console.log('Auto-play failed:', e));

            }}

        }}, 500);

    </script>

    """
    return html

# Initialize session state variables if they don't exist
if 'interviewer' not in st.session_state:
    st.session_state.interviewer = None
if 'current_question_index' not in st.session_state:
    st.session_state.current_question_index = 0
if 'current_question' not in st.session_state:
    st.session_state.current_question = ""
if 'conversation_history' not in st.session_state:
    st.session_state.conversation_history = []
if 'interview_started' not in st.session_state:
    st.session_state.interview_started = False
if 'interview_setup_done' not in st.session_state:
    st.session_state.interview_setup_done = False
if 'questions_generated' not in st.session_state:
    st.session_state.questions_generated = False
if 'interview_completed' not in st.session_state:
    st.session_state.interview_completed = False
if 'interview_scored' not in st.session_state:
    st.session_state.interview_scored = False
if 'score_results' not in st.session_state:
    st.session_state.score_results = None
if 'answer_submitted' not in st.session_state:
    st.session_state.answer_submitted = False
if 'current_answer' not in st.session_state:
    st.session_state.current_answer = ""
if 'generate_ideal_answers' not in st.session_state:
    st.session_state.generate_ideal_answers = True
if 'voice_type' not in st.session_state:
    st.session_state.voice_type = "female_casual"
if 'use_tts' not in st.session_state:
    st.session_state.use_tts = False
if 'current_audio_path' not in st.session_state:
    st.session_state.current_audio_path = ""
if 'audio_key' not in st.session_state:
    st.session_state.audio_key = str(uuid.uuid4())
if 'should_play_audio' not in st.session_state:
    st.session_state.should_play_audio = True

# Define callback functions
def reset_answer_input():
    st.session_state.answer_submitted = False
    st.session_state.current_answer = ""
    # We don't modify st.session_state.user_answer directly

# Function to generate audio for a question
def ensure_audio_for_question(question, voice_type):
    """Ensure audio exists for the given question and return the path."""
    if not question:
        return ""
        
    # Check if we already have audio for this question
    audio_path = st.session_state.interviewer.get_question_audio_path(question)
    
    # If no audio exists, generate it
    if not audio_path:
        with st.spinner("Generating audio..."):
            audio_path = st.session_state.interviewer.generate_question_audio(question, voice_type)
    
    # Update the current audio path in session state
    st.session_state.current_audio_path = audio_path
    
    # Generate a new audio key to force refresh
    st.session_state.audio_key = str(uuid.uuid4())
    
    return audio_path

# Function to handle replay button click
def replay_audio():
    st.session_state.should_play_audio = True
    st.session_state.audio_key = str(uuid.uuid4())

# Title and description
st.markdown("<h1 class='main-header'>🎯 Virtual Interviewer</h1>", unsafe_allow_html=True)
st.markdown("<p class='sub-header'>An AI-powered interview simulator to help you prepare for your next job interview.</p>", unsafe_allow_html=True)

# Create a two-column layout
left_col, right_col = st.columns([1, 1])

with left_col:
    # Interview setup section
    if not st.session_state.interview_setup_done:
        st.markdown("<h2 class='section-header'>πŸ“‹ Interview Setup</h2>", unsafe_allow_html=True)
        
        # 1a. Job requirement text box
        job_description = st.text_area(
            "πŸ’Ό Job Description",
            value=DEFAULT_JOB_DESCRIPTION,
            height=200
        )
        
        # 1b. OpenAI API Key
        api_key = st.text_input(
            "πŸ”‘ OpenAI API Key",
            type="password",
            placeholder="Enter your OpenAI API key"
        )
        
        # 2. Interview type dropdown
        interview_type = st.selectbox(
            "🎭 Interview Type",
            options=["Technical", "Non-technical"]
        )
        
        # 3. Difficulty level dropdown
        difficulty_level = st.selectbox(
            "πŸ“Š Difficulty Level",
            options=["Easy", "Medium", "Hard"]
        )
        
        # 4. Key topics text box
        key_topics = st.text_input(
            "πŸ” Key Topics",
            value=DEFAULT_KEY_TOPICS
        )
        
        # 5. Scoring option
        enable_scoring = st.radio(
            "πŸ“ Enable Scoring?",
            options=["Yes", "No"],
            horizontal=True
        )
        
        # New option for generating ideal answers
        generate_ideal_answers = st.radio(
            "πŸ’‘ Generate Ideal Answers?",
            options=["Yes", "No"],
            horizontal=True
        )
        
        # 6. Number of questions
        num_questions = st.number_input(
            "❓ Number of Questions",
            min_value=1,
            max_value=10,
            value=5
        )
        
        # Text-to-Speech options
        st.markdown("<h3 class='section-header'>πŸ”Š Text-to-Speech Options</h3>", unsafe_allow_html=True)
        
        use_tts = st.checkbox("Enable Text-to-Speech for questions", value=True)
        
        if use_tts:
            # Voice type selection with a single radio button for all voices
            st.markdown("<p style='margin-top: 1rem; font-weight: 500;'>Select a voice for the interviewer:</p>", unsafe_allow_html=True)
            
            # Create a single radio button with all voice options
            voice_options = [
                "πŸ‘¨ Male - Casual (Guy)",
                "πŸ‘¨ Male - Formal (Christopher)",
                "πŸ‘¨ Male - British (Ryan)",
                "πŸ‘© Female - Casual (Jenny)",
                "πŸ‘© Female - Formal (Aria)",
                "πŸ‘© Female - British (Sonia)"
            ]
            
            selected_voice = st.radio(
                "Voice Selection",
                options=voice_options,
                index=3,  # Default to Female Casual
                label_visibility="collapsed"  # Hide the label since we already have a header
            )
            
            # Map the selected voice to the backend voice type
            voice_mapping = {
                "πŸ‘¨ Male - Casual (Guy)": "male_casual",
                "πŸ‘¨ Male - Formal (Christopher)": "male_formal",
                "πŸ‘¨ Male - British (Ryan)": "male_british",
                "πŸ‘© Female - Casual (Jenny)": "female_casual",
                "πŸ‘© Female - Formal (Aria)": "female_formal",
                "πŸ‘© Female - British (Sonia)": "female_british"
            }
            
            voice_type = voice_mapping.get(selected_voice, "female_casual")
        else:
            voice_type = "female_casual"
        
        # Start interview button
        if st.button("πŸš€ Start Interview"):
            if not api_key:
                st.error("⚠️ Please enter your OpenAI API key.")
            elif not job_description:
                st.error("⚠️ Please enter a job description.")
            else:
                with st.spinner("Setting up your interview..."):
                    try:
                        # Initialize the interviewer
                        st.session_state.interviewer = VirtualInterviewer(api_key)
                        
                        # Store whether to generate ideal answers
                        should_generate_ideal_answers = (generate_ideal_answers == "Yes")
                        st.session_state.generate_ideal_answers = should_generate_ideal_answers
                        
                        # Store TTS settings
                        st.session_state.use_tts = use_tts
                        st.session_state.voice_type = voice_type
                        
                        # Generate questions
                        questions = st.session_state.interviewer.generate_interview_questions(
                            job_description=job_description,
                            interview_type=interview_type,
                            difficulty_level=difficulty_level,
                            key_topics=key_topics,
                            num_questions=int(num_questions),
                            generate_ideal_answers=should_generate_ideal_answers
                        )
                        
                        # Generate audio for the first question if TTS is enabled
                        if use_tts and questions:
                            with st.spinner("Generating audio for first question..."):
                                audio_path = st.session_state.interviewer.generate_question_audio(questions[0], voice_type)
                                st.session_state.current_audio_path = audio_path
                                st.session_state.audio_key = str(uuid.uuid4())
                                st.session_state.should_play_audio = True
                        
                        # Store interview parameters for scoring later
                        st.session_state.job_description = job_description
                        st.session_state.interview_type = interview_type
                        st.session_state.difficulty_level = difficulty_level
                        st.session_state.enable_scoring = (enable_scoring == "Yes")
                        st.session_state.num_questions = int(num_questions)
                        
                        # Set the first question
                        st.session_state.current_question = questions[0]
                        st.session_state.questions_generated = True
                        st.session_state.interview_setup_done = True
                        st.session_state.interview_started = True
                        st.session_state.answer_submitted = False
                        st.session_state.current_answer = ""
                        
                        # Rerun to update the UI
                        st.rerun()
                    except Exception as e:
                        st.error(f"⚠️ Error setting up the interview: {str(e)}")
    
    # Interview in progress section
    elif st.session_state.interview_started and not st.session_state.interview_completed:
        st.markdown("<h2 class='section-header'>πŸŽ™οΈ Interview in Progress</h2>", unsafe_allow_html=True)
        
        # Display current question number
        st.markdown(f"<p class='question-number'>Question {st.session_state.current_question_index + 1} of {len(st.session_state.interviewer.questions_asked)}</p>", unsafe_allow_html=True)
        
        # Display conversation history
        if st.session_state.conversation_history:
            st.markdown("<h3 class='section-header'>πŸ“œ Previous Questions and Answers</h3>", unsafe_allow_html=True)
            for i, qa in enumerate(st.session_state.conversation_history):
                if i % 2 == 0:  # Question (even index)
                    st.markdown(f"<p><strong style='color: #3949AB;'>Q{i//2 + 1}:</strong> {qa}</p>", unsafe_allow_html=True)
                else:  # Answer (odd index)
                    st.markdown(f"<p><em style='color: #455A64;'>A: {qa}</em></p>", unsafe_allow_html=True)
                    st.markdown("<hr style='margin: 0.5rem 0; border-color: #E0E0E0;'>", unsafe_allow_html=True)
    
    # Interview completed section
    elif st.session_state.interview_completed:
        st.markdown("<h2 class='section-header'>🏁 Interview Completed</h2>", unsafe_allow_html=True)
        
        # Display conversation history
        if st.session_state.conversation_history:
            st.markdown("<h3 class='section-header'>πŸ“‹ Interview Summary</h3>", unsafe_allow_html=True)
            for i, qa in enumerate(st.session_state.conversation_history):
                if i % 2 == 0:  # Question (even index)
                    st.markdown(f"<p><strong style='color: #3949AB;'>Q{i//2 + 1}:</strong> {qa}</p>", unsafe_allow_html=True)
                else:  # Answer (odd index)
                    st.markdown(f"<p><em style='color: #455A64;'>A: {qa}</em></p>", unsafe_allow_html=True)
                    st.markdown("<hr style='margin: 0.5rem 0; border-color: #E0E0E0;'>", unsafe_allow_html=True)
        
        # Option to restart
        if st.button("πŸ”„ Start New Interview"):
            # Reset all session state variables
            for key in list(st.session_state.keys()):
                del st.session_state[key]
            st.rerun()

# Right column for displaying the current question and answer input
with right_col:
    if st.session_state.interview_started and not st.session_state.interview_completed:
        st.markdown("<h2 class='section-header'>❓ Current Question</h2>", unsafe_allow_html=True)
        
        # Display the current question
        st.markdown(f"<p class='question-header'>{st.session_state.current_question}</p>", unsafe_allow_html=True)
        
        # Display audio player if TTS is enabled
        if st.session_state.use_tts:
            # Ensure we have audio for the current question
            current_question = st.session_state.current_question
            audio_path = ensure_audio_for_question(current_question, st.session_state.voice_type)
            
            # Display audio player with unique key to force refresh
            if audio_path and os.path.exists(audio_path):
                # Create a container for the audio player
                audio_container = st.empty()
                
                # Display the audio player with the current audio key
                audio_container.markdown(
                    get_audio_player_html(
                        audio_path, 
                        autoplay=st.session_state.should_play_audio,
                        player_id=st.session_state.audio_key
                    ), 
                    unsafe_allow_html=True
                )
                
                # Reset the should_play_audio flag after displaying
                if st.session_state.should_play_audio:
                    st.session_state.should_play_audio = False
                
                # Add a button to replay the audio
                if st.button("πŸ”Š Replay Question Audio"):
                    # Set flag to play audio and generate new key
                    replay_audio()
                    st.rerun()
        
        # Text area for the user's answer
        user_answer = st.text_area(
            "Your Answer",
            key="user_answer",
            height=300,
            placeholder="Type your answer here..."
        )
        
        # Submit button for the answer
        submit_button_col1, submit_button_col2, submit_button_col3 = st.columns([1, 1, 1])
        with submit_button_col2:
            if st.button("βœ… Submit Answer", key="submit_answer"):
                if user_answer:  # Use the local variable, not session_state
                    st.session_state.answer_submitted = True
                    st.session_state.current_answer = user_answer  # Store the answer in a different session state variable
                    st.markdown("<p class='success-text'>βœ… Answer submitted! Click 'Next Question' to continue.</p>", unsafe_allow_html=True)
                else:
                    st.markdown("<p class='warning-text'>⚠️ Please provide an answer before submitting.</p>", unsafe_allow_html=True)
    
    # Display score results if interview is scored
    elif st.session_state.interview_scored and st.session_state.score_results:
        st.markdown("<h2 class='section-header'>πŸ“Š Interview Results</h2>", unsafe_allow_html=True)
        
        score_results = st.session_state.score_results
        
        # Display overall score with a visual indicator
        if "overall_score" in score_results:
            overall_score = score_results['overall_score']
            
            # Create a visual score indicator
            score_color = "#4CAF50" if overall_score >= 4 else "#FF9800" if overall_score >= 3 else "#F44336"
            
            st.markdown(f"""

            <div style="background-color: #F3F4F6; padding: 1.5rem; border-radius: 10px; margin: 1rem 0; box-shadow: 0 2px 5px rgba(0,0,0,0.1);">

                <h3 style="color: #3949AB; margin-top: 0;">Overall Performance</h3>

                <div style="display: flex; align-items: center; margin-bottom: 1rem;">

                    <div style="background-color: {score_color}; color: white; font-size: 2rem; font-weight: bold; width: 80px; height: 80px; border-radius: 50%; display: flex; align-items: center; justify-content: center; margin-right: 1.5rem;">

                        {overall_score}/5

                    </div>

                    <div>

                        <p style="font-size: 1.1rem; margin: 0; color: #333;">{score_results['overall_feedback']}</p>

                    </div>

                </div>

            </div>

            """, unsafe_allow_html=True)
        
        # Display score table
        if "individual_scores" in score_results:
            st.markdown("<h3 class='section-header'>πŸ“ˆ Score Summary</h3>", unsafe_allow_html=True)
            
            # Extract data for the table
            questions = []
            scores = []
            
            for i, score_item in enumerate(score_results["individual_scores"]):
                # Truncate long questions for better display
                question_text = score_item['question']
                if len(question_text) > 80:
                    question_text = question_text[:77] + "..."
                
                questions.append(f"Q{i+1}: {question_text}")
                scores.append(score_item['score'])
            
            # Calculate average score
            if scores:
                avg_score = sum(scores) / len(scores)
                questions.append("**Average Score**")
                scores.append(f"**{avg_score:.2f}**")
            
            # Create DataFrame
            df = pd.DataFrame({
                "Question": questions,
                "Score (out of 5)": scores
            })
            
            # Convert DataFrame to HTML and display it
            table_html = df.to_html(classes='score-table', escape=False, index=False)
            st.markdown(f"""

            <div style="overflow-x: auto;">

                {table_html}

            </div>

            """, unsafe_allow_html=True)
        
        # Display individual scores with ideal answers
        if "individual_scores" in score_results:
            st.markdown("<h3 class='section-header'>πŸ“ Detailed Feedback</h3>", unsafe_allow_html=True)
            
            st.markdown("""

            <p style="margin-bottom: 1rem;">Click on each question below to see detailed feedback and ideal answers.</p>

            """, unsafe_allow_html=True)
            
            for i, score_item in enumerate(score_results["individual_scores"]):
                # Determine score color
                score_value = score_item['score']
                score_color = "#4CAF50" if score_value >= 4 else "#FF9800" if score_value >= 3 else "#F44336"
                
                with st.expander(f"Question {i+1}: {score_item['question']}"):
                    st.markdown(f"""

                    <div style="display: flex; align-items: center; margin-bottom: 1rem;">

                        <div style="background-color: {score_color}; color: white; font-size: 1.2rem; font-weight: bold; width: 50px; height: 50px; border-radius: 50%; display: flex; align-items: center; justify-content: center; margin-right: 1rem;">

                            {score_value}/5

                        </div>

                        <div>

                            <p style="font-size: 1.1rem; margin: 0; color: #333; font-weight: 500;">{score_item['feedback']}</p>

                        </div>

                    </div>

                    """, unsafe_allow_html=True)
                    
                    st.markdown("<h4 class='user-answer-header'>πŸ§‘β€πŸ’Ό Your Answer:</h4>", unsafe_allow_html=True)
                    st.markdown(f"{score_item['answer']}")
                    
                    # Only show ideal answers if they were generated
                    if st.session_state.generate_ideal_answers:
                        st.markdown("<h4 class='ideal-answer-header'>πŸ’‘ Ideal Answer:</h4>", unsafe_allow_html=True)
                        if "ideal_answer" in score_item:
                            st.markdown(f"{score_item['ideal_answer']}")
                        else:
                            st.markdown("No ideal answer available.")
    
    # Display a welcome message if interview hasn't started
    elif not st.session_state.interview_started:
        st.markdown("<h2 class='section-header'>πŸ‘‹ Welcome to Virtual Interviewer</h2>", unsafe_allow_html=True)
        st.markdown("""

        <div style="background-color: #E8EAF6; padding: 1.5rem; border-radius: 10px; margin-top: 1rem;">

            <h3 style="color: #3949AB; font-size: 1.3rem; margin-bottom: 1rem;">This tool will help you practice for your upcoming interviews by:</h3>

            <ol style="color: #303F9F; font-size: 1.1rem;">

                <li>Generating relevant interview questions based on a job description</li>

                <li>Simulating a real interview experience</li>

                <li>Providing feedback on your answers</li>

            </ol>

            <p style="color: #3949AB; font-size: 1.1rem; margin-top: 1rem;">To get started, fill out the interview setup form on the left and click "Start Interview".</p>

        </div>

        """, unsafe_allow_html=True)

# Bottom section for control buttons
if st.session_state.interview_started and not st.session_state.interview_completed:
    st.markdown("<hr style='margin: 2rem 0 1rem 0;'>", unsafe_allow_html=True)
    
    # Create a container for the buttons at the bottom
    button_container = st.container()
    
    with button_container:
        col1, col2, col3 = st.columns([1, 1, 1])
        
        with col1:
            pass  # Empty column for spacing
        
        with col2:
            next_button_disabled = not st.session_state.answer_submitted
            if st.button("⏭️ Next Question", disabled=next_button_disabled, use_container_width=True):
                # Store the current question and answer
                if st.session_state.current_answer:  # Use current_answer instead of user_answer
                    # Add to conversation history
                    st.session_state.conversation_history.append(st.session_state.current_question)
                    st.session_state.conversation_history.append(st.session_state.current_answer)
                    
                    # Store in the interviewer object
                    st.session_state.interviewer.store_user_answer(
                        st.session_state.current_question,
                        st.session_state.current_answer
                    )
                    
                    # Move to the next question
                    st.session_state.current_question_index += 1
                    
                    # Check if we've reached the end of the questions
                    if st.session_state.current_question_index >= len(st.session_state.interviewer.questions_asked):
                        st.session_state.interview_completed = True
                        
                        # Automatically score the interview if scoring is enabled
                        if st.session_state.enable_scoring:
                            with st.spinner("Scoring your interview..."):
                                try:
                                    # Score the interview
                                    score_results = st.session_state.interviewer.score_interview(
                                        job_description=st.session_state.job_description,
                                        interview_type=st.session_state.interview_type,
                                        difficulty_level=st.session_state.difficulty_level
                                    )
                                    
                                    st.session_state.score_results = score_results
                                    st.session_state.interview_scored = True
                                except Exception as e:
                                    st.error(f"⚠️ Error scoring the interview: {str(e)}")
                        
                        st.rerun()
                    else:
                        # Get the next question
                        next_question = st.session_state.interviewer.get_next_question(
                            st.session_state.current_question_index
                        )
                        st.session_state.current_question = next_question
                        
                        # Reset submission status and current answer
                        reset_answer_input()
                        
                        # Set flag to play audio for the new question
                        st.session_state.should_play_audio = True
                        st.session_state.audio_key = str(uuid.uuid4())
                        
                        st.rerun()
                else:
                    st.warning("⚠️ Please provide an answer before moving to the next question.")
        
        with col3:
            if st.session_state.enable_scoring:
                if st.button("πŸ“Š Score Interview", use_container_width=True, key="score_button"):
                    if len(st.session_state.interviewer.user_answers) > 0:
                        with st.spinner("Scoring your interview..."):
                            try:
                                # Score the interview
                                score_results = st.session_state.interviewer.score_interview(
                                    job_description=st.session_state.job_description,
                                    interview_type=st.session_state.interview_type,
                                    difficulty_level=st.session_state.difficulty_level
                                )
                                
                                st.session_state.score_results = score_results
                                st.session_state.interview_scored = True
                                st.session_state.interview_completed = True
                                st.rerun()
                            except Exception as e:
                                st.error(f"⚠️ Error scoring the interview: {str(e)}")
                    else:
                        st.warning("⚠️ Please answer at least one question before scoring.")

# Footer
st.markdown("<hr style='margin: 2rem 0 1rem 0;'>", unsafe_allow_html=True)
st.markdown("<p class='footer'>🎯 Powered by OpenAI GPT-4o | Created with Streamlit</p>", unsafe_allow_html=True)