IliaLarchenko commited on
Commit
e4558ca
·
1 Parent(s): 33e4d0e

Streaming by default LLM

Browse files
Files changed (1) hide show
  1. api/llm.py +73 -78
api/llm.py CHANGED
@@ -10,18 +10,27 @@ class PromptManager:
10
  self.limit = os.getenv("DEMO_WORD_LIMIT")
11
 
12
  def add_limit(self, prompt: str) -> str:
 
 
 
13
  if self.limit:
14
  prompt += f" Keep your responses very short and simple, no more than {self.limit} words."
15
  return prompt
16
 
17
  def get_system_prompt(self, key: str) -> str:
 
 
 
18
  prompt = self.prompts[key]
19
  return self.add_limit(prompt)
20
 
21
  def get_problem_requirements_prompt(
22
  self, type: str, difficulty: Optional[str] = None, topic: Optional[str] = None, requirements: Optional[str] = None
23
  ) -> str:
24
- prompt = f"Create a {type} problem. Difficulty: {difficulty}. Topic: {topic} Additional requirements: {requirements}. "
 
 
 
25
  return self.add_limit(prompt)
26
 
27
 
@@ -31,72 +40,63 @@ class LLMManager:
31
  self.client = OpenAI(base_url=config.llm.url, api_key=config.llm.key)
32
  self.prompt_manager = PromptManager(prompts)
33
 
34
- self.status = self.test_llm()
35
- self.streaming = self.test_llm_stream() if self.status else False
36
 
37
- if self.streaming:
38
- self.end_interview = self.end_interview_stream
39
- self.get_problem = self.get_problem_stream
40
- self.send_request = self.send_request_stream
41
- else:
42
- self.end_interview = self.end_interview_full
43
- self.get_problem = self.get_problem_full
44
- self.send_request = self.send_request_full
45
-
46
- def get_text(self, messages: List[Dict[str, str]]) -> str:
47
  try:
48
- response = self.client.chat.completions.create(model=self.config.llm.name, messages=messages, temperature=1, max_tokens=2000)
49
- if not response.choices:
50
- raise APIError("LLM Get Text Error", details="No choices in response")
51
- return response.choices[0].message.content.strip()
 
 
 
 
 
 
 
 
 
 
52
  except Exception as e:
53
  raise APIError(f"LLM Get Text Error: Unexpected error: {e}")
54
 
55
- def get_text_stream(self, messages: List[Dict[str, str]]) -> Generator[str, None, None]:
 
 
 
56
  try:
57
- response = self.client.chat.completions.create(
58
- model=self.config.llm.name, messages=messages, temperature=1, stream=True, max_tokens=2000
 
 
 
 
 
 
 
59
  )
60
- except Exception as e:
61
- raise APIError(f"LLM End Interview Error: Unexpected error: {e}")
62
- text = ""
63
- for chunk in response:
64
- if chunk.choices[0].delta.content:
65
- text += chunk.choices[0].delta.content
66
- yield text
67
-
68
- def test_llm(self) -> bool:
69
- try:
70
- self.get_text(
71
- [
72
- {"role": "system", "content": "You just help me test the connection."},
73
- {"role": "user", "content": "Hi!"},
74
- {"role": "user", "content": "Ping!"},
75
- ]
76
- )
77
- return True
78
- except:
79
- return False
80
-
81
- def test_llm_stream(self) -> bool:
82
- try:
83
- for _ in self.get_text_stream(
84
- [
85
- {"role": "system", "content": "You just help me test the connection."},
86
- {"role": "user", "content": "Hi!"},
87
- {"role": "user", "content": "Ping!"},
88
- ]
89
- ):
90
- pass
91
  return True
92
  except:
93
  return False
94
 
95
  def init_bot(self, problem: str, interview_type: str = "coding") -> List[Dict[str, str]]:
 
 
 
96
  system_prompt = self.prompt_manager.get_system_prompt(f"{interview_type}_interviewer_prompt")
97
  return [{"role": "system", "content": f"{system_prompt}\nThe candidate is solving the following problem:\n {problem}"}]
98
 
99
  def get_problem_prepare_messages(self, requirements: str, difficulty: str, topic: str, interview_type: str) -> List[Dict[str, str]]:
 
 
 
100
  system_prompt = self.prompt_manager.get_system_prompt(f"{interview_type}_problem_generation_prompt")
101
  full_prompt = self.prompt_manager.get_problem_requirements_prompt(interview_type, difficulty, topic, requirements)
102
  return [
@@ -104,41 +104,35 @@ class LLMManager:
104
  {"role": "user", "content": full_prompt},
105
  ]
106
 
107
- def get_problem_full(self, requirements: str, difficulty: str, topic: str, interview_type: str = "coding") -> str:
108
- messages = self.get_problem_prepare_messages(requirements, difficulty, topic, interview_type)
109
- return self.get_text(messages)
110
-
111
- def get_problem_stream(
112
- self, requirements: str, difficulty: str, topic: str, interview_type: str = "coding"
113
- ) -> Generator[str, None, None]:
114
  messages = self.get_problem_prepare_messages(requirements, difficulty, topic, interview_type)
115
- yield from self.get_text_stream(messages)
116
 
117
  def update_chat_history(
118
  self, code: str, previous_code: str, chat_history: List[Dict[str, str]], chat_display: List[List[Optional[str]]]
119
  ) -> List[Dict[str, str]]:
 
 
 
120
  message = chat_display[-1][0]
121
  if code != previous_code:
122
  message += "\nMY NOTES AND CODE:\n" + code
123
  chat_history.append({"role": "user", "content": message})
124
  return chat_history
125
 
126
- def send_request_full(
127
- self, code: str, previous_code: str, chat_history: List[Dict[str, str]], chat_display: List[List[Optional[str]]]
128
- ) -> Tuple[List[Dict[str, str]], List[List[Optional[str]]], str]:
129
- chat_history = self.update_chat_history(code, previous_code, chat_history, chat_display)
130
- reply = self.get_text(chat_history)
131
- chat_display.append([None, reply.split("#NOTES#")[0].strip()])
132
- chat_history.append({"role": "assistant", "content": reply})
133
- return chat_history, chat_display, code
134
-
135
- def send_request_stream(
136
  self, code: str, previous_code: str, chat_history: List[Dict[str, str]], chat_display: List[List[Optional[str]]]
137
  ) -> Generator[Tuple[List[Dict[str, str]], List[List[Optional[str]]], str], None, None]:
 
 
 
138
  chat_history = self.update_chat_history(code, previous_code, chat_history, chat_display)
139
  chat_display.append([None, ""])
140
  chat_history.append({"role": "assistant", "content": ""})
141
- reply = self.get_text_stream(chat_history)
142
  for message in reply:
143
  chat_display[-1][1] = message.split("#NOTES#")[0].strip()
144
  chat_history[-1]["content"] = message
@@ -147,6 +141,9 @@ class LLMManager:
147
  def end_interview_prepare_messages(
148
  self, problem_description: str, chat_history: List[Dict[str, str]], interview_type: str
149
  ) -> List[Dict[str, str]]:
 
 
 
150
  transcript = [f"{message['role'].capitalize()}: {message['content']}" for message in chat_history[1:]]
151
  system_prompt = self.prompt_manager.get_system_prompt(f"{interview_type}_grading_feedback_prompt")
152
  return [
@@ -156,16 +153,14 @@ class LLMManager:
156
  {"role": "user", "content": "Grade the interview based on the transcript provided and give feedback."},
157
  ]
158
 
159
- def end_interview_full(self, problem_description: str, chat_history: List[Dict[str, str]], interview_type: str = "coding") -> str:
160
- if len(chat_history) <= 2:
161
- return "No interview history available"
162
- messages = self.end_interview_prepare_messages(problem_description, chat_history, interview_type)
163
- return self.get_text(messages)
164
-
165
- def end_interview_stream(
166
  self, problem_description: str, chat_history: List[Dict[str, str]], interview_type: str = "coding"
167
  ) -> Generator[str, None, None]:
 
 
 
168
  if len(chat_history) <= 2:
169
  yield "No interview history available"
 
170
  messages = self.end_interview_prepare_messages(problem_description, chat_history, interview_type)
171
- yield from self.get_text_stream(messages)
 
10
  self.limit = os.getenv("DEMO_WORD_LIMIT")
11
 
12
  def add_limit(self, prompt: str) -> str:
13
+ """
14
+ Add word limit to the prompt if specified in the environment variables.
15
+ """
16
  if self.limit:
17
  prompt += f" Keep your responses very short and simple, no more than {self.limit} words."
18
  return prompt
19
 
20
  def get_system_prompt(self, key: str) -> str:
21
+ """
22
+ Retrieve and limit a system prompt by its key.
23
+ """
24
  prompt = self.prompts[key]
25
  return self.add_limit(prompt)
26
 
27
  def get_problem_requirements_prompt(
28
  self, type: str, difficulty: Optional[str] = None, topic: Optional[str] = None, requirements: Optional[str] = None
29
  ) -> str:
30
+ """
31
+ Create a problem requirements prompt with optional parameters.
32
+ """
33
+ prompt = f"Create a {type} problem. Difficulty: {difficulty}. Topic: {topic}. Additional requirements: {requirements}."
34
  return self.add_limit(prompt)
35
 
36
 
 
40
  self.client = OpenAI(base_url=config.llm.url, api_key=config.llm.key)
41
  self.prompt_manager = PromptManager(prompts)
42
 
43
+ self.status = self.test_llm(stream=False)
44
+ self.streaming = self.test_llm(stream=True) if self.status else False
45
 
46
+ def get_text(self, messages: List[Dict[str, str]], stream: Optional[bool] = None) -> Generator[str, None, None]:
47
+ """
48
+ Generate text from the LLM, optionally streaming the response.
49
+ """
50
+ if stream is None:
51
+ stream = self.streaming
 
 
 
 
52
  try:
53
+ if not stream:
54
+ response = self.client.chat.completions.create(
55
+ model=self.config.llm.name, messages=messages, temperature=1, max_tokens=2000
56
+ )
57
+ yield response.choices[0].message.content.strip()
58
+ else:
59
+ response = self.client.chat.completions.create(
60
+ model=self.config.llm.name, messages=messages, temperature=1, stream=True, max_tokens=2000
61
+ )
62
+ text = ""
63
+ for chunk in response:
64
+ if chunk.choices[0].delta.content:
65
+ text += chunk.choices[0].delta.content
66
+ yield text
67
  except Exception as e:
68
  raise APIError(f"LLM Get Text Error: Unexpected error: {e}")
69
 
70
+ def test_llm(self, stream=False) -> bool:
71
+ """
72
+ Test the LLM connection with or without streaming.
73
+ """
74
  try:
75
+ list(
76
+ self.get_text(
77
+ [
78
+ {"role": "system", "content": "You just help me test the connection."},
79
+ {"role": "user", "content": "Hi!"},
80
+ {"role": "user", "content": "Ping!"},
81
+ ],
82
+ stream=stream,
83
+ )
84
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
85
  return True
86
  except:
87
  return False
88
 
89
  def init_bot(self, problem: str, interview_type: str = "coding") -> List[Dict[str, str]]:
90
+ """
91
+ Initialize the bot with a system prompt and problem description.
92
+ """
93
  system_prompt = self.prompt_manager.get_system_prompt(f"{interview_type}_interviewer_prompt")
94
  return [{"role": "system", "content": f"{system_prompt}\nThe candidate is solving the following problem:\n {problem}"}]
95
 
96
  def get_problem_prepare_messages(self, requirements: str, difficulty: str, topic: str, interview_type: str) -> List[Dict[str, str]]:
97
+ """
98
+ Prepare messages for generating a problem based on given requirements.
99
+ """
100
  system_prompt = self.prompt_manager.get_system_prompt(f"{interview_type}_problem_generation_prompt")
101
  full_prompt = self.prompt_manager.get_problem_requirements_prompt(interview_type, difficulty, topic, requirements)
102
  return [
 
104
  {"role": "user", "content": full_prompt},
105
  ]
106
 
107
+ def get_problem(self, requirements: str, difficulty: str, topic: str, interview_type: str) -> Generator[str, None, None]:
108
+ """
109
+ Get a problem from the LLM based on the given requirements, difficulty, and topic.
110
+ """
 
 
 
111
  messages = self.get_problem_prepare_messages(requirements, difficulty, topic, interview_type)
112
+ yield from self.get_text(messages)
113
 
114
  def update_chat_history(
115
  self, code: str, previous_code: str, chat_history: List[Dict[str, str]], chat_display: List[List[Optional[str]]]
116
  ) -> List[Dict[str, str]]:
117
+ """
118
+ Update chat history with the latest user message and code.
119
+ """
120
  message = chat_display[-1][0]
121
  if code != previous_code:
122
  message += "\nMY NOTES AND CODE:\n" + code
123
  chat_history.append({"role": "user", "content": message})
124
  return chat_history
125
 
126
+ def send_request(
 
 
 
 
 
 
 
 
 
127
  self, code: str, previous_code: str, chat_history: List[Dict[str, str]], chat_display: List[List[Optional[str]]]
128
  ) -> Generator[Tuple[List[Dict[str, str]], List[List[Optional[str]]], str], None, None]:
129
+ """
130
+ Send a request to the LLM and update the chat display.
131
+ """
132
  chat_history = self.update_chat_history(code, previous_code, chat_history, chat_display)
133
  chat_display.append([None, ""])
134
  chat_history.append({"role": "assistant", "content": ""})
135
+ reply = self.get_text(chat_history)
136
  for message in reply:
137
  chat_display[-1][1] = message.split("#NOTES#")[0].strip()
138
  chat_history[-1]["content"] = message
 
141
  def end_interview_prepare_messages(
142
  self, problem_description: str, chat_history: List[Dict[str, str]], interview_type: str
143
  ) -> List[Dict[str, str]]:
144
+ """
145
+ Prepare messages to end the interview and generate feedback.
146
+ """
147
  transcript = [f"{message['role'].capitalize()}: {message['content']}" for message in chat_history[1:]]
148
  system_prompt = self.prompt_manager.get_system_prompt(f"{interview_type}_grading_feedback_prompt")
149
  return [
 
153
  {"role": "user", "content": "Grade the interview based on the transcript provided and give feedback."},
154
  ]
155
 
156
+ def end_interview(
 
 
 
 
 
 
157
  self, problem_description: str, chat_history: List[Dict[str, str]], interview_type: str = "coding"
158
  ) -> Generator[str, None, None]:
159
+ """
160
+ End the interview and get feedback from the LLM.
161
+ """
162
  if len(chat_history) <= 2:
163
  yield "No interview history available"
164
+ return
165
  messages = self.end_interview_prepare_messages(problem_description, chat_history, interview_type)
166
+ yield from self.get_text(messages)