- 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.
132 lines
4.4 KiB
Python
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,
|
|
}
|
|
)
|
|
)
|
|
|