Spaces:
Sleeping
Sleeping
| import json | |
| import os | |
| import random | |
| import string | |
| import time | |
| from collections import defaultdict | |
| from typing import Dict, Optional, Tuple | |
| from openai import OpenAI | |
| from api.llm import LLMManager | |
| from utils.config import Config | |
| from resources.data import fixed_messages, topic_lists | |
| from resources.prompts import prompts | |
| from tests.testing_prompts import candidate_prompt | |
| from ui.coding import send_request | |
| def complete_interview( | |
| interview_type: str, | |
| exp_name: str, | |
| llm_config: Optional[Config] = None, | |
| requirements: str = "", | |
| difficulty: str = "", | |
| topic: str = "", | |
| model: str = "gpt-4o-mini", | |
| pause: int = 0, | |
| mode: str = "normal", | |
| max_messages: Optional[int] = None, | |
| ) -> Tuple[str, Dict]: | |
| """ | |
| Complete an interview and record the results with additional strange use cases. | |
| :param interview_type: Type of interview to complete. | |
| :param exp_name: Experiment name for file saving. | |
| :param llm_config: Optional LLM configuration. | |
| :param requirements: Additional requirements for the interview. | |
| :param difficulty: Difficulty level for the interview. | |
| :param topic: Topic for the interview. | |
| :param model: Model to use for the candidate. | |
| :param pause: Pause duration between requests to prevent rate limits. | |
| :param mode: Mode of operation ("normal", "empty", "gibberish", "repeat"). | |
| :param max_messages: Maximum number of messages in the conversation. | |
| :return: Tuple containing the file path and interview data. | |
| """ | |
| client = OpenAI(base_url="https://api.openai.com/v1") | |
| config = Config() | |
| if llm_config: | |
| config.llm = llm_config | |
| llm = LLMManager(config, prompts) | |
| llm_name = config.llm.name | |
| print(f"Starting evaluation interviewer LLM: {llm_name}, candidate LLM: {model}, interview type: {interview_type}") | |
| # Select a random topic or difficulty if not provided | |
| topic = topic or random.choice(topic_lists[interview_type]) | |
| difficulty = difficulty or random.choice(["easy", "medium", "hard"]) | |
| # Fix: Iterate over all elements and keep the last one | |
| problem_statement_text = None | |
| for text in llm.get_problem(requirements, difficulty, topic, interview_type): | |
| problem_statement_text = text | |
| if problem_statement_text is None: | |
| raise ValueError("Failed to get problem statement") | |
| interview_data = defaultdict( | |
| lambda: None, | |
| { | |
| "interviewer_llm": llm_name, | |
| "candidate_llm": model, | |
| "inputs": { | |
| "interview_type": interview_type, | |
| "difficulty": difficulty, | |
| "topic": topic, | |
| "requirements": requirements, | |
| }, | |
| "problem_statement": problem_statement_text, | |
| "transcript": [], | |
| "feedback": None, | |
| "average_response_time_seconds": 0, | |
| }, | |
| ) | |
| # Initialize interviewer and candidate messages | |
| messages_interviewer = llm.init_bot(problem_statement_text, interview_type) | |
| chat_display = [[None, fixed_messages["start"]]] | |
| messages_candidate = [ | |
| {"role": "system", "content": candidate_prompt}, | |
| {"role": "user", "content": f"Your problem: {problem_statement_text}"}, | |
| {"role": "user", "content": chat_display[-1][1]}, | |
| ] | |
| response_times = [] | |
| previous_code = "" | |
| if max_messages is None: | |
| max_messages = 25 if mode == "normal" else 5 | |
| for _ in range(max_messages): | |
| code = "" | |
| if mode == "empty": | |
| candidate_message = "" | |
| elif mode == "gibberish": | |
| candidate_message = "".join(random.choices(string.ascii_letters + string.digits, k=50)) | |
| elif mode == "repeat": | |
| candidate_message = chat_display[-1][1] | |
| else: | |
| try: | |
| response = client.chat.completions.create( | |
| model=model, | |
| messages=messages_candidate, | |
| temperature=1, | |
| response_format={"type": "json_object"}, | |
| timeout=30, # Add a timeout to prevent indefinite waiting | |
| ) | |
| try: | |
| response_json = json.loads(response.choices[0].message.content) | |
| candidate_message = response_json.get("message", "") | |
| code = response_json.get("code_and_notes", "") | |
| finished = response_json.get("finished", False) | |
| question = response_json.get("question", False) | |
| if finished and not question and not code: | |
| break | |
| except: | |
| continue | |
| except Exception as e: | |
| print(f"Error in API call: {str(e)}, skipping this iteration") | |
| continue | |
| if not candidate_message and not code and mode != "empty": | |
| print("No message or code in response") | |
| continue | |
| if candidate_message: | |
| messages_candidate.append({"role": "assistant", "content": candidate_message}) | |
| interview_data["transcript"].append(f"CANDIDATE MESSAGE: {candidate_message}") | |
| if code: | |
| interview_data["transcript"].append(f"CANDIDATE CODE AND NOTES: {code}") | |
| messages_candidate.append({"role": "assistant", "content": code}) | |
| chat_display.append([candidate_message, None]) | |
| send_time = time.time() | |
| # Fix: Iterate over all elements and keep the last one | |
| last_result = None | |
| for result in send_request(code, previous_code, messages_interviewer, chat_display, llm, tts=None, silent=True): | |
| last_result = result | |
| if last_result is not None: | |
| messages_interviewer, chat_display, previous_code, _ = last_result | |
| else: | |
| print("send_request did not return any results, skipping this iteration") | |
| continue | |
| response_times.append(time.time() - send_time) | |
| messages_candidate.append({"role": "user", "content": chat_display[-1][1]}) | |
| message_split = messages_interviewer[-1]["content"].split("#NOTES#") | |
| interview_data["transcript"].append(f"INTERVIEWER MESSAGE: {message_split[0]}") | |
| if len(message_split) > 1: | |
| interview_data["transcript"].append(f"INTERVIEWER HIDDEN NOTE: {message_split[1]}") | |
| time.sleep(pause) # to prevent exceeding rate limits | |
| # Fix: Iterate over all elements and keep the last one | |
| feedback = None | |
| for fb in llm.end_interview(problem_statement_text, messages_interviewer, interview_type): | |
| feedback = fb | |
| interview_data["feedback"] = feedback | |
| interview_data["average_response_time_seconds"] = round(sum(response_times) / len(response_times), 2) if response_times else 0 | |
| current_time = time.strftime("%Y%m%d-%H%M%S") | |
| random_suffix = "".join(random.choices(string.ascii_letters + string.digits, k=10)) | |
| file_path = os.path.join("records", exp_name, f"{current_time}-{random_suffix}.json") | |
| os.makedirs(os.path.dirname(file_path), exist_ok=True) | |
| with open(file_path, "w") as file: | |
| json.dump(interview_data, file, indent=4) | |
| return file_path, interview_data | |