Spaces:
Running
Running
Navid Arabi
commited on
Commit
Β·
0fb23b8
1
Parent(s):
1ef4e10
base app
Browse files- app.py +8 -3
- components/dashboard_page.py +2 -11
- components/header.py +1 -0
- components/login_page.py +7 -4
- test/test.py +0 -96
- utils/auth.py +16 -16
- utils/database.py +1 -1
- utils/logger.py +10 -34
app.py
CHANGED
@@ -1,12 +1,13 @@
|
|
1 |
# app.py
|
2 |
-
|
3 |
import gradio as gr
|
4 |
from pathlib import Path
|
5 |
|
|
|
6 |
from components.login_page import LoginPage
|
7 |
from components.dashboard_page import DashboardPage
|
8 |
from config import conf
|
9 |
|
|
|
10 |
CSS_FILE = Path(__file__).parent / "assets" / "styles.css"
|
11 |
custom_css = CSS_FILE.read_text(encoding="utf-8")
|
12 |
|
@@ -24,9 +25,13 @@ def build_app() -> gr.Blocks:
|
|
24 |
dashboard_page.register_callbacks(login_page, session)
|
25 |
|
26 |
demo.queue(default_concurrency_limit=50)
|
27 |
-
|
28 |
return demo
|
29 |
|
30 |
|
31 |
if __name__ == "__main__":
|
32 |
-
|
|
|
|
|
|
|
|
|
|
1 |
# app.py
|
|
|
2 |
import gradio as gr
|
3 |
from pathlib import Path
|
4 |
|
5 |
+
from utils.logger import Logger
|
6 |
from components.login_page import LoginPage
|
7 |
from components.dashboard_page import DashboardPage
|
8 |
from config import conf
|
9 |
|
10 |
+
log = Logger()
|
11 |
CSS_FILE = Path(__file__).parent / "assets" / "styles.css"
|
12 |
custom_css = CSS_FILE.read_text(encoding="utf-8")
|
13 |
|
|
|
25 |
dashboard_page.register_callbacks(login_page, session)
|
26 |
|
27 |
demo.queue(default_concurrency_limit=50)
|
28 |
+
log.info("App Started.")
|
29 |
return demo
|
30 |
|
31 |
|
32 |
if __name__ == "__main__":
|
33 |
+
try:
|
34 |
+
log.info("Initial App ...")
|
35 |
+
build_app().launch()
|
36 |
+
except Exception as err:
|
37 |
+
log.error(err)
|
components/dashboard_page.py
CHANGED
@@ -1,6 +1,6 @@
|
|
1 |
# components/dashboard_page.py
|
|
|
2 |
import gradio as gr
|
3 |
-
from utils.auth import AuthService
|
4 |
from components.header import Header
|
5 |
|
6 |
|
@@ -13,18 +13,9 @@ class DashboardPage:
|
|
13 |
self.header = Header()
|
14 |
|
15 |
# βββββββββββ main body ββββββββββββ
|
16 |
-
self.echo_box = gr.Textbox(label="Echo β whatever you type will be returned")
|
17 |
-
self.echo_btn = gr.Button("Echo")
|
18 |
-
self.echo_output = gr.Markdown()
|
19 |
|
20 |
# βββββββββββββββββββ event wiring ββββββββββββββββββββ
|
21 |
def register_callbacks(self, login_page, session_state):
|
22 |
-
# Echo button: prepend current username
|
23 |
-
self.echo_btn.click(
|
24 |
-
fn=AuthService.echo,
|
25 |
-
inputs=[self.echo_box, session_state],
|
26 |
-
outputs=self.echo_output,
|
27 |
-
)
|
28 |
|
29 |
# Header handles its own logout button
|
30 |
-
self.header.register_callbacks(login_page, self, session_state)
|
|
|
1 |
# components/dashboard_page.py
|
2 |
+
|
3 |
import gradio as gr
|
|
|
4 |
from components.header import Header
|
5 |
|
6 |
|
|
|
13 |
self.header = Header()
|
14 |
|
15 |
# βββββββββββ main body ββββββββββββ
|
|
|
|
|
|
|
16 |
|
17 |
# βββββββββββββββββββ event wiring ββββββββββββββββββββ
|
18 |
def register_callbacks(self, login_page, session_state):
|
|
|
|
|
|
|
|
|
|
|
|
|
19 |
|
20 |
# Header handles its own logout button
|
21 |
+
self.header.register_callbacks(login_page, self, session_state)
|
components/header.py
CHANGED
@@ -1,4 +1,5 @@
|
|
1 |
# components/header.py
|
|
|
2 |
import gradio as gr
|
3 |
from utils.auth import AuthService
|
4 |
|
|
|
1 |
# components/header.py
|
2 |
+
|
3 |
import gradio as gr
|
4 |
from utils.auth import AuthService
|
5 |
|
components/login_page.py
CHANGED
@@ -1,4 +1,5 @@
|
|
1 |
# components/login_page.py
|
|
|
2 |
import gradio as gr
|
3 |
from utils.auth import AuthService
|
4 |
|
@@ -8,18 +9,20 @@ class LoginPage:
|
|
8 |
|
9 |
def __init__(self):
|
10 |
with gr.Row(visible=True) as self.container:
|
11 |
-
gr.Column(scale=1)
|
12 |
|
13 |
with gr.Column(scale=0) as self.form_col:
|
14 |
# components with min_width control overall width
|
15 |
self.username = gr.Text(label="Username", min_width=300)
|
16 |
-
self.password = gr.Text(
|
|
|
|
|
17 |
self.login_btn = gr.Button("Log in", min_width=300)
|
18 |
|
19 |
# β removed min_width (Markdown doesn't accept it)
|
20 |
self.message = gr.Markdown()
|
21 |
|
22 |
-
gr.Column(scale=1)
|
23 |
|
24 |
# event wiring unchanged β¦
|
25 |
def register_callbacks(self, dashboard_page, session_state):
|
@@ -34,4 +37,4 @@ class LoginPage:
|
|
34 |
lambda s: f"### User: {s.get('user', '')}",
|
35 |
inputs=session_state,
|
36 |
outputs=header.welcome,
|
37 |
-
)
|
|
|
1 |
# components/login_page.py
|
2 |
+
|
3 |
import gradio as gr
|
4 |
from utils.auth import AuthService
|
5 |
|
|
|
9 |
|
10 |
def __init__(self):
|
11 |
with gr.Row(visible=True) as self.container:
|
12 |
+
gr.Column(scale=1) # left spacer
|
13 |
|
14 |
with gr.Column(scale=0) as self.form_col:
|
15 |
# components with min_width control overall width
|
16 |
self.username = gr.Text(label="Username", min_width=300)
|
17 |
+
self.password = gr.Text(
|
18 |
+
label="Password", type="password", min_width=300
|
19 |
+
)
|
20 |
self.login_btn = gr.Button("Log in", min_width=300)
|
21 |
|
22 |
# β removed min_width (Markdown doesn't accept it)
|
23 |
self.message = gr.Markdown()
|
24 |
|
25 |
+
gr.Column(scale=1) # right spacer
|
26 |
|
27 |
# event wiring unchanged β¦
|
28 |
def register_callbacks(self, dashboard_page, session_state):
|
|
|
37 |
lambda s: f"### User: {s.get('user', '')}",
|
38 |
inputs=session_state,
|
39 |
outputs=header.welcome,
|
40 |
+
)
|
test/test.py
CHANGED
@@ -1,96 +0,0 @@
|
|
1 |
-
import gradio as gr
|
2 |
-
|
3 |
-
USERS = {"u1": "123", "u2": "234"}
|
4 |
-
|
5 |
-
|
6 |
-
def local_login(username: str, password: str, session: dict):
|
7 |
-
"""Authenticate against the in-memory USERS dict."""
|
8 |
-
if USERS.get(username) != password:
|
9 |
-
return (
|
10 |
-
"β Wrong username or password!",
|
11 |
-
gr.update(), # keep login form unchanged
|
12 |
-
gr.update(visible=False), # hide dashboard
|
13 |
-
)
|
14 |
-
|
15 |
-
# Successful login
|
16 |
-
session["user"] = username
|
17 |
-
return (
|
18 |
-
f"β
Hello *{username}*",
|
19 |
-
gr.update(visible=False), # hide login form
|
20 |
-
gr.update(visible=True), # show dashboard
|
21 |
-
)
|
22 |
-
|
23 |
-
|
24 |
-
# --- 1. Update the logout function -----------------------------------------
|
25 |
-
def local_logout(session: dict):
|
26 |
-
"""Clear the session, show the login form, hide the dashboard,
|
27 |
-
and clear any previous login message."""
|
28 |
-
session.clear()
|
29 |
-
return (
|
30 |
-
gr.update(visible=True), # show login_form
|
31 |
-
gr.update(visible=False), # hide dashboard
|
32 |
-
gr.update(value=""), # clear login_msg
|
33 |
-
)
|
34 |
-
|
35 |
-
|
36 |
-
def echo_with_user(text: str, session: dict):
|
37 |
-
"""Return 'username: text'."""
|
38 |
-
user = session.get("user", "(none)")
|
39 |
-
return f"{user}: {text}"
|
40 |
-
|
41 |
-
|
42 |
-
def oauth_welcome(profile: gr.OAuthProfile, session: dict):
|
43 |
-
"""Executed after a successful OAuth login."""
|
44 |
-
if profile is None:
|
45 |
-
return gr.update(visible=False)
|
46 |
-
|
47 |
-
session["user"] = profile.username
|
48 |
-
return gr.update(value=f"β
Welcome {profile.username}", visible=True)
|
49 |
-
|
50 |
-
|
51 |
-
with gr.Blocks(title="Multi-user Login Demo") as demo:
|
52 |
-
# Session state is kept per browser tab
|
53 |
-
session = gr.State({})
|
54 |
-
|
55 |
-
# -------------------- Login form --------------------
|
56 |
-
with gr.Column(visible=True) as login_form:
|
57 |
-
username = gr.Text(label="Username")
|
58 |
-
password = gr.Text(label="Password", type="password")
|
59 |
-
login_btn = gr.Button("Log in")
|
60 |
-
login_msg = gr.Markdown()
|
61 |
-
|
62 |
-
# -------------------- Dashboard --------------------
|
63 |
-
with gr.Column(visible=False) as dashboard:
|
64 |
-
welcome = gr.Markdown()
|
65 |
-
echo_box = gr.Textbox(label="Echo β whatever you type will be returned")
|
66 |
-
echo_btn = gr.Button("Echo") # renamed button
|
67 |
-
echo_output = gr.Markdown() # where result is shown
|
68 |
-
logout_btn = gr.Button("Log out")
|
69 |
-
|
70 |
-
# -------------- Callbacks (local DB version) --------
|
71 |
-
login_btn.click(
|
72 |
-
fn=local_login,
|
73 |
-
inputs=[username, password, session],
|
74 |
-
outputs=[login_msg, login_form, dashboard],
|
75 |
-
concurrency_limit=10,
|
76 |
-
).then(
|
77 |
-
lambda s: f"π Active user: {s.get('user', '')}",
|
78 |
-
inputs=session,
|
79 |
-
outputs=welcome,
|
80 |
-
)
|
81 |
-
|
82 |
-
logout_btn.click(
|
83 |
-
fn=local_logout,
|
84 |
-
inputs=session,
|
85 |
-
outputs=[login_form, dashboard, login_msg], # β added login_msg
|
86 |
-
)
|
87 |
-
|
88 |
-
echo_btn.click(
|
89 |
-
fn=echo_with_user,
|
90 |
-
inputs=[echo_box, session],
|
91 |
-
outputs=echo_output,
|
92 |
-
)
|
93 |
-
|
94 |
-
|
95 |
-
demo.queue(default_concurrency_limit=50)
|
96 |
-
demo.launch()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
utils/auth.py
CHANGED
@@ -1,42 +1,42 @@
|
|
1 |
# utils/auth.py
|
|
|
2 |
import gradio as gr
|
|
|
|
|
|
|
3 |
|
4 |
|
5 |
class AuthService:
|
6 |
-
"""
|
7 |
-
Authentication / business-logic layer.
|
8 |
-
Replace with real DB + hashed passwords in production.
|
9 |
-
"""
|
10 |
_USERS = {"u1": "123", "u2": "234"}
|
11 |
|
12 |
# βββββββββββββββββββ core actions ββββββββββββββββββββ
|
13 |
@staticmethod
|
14 |
def login(username: str, password: str, session: dict):
|
|
|
15 |
if AuthService._USERS.get(username) != password:
|
|
|
16 |
return (
|
17 |
"β Wrong username or password!",
|
18 |
-
gr.update(),
|
19 |
gr.update(visible=False), # hide dashboard
|
20 |
)
|
21 |
|
22 |
# success
|
23 |
session["user"] = username
|
|
|
24 |
return (
|
25 |
-
|
26 |
-
gr.update(visible=False),
|
27 |
-
gr.update(visible=True),
|
28 |
)
|
29 |
|
30 |
@staticmethod
|
31 |
def logout(session: dict):
|
|
|
32 |
session.clear()
|
|
|
33 |
return (
|
34 |
-
gr.update(visible=True),
|
35 |
-
gr.update(visible=False),
|
36 |
-
gr.update(value="")
|
37 |
)
|
38 |
-
|
39 |
-
@staticmethod
|
40 |
-
def echo(text: str, session: dict):
|
41 |
-
user = session.get("user", "(none)")
|
42 |
-
return f"{user}: {text}"
|
|
|
1 |
# utils/auth.py
|
2 |
+
|
3 |
import gradio as gr
|
4 |
+
from utils.logger import Logger
|
5 |
+
|
6 |
+
log = Logger()
|
7 |
|
8 |
|
9 |
class AuthService:
|
|
|
|
|
|
|
|
|
10 |
_USERS = {"u1": "123", "u2": "234"}
|
11 |
|
12 |
# βββββββββββββββββββ core actions ββββββββββββββββββββ
|
13 |
@staticmethod
|
14 |
def login(username: str, password: str, session: dict):
|
15 |
+
log.info(f"Login attempt: username={username}")
|
16 |
if AuthService._USERS.get(username) != password:
|
17 |
+
log.warning(f"Failed login for username={username}")
|
18 |
return (
|
19 |
"β Wrong username or password!",
|
20 |
+
gr.update(), # keep login form visible
|
21 |
gr.update(visible=False), # hide dashboard
|
22 |
)
|
23 |
|
24 |
# success
|
25 |
session["user"] = username
|
26 |
+
log.info(f"User '{username}' logged in successfully.")
|
27 |
return (
|
28 |
+
None,
|
29 |
+
gr.update(visible=False), # hide login form
|
30 |
+
gr.update(visible=True), # show dashboard
|
31 |
)
|
32 |
|
33 |
@staticmethod
|
34 |
def logout(session: dict):
|
35 |
+
username = session.get("user", "unknown")
|
36 |
session.clear()
|
37 |
+
log.info(f"User '{username}' logged out.")
|
38 |
return (
|
39 |
+
gr.update(visible=True), # show login page
|
40 |
+
gr.update(visible=False), # hide dashboard
|
41 |
+
gr.update(value=""), # clear old messages
|
42 |
)
|
|
|
|
|
|
|
|
|
|
utils/database.py
CHANGED
@@ -4,7 +4,7 @@ from contextlib import contextmanager
|
|
4 |
from config import conf
|
5 |
from utils.logger import Logger
|
6 |
|
7 |
-
log = Logger
|
8 |
|
9 |
|
10 |
def get_db_engine():
|
|
|
4 |
from config import conf
|
5 |
from utils.logger import Logger
|
6 |
|
7 |
+
log = Logger()
|
8 |
|
9 |
|
10 |
def get_db_engine():
|
utils/logger.py
CHANGED
@@ -1,39 +1,15 @@
|
|
1 |
-
import
|
2 |
-
import sys
|
3 |
-
from typing import Optional
|
4 |
-
|
5 |
|
6 |
class Logger:
|
7 |
-
|
8 |
-
|
9 |
-
|
10 |
-
def initialize(cls, level: str = "INFO", name: Optional[str] = None):
|
11 |
-
if cls._initialized:
|
12 |
-
return
|
13 |
-
|
14 |
-
logger = logging.getLogger(name or __name__)
|
15 |
-
logger.setLevel(level)
|
16 |
-
|
17 |
-
# Create console handler
|
18 |
-
handler = logging.StreamHandler(sys.stdout)
|
19 |
-
handler.setLevel(level)
|
20 |
-
|
21 |
-
# Simple formatter
|
22 |
-
formatter = logging.Formatter(
|
23 |
-
"%(asctime)s - %(name)s - %(levelname)s - %(message)s",
|
24 |
-
datefmt="%Y-%m-%d %H:%M:%S",
|
25 |
-
)
|
26 |
-
handler.setFormatter(formatter)
|
27 |
|
28 |
-
|
29 |
-
|
30 |
-
logger.addHandler(handler)
|
31 |
|
32 |
-
|
33 |
-
|
34 |
|
35 |
-
|
36 |
-
|
37 |
-
if not cls._initialized:
|
38 |
-
cls.initialize()
|
39 |
-
return logging.getLogger(name or __name__)
|
|
|
1 |
+
from datetime import datetime
|
|
|
|
|
|
|
2 |
|
3 |
class Logger:
|
4 |
+
def _log(self, level, message):
|
5 |
+
now = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
|
6 |
+
print(f"[{now}] [{level.upper()}] {message}")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
7 |
|
8 |
+
def info(self, message):
|
9 |
+
self._log('info', message)
|
|
|
10 |
|
11 |
+
def warning(self, message):
|
12 |
+
self._log('warning', message)
|
13 |
|
14 |
+
def error(self, message):
|
15 |
+
self._log('error', message)
|
|
|
|
|
|