"""Dify-hosted brain: prompt, workflow, tools, and context live in Dify.""" from __future__ import annotations from uuid import uuid4 from dify_client import AsyncClient from loguru import logger from models import AssistantConfig from pipecat.processors.aggregators.llm_context import LLMContext from pipecat.processors.frame_processor import FrameProcessor from services.brains.base import BaseBrain, BrainSpec from services.brains.dify_llm import DifyLLMService, normalize_api_base class DifyBrain(BaseBrain): spec = BrainSpec( type="dify", supported_runtime_modes=frozenset({"pipeline"}), owns_context=False, ) def __init__(self): self._user_id = f"ai-video-{uuid4().hex}" self._client: AsyncClient | None = None def _get_client(self, cfg: AssistantConfig) -> AsyncClient: if self._client is None: if not cfg.dify_api_key: raise ValueError("缺少 Dify Agent apiKey") self._client = AsyncClient( api_key=cfg.dify_api_key, api_base=normalize_api_base(cfg.dify_api_url), ) return self._client async def greeting(self, cfg: AssistantConfig) -> str: """Use Dify's opening statement, with the local greeting as fallback.""" try: api_base = normalize_api_base(cfg.dify_api_url) response = await self._get_client(cfg).arequest( f"{api_base}/parameters", "GET", params={"user": self._user_id}, timeout=15.0, ) opening = str(response.json().get("opening_statement") or "").strip() return opening or cfg.greeting except ValueError: raise except Exception as exc: # noqa: BLE001 - greeting failure should not block a call logger.warning(f"Dify 获取开场白失败,回退 cfg.greeting: {exc}") return cfg.greeting def build_llm(self, cfg: AssistantConfig, context: LLMContext) -> FrameProcessor: return DifyLLMService( cfg, client=self._get_client(cfg), user_id=self._user_id, )