feat: add cmhub settings panel
This commit is contained in:
@@ -1661,6 +1661,152 @@ class AccountLoginCheckWorker(BaseWorker):
|
||||
def _elapsed_ms(self, started):
|
||||
return _elapsed_ms(started)
|
||||
|
||||
class CMHubSettingsWorker(BaseWorker):
|
||||
"""Fetch cmhub aliases and optional balance without blocking the GUI."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
base_url,
|
||||
api_key,
|
||||
connect_timeout=10,
|
||||
include_balance=True,
|
||||
db_path=None,
|
||||
diagnostic_log_dir=None,
|
||||
):
|
||||
super().__init__()
|
||||
self.base_url = str(base_url or "").strip()
|
||||
self.api_key = str(api_key or "")
|
||||
self.connect_timeout = max(1, int(connect_timeout or 10))
|
||||
self.include_balance = bool(include_balance)
|
||||
self.db_path = db_path
|
||||
self.diagnostic_log_dir = diagnostic_log_dir
|
||||
self._run_id = None
|
||||
|
||||
def execute(self):
|
||||
self._run_id = self._create_run_log()
|
||||
started = time.monotonic()
|
||||
action = "测试连接/查余额" if self.include_balance else "刷新别名"
|
||||
self._log_run_event(f"step=cmhub_settings result=start detail={action}")
|
||||
try:
|
||||
models = ai.fetch_cmhub_models(
|
||||
self.base_url,
|
||||
self.api_key,
|
||||
connect_timeout=self.connect_timeout,
|
||||
)
|
||||
balance = None
|
||||
if self.include_balance:
|
||||
balance = ai.fetch_cmhub_balance(
|
||||
self.base_url,
|
||||
self.api_key,
|
||||
connect_timeout=self.connect_timeout,
|
||||
)
|
||||
except Exception as exc:
|
||||
error = self._safe_error(exc)
|
||||
elapsed_ms = self._elapsed_ms(started)
|
||||
self._log_run_event(
|
||||
f"step=cmhub_settings result=failed detail={error} elapsed_ms={elapsed_ms}",
|
||||
level="error",
|
||||
)
|
||||
self._write_diagnostic_log(
|
||||
"cmhub 设置检测失败",
|
||||
level="ERROR",
|
||||
step="cmhub_settings",
|
||||
elapsed_ms=elapsed_ms,
|
||||
payload={"base_url": self.base_url, "error": error},
|
||||
exc=exc,
|
||||
)
|
||||
_safe_finish_run_log(
|
||||
self._run_id,
|
||||
db_path=self.db_path,
|
||||
status="failed",
|
||||
done=0,
|
||||
failed_count=1,
|
||||
summary_json={"ok": False, "error": error},
|
||||
)
|
||||
raise RuntimeError(error) from exc
|
||||
|
||||
elapsed_ms = self._elapsed_ms(started)
|
||||
payload = {
|
||||
"ok": True,
|
||||
"models": appconfig.sanitize_for_log(models),
|
||||
"balance": appconfig.sanitize_for_log(balance or {}),
|
||||
"points_balance": (balance or {}).get("points_balance"),
|
||||
}
|
||||
title_count = self._priced_count(models, "title")
|
||||
image_count = self._priced_count(models, "image")
|
||||
self._log_run_event(
|
||||
"step=cmhub_settings result=success detail=title_aliases={title_count} image_aliases={image_count} points_balance={points_balance} elapsed_ms={elapsed_ms}".format(
|
||||
title_count=title_count,
|
||||
image_count=image_count,
|
||||
points_balance=payload.get("points_balance") if payload.get("points_balance") is not None else "",
|
||||
elapsed_ms=elapsed_ms,
|
||||
)
|
||||
)
|
||||
_safe_finish_run_log(
|
||||
self._run_id,
|
||||
db_path=self.db_path,
|
||||
status="done",
|
||||
done=1,
|
||||
success_count=1,
|
||||
summary_json=payload,
|
||||
)
|
||||
return payload
|
||||
|
||||
def _priced_count(self, models, operation):
|
||||
return sum(
|
||||
1
|
||||
for model in models or []
|
||||
if str(model.get("operation_type") or "").lower() == operation
|
||||
and str(model.get("pricing_status") or "").lower() != "unpriced"
|
||||
and str(model.get("alias") or "").strip()
|
||||
)
|
||||
|
||||
def _create_run_log(self):
|
||||
if not self.db_path:
|
||||
return None
|
||||
return _safe_create_run_log(
|
||||
"cmhub_settings_test",
|
||||
db_path=self.db_path,
|
||||
total=1,
|
||||
options={"base_url": self.base_url, "include_balance": self.include_balance},
|
||||
)
|
||||
|
||||
def _log_run_event(self, message, level="info"):
|
||||
safe_message = _safe_add_run_log_event(
|
||||
self._run_id,
|
||||
message,
|
||||
db_path=self.db_path,
|
||||
level=level,
|
||||
)
|
||||
self.log.emit(str(safe_message))
|
||||
|
||||
def _write_diagnostic_log(
|
||||
self,
|
||||
message,
|
||||
level="INFO",
|
||||
step=None,
|
||||
elapsed_ms=None,
|
||||
payload=None,
|
||||
exc=None,
|
||||
):
|
||||
_safe_write_diagnostic_log(
|
||||
message,
|
||||
level=level,
|
||||
step=step,
|
||||
elapsed_ms=elapsed_ms,
|
||||
payload=payload,
|
||||
exc=exc,
|
||||
log_dir=self.diagnostic_log_dir,
|
||||
)
|
||||
|
||||
def _safe_error(self, exc):
|
||||
raw = str(exc) or exc.__class__.__name__
|
||||
redacted = appconfig.redact_secrets(raw, [self.api_key])
|
||||
return diagnostics.redact_log_text(redacted)
|
||||
|
||||
def _elapsed_ms(self, started):
|
||||
return _elapsed_ms(started)
|
||||
|
||||
class AIModelTestWorker(BaseWorker):
|
||||
"""Test one AI model connection without blocking the GUI thread."""
|
||||
|
||||
|
||||
Reference in New Issue
Block a user