Files
ai-video-fullstack/backend/services/pipecat/workflow_services.py
Xin Wang 6e8fc70c5a Refactor pipeline and assistant page components for improved structure and performance
- Remove unused imports and classes from pipeline.py to streamline the codebase.
- Consolidate dynamic variable handling and workflow management in AssistantPage, enhancing clarity and maintainability.
- Update WorkflowEditor to utilize a more modular approach, improving the overall architecture and reducing complexity.
- Enhance the import structure across components for better organization and readability.
2026-07-14 12:59:41 +08:00

132 lines
4.4 KiB
Python

"""Workflow model resource loading and runtime service switching."""
from models import AssistantConfig
from services.pipecat.service_factory import (
config_with_resource,
create_llm,
create_stt,
create_tts,
)
from pipecat.frames.frames import (
ManuallySwitchServiceFrame,
OutputTransportMessageUrgentFrame,
)
from pipecat.pipeline.llm_switcher import LLMSwitcher
from pipecat.pipeline.service_switcher import ServiceSwitcher
from pipecat.processors.frame_processor import FrameProcessor
def build_workflow_voice_switcher(
cfg: AssistantConfig, capability: str, base_service: FrameProcessor
):
"""Build one switcher and an ID lookup for every referenced voice resource."""
create = create_stt if capability == "ASR" else create_tts
settings = cfg.graph.get("settings") or {}
default_key = (
"defaultAsrResourceId" if capability == "ASR" else "defaultTtsResourceId"
)
default_id = str(settings.get(default_key) or "")
services_by_id = {}
for resource_id, resource in cfg.workflow_model_resources.items():
if resource.capability != capability:
continue
services_by_id[resource_id] = (
base_service
if resource_id == default_id
else create(config_with_resource(cfg, resource))
)
primary = services_by_id.get(default_id, base_service)
services = [primary]
services.extend(
service for service in services_by_id.values() if service is not primary
)
if base_service is not primary:
services.append(base_service)
return ServiceSwitcher(services=services), services_by_id, primary
def build_workflow_llm_switcher(cfg: AssistantConfig, base_service):
"""Build an LLM switcher for the global model and Agent overrides."""
settings = cfg.graph.get("settings") or {}
default_id = str(settings.get("defaultLlmResourceId") or "")
services_by_id = {}
for resource_id, resource in cfg.workflow_model_resources.items():
if resource.capability != "LLM":
continue
services_by_id[resource_id] = (
base_service
if resource_id == default_id
else create_llm(config_with_resource(cfg, resource))
)
primary = services_by_id.get(default_id, base_service)
services = [primary]
services.extend(
service for service in services_by_id.values() if service is not primary
)
if base_service is not primary:
services.append(base_service)
return LLMSwitcher(llms=services), services_by_id, primary
class WorkflowServiceController:
"""Switch one Workflow stage's model resources without leaking state."""
def __init__(
self,
*,
worker,
llm_services: dict[str, FrameProcessor],
voice_services: dict[str, dict[str, FrameProcessor]],
current_services: dict[str, FrameProcessor],
) -> None:
self._worker = worker
self._services = {
"llm": llm_services,
"asr": voice_services["asr"],
"tts": voice_services["tts"],
}
self._current = dict(current_services)
self._defaults = dict(current_services)
async def switch(
self,
llm_resource_id: str | None,
asr_resource_id: str | None,
tts_resource_id: str | None,
) -> None:
requested = (
("llm", llm_resource_id),
("asr", asr_resource_id),
("tts", tts_resource_id),
)
for kind, resource_id in requested:
target = (
self._services[kind].get(resource_id)
if resource_id
else self._defaults[kind]
)
if target is None:
raise ValueError(
f"Workflow {kind.upper()} 资源未加载:{resource_id}"
)
if self._current[kind] is target:
continue
await self._worker.queue_frame(
ManuallySwitchServiceFrame(service=target)
)
self._current[kind] = target
await self._worker.queue_frame(
OutputTransportMessageUrgentFrame(
message={
"type": "service-switched",
"capability": kind.upper(),
"resourceId": resource_id,
}
)
)