simonguest commited on
Commit
f48e069
·
1 Parent(s): b353cf0

Initial rewrite of LangChain functionality

Browse files
Files changed (4) hide show
  1. app.py +35 -35
  2. prompts.py +8 -11
  3. test.py +9 -0
  4. tutor2.py +117 -0
app.py CHANGED
@@ -5,43 +5,42 @@ from io import StringIO
5
  from threading import Thread
6
  from urllib import parse
7
 
 
8
 
9
- from prompts import run_code_prompt, welcome_prompt
10
- from tutor import chat, create_llm_chain
11
- from gradio_callback import q, job_done
12
 
13
 
14
  def user(user_message, history):
15
  return "", history + [[user_message, None]]
16
 
17
 
18
- def code(editor, output, history):
19
- json_template = {"editor": editor, "output": output}
20
- print(json.dumps(json_template))
21
- return "", history + [[json.dumps(json_template), None]]
22
 
23
 
24
- def bot(history):
25
- user_message = history[-1][0]
26
- try: # Check to see if the user_message contains code
27
- json_template = json.loads(user_message)
28
- editor = json_template["editor"]
29
- output = json_template["output"]
30
- history[-1][0] = "Running your code..."
31
- yield history
32
- user_message = run_code_prompt(editor, output)
33
- except:
34
- pass
35
- history[-1][1] = ""
36
- thread = Thread(target=chat, kwargs={"user_message": user_message})
37
- thread.start()
38
- while True:
39
- next_token = q.get(block=True)
40
- if next_token is job_done:
41
- break
42
- history[-1][1] += next_token
43
- yield history
44
- thread.join()
45
 
46
 
47
  def run_code(code):
@@ -72,15 +71,16 @@ def load_level(request: gr.Request):
72
 
73
 
74
  with gr.Blocks() as demo:
 
75
  with gr.Row():
76
  instruction_panel = gr.Markdown()
77
  with gr.Row():
78
  with gr.Column(scale=1):
79
- chatbot = gr.Chatbot(label="AI Tutor", value=[[None, welcome_prompt()]])
80
  msg = gr.Textbox(show_label=False, placeholder="Type your message here...")
81
  msg.submit(
82
- user, [msg, chatbot], [msg, chatbot], queue=False, scroll_to_output=True
83
- ).then(bot, chatbot, chatbot)
84
  with gr.Column(scale=2):
85
  editor = gr.Code(
86
  value="Loading...",
@@ -102,12 +102,12 @@ with gr.Blocks() as demo:
102
  run.click(
103
  run_code, editor, output, queue=False, scroll_to_output=True
104
  ).then(
105
- code, [editor, output, chatbot], [msg, chatbot], queue=False
106
- ).then(
107
- bot, chatbot, chatbot
108
  )
109
  demo.load(load_level, None, [instruction_panel, editor], queue=False).then(
110
- create_llm_chain, [instruction_panel, editor]
 
 
111
  )
112
 
113
  demo.queue()
 
5
  from threading import Thread
6
  from urllib import parse
7
 
8
+ from tutor2 import load, chat, code, get_history
9
 
10
+ #rom prompts import run_code_prompt, welcome_prompt
11
+ #from tutor import chat, create_llm_chain
12
+ #from gradio_callback import q, job_done
13
 
14
 
15
  def user(user_message, history):
16
  return "", history + [[user_message, None]]
17
 
18
 
19
+ # def code(editor, output, history):
20
+ # json_template = {"editor": editor, "output": output}
21
+ # print(json.dumps(json_template))
22
+ # return "", history + [[json.dumps(json_template), None]]
23
 
24
 
25
+ def submit_chat(tutor, message):
26
+ # user_message = history[-1][0]
27
+ # history[-1][1] = ""
28
+ # print(tutor)
29
+ tutor = chat(tutor, message)
30
+ return [get_history(tutor), None]
31
+ # thread = Thread(target=chat, kwargs={"user_message": user_message})
32
+ # thread.start()
33
+ # while True:
34
+ # next_token = q.get(block=True)
35
+ # if next_token is job_done:
36
+ # break
37
+ # history[-1][1] += next_token
38
+ # yield history
39
+ # thread.join()
40
+
41
+ def submit_code(tutor, editor, output):
42
+ tutor = code(tutor, editor, output)
43
+ return get_history(tutor)
 
 
44
 
45
 
46
  def run_code(code):
 
71
 
72
 
73
  with gr.Blocks() as demo:
74
+ tutor = gr.State()
75
  with gr.Row():
76
  instruction_panel = gr.Markdown()
77
  with gr.Row():
78
  with gr.Column(scale=1):
79
+ chatbot = gr.Chatbot(label="AI Tutor", value=[])
80
  msg = gr.Textbox(show_label=False, placeholder="Type your message here...")
81
  msg.submit(
82
+ submit_chat, [tutor, msg], [chatbot, msg]
83
+ )
84
  with gr.Column(scale=2):
85
  editor = gr.Code(
86
  value="Loading...",
 
102
  run.click(
103
  run_code, editor, output, queue=False, scroll_to_output=True
104
  ).then(
105
+ submit_code, [tutor, editor, output], chatbot
 
 
106
  )
107
  demo.load(load_level, None, [instruction_panel, editor], queue=False).then(
108
+ load, [instruction_panel, editor], tutor
109
+ ).then(
110
+ get_history, tutor, chatbot
111
  )
112
 
113
  demo.queue()
prompts.py CHANGED
@@ -1,6 +1,3 @@
1
- from langchain import PromptTemplate
2
-
3
-
4
  def system_prompt(instructions, starter_code):
5
  template = f"""
6
  You are a computer science teacher helping a student learn computer science. You are friendly and want your students to succeed.
@@ -17,16 +14,12 @@ They will ask you for help. You may help them, but you must not give them the an
17
 
18
  Do not let the student deviate from the task at hand. If they ask you a question that is not related to the task at hand, you must redirect them to the task at hand.
19
 
20
- {{chat_history}}
21
- Student: {{student_input}}
22
- Teacher:"""
23
- return PromptTemplate(
24
- input_variables=["chat_history", "student_input"], template=template
25
- )
26
 
 
27
  def run_code_prompt(editor, output):
28
- return f"""
29
- I've written this code:
30
  ```
31
  {editor}
32
  ```
@@ -36,5 +29,9 @@ And it produces this output:
36
  ```
37
  """
38
 
 
 
 
 
39
  def welcome_prompt():
40
  return "Hi! I'm your AI-powered computer science tutor. Feel free to ask me any questions as you work on this level. I'll also try and provide help when you run your code."
 
 
 
 
1
  def system_prompt(instructions, starter_code):
2
  template = f"""
3
  You are a computer science teacher helping a student learn computer science. You are friendly and want your students to succeed.
 
14
 
15
  Do not let the student deviate from the task at hand. If they ask you a question that is not related to the task at hand, you must redirect them to the task at hand.
16
 
17
+ """
18
+ return template
 
 
 
 
19
 
20
+ CODE_HEADER = "I've written this code:"
21
  def run_code_prompt(editor, output):
22
+ return f"""{CODE_HEADER}
 
23
  ```
24
  {editor}
25
  ```
 
29
  ```
30
  """
31
 
32
+ def is_code_prompt(prompt):
33
+ if (prompt.startswith(CODE_HEADER)):
34
+ return True
35
+
36
  def welcome_prompt():
37
  return "Hi! I'm your AI-powered computer science tutor. Feel free to ask me any questions as you work on this level. I'll also try and provide help when you run your code."
test.py ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ from tutor2 import Tutor, STUDENT, TEACHER
2
+
3
+ tutor = Tutor("instructions", "print('hello world')")
4
+ #tutor.chat("hello")
5
+ #tutor.chat("How does a for loop work in Python?")
6
+ # tutor.chat("hi", role=TEACHER)
7
+ tutor.code("print('hello world')", "hello world")
8
+ # tutor.chat("not working", role=TEACHER)
9
+ print(tutor._memory_as_history())
tutor2.py ADDED
@@ -0,0 +1,117 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import openai
2
+ import os
3
+ from prompts import system_prompt, welcome_prompt, run_code_prompt, is_code_prompt
4
+
5
+ SYSTEM = "system"
6
+ TEACHER = "assistant"
7
+ STUDENT = "user"
8
+
9
+ def load(instructions, starter_code):
10
+ print("Loading tutor...")
11
+ return Tutor(instructions, starter_code).serialize()
12
+
13
+ def chat(serialized_tutor, message):
14
+ print("Chatting...")
15
+ tutor = Tutor()
16
+ tutor.deserialize(serialized_tutor)
17
+ tutor.chat(message)
18
+ return tutor.serialize()
19
+
20
+ def code(serialized_tutor, editor, output):
21
+ print("Submitting code...")
22
+ tutor = Tutor()
23
+ tutor.deserialize(serialized_tutor)
24
+ tutor.code(editor, output)
25
+ return tutor.serialize()
26
+
27
+ def get_history(serialized_tutor):
28
+ print("Getting history...")
29
+ tutor = Tutor()
30
+ tutor.deserialize(serialized_tutor)
31
+ return tutor._memory_as_history()
32
+
33
+
34
+ class Tutor:
35
+ def __init__(self, instructions="", starter_code="", debug=False):
36
+ self.memory = []
37
+ self.system_prompt = system_prompt(instructions, starter_code)
38
+ self.memory.append({SYSTEM: self.system_prompt})
39
+ self.memory.append({TEACHER: welcome_prompt()})
40
+ self.model = "gpt-4"
41
+ self.temperature = 0.0
42
+ self.api_key = os.getenv("OPENAI_API_KEY")
43
+ self.debug = debug
44
+
45
+ def serialize(self):
46
+ # Return memory as a dictionary
47
+ return {"memory": self.memory}
48
+
49
+ def deserialize(self, data):
50
+ # Make sure incoming data is a dictionary containing "memory"
51
+ if isinstance(data, dict) and "memory" in data:
52
+ self.memory = data["memory"]
53
+ else:
54
+ raise ValueError("Input must be a dictionary containing 'memory'")
55
+
56
+ def chat(self, message, role=STUDENT, request=True):
57
+ # Append incoming role and message to memory as a dictionary
58
+ self.memory.append({role: message})
59
+ # Make the call to OpenAI and append the response to memory
60
+ if request:
61
+ response = openai.ChatCompletion.create(
62
+ model=self.model,
63
+ api_key=self.api_key,
64
+ temperature=self.temperature,
65
+ messages=self._memory_as_openai_messages(),
66
+ )
67
+ self.memory.append({TEACHER: response.choices[0].message.content})
68
+
69
+ def code(self, editor, output, request=True):
70
+ # Run the code and append the output to memory
71
+ self.memory.append({STUDENT: run_code_prompt(editor, output)})
72
+ # Make the call to OpenAI and append the response to memory
73
+ if request:
74
+ response = openai.ChatCompletion.create(
75
+ model=self.model,
76
+ api_key=self.api_key,
77
+ temperature=self.temperature,
78
+ messages=self._memory_as_openai_messages(),
79
+ )
80
+ self.memory.append({TEACHER: response.choices[0].message.content})
81
+
82
+ def _memory_as_string(self):
83
+ # Convert memory to a formatted string
84
+ memory_string = ""
85
+ for entry in self.memory:
86
+ for role, message in entry.items():
87
+ memory_string += f"{role}: {message}\n"
88
+ return memory_string
89
+
90
+ def _memory_as_history(self):
91
+ # Convert memory to a list of message pairs
92
+ history = []
93
+ for i in range(0, len(self.memory), 2): # Step by 2, as we need pairs
94
+ # Get messages, ignoring role
95
+ if (i == 0):
96
+ message1 = None # Skip the system prompt
97
+ else:
98
+ message1 = list(self.memory[i].values())[0]
99
+ if message1 is not None and is_code_prompt(message1):
100
+ message1 = "Running your code..."
101
+ # If there's a next message, get it, else use an empty string
102
+ message2 = (
103
+ list(self.memory[i + 1].values())[0] if i + 1 < len(self.memory) else None
104
+ )
105
+ if message2 is not None and is_code_prompt(message2):
106
+ message2 = "Running your code..."
107
+ history.append([message1, message2])
108
+ return history
109
+
110
+ def _memory_as_openai_messages(self):
111
+ # Convert memory to a list of OpenAI style messages
112
+ messages = []
113
+ messages.append({"role": SYSTEM, "content": self.system_prompt})
114
+ for entry in self.memory:
115
+ for role, message in entry.items():
116
+ messages.append({"role": role, "content": message})
117
+ return messages