Files
ai-video-fullstack/backend/services/workflow/output.py

94 lines
2.7 KiB
Python

"""Client-visible Workflow output and fixed speech in one place."""
from __future__ import annotations
from typing import Any
from uuid import uuid4
from pipecat.frames.frames import OutputTransportMessageUrgentFrame
from pipecat.utils.time import time_now_iso8601
from services.fixed_speech import FixedSpeechOutput
class WorkflowOutput(FixedSpeechOutput):
"""Publish debug events and fixed speech without duplicating persistence."""
async def emit_node_active(self, node_id: str | None) -> None:
if node_id:
await self.emit({"type": "node-active", "nodeId": node_id})
async def emit_trace(
self,
event: str,
*,
revision: str,
transition_id: int,
**details: Any,
) -> None:
"""Publish one ordered, machine-readable Workflow runtime event."""
await self.emit(
{
"type": "workflow-event",
"eventId": f"wfe_{uuid4().hex[:20]}",
"event": event,
"timestamp": time_now_iso8601(),
"sessionId": self._runtime.session_id,
"workflowRevision": revision,
"transitionId": transition_id,
**details,
}
)
async def emit_variables(
self,
*,
reason: str,
node_id: str | None,
changed: list[str] | None = None,
) -> None:
message: dict[str, Any] = {
"type": "workflow-variables",
"reason": reason,
"variables": self.public_variables(),
}
if node_id:
message["nodeId"] = node_id
if changed:
message["changed"] = [
name
for name in changed
if not name.startswith(("system__", "secret__"))
]
await self.emit(message)
async def emit_error(
self,
message: str,
*,
node_id: str | None,
code: str = "workflow_runtime_error",
) -> None:
payload: dict[str, Any] = {
"type": "workflow-error",
"code": code,
"message": message,
}
if node_id:
payload["nodeId"] = node_id
await self.emit(payload)
def public_variables(self) -> dict[str, str | int | float | bool]:
return {
name: value
for name, value in self._store.values.items()
if not name.startswith(("system__", "secret__"))
and isinstance(value, (str, int, float, bool))
}
async def emit(self, message: dict[str, Any]) -> None:
await self._runtime.queue_frame(
OutputTransportMessageUrgentFrame(message=message)
)