Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -13,6 +13,7 @@ from datetime import datetime
|
|
| 13 |
from typing import Optional
|
| 14 |
|
| 15 |
import gradio as gr
|
|
|
|
| 16 |
|
| 17 |
# Import our CBT knowledge base
|
| 18 |
from cbt_knowledge import (
|
|
@@ -29,7 +30,8 @@ try:
|
|
| 29 |
from agents import CBTAgent
|
| 30 |
|
| 31 |
AGENT_AVAILABLE = True
|
| 32 |
-
except Exception:
|
|
|
|
| 33 |
CBTAgent = None # type: ignore
|
| 34 |
AGENT_AVAILABLE = False
|
| 35 |
|
|
@@ -44,7 +46,7 @@ def load_translations():
|
|
| 44 |
translations[lang] = json.load(f)
|
| 45 |
except FileNotFoundError:
|
| 46 |
# Fallback to embedded translations if files don't exist
|
| 47 |
-
|
| 48 |
|
| 49 |
# Fallback translations
|
| 50 |
if 'en' not in translations:
|
|
@@ -185,7 +187,7 @@ class CBTChatbot:
|
|
| 185 |
message: str,
|
| 186 |
history: list[list[str]],
|
| 187 |
use_agent: bool = False,
|
| 188 |
-
agent: Optional[
|
| 189 |
) -> tuple[list[list[str]], str, str, str]:
|
| 190 |
"""
|
| 191 |
Process user message and generate response with CBT analysis
|
|
@@ -332,6 +334,55 @@ def create_app(language='en'):
|
|
| 332 |
distortions_output = gr.Markdown(label="Patterns Detected")
|
| 333 |
reframe_output = gr.Markdown(label="Reframe Suggestion")
|
| 334 |
situations_output = gr.Markdown(label="Similar Situations")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 335 |
|
| 336 |
# Internal state for agent instance, selected model, and agentic enable flag
|
| 337 |
agent_state = gr.State(value=None)
|
|
@@ -510,7 +561,8 @@ def create_app(language='en'):
|
|
| 510 |
username = prof[key]
|
| 511 |
if username:
|
| 512 |
break
|
| 513 |
-
except Exception:
|
|
|
|
| 514 |
pass
|
| 515 |
raw = f"oauth:{username or 'unknown'}"
|
| 516 |
# req is expected to be provided by Gradio
|
|
@@ -526,17 +578,12 @@ def create_app(language='en'):
|
|
| 526 |
sess = getattr(req, "session_hash", None) or "?"
|
| 527 |
raw = f"ipua:{ip}|{ua}|{sess}"
|
| 528 |
return hashlib.sha256(f"{salt}|{raw}".encode()).hexdigest()
|
| 529 |
-
except Exception:
|
|
|
|
| 530 |
return "anon"
|
| 531 |
|
| 532 |
user_id = _user_id(request, profile)
|
| 533 |
-
|
| 534 |
-
try:
|
| 535 |
-
interactions_before = _interactions_today(user_id)
|
| 536 |
-
except Exception:
|
| 537 |
-
interactions_before = 0
|
| 538 |
-
|
| 539 |
-
# Per-user interaction quota (counts 1 per message)
|
| 540 |
def _interactions_today(uid: str) -> int:
|
| 541 |
data = _load_call_log()
|
| 542 |
day = _today_key()
|
|
@@ -547,15 +594,13 @@ def create_app(language='en'):
|
|
| 547 |
else {}
|
| 548 |
)
|
| 549 |
val = inter.get(uid, 0)
|
| 550 |
-
# Validar tipo antes de convertir
|
| 551 |
if isinstance(val, (str, int, float)):
|
| 552 |
try:
|
| 553 |
return int(val)
|
| 554 |
-
except Exception:
|
|
|
|
| 555 |
return 0
|
| 556 |
-
|
| 557 |
-
return 0
|
| 558 |
-
|
| 559 |
|
| 560 |
def _inc_interactions_today(uid: str):
|
| 561 |
data = _load_call_log()
|
|
@@ -571,6 +616,14 @@ def create_app(language='en'):
|
|
| 571 |
data[day] = day_blob
|
| 572 |
_save_call_log(data)
|
| 573 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 574 |
max_interactions_env = os.getenv("HF_AGENT_MAX_INTERACTIONS_PER_USER")
|
| 575 |
try:
|
| 576 |
# Default to a generous 12 if not configured
|
|
@@ -826,10 +879,10 @@ def create_app(language='en'):
|
|
| 826 |
billing_notice,
|
| 827 |
agentic_enabled_state,
|
| 828 |
],
|
| 829 |
-
).then(clear_input, outputs=[msg_input])
|
| 830 |
|
| 831 |
send_btn.click(
|
| 832 |
-
respond_stream,
|
| 833 |
inputs=[
|
| 834 |
msg_input,
|
| 835 |
chatbot_ui,
|
|
@@ -854,7 +907,7 @@ def create_app(language='en'):
|
|
| 854 |
return h, d, r, s, ""
|
| 855 |
|
| 856 |
clear_btn.click(
|
| 857 |
-
_clear_session_and_notice,
|
| 858 |
outputs=[
|
| 859 |
chatbot_ui,
|
| 860 |
distortions_output,
|
|
@@ -868,50 +921,10 @@ def create_app(language='en'):
|
|
| 868 |
with gr.Tab(t['learn']['title']):
|
| 869 |
create_learn_tab(t['learn'], COGNITIVE_DISTORTIONS)
|
| 870 |
|
| 871 |
-
|
| 872 |
-
with gr.Tab("Owner", visible=False) as owner_tab:
|
| 873 |
-
# Locked panel shown to non-admins
|
| 874 |
-
locked_panel = gr.Column(visible=True)
|
| 875 |
-
with locked_panel:
|
| 876 |
-
gr.Markdown("### Owner only\nPlease log in with your Hugging Face account.")
|
| 877 |
-
|
| 878 |
-
# Admin panel
|
| 879 |
-
admin_panel = gr.Column(visible=False)
|
| 880 |
-
with admin_panel:
|
| 881 |
-
gr.Markdown("## Admin Dashboard")
|
| 882 |
-
admin_summary = gr.Markdown("")
|
| 883 |
-
admin_limit_info = gr.Markdown("")
|
| 884 |
-
# Owner-only model selection
|
| 885 |
-
model_dropdown = gr.Dropdown(
|
| 886 |
-
label="Model (HF)",
|
| 887 |
-
choices=[
|
| 888 |
-
"meta-llama/Llama-3.1-8B-Instruct",
|
| 889 |
-
"meta-llama/Llama-3.1-70B-Instruct",
|
| 890 |
-
"Qwen/Qwen2.5-7B-Instruct",
|
| 891 |
-
"mistralai/Mixtral-8x7B-Instruct-v0.1",
|
| 892 |
-
"google/gemma-2-9b-it",
|
| 893 |
-
],
|
| 894 |
-
value=os.getenv("MODEL_NAME", "meta-llama/Llama-3.1-8B-Instruct"),
|
| 895 |
-
allow_custom_value=True,
|
| 896 |
-
info="Only visible to owner. Requires HF Inference API token.",
|
| 897 |
-
)
|
| 898 |
-
with gr.Row():
|
| 899 |
-
override_tb = gr.Textbox(
|
| 900 |
-
label="Per-user interaction limit override (blank to clear)"
|
| 901 |
-
)
|
| 902 |
-
set_override_btn = gr.Button("Set Limit Override", variant="secondary")
|
| 903 |
-
refresh_btn = gr.Button("Refresh Metrics", variant="secondary")
|
| 904 |
-
|
| 905 |
-
gr.Markdown("### Debug")
|
| 906 |
-
owner_identity_md = gr.Markdown("")
|
| 907 |
-
with gr.Row():
|
| 908 |
-
identity_btn = gr.Button("Refresh Identity", variant="secondary")
|
| 909 |
-
storage_btn = gr.Button("Check /data", variant="secondary")
|
| 910 |
-
storage_info_md = gr.Markdown("")
|
| 911 |
-
|
| 912 |
-
def _owner_is(profile: "gr.OAuthProfile | None") -> bool:
|
| 913 |
try:
|
| 914 |
-
# Prefer explicit OWNER_USER, fallback to the Space author
|
|
|
|
| 915 |
owner = (
|
| 916 |
os.getenv("OWNER_USER")
|
| 917 |
or os.getenv("SPACE_AUTHOR_NAME")
|
|
@@ -919,7 +932,7 @@ def create_app(language='en'):
|
|
| 919 |
).strip().lower()
|
| 920 |
if not owner:
|
| 921 |
return False
|
| 922 |
-
# Try common profile fields
|
| 923 |
username = None
|
| 924 |
for key in ("preferred_username", "username", "login", "name", "sub", "id"):
|
| 925 |
try:
|
|
@@ -929,12 +942,21 @@ def create_app(language='en'):
|
|
| 929 |
username = profile[key]
|
| 930 |
if username:
|
| 931 |
break
|
| 932 |
-
except Exception:
|
|
|
|
| 933 |
pass
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 934 |
if not username:
|
| 935 |
return False
|
| 936 |
return str(username).lower() == owner
|
| 937 |
-
except Exception:
|
|
|
|
| 938 |
return False
|
| 939 |
|
| 940 |
def _metrics_paths():
|
|
@@ -1007,18 +1029,6 @@ def create_app(language='en'):
|
|
| 1007 |
f"{override if override else 'None'})"
|
| 1008 |
)
|
| 1009 |
|
| 1010 |
-
def show_admin(profile: "gr.OAuthProfile | None"):
|
| 1011 |
-
visible = _owner_is(profile)
|
| 1012 |
-
return (
|
| 1013 |
-
gr.update(visible=visible), # owner_tab
|
| 1014 |
-
gr.update(visible=visible), # admin_panel
|
| 1015 |
-
gr.update(visible=not visible), # locked_panel
|
| 1016 |
-
_summarize_metrics_md() if visible else "",
|
| 1017 |
-
_limit_info_md(admin_state.value if hasattr(admin_state, "value") else None)
|
| 1018 |
-
if visible
|
| 1019 |
-
else "",
|
| 1020 |
-
)
|
| 1021 |
-
|
| 1022 |
def admin_set_limit(override_text: str, settings: dict | None):
|
| 1023 |
# Only update runtime state; does not change env var
|
| 1024 |
try:
|
|
@@ -1030,14 +1040,15 @@ def create_app(language='en'):
|
|
| 1030 |
if override <= 0:
|
| 1031 |
override = None
|
| 1032 |
settings["per_user_limit_override"] = override
|
| 1033 |
-
except Exception:
|
|
|
|
| 1034 |
settings = {"per_user_limit_override": None}
|
| 1035 |
return settings, _limit_info_md(settings)
|
| 1036 |
|
| 1037 |
def admin_refresh():
|
| 1038 |
return _summarize_metrics_md()
|
| 1039 |
|
| 1040 |
-
def _profile_username(profile: gr.OAuthProfile | None) -> str:
|
| 1041 |
try:
|
| 1042 |
for key in ("preferred_username", "username", "login", "name", "sub", "id"):
|
| 1043 |
if hasattr(profile, key):
|
|
@@ -1046,22 +1057,29 @@ def create_app(language='en'):
|
|
| 1046 |
return str(v)
|
| 1047 |
elif isinstance(profile, dict) and key in profile and profile[key]:
|
| 1048 |
return str(profile[key])
|
| 1049 |
-
except Exception:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1050 |
pass
|
| 1051 |
return "unknown"
|
| 1052 |
|
| 1053 |
-
def identity_refresh(profile: gr.OAuthProfile | None):
|
| 1054 |
-
viewer = _profile_username(profile)
|
| 1055 |
-
visible = _owner_is(profile)
|
| 1056 |
token_info = ""
|
| 1057 |
-
try:
|
| 1058 |
-
from huggingface_hub import whoami as _hf_whoami # local import
|
| 1059 |
info = _hf_whoami()
|
| 1060 |
uname = info.get("name") or info.get("fullname") or "?"
|
| 1061 |
ttype = info.get("type", "?")
|
| 1062 |
orgs = ", ".join([o.get("name", "?") for o in info.get("orgs", [])])
|
| 1063 |
token_info = f"Token user: `{uname}` (type: {ttype}); orgs: [{orgs}]"
|
| 1064 |
except Exception as e:
|
|
|
|
| 1065 |
token_info = f"Token whoami failed: {e}"
|
| 1066 |
return (
|
| 1067 |
f"Logged in as (OAuth): `{viewer}`\n\n"
|
|
@@ -1095,22 +1113,22 @@ def create_app(language='en'):
|
|
| 1095 |
return f"/data check failed: {e}"
|
| 1096 |
|
| 1097 |
# Wire admin interactions
|
| 1098 |
-
model_dropdown.change(lambda v: v, inputs=[model_dropdown], outputs=[model_state])
|
| 1099 |
set_override_btn.click(
|
| 1100 |
-
admin_set_limit,
|
| 1101 |
inputs=[override_tb, admin_state],
|
| 1102 |
outputs=[admin_state, admin_limit_info],
|
| 1103 |
)
|
| 1104 |
-
refresh_btn.click(admin_refresh, outputs=[admin_summary])
|
| 1105 |
-
identity_btn.click(identity_refresh, outputs=[owner_identity_md])
|
| 1106 |
-
storage_btn.click(storage_check, outputs=[storage_info_md])
|
| 1107 |
|
| 1108 |
-
# Gate
|
| 1109 |
try:
|
| 1110 |
# Also populate identity + storage placeholders
|
| 1111 |
-
def _load(profile:
|
| 1112 |
-
visible = _owner_is(profile)
|
| 1113 |
-
ident = identity_refresh(profile) if visible else ""
|
| 1114 |
return (
|
| 1115 |
gr.update(visible=visible),
|
| 1116 |
gr.update(visible=visible),
|
|
@@ -1125,9 +1143,11 @@ def create_app(language='en'):
|
|
| 1125 |
|
| 1126 |
app.load(
|
| 1127 |
_load,
|
| 1128 |
-
outputs=[
|
|
|
|
| 1129 |
)
|
| 1130 |
-
except Exception:
|
|
|
|
| 1131 |
# If OAuth not available, keep admin hidden
|
| 1132 |
pass
|
| 1133 |
|
|
|
|
| 13 |
from typing import Optional
|
| 14 |
|
| 15 |
import gradio as gr
|
| 16 |
+
from huggingface_hub import whoami as _hf_whoami
|
| 17 |
|
| 18 |
# Import our CBT knowledge base
|
| 19 |
from cbt_knowledge import (
|
|
|
|
| 30 |
from agents import CBTAgent
|
| 31 |
|
| 32 |
AGENT_AVAILABLE = True
|
| 33 |
+
except Exception as e:
|
| 34 |
+
print(f"Error importing CBTAgent: {e}")
|
| 35 |
CBTAgent = None # type: ignore
|
| 36 |
AGENT_AVAILABLE = False
|
| 37 |
|
|
|
|
| 46 |
translations[lang] = json.load(f)
|
| 47 |
except FileNotFoundError:
|
| 48 |
# Fallback to embedded translations if files don't exist
|
| 49 |
+
print(f"Error loading translations for {lang}: FileNotFoundError")
|
| 50 |
|
| 51 |
# Fallback translations
|
| 52 |
if 'en' not in translations:
|
|
|
|
| 187 |
message: str,
|
| 188 |
history: list[list[str]],
|
| 189 |
use_agent: bool = False,
|
| 190 |
+
agent: Optional[CBTAgent] = None,
|
| 191 |
) -> tuple[list[list[str]], str, str, str]:
|
| 192 |
"""
|
| 193 |
Process user message and generate response with CBT analysis
|
|
|
|
| 334 |
distortions_output = gr.Markdown(label="Patterns Detected")
|
| 335 |
reframe_output = gr.Markdown(label="Reframe Suggestion")
|
| 336 |
situations_output = gr.Markdown(label="Similar Situations")
|
| 337 |
+
# Owner-only Admin controls (gated at load)
|
| 338 |
+
admin_accordion = gr.Accordion(
|
| 339 |
+
"Owner Controls", open=False, visible=False
|
| 340 |
+
)
|
| 341 |
+
with admin_accordion:
|
| 342 |
+
# Locked message for non-owners (kept hidden unless needed)
|
| 343 |
+
chat_locked_panel = gr.Markdown(
|
| 344 |
+
"### Owner only\nPlease log in with your Hugging Face account.",
|
| 345 |
+
visible=False,
|
| 346 |
+
)
|
| 347 |
+
chat_admin_panel = gr.Column(visible=False)
|
| 348 |
+
with chat_admin_panel:
|
| 349 |
+
gr.Markdown("## Admin Dashboard")
|
| 350 |
+
admin_summary = gr.Markdown("")
|
| 351 |
+
admin_limit_info = gr.Markdown("")
|
| 352 |
+
# Owner-only model selection
|
| 353 |
+
model_dropdown = gr.Dropdown(
|
| 354 |
+
label="Model (HF)",
|
| 355 |
+
choices=[
|
| 356 |
+
"meta-llama/Llama-3.1-8B-Instruct",
|
| 357 |
+
"meta-llama/Llama-3.1-70B-Instruct",
|
| 358 |
+
"Qwen/Qwen2.5-7B-Instruct",
|
| 359 |
+
"mistralai/Mixtral-8x7B-Instruct-v0.1",
|
| 360 |
+
"google/gemma-2-9b-it",
|
| 361 |
+
],
|
| 362 |
+
value=os.getenv("MODEL_NAME", "meta-llama/Llama-3.1-8B-Instruct"),
|
| 363 |
+
allow_custom_value=True,
|
| 364 |
+
info="Only visible to owner. Requires HF Inference API token.",
|
| 365 |
+
)
|
| 366 |
+
with gr.Row():
|
| 367 |
+
override_tb = gr.Textbox(
|
| 368 |
+
label="Per-user interaction limit override (blank to clear)"
|
| 369 |
+
)
|
| 370 |
+
set_override_btn = gr.Button(
|
| 371 |
+
"Set Limit Override", variant="secondary"
|
| 372 |
+
)
|
| 373 |
+
refresh_btn = gr.Button(
|
| 374 |
+
"Refresh Metrics", variant="secondary"
|
| 375 |
+
)
|
| 376 |
+
gr.Markdown("### Debug")
|
| 377 |
+
owner_identity_md = gr.Markdown("")
|
| 378 |
+
with gr.Row():
|
| 379 |
+
identity_btn = gr.Button(
|
| 380 |
+
"Refresh Identity", variant="secondary"
|
| 381 |
+
)
|
| 382 |
+
storage_btn = gr.Button(
|
| 383 |
+
"Check /data", variant="secondary"
|
| 384 |
+
)
|
| 385 |
+
storage_info_md = gr.Markdown("")
|
| 386 |
|
| 387 |
# Internal state for agent instance, selected model, and agentic enable flag
|
| 388 |
agent_state = gr.State(value=None)
|
|
|
|
| 561 |
username = prof[key]
|
| 562 |
if username:
|
| 563 |
break
|
| 564 |
+
except Exception as e:
|
| 565 |
+
print(f"Error getting username from profile: {e}")
|
| 566 |
pass
|
| 567 |
raw = f"oauth:{username or 'unknown'}"
|
| 568 |
# req is expected to be provided by Gradio
|
|
|
|
| 578 |
sess = getattr(req, "session_hash", None) or "?"
|
| 579 |
raw = f"ipua:{ip}|{ua}|{sess}"
|
| 580 |
return hashlib.sha256(f"{salt}|{raw}".encode()).hexdigest()
|
| 581 |
+
except Exception as e:
|
| 582 |
+
print(f"Error getting user id: {e}")
|
| 583 |
return "anon"
|
| 584 |
|
| 585 |
user_id = _user_id(request, profile)
|
| 586 |
+
# Helper functions for tracking per-user interactions
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 587 |
def _interactions_today(uid: str) -> int:
|
| 588 |
data = _load_call_log()
|
| 589 |
day = _today_key()
|
|
|
|
| 594 |
else {}
|
| 595 |
)
|
| 596 |
val = inter.get(uid, 0)
|
|
|
|
| 597 |
if isinstance(val, (str, int, float)):
|
| 598 |
try:
|
| 599 |
return int(val)
|
| 600 |
+
except Exception as e:
|
| 601 |
+
print(f"Error getting interactions today: {e}")
|
| 602 |
return 0
|
| 603 |
+
return 0
|
|
|
|
|
|
|
| 604 |
|
| 605 |
def _inc_interactions_today(uid: str):
|
| 606 |
data = _load_call_log()
|
|
|
|
| 616 |
data[day] = day_blob
|
| 617 |
_save_call_log(data)
|
| 618 |
|
| 619 |
+
# Determine how many interactions the user has already had today
|
| 620 |
+
try:
|
| 621 |
+
interactions_before = _interactions_today(user_id)
|
| 622 |
+
except Exception as e:
|
| 623 |
+
print(f"Error getting interactions today: {e}")
|
| 624 |
+
interactions_before = 0
|
| 625 |
+
|
| 626 |
+
# Per-user interaction quota (counts 1 per message)
|
| 627 |
max_interactions_env = os.getenv("HF_AGENT_MAX_INTERACTIONS_PER_USER")
|
| 628 |
try:
|
| 629 |
# Default to a generous 12 if not configured
|
|
|
|
| 879 |
billing_notice,
|
| 880 |
agentic_enabled_state,
|
| 881 |
],
|
| 882 |
+
).then(fn=clear_input, outputs=[msg_input])
|
| 883 |
|
| 884 |
send_btn.click(
|
| 885 |
+
fn=respond_stream,
|
| 886 |
inputs=[
|
| 887 |
msg_input,
|
| 888 |
chatbot_ui,
|
|
|
|
| 907 |
return h, d, r, s, ""
|
| 908 |
|
| 909 |
clear_btn.click(
|
| 910 |
+
fn=_clear_session_and_notice,
|
| 911 |
outputs=[
|
| 912 |
chatbot_ui,
|
| 913 |
distortions_output,
|
|
|
|
| 921 |
with gr.Tab(t['learn']['title']):
|
| 922 |
create_learn_tab(t['learn'], COGNITIVE_DISTORTIONS)
|
| 923 |
|
| 924 |
+
def _owner_is(profile: gr.OAuthProfile | None, request: gr.Request | None = None) -> bool:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 925 |
try:
|
| 926 |
+
# Prefer explicit OWNER_USER, fallback to the Space author
|
| 927 |
+
# (useful if OWNER_USER not set)
|
| 928 |
owner = (
|
| 929 |
os.getenv("OWNER_USER")
|
| 930 |
or os.getenv("SPACE_AUTHOR_NAME")
|
|
|
|
| 932 |
).strip().lower()
|
| 933 |
if not owner:
|
| 934 |
return False
|
| 935 |
+
# Try common OAuth profile fields
|
| 936 |
username = None
|
| 937 |
for key in ("preferred_username", "username", "login", "name", "sub", "id"):
|
| 938 |
try:
|
|
|
|
| 942 |
username = profile[key]
|
| 943 |
if username:
|
| 944 |
break
|
| 945 |
+
except Exception as e:
|
| 946 |
+
print(f"Error getting username from profile: {e}")
|
| 947 |
pass
|
| 948 |
+
# Fallback to request.username provided by Gradio when OAuth is enabled
|
| 949 |
+
if not username and request is not None:
|
| 950 |
+
try:
|
| 951 |
+
username = getattr(request, "username", None)
|
| 952 |
+
except Exception as e:
|
| 953 |
+
print(f"Error getting username from request: {e}")
|
| 954 |
+
username = None
|
| 955 |
if not username:
|
| 956 |
return False
|
| 957 |
return str(username).lower() == owner
|
| 958 |
+
except Exception as e:
|
| 959 |
+
print(f"Error checking owner: {e}")
|
| 960 |
return False
|
| 961 |
|
| 962 |
def _metrics_paths():
|
|
|
|
| 1029 |
f"{override if override else 'None'})"
|
| 1030 |
)
|
| 1031 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1032 |
def admin_set_limit(override_text: str, settings: dict | None):
|
| 1033 |
# Only update runtime state; does not change env var
|
| 1034 |
try:
|
|
|
|
| 1040 |
if override <= 0:
|
| 1041 |
override = None
|
| 1042 |
settings["per_user_limit_override"] = override
|
| 1043 |
+
except Exception as e:
|
| 1044 |
+
print(f"Error setting limit override: {e}")
|
| 1045 |
settings = {"per_user_limit_override": None}
|
| 1046 |
return settings, _limit_info_md(settings)
|
| 1047 |
|
| 1048 |
def admin_refresh():
|
| 1049 |
return _summarize_metrics_md()
|
| 1050 |
|
| 1051 |
+
def _profile_username(profile: gr.OAuthProfile | None, request: gr.Request | None = None) -> str:
|
| 1052 |
try:
|
| 1053 |
for key in ("preferred_username", "username", "login", "name", "sub", "id"):
|
| 1054 |
if hasattr(profile, key):
|
|
|
|
| 1057 |
return str(v)
|
| 1058 |
elif isinstance(profile, dict) and key in profile and profile[key]:
|
| 1059 |
return str(profile[key])
|
| 1060 |
+
except Exception as e:
|
| 1061 |
+
print(f"Error getting username from profile: {e}")
|
| 1062 |
+
pass
|
| 1063 |
+
try:
|
| 1064 |
+
if request is not None and getattr(request, "username", None):
|
| 1065 |
+
return str(request.username)
|
| 1066 |
+
except Exception as e:
|
| 1067 |
+
print(f"Error getting username from request: {e}")
|
| 1068 |
pass
|
| 1069 |
return "unknown"
|
| 1070 |
|
| 1071 |
+
def identity_refresh(profile: gr.OAuthProfile | None, request: gr.Request | None = None):
|
| 1072 |
+
viewer = _profile_username(profile, request)
|
| 1073 |
+
visible = _owner_is(profile, request)
|
| 1074 |
token_info = ""
|
| 1075 |
+
try: # local import
|
|
|
|
| 1076 |
info = _hf_whoami()
|
| 1077 |
uname = info.get("name") or info.get("fullname") or "?"
|
| 1078 |
ttype = info.get("type", "?")
|
| 1079 |
orgs = ", ".join([o.get("name", "?") for o in info.get("orgs", [])])
|
| 1080 |
token_info = f"Token user: `{uname}` (type: {ttype}); orgs: [{orgs}]"
|
| 1081 |
except Exception as e:
|
| 1082 |
+
print(f"Error getting token info whoami: {e}")
|
| 1083 |
token_info = f"Token whoami failed: {e}"
|
| 1084 |
return (
|
| 1085 |
f"Logged in as (OAuth): `{viewer}`\n\n"
|
|
|
|
| 1113 |
return f"/data check failed: {e}"
|
| 1114 |
|
| 1115 |
# Wire admin interactions
|
| 1116 |
+
model_dropdown.change(fn=lambda v: v, inputs=[model_dropdown], outputs=[model_state])
|
| 1117 |
set_override_btn.click(
|
| 1118 |
+
fn=admin_set_limit,
|
| 1119 |
inputs=[override_tb, admin_state],
|
| 1120 |
outputs=[admin_state, admin_limit_info],
|
| 1121 |
)
|
| 1122 |
+
refresh_btn.click(fn=admin_refresh, outputs=[admin_summary])
|
| 1123 |
+
identity_btn.click(fn=identity_refresh, outputs=[owner_identity_md])
|
| 1124 |
+
storage_btn.click(fn=storage_check, outputs=[storage_info_md])
|
| 1125 |
|
| 1126 |
+
# Gate admin panel visibility on load (OAuth)
|
| 1127 |
try:
|
| 1128 |
# Also populate identity + storage placeholders
|
| 1129 |
+
def _load(profile: gr.OAuthProfile | None, request: gr.Request | None = None):
|
| 1130 |
+
visible = _owner_is(profile, request)
|
| 1131 |
+
ident = identity_refresh(profile, request) if visible else ""
|
| 1132 |
return (
|
| 1133 |
gr.update(visible=visible),
|
| 1134 |
gr.update(visible=visible),
|
|
|
|
| 1143 |
|
| 1144 |
app.load(
|
| 1145 |
_load,
|
| 1146 |
+
outputs=[admin_accordion, chat_admin_panel, chat_locked_panel, admin_summary,
|
| 1147 |
+
admin_limit_info, owner_identity_md, storage_info_md],
|
| 1148 |
)
|
| 1149 |
+
except Exception as e:
|
| 1150 |
+
print(f"Error loading app: {e}")
|
| 1151 |
# If OAuth not available, keep admin hidden
|
| 1152 |
pass
|
| 1153 |
|