kamaleswar Mohanta commited on
Commit
90dcfc0
·
1 Parent(s): bc8572b

still working on display part: Refactor LoadStreamlitUI to enhance graph diagram creation and update session recursion limit:

Browse files
src/langgraphagenticai/__pycache__/main.cpython-312.pyc CHANGED
Binary files a/src/langgraphagenticai/__pycache__/main.cpython-312.pyc and b/src/langgraphagenticai/__pycache__/main.cpython-312.pyc differ
 
src/langgraphagenticai/graph/__pycache__/graph_builder.cpython-312.pyc CHANGED
Binary files a/src/langgraphagenticai/graph/__pycache__/graph_builder.cpython-312.pyc and b/src/langgraphagenticai/graph/__pycache__/graph_builder.cpython-312.pyc differ
 
src/langgraphagenticai/graph/graph_builder.py CHANGED
@@ -4,11 +4,13 @@ from src.langgraphagenticai.nodes.blog_generation_node import BlogGenerationNode
4
  from src.langgraphagenticai.nodes.basic_chatbot_node import BasicChatbotNode
5
  from src.langgraphagenticai.nodes.chatbot_with_Tool_node import ChatbotWithToolNode
6
  from src.langgraphagenticai.tools.search_tool import get_tools, create_tool_nodes
7
- from langgraph.prebuilt import tools_condition,ToolNode
8
  from src.langgraphagenticai.state.state import State
9
  from langgraph.checkpoint.memory import MemorySaver
10
  from pydantic import BaseModel, Field
 
11
  import logging
 
12
 
13
  logger = logging.getLogger(__name__)
14
 
@@ -21,6 +23,84 @@ class GraphBuilder:
21
  self.llm = llm
22
  self.memory = MemorySaver()
23
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
24
  def basic_chatbot_build_graph(self):
25
  """
26
  Builds a graph for the Basic Chatbot use case.
@@ -38,10 +118,9 @@ class GraphBuilder:
38
  """
39
  graph_builder = StateGraph(state_schema=State)
40
 
41
- ## Define the tool and tool node
42
-
43
- tools=get_tools()
44
- tool_node=create_tool_nodes(tools)
45
 
46
  # Define chatbot node
47
  chatbot_with_tool_node = ChatbotWithToolNode(self.llm)
@@ -51,35 +130,28 @@ class GraphBuilder:
51
  graph_builder.add_node("tools", tool_node)
52
 
53
  graph_builder.add_edge(START, "chatbot")
54
- graph_builder.add_conditional_edges("chatbot",tools_condition,)
55
  graph_builder.add_edge("tools", "chatbot")
56
  return graph_builder.compile(checkpointer=self.memory)
57
 
58
  def blog_generation_build_graph(self):
59
  """
60
- Builds a graph for the Blog Generation use case with button-based feedback.
61
  """
62
  try:
63
  if not self.llm:
64
  raise ValueError("LLM model not initialized")
65
 
66
- # Add structure validation helper
67
- def validate_and_standardize_structure(structure: str) -> list:
68
- if not structure or structure.strip() == "":
69
- return ["Introduction", "Main Content", "Conclusion"]
70
- sections = [s.strip().capitalize() for s in structure.split(",")]
71
- if len(sections) < 1:
72
- return ["Introduction", "Main Content", "Conclusion"]
73
- return sections
74
-
75
  graph_builder = StateGraph(state_schema=State)
76
  blog_node = BlogGenerationNode(self.llm)
77
 
78
- # Modify user_input node to include structure validation
79
  def user_input_with_validation(state: State) -> dict:
80
- result = blog_node.user_input(state)
81
- raw_structure = result.get("structure", "")
82
- result["structure"] = ", ".join(validate_and_standardize_structure(raw_structure))
 
 
83
  logger.info(f"Validated structure: {result['structure']}")
84
  return result
85
 
 
4
  from src.langgraphagenticai.nodes.basic_chatbot_node import BasicChatbotNode
5
  from src.langgraphagenticai.nodes.chatbot_with_Tool_node import ChatbotWithToolNode
6
  from src.langgraphagenticai.tools.search_tool import get_tools, create_tool_nodes
7
+ from langgraph.prebuilt import tools_condition, ToolNode
8
  from src.langgraphagenticai.state.state import State
9
  from langgraph.checkpoint.memory import MemorySaver
10
  from pydantic import BaseModel, Field
11
+ from langchain_core.messages import SystemMessage, HumanMessage
12
  import logging
13
+ import json
14
 
15
  logger = logging.getLogger(__name__)
16
 
 
23
  self.llm = llm
24
  self.memory = MemorySaver()
25
 
26
+ def validate_and_standardize_structure(self, user_input: str) -> list:
27
+ """
28
+ Uses an LLM to interpret user input and generate a standardized list of blog section names.
29
+ Ensures the user's specified structure is respected if provided.
30
+
31
+ Args:
32
+ user_input (str): The full user input from the Streamlit form (e.g., "Topic: AI\nStructure: Intro, Benefits, Summary").
33
+
34
+ Returns:
35
+ List[str]: A list of standardized section names (e.g., ["Intro", "Benefits", "Summary"]).
36
+ """
37
+ # Default structure if all else fails
38
+ default_structure = ["Introduction", "Main Content", "Conclusion"]
39
+
40
+ # If input is empty or whitespace-only, return default
41
+ if not user_input or not user_input.strip():
42
+ logger.info("Empty or whitespace-only input; returning default structure")
43
+ return default_structure
44
+
45
+ # Extract the user's structure if provided
46
+ user_structure = None
47
+ for line in user_input.split("\n"):
48
+ if line.lower().startswith("structure:"):
49
+ user_structure = line.split(":", 1)[1].strip()
50
+ break
51
+
52
+ # Define the prompt for the LLM
53
+ system_prompt = (
54
+ "You are an expert blog planner. Your task is to analyze the user's input and extract or infer a clear, concise structure "
55
+ "for a blog post as a list of section names. The input may explicitly list sections (e.g., 'Structure: Intro, Benefits, Summary') "
56
+ "or describe them implicitly (e.g., 'I want an intro, some benefits, and a conclusion'). "
57
+ "If the user provides a 'Structure' field (e.g., 'Structure: Intro, Benefits, Summary'), you MUST use those exact section names "
58
+ "without modification, except for capitalizing the first letter of each section. "
59
+ "If no structure is provided or it's unclear, propose a logical default structure based on the topic or context. "
60
+ "Return the result as a JSON object with a single key 'sections' containing the list of section names. "
61
+ "Capitalize each section name and avoid adding unnecessary sections beyond what’s indicated."
62
+ )
63
+
64
+ # Prepare messages for the LLM
65
+ messages = [
66
+ SystemMessage(content=system_prompt),
67
+ HumanMessage(content=f"User input: {user_input}")
68
+ ]
69
+
70
+ try:
71
+ # Invoke the LLM and expect a JSON response
72
+ response = self.llm.invoke(messages)
73
+ response_content = response.content if hasattr(response, "content") else str(response)
74
+ logger.info(f"LLM response for structure: {response_content}")
75
+
76
+ # Parse the JSON response
77
+ result = json.loads(response_content)
78
+ sections = result.get("sections", default_structure)
79
+
80
+ # Validate and standardize the output
81
+ if not isinstance(sections, list) or not sections:
82
+ logger.warning("LLM returned invalid sections; using default structure")
83
+ return default_structure
84
+
85
+ # Clean up section names: strip whitespace, capitalize, remove empty strings
86
+ cleaned_sections = [s.strip().capitalize() for s in sections if s.strip()]
87
+
88
+ # If user provided a structure, enforce it
89
+ if user_structure:
90
+ user_sections = [s.strip().capitalize() for s in user_structure.split(",") if s.strip()]
91
+ if len(cleaned_sections) == len(user_sections):
92
+ # Override LLM sections with user sections if lengths match
93
+ cleaned_sections = user_sections
94
+ else:
95
+ logger.warning(f"LLM section count ({len(cleaned_sections)}) doesn't match user section count ({len(user_sections)}); using user structure")
96
+ cleaned_sections = user_sections
97
+
98
+ return cleaned_sections if cleaned_sections else default_structure
99
+
100
+ except Exception as e:
101
+ logger.error(f"Error in LLM structure generation: {e}")
102
+ return default_structure
103
+
104
  def basic_chatbot_build_graph(self):
105
  """
106
  Builds a graph for the Basic Chatbot use case.
 
118
  """
119
  graph_builder = StateGraph(state_schema=State)
120
 
121
+ # Define the tool and tool node
122
+ tools = get_tools()
123
+ tool_node = create_tool_nodes(tools)
 
124
 
125
  # Define chatbot node
126
  chatbot_with_tool_node = ChatbotWithToolNode(self.llm)
 
130
  graph_builder.add_node("tools", tool_node)
131
 
132
  graph_builder.add_edge(START, "chatbot")
133
+ graph_builder.add_conditional_edges("chatbot", tools_condition)
134
  graph_builder.add_edge("tools", "chatbot")
135
  return graph_builder.compile(checkpointer=self.memory)
136
 
137
  def blog_generation_build_graph(self):
138
  """
139
+ Builds a graph for the Blog Generation use case with button-based feedback and LLM-driven structure generation.
140
  """
141
  try:
142
  if not self.llm:
143
  raise ValueError("LLM model not initialized")
144
 
 
 
 
 
 
 
 
 
 
145
  graph_builder = StateGraph(state_schema=State)
146
  blog_node = BlogGenerationNode(self.llm)
147
 
148
+ # Modify user_input node to use LLM for structure
149
  def user_input_with_validation(state: State) -> dict:
150
+ user_message = state["messages"][-1].content if state["messages"] else ""
151
+ result = blog_node.user_input(state) # Initial parsing
152
+ # Use LLM to interpret full user input for structure
153
+ full_input = user_message # Use raw message for maximum context
154
+ result["structure"] = ", ".join(self.validate_and_standardize_structure(full_input))
155
  logger.info(f"Validated structure: {result['structure']}")
156
  return result
157
 
src/langgraphagenticai/main.py CHANGED
@@ -71,7 +71,7 @@ def load_langgraph_agenticai_app():
71
  if "current_usecase" not in st.session_state:
72
  st.session_state.current_usecase = None
73
 
74
- config = {"configurable": {"session_id": st.session_state.session_id, "thread_id": st.session_state.thread_id, "recursion_limit": 50}}
75
  logger.info(f"Session ID: {st.session_state.session_id}, Thread ID: {st.session_state.thread_id}")
76
 
77
  # Load LLM
 
71
  if "current_usecase" not in st.session_state:
72
  st.session_state.current_usecase = None
73
 
74
+ config = {"configurable": {"session_id": st.session_state.session_id, "thread_id": st.session_state.thread_id, "recursion_limit": 10}}
75
  logger.info(f"Session ID: {st.session_state.session_id}, Thread ID: {st.session_state.thread_id}")
76
 
77
  # Load LLM
src/langgraphagenticai/nodes/__pycache__/chatbot_with_Tool_node.cpython-312.pyc CHANGED
Binary files a/src/langgraphagenticai/nodes/__pycache__/chatbot_with_Tool_node.cpython-312.pyc and b/src/langgraphagenticai/nodes/__pycache__/chatbot_with_Tool_node.cpython-312.pyc differ
 
src/langgraphagenticai/tools/__pycache__/search_tool.cpython-312.pyc CHANGED
Binary files a/src/langgraphagenticai/tools/__pycache__/search_tool.cpython-312.pyc and b/src/langgraphagenticai/tools/__pycache__/search_tool.cpython-312.pyc differ
 
src/langgraphagenticai/tools/search_tool.py CHANGED
@@ -20,6 +20,9 @@ def get_tools(max_results=3):
20
  return []
21
 
22
  def create_tool_nodes(tools):
 
 
 
23
  try:
24
  if not tools:
25
  st.error("Error: No tools provided")
 
20
  return []
21
 
22
  def create_tool_nodes(tools):
23
+ """
24
+ Creates tool nodes based on the provided tools.
25
+ """
26
  try:
27
  if not tools:
28
  st.error("Error: No tools provided")
src/langgraphagenticai/ui/streamlitui/__pycache__/display_result.cpython-312.pyc CHANGED
Binary files a/src/langgraphagenticai/ui/streamlitui/__pycache__/display_result.cpython-312.pyc and b/src/langgraphagenticai/ui/streamlitui/__pycache__/display_result.cpython-312.pyc differ
 
src/langgraphagenticai/ui/streamlitui/__pycache__/loadui.cpython-312.pyc CHANGED
Binary files a/src/langgraphagenticai/ui/streamlitui/__pycache__/loadui.cpython-312.pyc and b/src/langgraphagenticai/ui/streamlitui/__pycache__/loadui.cpython-312.pyc differ
 
src/langgraphagenticai/ui/streamlitui/display_result.py CHANGED
@@ -1,5 +1,8 @@
1
  import streamlit as st
2
  from langchain_core.messages import HumanMessage, AIMessage
 
 
 
3
 
4
  class DisplayResultStreamlit:
5
  def __init__(self, graph, with_message_history, config, usecase):
@@ -7,14 +10,35 @@ class DisplayResultStreamlit:
7
  self.with_message_history = with_message_history
8
  self.config = config
9
  self.usecase = usecase
 
 
10
  self.session_history = self._get_session_history()
11
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12
  def _get_session_history(self):
13
  from langchain_community.chat_message_histories import ChatMessageHistory
14
  store = {}
15
  session_id = self.config["configurable"]["session_id"]
16
  if session_id not in store:
17
  store[session_id] = ChatMessageHistory()
 
 
 
 
 
18
  return store[session_id]
19
 
20
  def display_chat_history(self):
@@ -32,6 +56,13 @@ class DisplayResultStreamlit:
32
  self._handle_chatbot_input()
33
 
34
  def _handle_blog_generation(self):
 
 
 
 
 
 
 
35
  if st.session_state.waiting_for_feedback:
36
  self._process_feedback()
37
  elif not st.session_state.blog_requirements_collected:
@@ -64,11 +95,22 @@ class DisplayResultStreamlit:
64
  self.session_history.add_user_message(user_message)
65
  with st.chat_message("user"):
66
  st.markdown(user_message)
 
 
 
67
  st.session_state.blog_requirements_collected = True
68
  self._process_graph_stream(HumanMessage(content=user_message))
69
 
70
  def _process_feedback(self):
71
  latest_state = st.session_state.graph_state.values if st.session_state.graph_state else {}
 
 
 
 
 
 
 
 
72
  if "completed_sections" in latest_state and not st.session_state.get("draft_displayed", False):
73
  with st.chat_message("assistant"):
74
  draft_content = "\n\n".join(latest_state["completed_sections"])
@@ -77,6 +119,7 @@ class DisplayResultStreamlit:
77
  st.session_state.draft_displayed = True
78
 
79
  current_node = st.session_state.graph_state.next[0] if st.session_state.graph_state.next else None
 
80
  if current_node == "outline_review":
81
  st.write("Review the outline:")
82
  col1, col2 = st.columns(2)
@@ -84,10 +127,12 @@ class DisplayResultStreamlit:
84
  if st.button("Looks good", key="outline_approve"):
85
  st.session_state.outline_feedback = "approved"
86
  st.session_state.waiting_for_feedback = False
 
87
  with col2:
88
  if st.button("Add more details", key="outline_reject"):
89
  st.session_state.outline_feedback = "add_more_details"
90
  st.session_state.waiting_for_feedback = False
 
91
  elif current_node == "draft_review":
92
  st.write("Review the draft:")
93
  col1, col2 = st.columns(2)
@@ -96,11 +141,13 @@ class DisplayResultStreamlit:
96
  st.session_state.draft_feedback = "approved"
97
  st.session_state.waiting_for_feedback = False
98
  st.session_state.draft_displayed = False
 
99
  with col2:
100
  if st.button("Add more details", key="draft_reject"):
101
  st.session_state.draft_feedback = "add_more_details"
102
  st.session_state.waiting_for_feedback = False
103
  st.session_state.draft_displayed = False
 
104
 
105
  if not st.session_state.waiting_for_feedback:
106
  self._process_graph_stream()
@@ -115,35 +162,42 @@ class DisplayResultStreamlit:
115
 
116
  def _process_graph_stream(self, input_message=None):
117
  with st.spinner("Processing..."):
118
- input_data = {"messages": [input_message]} if input_message else None
119
- for event in (self.graph.stream(input_data, self.config) if input_data else self.graph.stream(None, self.config)):
120
- for node, state in event.items():
121
- if "messages" in state and state["messages"]:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
122
  with st.chat_message("assistant"):
123
- self._display_result(state)
124
- self.session_history.add_ai_message(state["messages"][-1].content)
125
- graph_state = self.graph.get_state(self.config)
126
- if graph_state.next and graph_state.next[0] in ["outline_review", "draft_review"]:
127
- st.session_state.waiting_for_feedback = True
128
- st.session_state.graph_state = graph_state
129
- break
130
- elif not graph_state.next and self.usecase == "Blog Generation":
131
- st.session_state.blog_requirements_collected = False
132
- with st.chat_message("assistant"):
133
- st.markdown("✅ Blog generation completed!")
134
- if st.button("New Blog Generation"):
135
- self.session_history.clear()
136
- st.session_state.graph_state = None
137
- st.session_state.waiting_for_feedback = False
138
- st.rerun()
139
 
140
  def _display_result(self, response):
 
141
  if self.usecase == "Blog Generation":
142
- if "sections" in response and not st.session_state.get("outline_displayed", False):
143
- outline_text = "### Generated Outline\n\n" + "\n\n".join(f"**{s['name']}**: {s['description']}" for s in response["sections"])
144
- st.markdown(outline_text)
145
- st.markdown("Please review the outline above.")
146
- st.session_state.outline_displayed = True
147
  messages = response.get("messages", [])
148
  if messages:
149
  content = messages[-1].content
 
1
  import streamlit as st
2
  from langchain_core.messages import HumanMessage, AIMessage
3
+ import logging
4
+
5
+ logger = logging.getLogger(__name__)
6
 
7
  class DisplayResultStreamlit:
8
  def __init__(self, graph, with_message_history, config, usecase):
 
10
  self.with_message_history = with_message_history
11
  self.config = config
12
  self.usecase = usecase
13
+ # Initialize session state defaults
14
+ self._initialize_session_state()
15
  self.session_history = self._get_session_history()
16
 
17
+ def _initialize_session_state(self):
18
+ """Initialize all session state variables."""
19
+ defaults = {
20
+ "waiting_for_feedback": False,
21
+ "blog_requirements_collected": False,
22
+ "outline_displayed": False,
23
+ "draft_displayed": False,
24
+ "graph_state": None,
25
+ "current_session_id": None
26
+ }
27
+ for key, value in defaults.items():
28
+ if key not in st.session_state:
29
+ st.session_state[key] = value
30
+
31
  def _get_session_history(self):
32
  from langchain_community.chat_message_histories import ChatMessageHistory
33
  store = {}
34
  session_id = self.config["configurable"]["session_id"]
35
  if session_id not in store:
36
  store[session_id] = ChatMessageHistory()
37
+ # Reset display flags if session ID changes
38
+ if st.session_state.current_session_id != session_id:
39
+ st.session_state.outline_displayed = False
40
+ st.session_state.draft_displayed = False
41
+ st.session_state.current_session_id = session_id
42
  return store[session_id]
43
 
44
  def display_chat_history(self):
 
56
  self._handle_chatbot_input()
57
 
58
  def _handle_blog_generation(self):
59
+ # Fallback: Check graph state if waiting_for_feedback isn't set
60
+ if not st.session_state.waiting_for_feedback and st.session_state.graph_state:
61
+ graph_state = st.session_state.graph_state
62
+ if graph_state.next and graph_state.next[0] in ["outline_review", "draft_review"]:
63
+ logger.info("Fallback: Setting waiting_for_feedback based on graph state")
64
+ st.session_state.waiting_for_feedback = True
65
+
66
  if st.session_state.waiting_for_feedback:
67
  self._process_feedback()
68
  elif not st.session_state.blog_requirements_collected:
 
95
  self.session_history.add_user_message(user_message)
96
  with st.chat_message("user"):
97
  st.markdown(user_message)
98
+ # Reset display flags for new blog generation
99
+ st.session_state.outline_displayed = False
100
+ st.session_state.draft_displayed = False
101
  st.session_state.blog_requirements_collected = True
102
  self._process_graph_stream(HumanMessage(content=user_message))
103
 
104
  def _process_feedback(self):
105
  latest_state = st.session_state.graph_state.values if st.session_state.graph_state else {}
106
+ # Display the outline if it hasn't been displayed yet
107
+ if "sections" in latest_state and not st.session_state.get("outline_displayed", False):
108
+ with st.chat_message("assistant"):
109
+ outline_text = "### Generated Outline\n\n" + "\n\n".join(f"**{s['name']}**: {s['description']}" for s in latest_state["sections"])
110
+ st.markdown(outline_text)
111
+ st.markdown("Please review the outline above.")
112
+ st.session_state.outline_displayed = True
113
+
114
  if "completed_sections" in latest_state and not st.session_state.get("draft_displayed", False):
115
  with st.chat_message("assistant"):
116
  draft_content = "\n\n".join(latest_state["completed_sections"])
 
119
  st.session_state.draft_displayed = True
120
 
121
  current_node = st.session_state.graph_state.next[0] if st.session_state.graph_state.next else None
122
+ logger.info(f"Current node in _process_feedback: {current_node}")
123
  if current_node == "outline_review":
124
  st.write("Review the outline:")
125
  col1, col2 = st.columns(2)
 
127
  if st.button("Looks good", key="outline_approve"):
128
  st.session_state.outline_feedback = "approved"
129
  st.session_state.waiting_for_feedback = False
130
+ logger.info("Outline approved")
131
  with col2:
132
  if st.button("Add more details", key="outline_reject"):
133
  st.session_state.outline_feedback = "add_more_details"
134
  st.session_state.waiting_for_feedback = False
135
+ logger.info("Outline regeneration requested")
136
  elif current_node == "draft_review":
137
  st.write("Review the draft:")
138
  col1, col2 = st.columns(2)
 
141
  st.session_state.draft_feedback = "approved"
142
  st.session_state.waiting_for_feedback = False
143
  st.session_state.draft_displayed = False
144
+ logger.info("Draft approved")
145
  with col2:
146
  if st.button("Add more details", key="draft_reject"):
147
  st.session_state.draft_feedback = "add_more_details"
148
  st.session_state.waiting_for_feedback = False
149
  st.session_state.draft_displayed = False
150
+ logger.info("Draft regeneration requested")
151
 
152
  if not st.session_state.waiting_for_feedback:
153
  self._process_graph_stream()
 
162
 
163
  def _process_graph_stream(self, input_message=None):
164
  with st.spinner("Processing..."):
165
+ try:
166
+ input_data = {"messages": [input_message]} if input_message else None
167
+ for event in (self.graph.stream(input_data, self.config) if input_data else self.graph.stream(None, self.config)):
168
+ logger.info(f"Graph event: {event}")
169
+ for node, state in event.items():
170
+ if "messages" in state and state["messages"]:
171
+ with st.chat_message("assistant"):
172
+ self._display_result(state)
173
+ self.session_history.add_ai_message(state["messages"][-1].content)
174
+ graph_state = self.graph.get_state(self.config)
175
+ logger.info(f"Graph state next: {graph_state.next}")
176
+ if graph_state.next and graph_state.next[0] in ["outline_review", "draft_review"]:
177
+ st.session_state.waiting_for_feedback = True
178
+ st.session_state.graph_state = graph_state
179
+ logger.info(f"Paused at {graph_state.next[0]} for feedback")
180
+ st.rerun() # Force UI update to ensure feedback buttons appear
181
+ break
182
+ elif not graph_state.next and self.usecase == "Blog Generation":
183
+ st.session_state.blog_requirements_collected = False
184
+ st.session_state.outline_displayed = False # Reset for new blog
185
+ st.session_state.draft_displayed = False # Reset for new blog
186
  with st.chat_message("assistant"):
187
+ st.markdown("✅ Blog generation completed!")
188
+ if st.button("New Blog Generation"):
189
+ self.session_history.clear()
190
+ st.session_state.graph_state = None
191
+ st.session_state.waiting_for_feedback = False
192
+ st.rerun()
193
+ except Exception as e:
194
+ logger.error(f"Error in graph streaming: {e}")
195
+ st.error(f"Error processing workflow: {e}")
 
 
 
 
 
 
 
196
 
197
  def _display_result(self, response):
198
+ logger.info(f"Display result response: {response}")
199
  if self.usecase == "Blog Generation":
200
+ # Outline display moved to _process_feedback
 
 
 
 
201
  messages = response.get("messages", [])
202
  if messages:
203
  content = messages[-1].content
src/langgraphagenticai/ui/streamlitui/loadui.py CHANGED
@@ -24,41 +24,64 @@ class LoadStreamlitUI:
24
  }
25
 
26
  def create_graph_diagram(self, usecase):
27
- """Create a graph diagram for the selected use case using GraphBuilder."""
28
  dot = graphviz.Digraph(comment=f"{usecase} Graph", format="png")
 
29
 
30
- # Define graph structure based on use case
31
  if usecase == "Basic Chatbot":
 
32
  dot.node("START", "START")
33
  dot.node("chatbot", "Chatbot")
34
  dot.node("END", "END")
35
- dot.edges([("START", "chatbot"), ("chatbot", "END")])
 
 
 
36
  elif usecase == "Chatbot with Tool":
 
37
  dot.node("START", "START")
38
  dot.node("chatbot", "Chatbot")
39
  dot.node("tools", "Tools")
40
  dot.node("END", "END")
41
- dot.edges([("START", "chatbot"), ("chatbot", "tools"), ("tools", "chatbot")])
42
- dot.edge("chatbot", "chatbot", label="conditional", style="dashed")
 
 
 
 
43
  elif usecase == "Blog Generation":
 
44
  dot.node("START", "START")
45
- dot.node("orchestrator", "Orchestrator")
46
- dot.node("llm_call", "LLM Call (Workers)")
47
- dot.node("synthesizer", "Synthesizer")
 
 
 
 
48
  dot.node("END", "END")
49
- dot.edges([
50
- ("START", "orchestrator"),
51
- ("llm_call", "synthesizer"),
52
- ("synthesizer", "END"),
53
-
54
- ])
55
- dot.edge("orchestrator", "llm_call", label="parallel", style="dashed")
56
- dot.edge("llm_call", "synthesizer", label="parallel", style="dashed")
57
- elif usecase == "Coding Peer Review":
 
 
 
 
 
 
 
 
 
58
  dot.node("START", "START")
59
- dot.node("reviewer", "Reviewer")
60
  dot.node("END", "END")
61
- dot.edges([("START", "reviewer"), ("reviewer", "END")])
62
 
63
  return dot
64
 
 
24
  }
25
 
26
  def create_graph_diagram(self, usecase):
27
+ """Create a graph diagram for the selected use case based on GraphBuilder's structure."""
28
  dot = graphviz.Digraph(comment=f"{usecase} Graph", format="png")
29
+ dot.attr(rankdir="TB") # Top-to-bottom layout for clarity
30
 
 
31
  if usecase == "Basic Chatbot":
32
+ # Nodes
33
  dot.node("START", "START")
34
  dot.node("chatbot", "Chatbot")
35
  dot.node("END", "END")
36
+ # Edges
37
+ dot.edge("START", "chatbot")
38
+ dot.edge("chatbot", "END")
39
+
40
  elif usecase == "Chatbot with Tool":
41
+ # Nodes
42
  dot.node("START", "START")
43
  dot.node("chatbot", "Chatbot")
44
  dot.node("tools", "Tools")
45
  dot.node("END", "END")
46
+ # Edges
47
+ dot.edge("START", "chatbot")
48
+ dot.edge("chatbot", "tools", label="tools_condition", style="dashed", constraint="false")
49
+ dot.edge("tools", "chatbot", label="return")
50
+ dot.edge("chatbot", "END", label="no tools", style="dashed", constraint="false")
51
+
52
  elif usecase == "Blog Generation":
53
+ # Nodes
54
  dot.node("START", "START")
55
+ dot.node("user_input", "User Input")
56
+ dot.node("outline_generator", "Outline Generator")
57
+ dot.node("outline_review", "Outline Review\n(Human)", shape="diamond")
58
+ dot.node("web_search", "Web Search")
59
+ dot.node("draft_generator", "Draft Generator")
60
+ dot.node("draft_review", "Draft Review\n(Human)", shape="diamond")
61
+ dot.node("revision_generator", "Revision Generator")
62
  dot.node("END", "END")
63
+ # Static Edges
64
+ dot.edge("START", "user_input")
65
+ dot.edge("user_input", "outline_generator")
66
+ dot.edge("outline_generator", "outline_review")
67
+ dot.edge("web_search", "draft_generator")
68
+ dot.edge("revision_generator", "draft_review")
69
+ # Conditional Edges for outline_review
70
+ dot.edge("outline_review", "draft_generator", label="approved", style="dashed", color="green")
71
+ dot.edge("outline_review", "outline_generator", label="add details", style="dashed", color="orange", constraint="false")
72
+ # Conditional Edges for draft_generator
73
+ dot.edge("draft_generator", "web_search", label="needs facts", style="dashed", color="blue")
74
+ dot.edge("draft_generator", "draft_review", label="has facts", style="dashed", color="green")
75
+ # Conditional Edges for draft_review
76
+ dot.edge("draft_review", "END", label="approved", style="dashed", color="green")
77
+ dot.edge("draft_review", "revision_generator", label="add details", style="dashed", color="orange", constraint="false")
78
+
79
+ # Note: Coding Peer Review not implemented in GraphBuilder, so skipping it
80
+ else:
81
  dot.node("START", "START")
82
+ dot.node("unknown", f"Unknown Use Case:\n{usecase}")
83
  dot.node("END", "END")
84
+ dot.edges([("START", "unknown"), ("unknown", "END")])
85
 
86
  return dot
87