File size: 5,934 Bytes
e8552c6
 
 
 
 
 
 
 
 
 
 
 
845cbef
e8552c6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import json
import gradio as gr
from transformers import AutoTokenizer, AutoModelForSeq2SeqLM
import torch
import os

# Set up device
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

hf_token = os.environ["HF_TOKEN"]

# Load model and tokenizer from local files
model_path = "AI-Mock-Interviewer/T5"  # Assuming all files are in the root directory
tokenizer = AutoTokenizer.from_pretrained(model_path)
model = AutoModelForSeq2SeqLM.from_pretrained(model_path)

# Move model to the appropriate device
model.to(device)

# ------------------- SYSTEM PROMPT -------------------
system_prompt = """
You are conducting a mock technical interview. The candidate's experience level can be entry-level, mid-level, or senior-level. Generate questions and follow-up questions based on the domain and the candidate's experience level. Consider these aspects:
1. The question should be relevant to the domain (e.g., software engineering, machine learning) and appropriate for the candidate's experience level.
2. For follow-up questions, analyze the candidate's last response and ask questions that probe deeper into their understanding, challenge their approach, or request clarification.
3. The follow-up question should aim to explore the candidate's depth of knowledge and ability to adapt.
4. Ensure each question is unique and does not repeat previously asked questions.
5. Ensure each question covers a different sub-topic within the domain, avoiding redundancy.
6. If no clear follow-up can be derived, generate a fresh, related question from a different aspect of the domain.
Important: Ensure that each question is clear, concise, and allows the candidate to demonstrate their technical and communicative abilities effectively.
"""

# Define sub-topic categories for different domains
subtopic_keywords = {
    "data analysis": ["data cleaning", "missing data", "EDA", "visualization"],
    "machine learning": ["supervised learning", "overfitting", "hyperparameter tuning"],
    "software engineering": ["code optimization", "design patterns", "database design"],
}

def identify_subtopic(question, domain):
    """Identify the sub-topic of a question using predefined keywords."""
    domain = domain.lower()
    if domain in subtopic_keywords:
        for subtopic in subtopic_keywords[domain]:
            if subtopic in question.lower():
                return subtopic
    return None

# Tracking asked questions
def generate_question(prompt, domain, state=None):
    """
    Generates a unique question based on the prompt and domain.
    Uses 'state' to track uniqueness in the conversation session.
    """
    full_prompt = system_prompt + "\n" + prompt
    inputs = tokenizer(full_prompt, return_tensors="pt").to(device)
    
    outputs = model.generate(
        inputs["input_ids"],
        max_new_tokens=50,
        num_return_sequences=1,
        no_repeat_ngram_size=2,
        top_k=30,
        top_p=0.9,
        temperature=0.7,
        do_sample=True,
        pad_token_id=tokenizer.eos_token_id,
    )
    
    question = tokenizer.decode(outputs[0], skip_special_tokens=True).strip()

    # Ensure question ends with a question mark
    if not question.endswith("?"):
        question += "?"

    # Identify the subtopic
    subtopic = identify_subtopic(question, domain)

    # Check for uniqueness
    if state is not None:
        if (question not in state["asked_questions"] and
            (subtopic is None or subtopic not in state["asked_subtopics"])):
            state["asked_questions"].add(question)
            if subtopic:
                state["asked_subtopics"].add(subtopic)
            return question
    return question  # Fallback

# Initialize conversation state
def reset_state(domain, company, level):
    return {
        "domain": domain,
        "company": company,
        "level": level,
        "asked_questions": set(),
        "asked_subtopics": set(),
        "conversation": []  # List of (speaker, message) tuples
    }

def start_interview(domain, company, level):
    state = reset_state(domain, company, level)
    prompt = f"Domain: {domain}. Candidate experience level: {level}. Generate the first question:"
    
    question = generate_question(prompt, domain, state)
    state["conversation"].append(("Interviewer", question))
    return state["conversation"], state

def submit_response(candidate_response, state):
    state["conversation"].append(("Candidate", candidate_response))
    prompt = (f"Domain: {state['domain']}. Candidate's last response: {candidate_response}. Generate a follow-up question:")
    
    question = generate_question(prompt, state["domain"], state)
    state["conversation"].append(("Interviewer", question))
    return state["conversation"], state

# ----------- Gradio UI -----------

with gr.Blocks() as demo:
    gr.Markdown("# Interactive AI-Powered Mock Interview")
    
    with gr.Row():
        domain_input = gr.Textbox(label="Domain", placeholder="e.g. Software Engineering")
        company_input = gr.Textbox(label="Company (Optional)", placeholder="e.g. Google")
        level_input = gr.Dropdown(
            label="Experience Level",
            choices=["Entry-Level", "Mid-Level", "Senior-Level"],
            value="Entry-Level"
        )

    start_button = gr.Button("Start Interview")
    chatbot = gr.Chatbot(label="Interview Conversation")

    with gr.Row():
        response_input = gr.Textbox(label="Your Response")
        submit_button = gr.Button("Submit")
        clear_button = gr.Button("Clear Chat")

    state = gr.State()  # Holds session data

    start_button.click(start_interview, inputs=[domain_input, company_input, level_input], outputs=[chatbot, state])
    submit_button.click(submit_response, inputs=[response_input, state], outputs=[chatbot, state]).then(lambda: "", None, response_input)
    clear_button.click(lambda: ([], None), outputs=[chatbot, state])

demo.launch()