개선관리 요구사항과 Google 로그인을 완료

This commit is contained in:
Yun Chan 2026-08-28 16:07:09 +09:00
parent cc0a15b7c6
commit 2a39636163
112 changed files with 10166 additions and 527 deletions

View file

@ -139,24 +139,38 @@ class EngineClient:
async def health(self) -> bool:
return bool((await self.health_detail()).get("ok"))
async def health_detail(self) -> dict[str, Any]:
async def _provider_health_detail(
self,
*,
provider: EngineProvider,
model: str | None = None,
reasoning_effort: ReasoningEffort | None = None,
) -> dict[str, Any]:
try:
params: dict[str, str] = {"provider": self.engine_mode}
if self.default_model:
params["model"] = self.default_model
if self.default_reasoning_effort:
params["reasoning_effort"] = self.default_reasoning_effort
params: dict[str, str] = {"provider": provider}
if model:
params["model"] = model
if reasoning_effort:
params["reasoning_effort"] = reasoning_effort
r = await self.client.get("/ready", params=params)
if r.status_code == 404:
live = await self.client.get("/health")
return {
"ok": live.status_code == 200,
"detail": "gateway liveness only; readiness endpoint unavailable",
# 게이트웨이 프로세스가 살아 있다는 사실만으로 특정 provider가
# 응답을 만들 수 있다고 판정하면 회기 화면이 거짓 GREEN이 된다.
"ok": False,
"detail": (
"게이트웨이는 응답하지만 공급자 준비상태 엔드포인트를 사용할 수 없음"
if live.status_code == 200
else "게이트웨이와 공급자 준비상태를 확인할 수 없음"
),
"status_code": live.status_code,
"cached": False,
}
payload: dict[str, Any] = {}
try:
payload = r.json()
decoded = r.json()
payload = decoded if isinstance(decoded, dict) else {}
except ValueError:
payload = {}
return {
@ -170,8 +184,62 @@ class EngineClient:
"ok": False,
"detail": f"engine readiness transport error: {exc}",
"status_code": None,
"cached": False,
}
async def health_detail(self) -> dict[str, Any]:
"""관리자 기본 lane과 실시간 내담자 lane의 준비상태를 함께 반환한다.
내담자 턴은 ``live_client_provider``, 평가·리뷰는 ``engine_mode``
분리될 있으므로 기본 공급자 하나만 확인해서는 실제 응답 가능 여부를 없다.
"""
default_detail = await self._provider_health_detail(
provider=self.engine_mode,
model=self.default_model,
reasoning_effort=self.default_reasoning_effort,
)
live_provider = self.live_client_provider or self.engine_mode
if live_provider == self.engine_mode:
live_detail = dict(default_detail)
else:
# 관리자 기본 model/reasoning 값은 engine_mode 소속이므로 별도 client
# provider readiness에는 넘기지 않는다(_payload 계약과 동일).
live_detail = await self._provider_health_detail(provider=live_provider)
default_ok = bool(default_detail.get("ok"))
live_ok = bool(live_detail.get("ok"))
if not default_ok:
detail = (
f"기본 공급자 {self.engine_mode}: "
f"{default_detail.get('detail') or 'readiness failed'}"
)
status_code = default_detail.get("status_code")
elif not live_ok:
detail = (
f"실시간 내담자 공급자 {live_provider}: "
f"{live_detail.get('detail') or 'readiness failed'}"
)
status_code = live_detail.get("status_code")
else:
detail = str(live_detail.get("detail") or default_detail.get("detail") or "ready")
status_code = live_detail.get("status_code")
return {
"ok": default_ok and live_ok,
"detail": detail,
"status_code": status_code,
"cached": bool(default_detail.get("cached")) and bool(live_detail.get("cached")),
"default_engine": {
"provider": self.engine_mode,
**default_detail,
},
"live_client_engine": {
"provider": live_provider,
**live_detail,
},
}
async def capabilities(
self,
*,