spagestic commited on
Commit
1c4c2e7
·
1 Parent(s): a9deb6d

auth button fixed

Browse files
Files changed (4) hide show
  1. app.py +43 -0
  2. assets/app.js +34 -1
  3. assets/index.html +6 -2
  4. assets/server.css +4 -0
app.py CHANGED
@@ -7,12 +7,18 @@ import subprocess
7
  # Python port (7861). Stale Node workers from prior restarts can block it.
8
  os.environ["GRADIO_NUM_PORTS"] = "20"
9
 
 
10
  from pathlib import Path
 
11
 
12
  import gradio as gr
 
13
  from fastapi.responses import HTMLResponse
14
  from fastapi.staticfiles import StaticFiles
15
  from gradio import Server
 
 
 
16
 
17
  from ui import server_api
18
 
@@ -27,6 +33,29 @@ async def homepage() -> str:
27
  return (ASSETS_DIR / "index.html").read_text(encoding="utf-8")
28
 
29
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
30
  @app.api(name="get_intake_choices")
31
  def api_get_intake_choices() -> dict:
32
  return server_api.get_intake_choices()
@@ -95,6 +124,20 @@ def _cleanup_stale_gradio_nodes() -> None:
95
  pass
96
 
97
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
98
  if __name__ == "__main__":
99
  _cleanup_stale_gradio_nodes()
100
  app.launch(show_error=True)
 
7
  # Python port (7861). Stale Node workers from prior restarts can block it.
8
  os.environ["GRADIO_NUM_PORTS"] = "20"
9
 
10
+ import time
11
  from pathlib import Path
12
+ from typing import Any
13
 
14
  import gradio as gr
15
+ from fastapi import Request
16
  from fastapi.responses import HTMLResponse
17
  from fastapi.staticfiles import StaticFiles
18
  from gradio import Server
19
+ from gradio.blocks import Blocks
20
+ from gradio.components import LoginButton
21
+ from gradio.events import api as gr_api
22
 
23
  from ui import server_api
24
 
 
33
  return (ASSETS_DIR / "index.html").read_text(encoding="utf-8")
34
 
35
 
36
+ @app.get("/api/auth/status")
37
+ async def auth_status(request: Request) -> dict[str, Any]:
38
+ session = getattr(request, "session", None)
39
+ if session is None:
40
+ return {"logged_in": False}
41
+
42
+ oauth_info = session.get("oauth_info")
43
+ if not oauth_info:
44
+ return {"logged_in": False}
45
+
46
+ expires_at = oauth_info.get("expires_at")
47
+ if expires_at is not None and expires_at <= time.time():
48
+ session.pop("oauth_info", None)
49
+ return {"logged_in": False}
50
+
51
+ userinfo = oauth_info.get("userinfo") or {}
52
+ return {
53
+ "logged_in": True,
54
+ "username": userinfo.get("preferred_username"),
55
+ "name": userinfo.get("name"),
56
+ }
57
+
58
+
59
  @app.api(name="get_intake_choices")
60
  def api_get_intake_choices() -> dict:
61
  return server_api.get_intake_choices()
 
124
  pass
125
 
126
 
127
+ def _launch_with_oauth(**kwargs: Any):
128
+ """Launch with a hidden LoginButton so HF OAuth routes are registered."""
129
+ with Blocks() as blocks:
130
+ LoginButton(visible=False)
131
+ for fn, api_kwargs in app._deferred_apis:
132
+ gr_api(fn=fn, **api_kwargs)
133
+
134
+ os.environ["GRADIO_SERVER_MODE_ENABLED"] = "1"
135
+ return blocks.launch(_app=app, **kwargs)
136
+
137
+
138
+ app.launch = _launch_with_oauth # type: ignore[method-assign]
139
+
140
+
141
  if __name__ == "__main__":
142
  _cleanup_stale_gradio_nodes()
143
  app.launch(show_error=True)
assets/app.js CHANGED
@@ -40,8 +40,41 @@ const els = {
40
  intakeForm: document.getElementById("intake-form"),
41
  createPrompt: document.getElementById("create-prompt"),
42
  personaList: document.getElementById("persona-list"),
 
 
43
  };
44
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
45
  function activeStatusBanner() {
46
  return state.view === "form" ? els.formStatus : els.statusBanner;
47
  }
@@ -314,5 +347,5 @@ els.chatInput.addEventListener("keydown", (event) => {
314
  }
315
  });
316
 
317
- await loadChoices();
318
  renderMessages();
 
40
  intakeForm: document.getElementById("intake-form"),
41
  createPrompt: document.getElementById("create-prompt"),
42
  personaList: document.getElementById("persona-list"),
43
+ authLogin: document.getElementById("auth-login"),
44
+ authLogout: document.getElementById("auth-logout"),
45
  };
46
 
47
+ function authRedirectTarget() {
48
+ return encodeURIComponent(window.location.pathname + window.location.search);
49
+ }
50
+
51
+ function updateAuthUI({ logged_in: loggedIn, username }) {
52
+ const target = authRedirectTarget();
53
+ if (loggedIn) {
54
+ els.authLogin.hidden = true;
55
+ els.authLogout.hidden = false;
56
+ els.authLogout.textContent = username ? `Log out (${username})` : "Log out";
57
+ els.authLogout.href = `/logout?_target_url=${target}`;
58
+ } else {
59
+ els.authLogin.hidden = false;
60
+ els.authLogout.hidden = true;
61
+ els.authLogin.href = `/login/huggingface?_target_url=${target}`;
62
+ }
63
+ }
64
+
65
+ async function loadAuthStatus() {
66
+ try {
67
+ const response = await fetch("/api/auth/status", { credentials: "include" });
68
+ if (!response.ok) {
69
+ updateAuthUI({ logged_in: false });
70
+ return;
71
+ }
72
+ updateAuthUI(await response.json());
73
+ } catch {
74
+ updateAuthUI({ logged_in: false });
75
+ }
76
+ }
77
+
78
  function activeStatusBanner() {
79
  return state.view === "form" ? els.formStatus : els.statusBanner;
80
  }
 
347
  }
348
  });
349
 
350
+ await Promise.all([loadChoices(), loadAuthStatus()]);
351
  renderMessages();
assets/index.html CHANGED
@@ -21,8 +21,12 @@
21
  </p>
22
  </div>
23
  <div class="auth-actions">
24
- <a href="/login/huggingface">Log in with Hugging Face</a>
25
- <a href="/logout">Log out</a>
 
 
 
 
26
  </div>
27
  </header>
28
 
 
21
  </p>
22
  </div>
23
  <div class="auth-actions">
24
+ <a id="auth-login" class="auth-button" href="/login/huggingface" hidden>
25
+ Log in with Hugging Face
26
+ </a>
27
+ <a id="auth-logout" class="auth-button" href="/logout" hidden>
28
+ Log out
29
+ </a>
30
  </div>
31
  </header>
32
 
assets/server.css CHANGED
@@ -46,6 +46,10 @@ a {
46
  align-items: center;
47
  }
48
 
 
 
 
 
49
  .auth-actions a,
50
  button {
51
  border-radius: 8px;
 
46
  align-items: center;
47
  }
48
 
49
+ .auth-actions [hidden] {
50
+ display: none !important;
51
+ }
52
+
53
  .auth-actions a,
54
  button {
55
  border-radius: 8px;