IliaLarchenko commited on
Commit
c62e737
1 Parent(s): fb73ff7

Added support of the HuggingFace models

Browse files
Files changed (3) hide show
  1. config.py +21 -11
  2. llm.py +36 -26
  3. prompts.py +0 -4
config.py CHANGED
@@ -1,18 +1,28 @@
1
- LLM_URL = f"https://api.openai.com/v1"
2
- LLM_KEY_TYPE = "OPENAI_API_KEY" # there should be an environment variable with this name
 
 
 
 
 
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 = f"https://api.openai.com/v1"
8
- STT_KEY_TYPE = "OPENAI_API_KEY" # there should be an environment variable with this name
9
  STT_NAME = "whisper-1"
10
- # "whisper-1" - the only OpenAI STT model available
11
-
 
 
12
 
13
- TTS_URL = f"https://api.openai.com/v1"
14
- TTS_KEY_TYPE = "OPENAI_API_KEY" # there should be an environment variable with this name
15
  TTS_NAME = "tts-1"
16
- # Recommended options
17
- # "tts-1" - good quality and close to real-time response. Just use this one
18
- # "tts-1-hd" - slightly better quality with slightly longer response time
 
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 LLM_KEY_TYPE, LLM_NAME, LLM_URL, STT_KEY_TYPE, STT_NAME, STT_URL, TTS_KEY_TYPE, TTS_NAME, TTS_URL
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(LLM_KEY_TYPE))
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, response_format={"type": "json_object"}, messages=chat_history)
77
-
78
- json_reply = response.choices[0].message.content.strip()
79
 
80
- try:
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": json_reply})
88
- chat_display.append([message, str(reply)])
89
 
90
  return chat_history, chat_display, "", code
91
 
92
 
93
- def speech_to_text(audio, client=client_STT):
94
- transcription = client.audio.transcriptions.create(
95
- model=STT_NAME, file=("temp.wav", numpy_audio_to_bytes(audio[1]), "audio/wav"), response_format="text"
96
- )
 
 
 
 
 
 
 
 
97
  return transcription
98
 
99
 
100
- def text_to_speech(text, client=client_TTS):
101
- response = client.audio.speech.create(model=TTS_NAME, voice="alloy", input=text)
102
- return response.content
 
 
 
 
 
 
 
 
 
103
 
104
 
105
  def read_last_message(chat_display):
106
  last_message = chat_display[-1][1]
107
-
108
- audio = text_to_speech(last_message)
109
- return audio
 
 
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