Skip to content

Commit 54b94e5

Browse files
committed
stream events
1 parent 92495d2 commit 54b94e5

File tree

3 files changed

+60
-10
lines changed

3 files changed

+60
-10
lines changed

src/app/workflow.py

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
import asyncio
2+
import time
23

34
from workflows import Context, Workflow, step
4-
from workflows.events import StartEvent, StopEvent
5+
from workflows.events import StartEvent, StopEvent, Event
56
import logging
7+
from datetime import datetime
68

79
logger = logging.getLogger(__name__)
810

@@ -11,15 +13,30 @@ class PingEvent(StartEvent):
1113
message: str
1214

1315

14-
class PongEvent(StopEvent):
16+
class PongEvent(Event):
1517
message: str
1618

1719

20+
class WorkflowCompletedEvent(StopEvent):
21+
timestamp: str
22+
23+
1824
class DefaultWorkflow(Workflow):
1925
@step
20-
async def start(self, event: PingEvent, context: Context) -> PongEvent:
26+
async def start(self, event: PingEvent, context: Context) -> WorkflowCompletedEvent:
27+
start = time.monotonic()
2128
logger.info(f"Received message: {event.message}")
22-
return PongEvent(message=f"PONG for '{event.message}'")
29+
for i in range(5):
30+
logger.info(f"Processing message: {event.message} {i}")
31+
elapsed = (time.monotonic() - start) * 1000
32+
context.write_event_to_stream(
33+
PongEvent(message=f"+{elapsed:.0f}ms PONG {i + 1}/5 ")
34+
)
35+
await asyncio.sleep(0.2)
36+
return WorkflowCompletedEvent(
37+
timestamp="workflow completed at "
38+
+ datetime.now().isoformat(timespec="seconds")
39+
)
2340

2441

2542
workflow = DefaultWorkflow()

ui/src/index.css

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,3 +83,15 @@ body {
8383
filter: blur(28px) saturate(110%);
8484
}
8585
}
86+
87+
/* Simple fade-in-up animation for streamed items */
88+
@keyframes fade-in-left {
89+
from {
90+
opacity: 0;
91+
transform: translateX(36px);
92+
}
93+
to {
94+
opacity: 1;
95+
transform: translateX(0);
96+
}
97+
}

ui/src/pages/Home.tsx

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@ export default function Home() {
1313
llama-ui to call the workflow. Customize this app with your own
1414
workflow and UI.
1515
</div>
16-
<div className="flex flex-row gap-4 items-center justify-center w-full">
16+
<div className="flex flex-row gap-4 items-start justify-center w-full">
1717
{taskId ? (
18-
<HandlerOuput handlerId={taskId} />
18+
<HandlerOutput handlerId={taskId} />
1919
) : (
2020
<Output>
2121
<span className="text-black/60 dark:text-white/60">
@@ -71,14 +71,35 @@ function RunButton({
7171
);
7272
}
7373

74-
function HandlerOuput({ handlerId }: { handlerId: string }) {
74+
function HandlerOutput({ handlerId }: { handlerId: string }) {
75+
// stream events and result from the workflow
7576
const taskData = useWorkflowTask(handlerId);
7677

77-
const result = taskData.events.find((event) =>
78+
// read workflow events here
79+
const pongs = taskData.events.filter((event) =>
7880
event.type.match(/PongEvent$/),
79-
) as { type: string; data: { message: string } } | undefined;
81+
) as { type: string; data: { message: string } }[];
82+
const completed = taskData.events.find((event) =>
83+
event.type.match(/WorkflowCompletedEvent$/),
84+
) as { type: string; data: { timestamp: string } } | undefined;
8085

81-
return <Output>{result ? result.data.message : "Running... "}</Output>;
86+
return (
87+
<div className="flex flex-col gap-4 w-full min-h-60">
88+
<Output>{completed ? completed.data.timestamp : "Running... "}</Output>
89+
{pongs.map((pong, index) => (
90+
<span
91+
className="text-black/60 dark:text-white/60 text-sm m-0"
92+
key={pong.data.message}
93+
style={{
94+
animation: "fade-in-left 80ms ease-out both",
95+
willChange: "opacity, transform",
96+
}}
97+
>
98+
{pong.data.message}
99+
</span>
100+
))}
101+
</div>
102+
);
82103
}
83104

84105
function Output({ children }: { children: React.ReactNode }) {

0 commit comments

Comments
 (0)