feat: add cmhub settings panel

This commit is contained in:
chengma
2026-07-04 16:29:15 +08:00
parent 1efb095767
commit 27f23a4738
9 changed files with 813 additions and 21 deletions
+146
View File
@@ -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."""