Skip to content

Commit 2a0de3f

Browse files
committed
Samples: improvements for ticket classification sample
1 parent 672c99d commit 2a0de3f

File tree

4 files changed

+42
-21
lines changed

4 files changed

+42
-21
lines changed
Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,19 @@
1-
%%{init: {'flowchart': {'curve': 'linear'}}}%%
1+
---
2+
config:
3+
flowchart:
4+
curve: linear
5+
---
26
graph TD;
37
__start__([<p>__start__</p>]):::first
48
classify(classify)
5-
create_action(create_action)
6-
human_approval(human_approval)
9+
human_approval_node(human_approval_node)
710
notify_team(notify_team)
811
__end__([<p>__end__</p>]):::last
912
__start__ --> classify;
10-
classify --> create_action;
11-
create_action --> human_approval;
12-
human_approval --> notify_team;
13+
classify --> human_approval_node;
1314
notify_team --> __end__;
15+
human_approval_node -.-> classify;
16+
human_approval_node -.-> notify_team;
1417
classDef default fill:#f2f0ff,line-height:1.2
1518
classDef first fill-opacity:0
1619
classDef last fill:#bfb6fc

samples/ticket-classification/escalation app/escalation_agent_app.uiapp

Lines changed: 1 addition & 0 deletions
Large diffs are not rendered by default.

samples/ticket-classification/main.py

Lines changed: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import logging
22
import os
3-
from typing import Literal, Optional
3+
from typing import Literal, Optional, List
44

55
from langchain_openai import AzureChatOpenAI
66
from langchain_core.output_parsers import PydanticOutputParser
@@ -10,14 +10,15 @@
1010
from pydantic import BaseModel, Field
1111

1212
from uipath_sdk import UiPathSDK
13-
13+
from uipath_sdk._models import CreateAction
1414
logger = logging.getLogger(__name__)
1515

1616
uipath = UiPathSDK()
1717

1818
class GraphInput(BaseModel):
1919
message: str
2020
ticket_id: str
21+
assignee: Optional[str]
2122

2223
class GraphOutput(BaseModel):
2324
label: str
@@ -26,9 +27,11 @@ class GraphOutput(BaseModel):
2627
class GraphState(BaseModel):
2728
message: str
2829
ticket_id: str
30+
assignee: Optional[str] = None
2931
label: Optional[str] = None
3032
confidence: Optional[float] = None
31-
33+
rejected_categories: List[str] = []
34+
human_approval: Optional[bool] = None
3235

3336
class TicketClassification(BaseModel):
3437
label: Literal["security", "error", "system", "billing", "performance"] = Field(
@@ -78,15 +81,23 @@ def get_azure_openai_api_key() -> str:
7881

7982
return api_key
8083

84+
def decide_next_node(state: GraphState) -> Literal["classify", "notify_team"]:
85+
if state.human_approval_result is True:
86+
return "notify_team"
87+
return "classify"
8188

8289
async def classify(state: GraphState) -> GraphState:
90+
logger.info("classify")
91+
8392
"""Classify the support ticket using LLM."""
8493
llm = AzureChatOpenAI(
8594
azure_deployment="gpt-4o-mini",
8695
api_key=get_azure_openai_api_key(),
8796
azure_endpoint=os.getenv("AZURE_OPENAI_ENDPOINT"),
8897
api_version="2024-10-21"
8998
)
99+
if len(state.rejected_categories) > 0:
100+
prompt.append(("user", f"The ticket is 100% not part of the following categories '{state.rejected_categories}'. Choose another one."))
90101
_prompt = prompt.partial(
91102
format_instructions=output_parser.get_format_instructions()
92103
)
@@ -109,17 +120,22 @@ async def classify(state: GraphState) -> GraphState:
109120

110121
async def wait_for_human(state: GraphState) -> GraphState:
111122
logger.info("Wait for human approval")
112-
feedback = interrupt(f"Label: {state.label} Confidence: {state.confidence}")
113-
114-
if isinstance(feedback, bool) and feedback is True:
115-
return Command(goto="notify_team")
116-
else:
117-
return Command(goto=END)
123+
action_data = interrupt(CreateAction(name="escalation_agent_app",
124+
title="Action Required: Review classification",
125+
data={
126+
"AgentOutput": f"This is how I classified the ticket: '{state.ticket_id}', with message '{state.message}' \n Label: '{state.label}' Confidence: '{state.confidence}'",
127+
"AgentName": "ticket-classification "},
128+
app_version=1,
129+
assignee=state.assignee,
130+
))
131+
state.human_approval = isinstance(action_data["Answer"], bool) and action_data["Answer"] is True
132+
if not state.human_approval:
133+
state.rejected_categories.append(state.label)
134+
return state
118135

119-
async def notify_team(state: GraphState) -> GraphState:
136+
async def notify_team(state: GraphState) -> GraphOutput:
120137
logger.info("Send team email notification")
121-
print(state)
122-
return state
138+
return GraphOutput(label=state.label, confidence=state.confidence)
123139

124140
"""Process a support ticket through the workflow."""
125141

@@ -131,7 +147,7 @@ async def notify_team(state: GraphState) -> GraphState:
131147

132148
builder.add_edge(START, "classify")
133149
builder.add_edge("classify", "human_approval")
134-
builder.add_edge("human_approval", "notify_team")
150+
builder.add_conditional_edges("human_approval", decide_next_node)
135151
builder.add_edge("notify_team", END)
136152

137153

@@ -140,3 +156,4 @@ async def notify_team(state: GraphState) -> GraphState:
140156
memory = MemorySaver()
141157

142158
graph = builder.compile(checkpointer=memory)
159+

samples/ticket-classification/pyproject.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ dependencies = [
99
"langchain-openai>=0.3.9",
1010
"langgraph-checkpoint-sqlite>=2.0.3",
1111
"python-dotenv>=1.0.1",
12-
"uipath-sdk>=0.0.89",
13-
"uipath-langchain>=0.0.62",
12+
"uipath-sdk==0.0.110",
13+
"uipath-langchain==0.0.81",
1414
"pydantic>=2.10.6",
1515
"aiohttp>=3.11.12",
1616
"typing-extensions>=4.12.2",

0 commit comments

Comments
 (0)