Spaces:
Sleeping
Refactor chainlit_frontend.py to streamline message processing and integrate new agent states
Browse files- Reduce recursion limit in tutor_chain.stream to improve performance
- Simplify message processing logic by removing conditional checks for end state and directly processing agent states
- Implement direct handling for QAAgent, QuizAgent, and FlashcardsAgent with specific actions for each agent type
- Update flashcards creation flow to use a dynamic path stored in agent state, enhancing flexibility
- Replace langchain.pydantic_v1 import with pydantic in tools.py for BaseModel and Field, aligning with updated dependencies
- Add explicit directory creation for flashcard files to ensure path validity
- Introduce debug prints across chainlit_frontend.py, tools.py, and graph.py for better traceability of the processing flow
- Adjust states.py to replace flashcard_filename with flashcard_path, reflecting the new method of handling flashcard file paths
- notebook_tutor/chainlit_frontend.py +23 -32
- notebook_tutor/graph.py +4 -1
- notebook_tutor/states.py +1 -1
- notebook_tutor/tools.py +4 -2
@@ -78,52 +78,43 @@ async def main(message: cl.Message):
|
|
78 |
print("\033[93m" + f"Initial state: {state}" + "\033[0m")
|
79 |
|
80 |
# Process the message through the LangGraph chain
|
81 |
-
for s in tutor_chain.stream(state, {"recursion_limit":
|
82 |
print("\033[93m" + f"State after processing: {s}" + "\033[0m")
|
83 |
|
84 |
-
|
85 |
-
|
86 |
-
agent_state = next(iter(s.values()))
|
87 |
-
if "messages" in agent_state:
|
88 |
-
response = agent_state["messages"][-1].content
|
89 |
-
print("\033[93m" + f"Response: {response}" + "\033[0m")
|
90 |
-
await cl.Message(content=response).send()
|
91 |
-
else:
|
92 |
-
print("Error: No messages found in agent state.")
|
93 |
-
else:
|
94 |
-
# Extract the final state
|
95 |
-
final_state = next(iter(s.values()))
|
96 |
-
print("\033[93m" + f"Final state: {final_state}" + "\033[0m")
|
97 |
-
|
98 |
-
# Check if the quiz was created and send it to the frontend
|
99 |
-
if final_state.get("quiz_created"):
|
100 |
-
quiz_message = final_state["messages"][-1].content
|
101 |
-
await cl.Message(content=quiz_message).send()
|
102 |
|
103 |
-
|
104 |
-
if
|
105 |
-
|
|
|
106 |
await cl.Message(content=qa_message).send()
|
107 |
|
108 |
-
|
109 |
-
if
|
110 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
111 |
await cl.Message(content=flashcards_message).send()
|
112 |
|
113 |
-
|
114 |
-
flashcard_filename = final_state["flashcard_filename"]
|
115 |
-
print("\033[93m" + f"Flashcard filename: {flashcard_filename}" + "\033[0m")
|
116 |
-
flashcard_path = os.path.join(".files", flashcard_filename)
|
117 |
print("\033[93m" + f"Flashcard path: {flashcard_path}" + "\033[0m")
|
118 |
|
|
|
119 |
# Use the File class to send the file
|
120 |
-
file_element = cl.File(name=
|
121 |
print("\033[93m" + f"Sending flashcards file: {file_element}" + "\033[0m")
|
122 |
await cl.Message(
|
123 |
content="Here are your flashcards:",
|
124 |
elements=[file_element]
|
125 |
).send()
|
126 |
|
127 |
-
|
|
|
128 |
|
129 |
-
|
|
|
78 |
print("\033[93m" + f"Initial state: {state}" + "\033[0m")
|
79 |
|
80 |
# Process the message through the LangGraph chain
|
81 |
+
for s in tutor_chain.stream(state, {"recursion_limit": 3}):
|
82 |
print("\033[93m" + f"State after processing: {s}" + "\033[0m")
|
83 |
|
84 |
+
agent_state = next(iter(s.values()))
|
85 |
+
print("\033[93m" + f"Agent state: {agent_state}" + "\033[0m")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
86 |
|
87 |
+
if "QAAgent" in s:
|
88 |
+
if s['QAAgent']['question_answered']:
|
89 |
+
print("\033[93m" + "************************Question answered**********************." + "\033[0m")
|
90 |
+
qa_message = agent_state["messages"][-1].content
|
91 |
await cl.Message(content=qa_message).send()
|
92 |
|
93 |
+
if "QuizAgent" in s:
|
94 |
+
if s['QuizAgent']['quiz_created']:
|
95 |
+
print("\033[93m" + "************************Quiz created**********************." + "\033[0m")
|
96 |
+
quiz_message = agent_state["messages"][-1].content
|
97 |
+
await cl.Message(content=quiz_message).send()
|
98 |
+
|
99 |
+
if "FlashcardsAgent" in s:
|
100 |
+
if s['FlashcardsAgent']['flashcards_created']:
|
101 |
+
print("\033[93m" + "************************Flashcards created**********************." + "\033[0m")
|
102 |
+
flashcards_message = agent_state["messages"][-1].content
|
103 |
await cl.Message(content=flashcards_message).send()
|
104 |
|
105 |
+
flashcard_path = agent_state["flashcard_path"]
|
|
|
|
|
|
|
106 |
print("\033[93m" + f"Flashcard path: {flashcard_path}" + "\033[0m")
|
107 |
|
108 |
+
|
109 |
# Use the File class to send the file
|
110 |
+
file_element = cl.File(name="Flashcards", path=flashcard_path)
|
111 |
print("\033[93m" + f"Sending flashcards file: {file_element}" + "\033[0m")
|
112 |
await cl.Message(
|
113 |
content="Here are your flashcards:",
|
114 |
elements=[file_element]
|
115 |
).send()
|
116 |
|
117 |
+
final_state = s # Save the final state after processing
|
118 |
+
print("\033[93m" + f"Final state: {final_state}" + "\033[0m")
|
119 |
|
120 |
+
print("\033[93m" + "Reached END state." + "\033[0m")
|
@@ -69,6 +69,8 @@ def agent_node(state, agent, name):
|
|
69 |
raise ValueError(f"No messages found in agent state: {result}")
|
70 |
new_state = {"messages": state["messages"] + [AIMessage(content=result["output"], name=name)]}
|
71 |
|
|
|
|
|
72 |
# Set the appropriate flags and next state
|
73 |
if name == "QuizAgent":
|
74 |
new_state["quiz_created"] = True
|
@@ -76,7 +78,8 @@ def agent_node(state, agent, name):
|
|
76 |
new_state["question_answered"] = True
|
77 |
elif name == "FlashcardsAgent":
|
78 |
new_state["flashcards_created"] = True
|
79 |
-
|
|
|
80 |
|
81 |
new_state["next"] = "FINISH"
|
82 |
return new_state
|
|
|
69 |
raise ValueError(f"No messages found in agent state: {result}")
|
70 |
new_state = {"messages": state["messages"] + [AIMessage(content=result["output"], name=name)]}
|
71 |
|
72 |
+
print("\033[93m" + f"agent_node function state {state}" + "\033[0m")
|
73 |
+
|
74 |
# Set the appropriate flags and next state
|
75 |
if name == "QuizAgent":
|
76 |
new_state["quiz_created"] = True
|
|
|
78 |
new_state["question_answered"] = True
|
79 |
elif name == "FlashcardsAgent":
|
80 |
new_state["flashcards_created"] = True
|
81 |
+
print("\033[93m" + f"agent_node function result_output {result}" + "\033[0m")
|
82 |
+
# new_state["flashcard_path"] = result["output"]
|
83 |
|
84 |
new_state["next"] = "FINISH"
|
85 |
return new_state
|
@@ -9,4 +9,4 @@ class TutorState(TypedDict):
|
|
9 |
quiz_created: bool
|
10 |
question_answered: bool
|
11 |
flashcards_created: bool
|
12 |
-
|
|
|
9 |
quiz_created: bool
|
10 |
question_answered: bool
|
11 |
flashcards_created: bool
|
12 |
+
flashcard_path: str
|
@@ -1,5 +1,5 @@
|
|
1 |
from typing import Optional, Type
|
2 |
-
from
|
3 |
from langchain.tools import BaseTool
|
4 |
from langchain.callbacks.manager import (
|
5 |
AsyncCallbackManagerForToolRun,
|
@@ -23,7 +23,9 @@ class FlashcardTool(BaseTool):
|
|
23 |
"""Use the tool to create flashcards."""
|
24 |
filename = f"flashcards_{uuid.uuid4()}.csv"
|
25 |
save_path = os.path.join('.files', filename)
|
26 |
-
|
|
|
|
|
27 |
with open(save_path, 'w', newline='') as csvfile:
|
28 |
fieldnames = ['Front', 'Back']
|
29 |
writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
|
|
|
1 |
from typing import Optional, Type
|
2 |
+
from pydantic import BaseModel, Field
|
3 |
from langchain.tools import BaseTool
|
4 |
from langchain.callbacks.manager import (
|
5 |
AsyncCallbackManagerForToolRun,
|
|
|
23 |
"""Use the tool to create flashcards."""
|
24 |
filename = f"flashcards_{uuid.uuid4()}.csv"
|
25 |
save_path = os.path.join('.files', filename)
|
26 |
+
print("\033[91m" + f"Saving flashcards to {save_path}" + "\033[0m")
|
27 |
+
|
28 |
+
os.makedirs(os.path.dirname(save_path), exist_ok=True) # Create directory if it doesn't exist
|
29 |
with open(save_path, 'w', newline='') as csvfile:
|
30 |
fieldnames = ['Front', 'Back']
|
31 |
writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
|