Spaces:
Sleeping
Sleeping
Commit
·
c62e737
1
Parent(s):
fb73ff7
Added support of the HuggingFace models
Browse files- config.py +21 -11
- llm.py +36 -26
- prompts.py +0 -4
config.py
CHANGED
|
@@ -1,18 +1,28 @@
|
|
| 1 |
-
|
| 2 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3 |
LLM_NAME = "gpt-3.5-turbo"
|
| 4 |
# "gpt-3.5-turbo" - ~3 seconds delay with decent quality
|
| 5 |
# "gpt-4-turbo","gpt-4", etc. 10+ seconds delay but higher quality
|
|
|
|
|
|
|
|
|
|
| 6 |
|
| 7 |
-
STT_URL =
|
| 8 |
-
|
| 9 |
STT_NAME = "whisper-1"
|
| 10 |
-
# "whisper-1"
|
| 11 |
-
|
|
|
|
|
|
|
| 12 |
|
| 13 |
-
TTS_URL =
|
| 14 |
-
|
| 15 |
TTS_NAME = "tts-1"
|
| 16 |
-
#
|
| 17 |
-
# "tts-1" -
|
| 18 |
-
#
|
|
|
|
| 1 |
+
# X_URL - the URL for the model endpoint, can be None if using OpenAI API
|
| 2 |
+
# X_TYPE - the type of the model, can be "OPENAI_API" or "HF_API"
|
| 3 |
+
# there should be an environment variable with the f"{}_KEY" name and the key as the value to authenticate the API
|
| 4 |
+
# X_NAME - the name of the model, used only for OpenAI API
|
| 5 |
+
|
| 6 |
+
LLM_URL = None
|
| 7 |
+
LLM_TYPE = "OPENAI_API"
|
| 8 |
LLM_NAME = "gpt-3.5-turbo"
|
| 9 |
# "gpt-3.5-turbo" - ~3 seconds delay with decent quality
|
| 10 |
# "gpt-4-turbo","gpt-4", etc. 10+ seconds delay but higher quality
|
| 11 |
+
# For HuggingFace models, the Messages API is used, it if compatible with Open AI API
|
| 12 |
+
# Don't forget to add "/v1" to the end of the URL for HuggingFace LLM models
|
| 13 |
+
# https://huggingface.co/docs/text-generation-inference/en/messages_api
|
| 14 |
|
| 15 |
+
STT_URL = "https://api-inference.huggingface.co/models/openai/whisper-tiny.en"
|
| 16 |
+
STT_TYPE = "HF_API"
|
| 17 |
STT_NAME = "whisper-1"
|
| 18 |
+
# "whisper-1" is the only OpenAI STT model available for OpenAI API
|
| 19 |
+
# The whisper family with more models is available on HuggingFace:
|
| 20 |
+
# https://huggingface.co/collections/openai/whisper-release-6501bba2cf999715fd953013
|
| 21 |
+
# you can also use any other compatible model from HuggingFace
|
| 22 |
|
| 23 |
+
TTS_URL = None
|
| 24 |
+
TTS_TYPE = "OPENAI_API"
|
| 25 |
TTS_NAME = "tts-1"
|
| 26 |
+
# OpenAI "tts-1" - very good quality and close to real-time response
|
| 27 |
+
# OpenAI "tts-1-hd" - slightly better quality with slightly longer response time (no obvious benefits in this case)
|
| 28 |
+
# I think OS models on HuggingFace have much more artificial voices, but you can try them out
|
llm.py
CHANGED
|
@@ -1,19 +1,18 @@
|
|
| 1 |
import json
|
| 2 |
import os
|
| 3 |
|
|
|
|
|
|
|
| 4 |
from dotenv import load_dotenv
|
| 5 |
from openai import OpenAI
|
| 6 |
|
| 7 |
from audio import numpy_audio_to_bytes
|
| 8 |
-
from config import
|
| 9 |
from prompts import coding_interviewer_prompt, grading_feedback_prompt, problem_generation_prompt
|
| 10 |
|
| 11 |
load_dotenv()
|
| 12 |
|
| 13 |
-
client_LLM = OpenAI(base_url=LLM_URL, api_key=os.getenv(
|
| 14 |
-
print(client_LLM.base_url)
|
| 15 |
-
client_STT = OpenAI(base_url=STT_URL, api_key=os.getenv(STT_KEY_TYPE))
|
| 16 |
-
client_TTS = OpenAI(base_url=TTS_URL, api_key=os.getenv(TTS_KEY_TYPE))
|
| 17 |
|
| 18 |
|
| 19 |
def init_bot(problem=""):
|
|
@@ -73,37 +72,48 @@ def send_request(code, previous_code, message, chat_history, chat_display, clien
|
|
| 73 |
chat_history.append({"role": "user", "content": f"My latest code:\n{code}"})
|
| 74 |
chat_history.append({"role": "user", "content": message})
|
| 75 |
|
| 76 |
-
response = client.chat.completions.create(model=LLM_NAME,
|
| 77 |
-
|
| 78 |
-
json_reply = response.choices[0].message.content.strip()
|
| 79 |
|
| 80 |
-
|
| 81 |
-
data = json.loads(json_reply)
|
| 82 |
-
reply = data["reply_to_candidate"]
|
| 83 |
-
except json.JSONDecodeError as e:
|
| 84 |
-
print("Failed to decode JSON:", str(e))
|
| 85 |
-
reply = "There was an error processing your request."
|
| 86 |
|
| 87 |
-
chat_history.append({"role": "assistant", "content":
|
| 88 |
-
chat_display.append([message,
|
| 89 |
|
| 90 |
return chat_history, chat_display, "", code
|
| 91 |
|
| 92 |
|
| 93 |
-
def speech_to_text(audio
|
| 94 |
-
|
| 95 |
-
|
| 96 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 97 |
return transcription
|
| 98 |
|
| 99 |
|
| 100 |
-
def text_to_speech(text
|
| 101 |
-
|
| 102 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 103 |
|
| 104 |
|
| 105 |
def read_last_message(chat_display):
|
| 106 |
last_message = chat_display[-1][1]
|
| 107 |
-
|
| 108 |
-
|
| 109 |
-
|
|
|
|
|
|
| 1 |
import json
|
| 2 |
import os
|
| 3 |
|
| 4 |
+
import requests
|
| 5 |
+
|
| 6 |
from dotenv import load_dotenv
|
| 7 |
from openai import OpenAI
|
| 8 |
|
| 9 |
from audio import numpy_audio_to_bytes
|
| 10 |
+
from config import LLM_NAME, LLM_TYPE, LLM_URL, STT_NAME, STT_TYPE, STT_URL, TTS_NAME, TTS_TYPE, TTS_URL
|
| 11 |
from prompts import coding_interviewer_prompt, grading_feedback_prompt, problem_generation_prompt
|
| 12 |
|
| 13 |
load_dotenv()
|
| 14 |
|
| 15 |
+
client_LLM = OpenAI(base_url=LLM_URL, api_key=os.getenv(f"{LLM_TYPE}_KEY"))
|
|
|
|
|
|
|
|
|
|
| 16 |
|
| 17 |
|
| 18 |
def init_bot(problem=""):
|
|
|
|
| 72 |
chat_history.append({"role": "user", "content": f"My latest code:\n{code}"})
|
| 73 |
chat_history.append({"role": "user", "content": message})
|
| 74 |
|
| 75 |
+
response = client.chat.completions.create(model=LLM_NAME, messages=chat_history)
|
|
|
|
|
|
|
| 76 |
|
| 77 |
+
reply = response.choices[0].message.content.strip()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 78 |
|
| 79 |
+
chat_history.append({"role": "assistant", "content": reply})
|
| 80 |
+
chat_display.append([message, reply])
|
| 81 |
|
| 82 |
return chat_history, chat_display, "", code
|
| 83 |
|
| 84 |
|
| 85 |
+
def speech_to_text(audio):
|
| 86 |
+
assert STT_TYPE in ["OPENAI_API", "HF_API"]
|
| 87 |
+
|
| 88 |
+
if STT_TYPE == "OPENAI_API":
|
| 89 |
+
data = ("temp.wav", numpy_audio_to_bytes(audio[1]), "audio/wav")
|
| 90 |
+
client = OpenAI(base_url=STT_URL, api_key=os.getenv(f"{STT_TYPE}_KEY"))
|
| 91 |
+
transcription = client.audio.transcriptions.create(model=STT_NAME, file=data, response_format="text")
|
| 92 |
+
elif STT_TYPE == "HF_API":
|
| 93 |
+
headers = {"Authorization": "Bearer " + os.getenv(f"{STT_TYPE}_KEY")}
|
| 94 |
+
transcription = requests.post(STT_URL, headers=headers, data=numpy_audio_to_bytes(audio[1]))
|
| 95 |
+
transcription = transcription.json()["text"]
|
| 96 |
+
|
| 97 |
return transcription
|
| 98 |
|
| 99 |
|
| 100 |
+
def text_to_speech(text):
|
| 101 |
+
assert TTS_TYPE in ["OPENAI_API", "HF_API"]
|
| 102 |
+
|
| 103 |
+
if TTS_TYPE == "OPENAI_API":
|
| 104 |
+
client = OpenAI(base_url=TTS_URL, api_key=os.getenv(f"{TTS_TYPE}_KEY"))
|
| 105 |
+
response = client.audio.speech.create(model=TTS_NAME, voice="alloy", input=text)
|
| 106 |
+
elif TTS_TYPE == "HF_API":
|
| 107 |
+
headers = {"Authorization": "Bearer " + os.getenv(f"{STT_TYPE}_KEY")}
|
| 108 |
+
response = requests.post(TTS_URL, headers=headers)
|
| 109 |
+
|
| 110 |
+
audio = response.content
|
| 111 |
+
return audio
|
| 112 |
|
| 113 |
|
| 114 |
def read_last_message(chat_display):
|
| 115 |
last_message = chat_display[-1][1]
|
| 116 |
+
if last_message is not None:
|
| 117 |
+
audio = text_to_speech(last_message)
|
| 118 |
+
return audio
|
| 119 |
+
return None
|
prompts.py
CHANGED
|
@@ -14,10 +14,6 @@ coding_interviewer_prompt = (
|
|
| 14 |
"If the candidate deviates from the problem, gently guide them back to focus on the task at hand. "
|
| 15 |
"After multiple unsuccessful attempts by the candidate to identify or fix an error, provide more direct hints or rephrase the problem slightly to aid understanding. "
|
| 16 |
"Encourage the candidate to think about real-world applications and scalability of their solutions, asking how changes to the problem parameters might affect their approach. "
|
| 17 |
-
"Responses should be structured in JSON format with two fields: "
|
| 18 |
-
"1. 'reply_to_candidate': contains visible feedback and guidance for the candidate, structured to facilitate learning and insight without giving away answers. "
|
| 19 |
-
"2. 'hidden_note': internal notes for the grading AI, including observations on the candidate’s performance across various criteria such as problem-solving skills, debugging effectiveness, and adaptability. These notes may include specific code snippets the candidate struggled with, key mistakes made, and any notable strengths or weaknesses observed. "
|
| 20 |
-
"The 'hidden_note' should also reflect a self-critical perspective if the interviewer's expectations do not align with a valid candidate solution, acknowledging and adjusting for any potential bias or error. "
|
| 21 |
)
|
| 22 |
|
| 23 |
|
|
|
|
| 14 |
"If the candidate deviates from the problem, gently guide them back to focus on the task at hand. "
|
| 15 |
"After multiple unsuccessful attempts by the candidate to identify or fix an error, provide more direct hints or rephrase the problem slightly to aid understanding. "
|
| 16 |
"Encourage the candidate to think about real-world applications and scalability of their solutions, asking how changes to the problem parameters might affect their approach. "
|
|
|
|
|
|
|
|
|
|
|
|
|
| 17 |
)
|
| 18 |
|
| 19 |
|