Skip to content

Commit cac4657

Browse files
committed
refactor news summarizer agent
1 parent 2489c48 commit cac4657

File tree

3 files changed

+59
-54
lines changed

3 files changed

+59
-54
lines changed

scripts/agent_operator.py

Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
from template_langgraph.agents.news_summarizer_agent.agent import (
1111
graph as news_summarizer_agent_graph,
1212
)
13+
from template_langgraph.agents.news_summarizer_agent.models import Article
1314
from template_langgraph.agents.task_decomposer_agent.agent import graph as task_decomposer_agent_graph
1415
from template_langgraph.loggers import get_logger
1516

@@ -117,11 +118,11 @@ def run(
117118

118119
@app.command()
119120
def news_summarizer_agent(
120-
request: str = typer.Option(
121+
prompt: str = typer.Option(
121122
"Please summarize the latest news articles in Japanese briefly in 3 sentences.",
122-
"--request",
123-
"-r",
124-
help="Request to the agent",
123+
"--prompt",
124+
"-p",
125+
help="Prompt for the agent",
125126
),
126127
urls: str = typer.Option(
127128
"https://example.com/article1,https://example.com/article2",
@@ -138,7 +139,6 @@ def news_summarizer_agent(
138139
):
139140
from template_langgraph.agents.news_summarizer_agent.models import (
140141
AgentInputState,
141-
AgentOutputState,
142142
AgentState,
143143
)
144144

@@ -150,25 +150,19 @@ def news_summarizer_agent(
150150
for event in graph.stream(
151151
input=AgentState(
152152
input=AgentInputState(
153-
request=request,
154-
request_id=str(uuid4()),
153+
prompt=prompt,
154+
id=str(uuid4()),
155155
urls=urls.split(",") if urls else [],
156156
),
157-
output=AgentOutputState(
158-
result="N/A",
159-
articles=[],
160-
),
161-
target_url_index=None,
157+
articles=[],
162158
)
163159
):
164160
logger.info("-" * 20)
165161
logger.info(f"Event: {event}")
166162

167-
output: AgentOutputState = event["notify"]["output"]
168-
for article in output.articles:
169-
logger.info(article.url)
170-
logger.info(f"is_valid_url: {article.is_valid_url}, is_valid_content: {article.is_valid_content}")
171-
logger.info(article.structured_article.model_dump_json(indent=2))
163+
articles: list[Article] = event["notify"]["articles"]
164+
for article in articles:
165+
logger.info(f"{article.model_dump_json(indent=2)}")
172166

173167

174168
if __name__ == "__main__":

template_langgraph/agents/news_summarizer_agent/agent.py

Lines changed: 37 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,22 @@
22
from langgraph.graph import StateGraph
33
from langgraph.types import Send
44

5-
from template_langgraph.agents.news_summarizer_agent.models import AgentState, Article, StructuredArticle
5+
from template_langgraph.agents.news_summarizer_agent.models import (
6+
AgentState,
7+
Article,
8+
StructuredArticle,
9+
SummarizeWebContentState,
10+
)
611
from template_langgraph.llms.azure_openais import AzureOpenAiWrapper
712
from template_langgraph.loggers import get_logger
813

914
logger = get_logger(__name__)
1015

1116

1217
class MockNotifier:
13-
def notify(self, request_id: str, body: dict) -> None:
18+
def notify(self, id: str, body: dict) -> None:
1419
"""Simulate sending a notification to the user."""
15-
logger.info(f"Notification sent for request {request_id}: {body}")
20+
logger.info(f"Notification sent for request {id}: {body}")
1621

1722

1823
class MockScraper:
@@ -85,16 +90,19 @@ def create_graph(self):
8590

8691
# Create nodes
8792
workflow.add_node("initialize", self.initialize)
88-
workflow.add_node("fetch_web_content", self.fetch_web_content)
93+
workflow.add_node("summarize_web_content", self.summarize_web_content)
8994
workflow.add_node("notify", self.notify)
9095

9196
# Create edges
9297
workflow.set_entry_point("initialize")
9398
workflow.add_conditional_edges(
9499
source="initialize",
95100
path=self.run_subtasks,
101+
path_map={
102+
"summarize_web_content": "summarize_web_content",
103+
},
96104
)
97-
workflow.add_edge("fetch_web_content", "notify")
105+
workflow.add_edge("summarize_web_content", "notify")
98106
workflow.set_finish_point("notify")
99107
return workflow.compile(
100108
name=NewsSummarizerAgent.__name__,
@@ -111,61 +119,61 @@ def run_subtasks(self, state: AgentState) -> list[Send]:
111119
logger.info(f"Running subtasks with state: {state}")
112120
return [
113121
Send(
114-
node="fetch_web_content",
115-
arg=AgentState(
116-
input=state.input,
117-
output=state.output,
118-
target_url_index=idx,
122+
node="summarize_web_content",
123+
arg=SummarizeWebContentState(
124+
url=state.input.urls[idx],
125+
prompt=state.input.prompt,
119126
),
120127
)
121128
for idx, _ in enumerate(state.input.urls)
122129
]
123130

124-
def fetch_web_content(self, state: AgentState):
125-
url: str = state.input.urls[state.target_url_index]
126-
is_valid_url = url.startswith("http")
131+
def summarize_web_content(self, state: SummarizeWebContentState):
132+
is_valid_url = state.url.startswith("http")
127133
is_valid_content = False
128134
content = ""
129135

130136
# Check if the URL is valid
131137
if not is_valid_url:
132-
logger.error(f"Invalid URL: {url}")
138+
logger.error(f"Invalid URL: {state.url}")
133139
is_valid_content = False
134140
else:
135141
# Scrape the web content
136142
try:
137-
logger.info(f"Scraping URL: {url}")
138-
content = self.scraper.scrape(url)
143+
logger.info(f"Scraping URL: {state.url}")
144+
content = self.scraper.scrape(state.url)
139145
is_valid_content = True
140146
except httpx.RequestError as e:
141147
logger.error(f"Error fetching web content: {e}")
142148

143149
if is_valid_content:
144-
logger.info(f"Summarizing content with LLM @ {state.target_url_index}: {url}")
150+
logger.info(f"Summarizing content with LLM: {state.url}")
145151
structured_article: StructuredArticle = self.summarizer.summarize(
146-
prompt=state.input.request,
152+
prompt=state.prompt,
147153
content=content,
148154
)
149-
state.output.articles.append(
150-
Article(
151-
is_valid_url=is_valid_url,
152-
is_valid_content=is_valid_content,
153-
content=content,
154-
url=url,
155-
structured_article=structured_article,
156-
),
157-
)
155+
return {
156+
"articles": [
157+
Article(
158+
is_valid_url=is_valid_url,
159+
is_valid_content=is_valid_content,
160+
content=content,
161+
url=state.url,
162+
structured_article=structured_article,
163+
),
164+
]
165+
}
158166

159167
def notify(self, state: AgentState) -> AgentState:
160168
"""Send notifications to the user."""
161169
logger.info(f"Sending notifications with state: {state}")
162170
# Simulate sending notifications
163171
# convert list of articles to a dictionary for notification
164172
summary = {}
165-
for i, article in enumerate(state.output.articles):
173+
for i, article in enumerate(state.articles):
166174
summary[i] = article.model_dump()
167175
self.notifier.notify(
168-
request_id=state.input.request_id,
176+
id=state.input.id,
169177
body=summary,
170178
)
171179
return state

template_langgraph/agents/news_summarizer_agent/models.py

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,14 @@
1+
import operator
2+
from typing import Annotated
3+
14
from pydantic import BaseModel, Field
25

36

7+
class SummarizeWebContentState(BaseModel):
8+
prompt: str = Field(..., description="Prompt for summarization")
9+
url: str = Field(..., description="URL of the article to summarize")
10+
11+
412
class StructuredArticle(BaseModel):
513
title: str = Field(..., description="Title of the article")
614
date: str = Field(..., description="Publication date of the article")
@@ -18,16 +26,11 @@ class Article(BaseModel):
1826

1927

2028
class AgentInputState(BaseModel):
21-
request: str = Field(..., description="Request from the user")
22-
request_id: str = Field(..., description="Unique identifier for the request")
29+
prompt: str = Field(..., description="Prompt for the agent")
30+
id: str = Field(..., description="Unique identifier for the request")
2331
urls: list[str] = Field(..., description="List of article URLs")
2432

2533

26-
class AgentOutputState(BaseModel):
27-
articles: list[Article] = Field(..., description="List of articles processed by the agent")
28-
29-
3034
class AgentState(BaseModel):
3135
input: AgentInputState = Field(..., description="Input state for the agent")
32-
output: AgentOutputState = Field(..., description="Output state for the agent")
33-
target_url_index: int | None = Field(..., description="Index of the target URL being processed")
36+
articles: Annotated[list[Article], operator.add]

0 commit comments

Comments
 (0)