73 lines
2.6 KiB
Python
73 lines
2.6 KiB
Python
# Copyright (c) 2025 Patrick Motsch
|
|
# All rights reserved.
|
|
|
|
"""Shared helpers for AI workflow actions."""
|
|
|
|
import json
|
|
from typing import Any, Optional
|
|
|
|
|
|
def is_image_action_document_list(val: Any) -> bool:
|
|
"""True if ``val`` is a non-empty list of ActionDocument-shaped dicts (mimeType image/*)."""
|
|
if not isinstance(val, list) or not val:
|
|
return False
|
|
for item in val:
|
|
if not isinstance(item, dict):
|
|
return False
|
|
mime = str(item.get("mimeType") or "").strip().lower()
|
|
if not mime.startswith("image/"):
|
|
return False
|
|
return True
|
|
|
|
|
|
def _handover_response_plain(val: Any) -> Optional[str]:
|
|
"""If ``val`` is a dict with a non-empty ``response`` string, return it (BOM-stripped)."""
|
|
if not isinstance(val, dict):
|
|
return None
|
|
r = val.get("response")
|
|
if r is None or not str(r).strip():
|
|
return None
|
|
return str(r).strip().lstrip("\ufeff")
|
|
|
|
|
|
def serialize_context(val: Any, *, prefer_handover_primary: bool = False) -> str:
|
|
"""Convert any context value to a readable string for use in AI prompts.
|
|
|
|
- None / empty string → ""
|
|
- empty dict (no keys) → "" (avoids literal "{}" in file.create / prompts)
|
|
- str → as-is
|
|
- dict / list → pretty-printed JSON (unless ``prefer_handover_primary`` and dict has ``response``)
|
|
- if JSON encoding fails (cycles, etc.) but dict has ``response``, return that text instead of ``str(dict)``
|
|
- anything else → str()
|
|
"""
|
|
if val is None or val == "" or val == []:
|
|
return ""
|
|
if isinstance(val, dict) and len(val) == 0:
|
|
return ""
|
|
if prefer_handover_primary:
|
|
got = _handover_response_plain(val)
|
|
if got is not None:
|
|
return got
|
|
if isinstance(val, str):
|
|
return val.strip().lstrip("\ufeff")
|
|
try:
|
|
return json.dumps(val, ensure_ascii=False, indent=2, default=str)
|
|
except Exception:
|
|
got = _handover_response_plain(val)
|
|
if got is not None:
|
|
return got
|
|
return str(val)
|
|
|
|
|
|
def applyCommonAiParams(parameters: dict, request) -> None:
|
|
"""Apply common AI parameters (requireNeutralization, allowedModels) from node to request."""
|
|
requireNeutralization = parameters.get("requireNeutralization")
|
|
if requireNeutralization is not None:
|
|
request.requireNeutralization = bool(requireNeutralization)
|
|
|
|
allowedModels = parameters.get("allowedModels")
|
|
if allowedModels and isinstance(allowedModels, list):
|
|
if not request.options:
|
|
from modules.datamodels.datamodelAi import AiCallOptions
|
|
request.options = AiCallOptions()
|
|
request.options.allowedModels = allowedModels
|