Spaces:
Build error
Build error
kamaleswar Mohanta commited on
Commit ·
f056e53
1
Parent(s): 006ec78
basic blog generation & code review added
Browse files- src/langgraphagenticai/graph/__pycache__/graph_builder.cpython-312.pyc +0 -0
- src/langgraphagenticai/graph/graph_builder.py +43 -0
- src/langgraphagenticai/nodes/__pycache__/blog_generation_node.cpython-312.pyc +0 -0
- src/langgraphagenticai/nodes/__pycache__/code_peer_review_node.cpython-312.pyc +0 -0
- src/langgraphagenticai/nodes/blog_generation_node.py +53 -0
- src/langgraphagenticai/nodes/code_peer_review_node.py +21 -0
- src/langgraphagenticai/state/__pycache__/state.cpython-312.pyc +0 -0
- src/langgraphagenticai/state/state.py +40 -5
- src/langgraphagenticai/ui/streamlitui/__pycache__/display_result.cpython-312.pyc +0 -0
- src/langgraphagenticai/ui/streamlitui/display_result.py +33 -1
- src/langgraphagenticai/ui/uiconfigfile.ini +2 -2
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
|
@@ -5,6 +5,8 @@ from src.langgraphagenticai.state.state import State
|
|
| 5 |
from src.langgraphagenticai.nodes.basic_chatbot_node import BasicChatbotNode
|
| 6 |
from src.langgraphagenticai.nodes.chatbot_with_Tool_node import ChatbotWithToolNode
|
| 7 |
from src.langgraphagenticai.tools.search_tool import get_tools, create_tool_nodes
|
|
|
|
|
|
|
| 8 |
|
| 9 |
class GraphBuilder:
|
| 10 |
|
|
@@ -52,6 +54,41 @@ class GraphBuilder:
|
|
| 52 |
self.graph_builder.add_edge(START,"chatbot")
|
| 53 |
self.graph_builder.add_conditional_edges("chatbot", tools_condition)
|
| 54 |
self.graph_builder.add_edge("tools","chatbot")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 55 |
|
| 56 |
def setup_graph(self,usecase: str):
|
| 57 |
"""
|
|
@@ -61,4 +98,10 @@ class GraphBuilder:
|
|
| 61 |
self.basic_chatbot_build_graph()
|
| 62 |
elif usecase == "Chatbot with Tool":
|
| 63 |
self.chatbot_with_tools_build_graph()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 64 |
return self.graph_builder.compile()
|
|
|
|
| 5 |
from src.langgraphagenticai.nodes.basic_chatbot_node import BasicChatbotNode
|
| 6 |
from src.langgraphagenticai.nodes.chatbot_with_Tool_node import ChatbotWithToolNode
|
| 7 |
from src.langgraphagenticai.tools.search_tool import get_tools, create_tool_nodes
|
| 8 |
+
from src.langgraphagenticai.nodes.blog_generation_node import BlogGenerationNode
|
| 9 |
+
from src.langgraphagenticai.nodes.code_peer_review_node import CodeReviewerNode
|
| 10 |
|
| 11 |
class GraphBuilder:
|
| 12 |
|
|
|
|
| 54 |
self.graph_builder.add_edge(START,"chatbot")
|
| 55 |
self.graph_builder.add_conditional_edges("chatbot", tools_condition)
|
| 56 |
self.graph_builder.add_edge("tools","chatbot")
|
| 57 |
+
def blog_generation_build_graph(self):
|
| 58 |
+
"""
|
| 59 |
+
Builds a blog generation graph.
|
| 60 |
+
Includes orchestrator, worker (llm_call), and synthesizer nodes.
|
| 61 |
+
"""
|
| 62 |
+
blog_node = BlogGenerationNode(self.llm)
|
| 63 |
+
|
| 64 |
+
# Add nodes
|
| 65 |
+
self.graph_builder.add_node("orchestrator", blog_node.orchestrator)
|
| 66 |
+
self.graph_builder.add_node("llm_call", blog_node.llm_call)
|
| 67 |
+
self.graph_builder.add_node("synthesizer", blog_node.synthesizer)
|
| 68 |
+
|
| 69 |
+
# Define edges
|
| 70 |
+
self.graph_builder.add_edge(START, "orchestrator")
|
| 71 |
+
self.graph_builder.add_conditional_edges(
|
| 72 |
+
"orchestrator",
|
| 73 |
+
blog_node.assign_workers,
|
| 74 |
+
{
|
| 75 |
+
"llm_call": "llm_call" # Maps to the worker node
|
| 76 |
+
}
|
| 77 |
+
)
|
| 78 |
+
self.graph_builder.add_edge("llm_call", "synthesizer")
|
| 79 |
+
self.graph_builder.add_edge("synthesizer", END)
|
| 80 |
+
|
| 81 |
+
def code_reviewer_build_graph(self):
|
| 82 |
+
"""
|
| 83 |
+
Builds a code reviewer graph.
|
| 84 |
+
Includes a single node to review code and output feedback.
|
| 85 |
+
"""
|
| 86 |
+
code_reviewer_node = CodeReviewerNode(self.llm)
|
| 87 |
+
self.graph_builder.add_node("reviewer", code_reviewer_node.review_code)
|
| 88 |
+
self.graph_builder.add_edge(START, "reviewer")
|
| 89 |
+
self.graph_builder.add_edge("reviewer", END)
|
| 90 |
+
|
| 91 |
+
|
| 92 |
|
| 93 |
def setup_graph(self,usecase: str):
|
| 94 |
"""
|
|
|
|
| 98 |
self.basic_chatbot_build_graph()
|
| 99 |
elif usecase == "Chatbot with Tool":
|
| 100 |
self.chatbot_with_tools_build_graph()
|
| 101 |
+
elif usecase == "Blog Generation":
|
| 102 |
+
self.blog_generation_build_graph()
|
| 103 |
+
elif usecase == "Coding Peer Review":
|
| 104 |
+
self.code_reviewer_build_graph()
|
| 105 |
+
else:
|
| 106 |
+
raise ValueError(f"Unknown use case: {usecase}")
|
| 107 |
return self.graph_builder.compile()
|
src/langgraphagenticai/nodes/__pycache__/blog_generation_node.cpython-312.pyc
ADDED
|
Binary file (3.54 kB). View file
|
|
|
src/langgraphagenticai/nodes/__pycache__/code_peer_review_node.cpython-312.pyc
ADDED
|
Binary file (1.36 kB). View file
|
|
|
src/langgraphagenticai/nodes/blog_generation_node.py
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# blog_generation_node.py
|
| 2 |
+
from src.langgraphagenticai.state.state import State, WorkerState, Section
|
| 3 |
+
from pydantic import BaseModel, Field
|
| 4 |
+
from typing import List
|
| 5 |
+
from langgraph.constants import Send
|
| 6 |
+
from langchain_core.messages import HumanMessage, SystemMessage
|
| 7 |
+
|
| 8 |
+
class Sections(BaseModel):
|
| 9 |
+
sections: List[Section] = Field(description="Sections of the report.")
|
| 10 |
+
|
| 11 |
+
class BlogGenerationNode:
|
| 12 |
+
def __init__(self, model):
|
| 13 |
+
# Planner uses structured output for sections
|
| 14 |
+
self.planner = model.with_structured_output(Sections)
|
| 15 |
+
# LLM for content generation does not use structured output
|
| 16 |
+
self.llm = model # Raw LLM for generating text
|
| 17 |
+
|
| 18 |
+
def orchestrator(self, state: State) -> dict:
|
| 19 |
+
"""Orchestrator that generates a plan for the report"""
|
| 20 |
+
report_sections = self.planner.invoke(
|
| 21 |
+
[
|
| 22 |
+
SystemMessage(content="Generate a plan for the report."),
|
| 23 |
+
HumanMessage(content=f"Here is the report topic: {state['topic']}"),
|
| 24 |
+
]
|
| 25 |
+
)
|
| 26 |
+
print("Report Sections:", report_sections)
|
| 27 |
+
return {"sections": report_sections.sections}
|
| 28 |
+
|
| 29 |
+
def llm_call(self, state: WorkerState) -> dict:
|
| 30 |
+
"""Worker writes a section of the report"""
|
| 31 |
+
section_content = self.llm.invoke(
|
| 32 |
+
[
|
| 33 |
+
SystemMessage(
|
| 34 |
+
content="Write a report section following the provided name and description. Include no preamble for each section. Use markdown formatting."
|
| 35 |
+
),
|
| 36 |
+
HumanMessage(
|
| 37 |
+
content=f"Here is the section name: {state['section'].name} and description: {state['section'].description}"
|
| 38 |
+
),
|
| 39 |
+
]
|
| 40 |
+
)
|
| 41 |
+
# Ensure we get the content as a string
|
| 42 |
+
content = section_content.content if hasattr(section_content, "content") else str(section_content)
|
| 43 |
+
return {"completed_sections": [content]}
|
| 44 |
+
|
| 45 |
+
def synthesizer(self, state: State) -> dict:
|
| 46 |
+
"""Synthesize full report from sections"""
|
| 47 |
+
completed_sections = state["completed_sections"]
|
| 48 |
+
completed_report_sections = "\n\n---\n\n".join(completed_sections)
|
| 49 |
+
return {"final_report": completed_report_sections}
|
| 50 |
+
|
| 51 |
+
def assign_workers(self, state: State) -> List[Send]:
|
| 52 |
+
"""Assign a worker to each section in the plan"""
|
| 53 |
+
return [Send("llm_call", {"section": s}) for s in state["sections"]]
|
src/langgraphagenticai/nodes/code_peer_review_node.py
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# code_reviewer_node.py
|
| 2 |
+
from src.langgraphagenticai.state.state import State
|
| 3 |
+
from langchain_core.messages import HumanMessage, SystemMessage
|
| 4 |
+
|
| 5 |
+
class CodeReviewerNode:
|
| 6 |
+
def __init__(self, model):
|
| 7 |
+
self.llm = model
|
| 8 |
+
|
| 9 |
+
def review_code(self, state: State) -> dict:
|
| 10 |
+
"""Review the provided code and return feedback"""
|
| 11 |
+
code = state["code_input"]
|
| 12 |
+
review = self.llm.invoke(
|
| 13 |
+
[
|
| 14 |
+
SystemMessage(content="Review the following code and provide feedback in markdown format."),
|
| 15 |
+
HumanMessage(content=code),
|
| 16 |
+
]
|
| 17 |
+
)
|
| 18 |
+
return {
|
| 19 |
+
"messages": [SystemMessage(content="Code review completed")],
|
| 20 |
+
"review_output": review.content
|
| 21 |
+
}
|
src/langgraphagenticai/state/__pycache__/state.cpython-312.pyc
CHANGED
|
Binary files a/src/langgraphagenticai/state/__pycache__/state.cpython-312.pyc and b/src/langgraphagenticai/state/__pycache__/state.cpython-312.pyc differ
|
|
|
src/langgraphagenticai/state/state.py
CHANGED
|
@@ -1,10 +1,45 @@
|
|
| 1 |
-
from typing import Annotated, Literal, Optional, List
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2 |
from typing_extensions import TypedDict
|
| 3 |
from langgraph.graph.message import add_messages
|
| 4 |
-
|
|
|
|
| 5 |
|
| 6 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 7 |
"""
|
| 8 |
-
Represents the structure of the state used in the graph
|
|
|
|
|
|
|
|
|
|
|
|
|
| 9 |
"""
|
| 10 |
-
messages: Annotated[
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# from typing import Annotated, Literal, Optional, List
|
| 2 |
+
# from typing_extensions import TypedDict
|
| 3 |
+
# from langgraph.graph.message import add_messages
|
| 4 |
+
# from langchain_core.messages import HumanMessage, AIMessage
|
| 5 |
+
|
| 6 |
+
# class State(TypedDict):
|
| 7 |
+
# """
|
| 8 |
+
# Represents the structure of the state used in the graph.
|
| 9 |
+
# """
|
| 10 |
+
# messages: Annotated[list,add_messages]
|
| 11 |
+
|
| 12 |
+
# state.py
|
| 13 |
+
from typing import Annotated, List, Optional
|
| 14 |
from typing_extensions import TypedDict
|
| 15 |
from langgraph.graph.message import add_messages
|
| 16 |
+
import operator
|
| 17 |
+
from pydantic import BaseModel, Field
|
| 18 |
|
| 19 |
+
# Schema for Blog Generation sections
|
| 20 |
+
class Section(BaseModel):
|
| 21 |
+
name: str = Field(description="Name for this section of the report.")
|
| 22 |
+
description: str = Field(description="Brief overview of the main topics and concepts to be covered in this section.")
|
| 23 |
+
|
| 24 |
+
# Unified State for all use cases
|
| 25 |
+
class State(TypedDict, total=False): # total=False makes all fields optional
|
| 26 |
"""
|
| 27 |
+
Represents the structure of the state used in the graph for multiple use cases:
|
| 28 |
+
- Chat Bot: messages
|
| 29 |
+
- Bot with Tool: messages, tool_output
|
| 30 |
+
- Blog Generation: messages, topic, sections, completed_sections, final_report
|
| 31 |
+
- Code Reviewer: messages, code_input, review_output
|
| 32 |
"""
|
| 33 |
+
messages: Annotated[List, add_messages] # Common to all: Chat history
|
| 34 |
+
topic: str # Blog Generation: Report topic
|
| 35 |
+
sections: List[Section] # Blog Generation: List of report sections
|
| 36 |
+
completed_sections: Annotated[List[str], operator.add] # Blog Generation: Completed sections
|
| 37 |
+
final_report: str # Blog Generation: Final report
|
| 38 |
+
tool_output: str # Bot with Tool: Output from tool execution
|
| 39 |
+
code_input: str # Code Reviewer: Input code to review
|
| 40 |
+
review_output: str # Code Reviewer: Review results
|
| 41 |
+
|
| 42 |
+
# Worker State for Blog Generation
|
| 43 |
+
class WorkerState(TypedDict):
|
| 44 |
+
section: Section
|
| 45 |
+
completed_sections: Annotated[List[str], operator.add]
|
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/display_result.py
CHANGED
|
@@ -37,4 +37,36 @@ class DisplayResultStreamlit:
|
|
| 37 |
st.write("Tool Call End")
|
| 38 |
elif type(message)==AIMessage and message.content:
|
| 39 |
with st.chat_message("assistant"):
|
| 40 |
-
st.write(message.content)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 37 |
st.write("Tool Call End")
|
| 38 |
elif type(message)==AIMessage and message.content:
|
| 39 |
with st.chat_message("assistant"):
|
| 40 |
+
st.write(message.content)
|
| 41 |
+
elif usecase == "Blog Generation":
|
| 42 |
+
# Prepare state and invoke the graph for blog generation
|
| 43 |
+
initial_state = {
|
| 44 |
+
"messages": [HumanMessage(content=user_message)],
|
| 45 |
+
"topic": user_message, # Assume user_message is the topic
|
| 46 |
+
"sections": [],
|
| 47 |
+
"completed_sections": [],
|
| 48 |
+
"final_report": ""
|
| 49 |
+
}
|
| 50 |
+
res = graph.invoke(initial_state)
|
| 51 |
+
with st.chat_message("user"):
|
| 52 |
+
st.write(f"Blog topic: {user_message}")
|
| 53 |
+
with st.chat_message("assistant"):
|
| 54 |
+
st.markdown("### Generated Blog")
|
| 55 |
+
st.markdown(res["final_report"]) # Display the final report in markdown
|
| 56 |
+
|
| 57 |
+
elif usecase == "Coding Peer Review":
|
| 58 |
+
# Prepare state and invoke the graph for code review
|
| 59 |
+
initial_state = {
|
| 60 |
+
"messages": [HumanMessage(content="Review this code")],
|
| 61 |
+
"code_input": user_message, # Assume user_message is the code
|
| 62 |
+
"review_output": ""
|
| 63 |
+
}
|
| 64 |
+
res = graph.invoke(initial_state)
|
| 65 |
+
with st.chat_message("user"):
|
| 66 |
+
st.code(user_message, language="python") # Display code in a code block
|
| 67 |
+
with st.chat_message("assistant"):
|
| 68 |
+
st.markdown("### Code Review Feedback")
|
| 69 |
+
st.markdown(res["review_output"]) # Display review in markdown
|
| 70 |
+
|
| 71 |
+
else:
|
| 72 |
+
st.error(f"Unknown use case: {usecase}")
|
src/langgraphagenticai/ui/uiconfigfile.ini
CHANGED
|
@@ -1,5 +1,5 @@
|
|
| 1 |
[DEFAULT]
|
| 2 |
-
PAGE_TITLE = LangGraph:
|
| 3 |
LLM_OPTIONS = Groq
|
| 4 |
-
USECASE_OPTIONS = Basic Chatbot, Chatbot with Tool
|
| 5 |
GROQ_MODEL_OPTIONS = mixtral-8x7b-32768, llama3-8b-8192, llama3-70b-8192, gemma-7b-i, gemma2-9b-it, qwen2.5-32b, qwen-2.5-coder-32b
|
|
|
|
| 1 |
[DEFAULT]
|
| 2 |
+
PAGE_TITLE = Dynamic Multi-Agent Workflows with LangGraph: Scalable, Modular, and Intelligent
|
| 3 |
LLM_OPTIONS = Groq
|
| 4 |
+
USECASE_OPTIONS = Basic Chatbot, Chatbot with Tool, Blog Generation, Coding Peer Review
|
| 5 |
GROQ_MODEL_OPTIONS = mixtral-8x7b-32768, llama3-8b-8192, llama3-70b-8192, gemma-7b-i, gemma2-9b-it, qwen2.5-32b, qwen-2.5-coder-32b
|