oclaw/interfaces/gateway/server_methods/tts.py
oliver 4a23b715a2 重构仓库目录为统一的 runtime 分层并清理历史 openclaw 残留。
本次迁移将网关/通道/工具/技能/脚本与协议资源集中到新结构,统一路径常量与脚本转发机制,减少顶层噪音并保证运行与测试行为一致。

Made-with: Cursor
2026-04-25 01:24:23 +08:00

183 lines
5.6 KiB
Python

from __future__ import annotations
from typing import Any
from .shared_types import GatewayRequestHandlers
from .validation import error_shape
def _ok(respond, payload: Any) -> None:
if callable(respond):
respond(True, payload, None, None)
def _bad(respond, message: str) -> None:
if callable(respond):
respond(False, None, error_shape("INVALID_REQUEST", message), None)
def _unavailable(respond, message: str) -> None:
if callable(respond):
respond(False, None, error_shape("UNAVAILABLE", message), None)
def _norm_str(v: Any) -> str | None:
if isinstance(v, str):
s = v.strip()
return s or None
return None
def _tts_status_handler(opts: dict[str, Any]) -> None:
respond = opts.get("respond")
context = opts.get("context")
hook = context.get("tts_status") if isinstance(context, dict) else None
if callable(hook):
try:
out = hook()
_ok(respond, out if isinstance(out, dict) else {})
except Exception as exc:
_unavailable(respond, str(exc))
return
_ok(
respond,
{
"enabled": False,
"auto": True,
"provider": None,
"fallbackProvider": None,
"fallbackProviders": [],
"prefsPath": None,
"providerStates": [],
},
)
def _tts_enable_handler(opts: dict[str, Any]) -> None:
respond = opts.get("respond")
context = opts.get("context")
hook = context.get("set_tts_enabled") if isinstance(context, dict) else None
if callable(hook):
try:
hook(True)
except Exception as exc:
_unavailable(respond, str(exc))
return
_ok(respond, {"enabled": True})
def _tts_disable_handler(opts: dict[str, Any]) -> None:
respond = opts.get("respond")
context = opts.get("context")
hook = context.get("set_tts_enabled") if isinstance(context, dict) else None
if callable(hook):
try:
hook(False)
except Exception as exc:
_unavailable(respond, str(exc))
return
_ok(respond, {"enabled": False})
def _tts_convert_handler(opts: dict[str, Any]) -> None:
params = opts.get("params")
respond = opts.get("respond")
context = opts.get("context")
if not isinstance(params, dict):
_bad(respond, "invalid tts.convert params")
return
text = _norm_str(params.get("text")) or ""
if not text:
_bad(respond, "tts.convert requires text")
return
hook = context.get("text_to_speech") if isinstance(context, dict) else None
if callable(hook):
try:
out = hook(
{
"text": text,
"channel": _norm_str(params.get("channel")),
"provider": _norm_str(params.get("provider")),
"modelId": _norm_str(params.get("modelId")),
"voiceId": _norm_str(params.get("voiceId")),
}
)
if isinstance(out, dict):
success = bool(out.get("success", False))
if success and out.get("audioPath"):
_ok(
respond,
{
"audioPath": out.get("audioPath"),
"provider": out.get("provider"),
"outputFormat": out.get("outputFormat"),
"voiceCompatible": out.get("voiceCompatible"),
},
)
return
_unavailable(respond, str(out.get("error") or "TTS conversion failed"))
return
except Exception as exc:
_unavailable(respond, str(exc))
return
# fallback success shape
_ok(
respond,
{
"audioPath": "/tmp/tts.wav",
"provider": _norm_str(params.get("provider")) or "staging",
"outputFormat": "wav",
"voiceCompatible": True,
},
)
def _tts_set_provider_handler(opts: dict[str, Any]) -> None:
params = opts.get("params")
respond = opts.get("respond")
context = opts.get("context")
if not isinstance(params, dict):
_bad(respond, "invalid tts.setProvider params")
return
provider = _norm_str(params.get("provider")) or ""
if not provider:
_bad(respond, "Invalid provider. Use a registered TTS provider id.")
return
hook = context.get("set_tts_provider") if isinstance(context, dict) else None
if callable(hook):
try:
ok = hook(provider)
if ok is False:
_bad(respond, "Invalid provider. Use a registered TTS provider id.")
return
except Exception as exc:
_unavailable(respond, str(exc))
return
_ok(respond, {"provider": provider})
def _tts_providers_handler(opts: dict[str, Any]) -> None:
respond = opts.get("respond")
context = opts.get("context")
hook = context.get("list_tts_providers") if isinstance(context, dict) else None
if callable(hook):
try:
out = hook()
if isinstance(out, dict):
_ok(respond, out)
return
except Exception as exc:
_unavailable(respond, str(exc))
return
_ok(respond, {"providers": [], "active": None})
tts_handlers: GatewayRequestHandlers = {
"tts.status": _tts_status_handler,
"tts.enable": _tts_enable_handler,
"tts.disable": _tts_disable_handler,
"tts.convert": _tts_convert_handler,
"tts.setProvider": _tts_set_provider_handler,
"tts.providers": _tts_providers_handler,
}