helloparthshah commited on
Commit
980918c
·
1 Parent(s): 5d748e2

Fixed streaming

Browse files
Files changed (3) hide show
  1. mainV2.py +31 -28
  2. models/system3.prompt +1 -1
  3. src/manager.py +47 -42
mainV2.py CHANGED
@@ -11,48 +11,51 @@ if __name__ == "__main__":
11
 
12
  model_manager = GeminiManager(toolsLoader=tool_loader, gemini_model="gemini-2.0-flash")
13
 
14
- def respond(message, chat_history):
15
- return model_manager.ask(message, chat_history)
16
-
17
  def user_message(msg: str, history: list) -> tuple[str, list]:
18
  """Adds user message to chat history"""
19
  history.append(gr.ChatMessage(role="user", content=msg))
20
  return "", history
 
 
 
21
 
22
- with gr.Blocks() as demo:
 
 
 
 
 
 
 
 
 
 
 
23
  chatbot = gr.Chatbot(
24
  avatar_images=("HASHIRU_2.png", "HASHIRU.png"),
25
- type="messages"
 
 
 
26
  )
27
- input_box = gr.Textbox()
28
- clear = gr.ClearButton([input_box, chatbot])
29
-
30
- def respond(message, chat_history):
31
-
32
- chat_history.append({
33
- "role":"user",
34
- "content":message
35
- })
36
- print("Chat history:", chat_history)
37
- chat_history = model_manager.run(chat_history)
38
- return "", chat_history
39
-
40
- msg_store = gr.State("")
41
 
42
  input_box.submit(
43
- lambda msg: (msg, msg, ""), # Store message and clear input
44
- inputs=[input_box],
45
- outputs=[msg_store, input_box, input_box],
46
- queue=False
47
- ).then(
48
  user_message, # Add user message to chat
49
- inputs=[msg_store, chatbot],
50
  outputs=[input_box, chatbot],
51
- queue=False
52
  ).then(
53
  model_manager.run, # Generate and stream response
54
- inputs=[msg_store, chatbot],
55
- outputs=chatbot
 
 
56
  )
 
57
 
58
  demo.launch(share=True)
 
11
 
12
  model_manager = GeminiManager(toolsLoader=tool_loader, gemini_model="gemini-2.0-flash")
13
 
 
 
 
14
  def user_message(msg: str, history: list) -> tuple[str, list]:
15
  """Adds user message to chat history"""
16
  history.append(gr.ChatMessage(role="user", content=msg))
17
  return "", history
18
+
19
+ def handle_undo(history, undo_data: gr.UndoData):
20
+ return history[:undo_data.index], history[undo_data.index]['content']
21
 
22
+ def handle_retry(history, retry_data: gr.RetryData):
23
+ new_history = history[:retry_data.index]
24
+ yield from model_manager.run(new_history)
25
+
26
+ def handle_edit(history, edit_data: gr.EditData):
27
+ new_history = history[:edit_data.index]
28
+ new_history[-1]['content'] = edit_data.value
29
+ return new_history
30
+
31
+ with gr.Blocks(fill_width=True, fill_height=True) as demo:
32
+ gr.Markdown("# Hashiru AI")
33
+
34
  chatbot = gr.Chatbot(
35
  avatar_images=("HASHIRU_2.png", "HASHIRU.png"),
36
+ type="messages",
37
+ show_copy_button=True,
38
+ editable="user",
39
+ scale=1
40
  )
41
+ input_box = gr.Textbox(submit_btn=True, stop_btn=True, max_lines=5, label="Chat Message", scale=0)
42
+
43
+ chatbot.undo(handle_undo, chatbot, [chatbot, input_box])
44
+ chatbot.retry(handle_retry, chatbot, chatbot)
45
+ chatbot.edit(handle_edit, chatbot, chatbot)
 
 
 
 
 
 
 
 
 
46
 
47
  input_box.submit(
 
 
 
 
 
48
  user_message, # Add user message to chat
49
+ inputs=[input_box, chatbot],
50
  outputs=[input_box, chatbot],
51
+ queue=False,
52
  ).then(
53
  model_manager.run, # Generate and stream response
54
+ inputs=chatbot,
55
+ outputs=chatbot,
56
+ show_progress="full",
57
+ trigger_mode="always_last"
58
  )
59
+ input_box.submit(lambda: "", None, [input_box])
60
 
61
  demo.launch(share=True)
models/system3.prompt CHANGED
@@ -103,7 +103,7 @@ Strictly follow the schema required for invoking the tools and agents. Do not de
103
  </Rule>
104
 
105
  <Rule>
106
- Once you have the answer, provide it to the user in a clear and concise manner ending with a "EOF" message.
107
  </Rule>
108
 
109
  <Rule>
 
103
  </Rule>
104
 
105
  <Rule>
106
+ Once you have the answer, provide it to the user in a clear and concise manner.
107
  </Rule>
108
 
109
  <Rule>
src/manager.py CHANGED
@@ -16,6 +16,7 @@ handler = logging.StreamHandler(sys.stdout)
16
  # handler.setLevel(logging.DEBUG)
17
  logger.addHandler(handler)
18
 
 
19
  class GeminiManager:
20
  def __init__(self, toolsLoader: ToolLoader, system_prompt_file="./models/system3.prompt", gemini_model="gemini-2.5-pro-exp-03-25"):
21
  load_dotenv()
@@ -30,22 +31,24 @@ class GeminiManager:
30
 
31
  def generate_response(self, messages):
32
  return self.client.models.generate_content(
33
- model=self.model_name,
34
- contents=messages,
35
- config=types.GenerateContentConfig(
36
- system_instruction=self.system_prompt,
37
- temperature=0.2,
38
- tools=self.toolsLoader.getTools(),
39
- ),
40
- )
41
-
42
  def handle_tool_calls(self, response):
43
  parts = []
44
  for function_call in response.function_calls:
45
  toolResponse = None
46
- logger.info(f"Function Name: {function_call.name}, Arguments: {function_call.args}")
 
47
  try:
48
- toolResponse = self.toolsLoader.runTool(function_call.name, function_call.args)
 
49
  except Exception as e:
50
  logger.warning(f"Error running tool: {e}")
51
  toolResponse = {
@@ -55,53 +58,57 @@ class GeminiManager:
55
  }
56
  logger.debug(f"Tool Response: {toolResponse}")
57
  tool_content = types.Part.from_function_response(
58
- name=function_call.name,
59
- response = {"result":toolResponse})
60
  try:
61
  self.toolsLoader.load_tools()
62
  except Exception as e:
63
  logger.info(f"Error loading tools: {e}. Deleting the tool.")
64
  # delete the created tool
65
- self.toolsLoader.delete_tool(toolResponse['output']['tool_name'], toolResponse['output']['tool_file_path'])
 
66
  tool_content = types.Part.from_function_response(
67
- name=function_call.name,
68
- response={"result":f"{function_call.name} with {function_call.args} doesn't follow the required format, please read the other tool implementations for reference." + str(e)})
69
  parts.append(tool_content)
70
  return {
71
- "role": "tool",
72
- "content": repr(types.Content(
73
  role='model' if self.model_name == "gemini-2.5-pro-exp-03-25" else 'tool',
74
  parts=parts
75
- ))
76
- }
77
-
78
  def format_chat_history(self, messages=[]):
79
  formatted_history = []
80
  for message in messages:
81
  # Skip thinking messages (messages with metadata)
82
  if not (message.get("role") == "assistant" and "metadata" in message):
83
  role = "model"
84
- parts=[types.Part.from_text(text=message.get("content", ""))]
85
  match message.get("role"):
86
  case "user":
87
  role = "user"
88
  case "tool":
89
  role = "tool"
90
- formatted_history.append(eval(message.get("content", "")))
 
91
  continue
92
  case "function_call":
93
  role = "model"
94
- formatted_history.append(eval(message.get("content", "")))
 
95
  continue
96
  case _:
97
- role = "model"
98
  formatted_history.append(types.Content(
99
  role=role,
100
  parts=parts
101
  ))
102
  return formatted_history
103
-
104
- def run(self, message, messages):
 
105
  chat_history = self.format_chat_history(messages)
106
  logger.debug(f"Chat history: {chat_history}")
107
  try:
@@ -109,18 +116,19 @@ class GeminiManager:
109
  except Exception as e:
110
  logger.debug(f"Error generating response: {e}")
111
  messages.append({
112
- "role":"assistant",
113
- "content":f"Error generating response: {e}"
114
  })
115
  logger.error(f"Error generating response: {e}")
116
  return messages
117
  logger.debug(f"Response: {response}")
118
-
 
119
  if (not response.text and not response.function_calls):
120
  messages.append({
121
- "role":"assistant",
122
- "content":"No response from the model.",
123
- "metadata":{"title":"No response from the model."}
124
  })
125
 
126
  # Attach the llm response to the messages
@@ -130,22 +138,19 @@ class GeminiManager:
130
  "content": response.text
131
  })
132
  yield messages
133
-
134
  # Attach the function call response to the messages
135
  if response.candidates[0].content and response.candidates[0].content.parts:
136
  # messages.append(response.candidates[0].content)
137
  messages.append({
138
- "role":"function_call",
139
  "content": repr(response.candidates[0].content),
140
  })
141
- yield messages
142
-
143
  # Invoke the function calls if any and attach the response to the messages
144
  if response.function_calls:
145
  calls = self.handle_tool_calls(response)
146
  messages.append(calls)
147
- yield messages
148
- for value in self.run(message, messages):
149
- yield value
150
- return
151
- return messages
 
16
  # handler.setLevel(logging.DEBUG)
17
  logger.addHandler(handler)
18
 
19
+
20
  class GeminiManager:
21
  def __init__(self, toolsLoader: ToolLoader, system_prompt_file="./models/system3.prompt", gemini_model="gemini-2.5-pro-exp-03-25"):
22
  load_dotenv()
 
31
 
32
  def generate_response(self, messages):
33
  return self.client.models.generate_content(
34
+ model=self.model_name,
35
+ contents=messages,
36
+ config=types.GenerateContentConfig(
37
+ system_instruction=self.system_prompt,
38
+ temperature=0.2,
39
+ tools=self.toolsLoader.getTools(),
40
+ ),
41
+ )
42
+
43
  def handle_tool_calls(self, response):
44
  parts = []
45
  for function_call in response.function_calls:
46
  toolResponse = None
47
+ logger.info(
48
+ f"Function Name: {function_call.name}, Arguments: {function_call.args}")
49
  try:
50
+ toolResponse = self.toolsLoader.runTool(
51
+ function_call.name, function_call.args)
52
  except Exception as e:
53
  logger.warning(f"Error running tool: {e}")
54
  toolResponse = {
 
58
  }
59
  logger.debug(f"Tool Response: {toolResponse}")
60
  tool_content = types.Part.from_function_response(
61
+ name=function_call.name,
62
+ response={"result": toolResponse})
63
  try:
64
  self.toolsLoader.load_tools()
65
  except Exception as e:
66
  logger.info(f"Error loading tools: {e}. Deleting the tool.")
67
  # delete the created tool
68
+ self.toolsLoader.delete_tool(
69
+ toolResponse['output']['tool_name'], toolResponse['output']['tool_file_path'])
70
  tool_content = types.Part.from_function_response(
71
+ name=function_call.name,
72
+ response={"result": f"{function_call.name} with {function_call.args} doesn't follow the required format, please read the other tool implementations for reference." + str(e)})
73
  parts.append(tool_content)
74
  return {
75
+ "role": "tool",
76
+ "content": repr(types.Content(
77
  role='model' if self.model_name == "gemini-2.5-pro-exp-03-25" else 'tool',
78
  parts=parts
79
+ ))
80
+ }
81
+
82
  def format_chat_history(self, messages=[]):
83
  formatted_history = []
84
  for message in messages:
85
  # Skip thinking messages (messages with metadata)
86
  if not (message.get("role") == "assistant" and "metadata" in message):
87
  role = "model"
88
+ parts = [types.Part.from_text(text=message.get("content", ""))]
89
  match message.get("role"):
90
  case "user":
91
  role = "user"
92
  case "tool":
93
  role = "tool"
94
+ formatted_history.append(
95
+ eval(message.get("content", "")))
96
  continue
97
  case "function_call":
98
  role = "model"
99
+ formatted_history.append(
100
+ eval(message.get("content", "")))
101
  continue
102
  case _:
103
+ role = "model"
104
  formatted_history.append(types.Content(
105
  role=role,
106
  parts=parts
107
  ))
108
  return formatted_history
109
+
110
+ def run(self, messages):
111
+ print("Messages: ", messages)
112
  chat_history = self.format_chat_history(messages)
113
  logger.debug(f"Chat history: {chat_history}")
114
  try:
 
116
  except Exception as e:
117
  logger.debug(f"Error generating response: {e}")
118
  messages.append({
119
+ "role": "assistant",
120
+ "content": f"Error generating response: {e}"
121
  })
122
  logger.error(f"Error generating response: {e}")
123
  return messages
124
  logger.debug(f"Response: {response}")
125
+ print("Response: ", response)
126
+
127
  if (not response.text and not response.function_calls):
128
  messages.append({
129
+ "role": "assistant",
130
+ "content": "No response from the model.",
131
+ "metadata": {"title": "No response from the model."}
132
  })
133
 
134
  # Attach the llm response to the messages
 
138
  "content": response.text
139
  })
140
  yield messages
141
+
142
  # Attach the function call response to the messages
143
  if response.candidates[0].content and response.candidates[0].content.parts:
144
  # messages.append(response.candidates[0].content)
145
  messages.append({
146
+ "role": "function_call",
147
  "content": repr(response.candidates[0].content),
148
  })
149
+
 
150
  # Invoke the function calls if any and attach the response to the messages
151
  if response.function_calls:
152
  calls = self.handle_tool_calls(response)
153
  messages.append(calls)
154
+ yield from self.run(messages)
155
+ print("Final messages: ", messages)
156
+ return messages