Spaces:
Running
on
CPU Upgrade
Running
on
CPU Upgrade
oauth verification update (big)
Browse files
app.py
CHANGED
@@ -1,41 +1,46 @@
|
|
1 |
-
import
|
|
|
2 |
import csv
|
3 |
-
import datetime
|
4 |
import json
|
|
|
|
|
|
|
|
|
5 |
import logging
|
6 |
-
import os
|
7 |
import os.path
|
8 |
-
import
|
9 |
-
import
|
|
|
|
|
10 |
import threading
|
11 |
-
import time
|
12 |
-
|
13 |
-
import discord
|
14 |
-
import gradio as gr
|
15 |
import gradio_client
|
16 |
-
|
17 |
import numpy as np
|
18 |
import pandas as pd
|
19 |
-
import
|
20 |
import plotly.graph_objects as go
|
21 |
|
|
|
22 |
from requests import HTTPError
|
23 |
-
from
|
24 |
-
from apscheduler.schedulers.background import BackgroundScheduler
|
25 |
from discord import Color, Embed
|
|
|
26 |
from discord.ext import commands, tasks
|
27 |
-
from
|
28 |
-
from
|
29 |
from gspread_formatting.dataframe import format_with_dataframe
|
|
|
|
|
30 |
from huggingface_hub import HfApi, list_liked_repos, list_metrics, list_models
|
31 |
-
from tabulate import tabulate
|
32 |
-
from datetime import datetime, timedelta
|
33 |
-
|
34 |
|
35 |
DISCORD_TOKEN = os.environ.get("DISCORD_TOKEN", None)
|
36 |
intents = discord.Intents.all()
|
37 |
bot = commands.Bot(command_prefix='!', intents=intents)
|
38 |
|
|
|
|
|
|
|
|
|
39 |
|
40 |
""""""
|
41 |
XP_PER_MESSAGE = 10 # 100k messages = 1M exp = lvl 100
|
@@ -60,6 +65,31 @@ community_global_df_gradio = pd.DataFrame()
|
|
60 |
test_merge = pd.read_csv("https://docs.google.com/spreadsheets/d/1C8aLqgCqLYcMiIFf-P_Aosaa03C_WLIB_UyqvjSdWg8/export?format=csv&gid=0")
|
61 |
|
62 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
63 |
@bot.event
|
64 |
async def on_ready():
|
65 |
try:
|
@@ -67,6 +97,22 @@ async def on_ready():
|
|
67 |
await asyncio.sleep(1.1)
|
68 |
print(f'Logged in as {bot.user.name}')
|
69 |
print(f"XP_PER_MESSAGE: {XP_PER_MESSAGE}")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
70 |
|
71 |
"""import data from google sheets -> HF Space df (doesn't make API call this way, as it's read-only)"""
|
72 |
global_df = test_merge
|
@@ -466,7 +512,6 @@ async def add_exp(member_id):
|
|
466 |
|
467 |
@bot.event
|
468 |
async def on_message(message):
|
469 |
-
global global_df
|
470 |
org_link = "https://huggingface.co/organizations/discord-community/share/wPKRAHYbAlaEaCxUxcqVyaaaeZcYagDvqc"
|
471 |
invite_message = "Click to join our community org on the HF Hub!"
|
472 |
try:
|
@@ -478,109 +523,8 @@ async def on_message(message):
|
|
478 |
# add check for verification
|
479 |
if message.content.find("!help") != -1:
|
480 |
await message.channel.send(
|
481 |
-
"To verify your π€ account,
|
482 |
-
)
|
483 |
-
if message.content.startswith('!auth'):
|
484 |
-
await asyncio.sleep(3)
|
485 |
-
lunar = bot.get_user(811235357663297546)
|
486 |
-
token = message.content.split()[-1].strip()
|
487 |
-
try:
|
488 |
-
user = HfApi().whoami(token)
|
489 |
-
except HTTPError as e:
|
490 |
-
await message.channel.send(f"Error occured when trying to authenticate. Likely invalid API Token. {e}")
|
491 |
-
token = "abc" # reset right after we use to be safe
|
492 |
-
|
493 |
-
if user['type'] == 'org':
|
494 |
-
await message.channel.send(
|
495 |
-
"Authentication failed because you tried to authenticate with an organization's API token. Please authenticate with your User API token instead."
|
496 |
-
)
|
497 |
-
return
|
498 |
-
|
499 |
-
try:
|
500 |
-
server = bot.get_guild(879548962464493619)
|
501 |
-
#role = discord.utils.get(server.roles, name="verified")
|
502 |
-
role = server.get_role(900063512829755413)
|
503 |
-
member = server.get_member(message.author.id)
|
504 |
-
verified_date = datetime.now().strftime("%m/%d/%Y, %H:%M:%S")
|
505 |
-
likes = 0
|
506 |
-
models = 0
|
507 |
-
datasets = 0
|
508 |
-
spaces = 0
|
509 |
-
discussions = 0
|
510 |
-
papers = 0
|
511 |
-
upvotes = 0
|
512 |
-
# important!-----------------------------------------------------------------------------
|
513 |
-
# In order to add verification to a discord account, some important checks must ALL pass:
|
514 |
-
# 1. Discord account should not already have verified role.
|
515 |
-
# 2. hf_user_name should not already exist in the dataframe.
|
516 |
-
# -----> If it does, it means we are trying to link 1 HF account to multiple discord accounts. 1->many is disallowed.
|
517 |
-
|
518 |
-
# check if the member has the verified role (prevent duplicate entries in google sheet)
|
519 |
-
# if users want to change discord / HF accounts, we can deal with that manually
|
520 |
-
if role in member.roles:
|
521 |
-
await message.channel.send(f"{member} already has has the '{role}' role and is already verified! To change discord accounts or HF accounts, contact <@811235357663297546> or adam@huggingface.co")
|
522 |
-
return
|
523 |
-
|
524 |
-
# check if hf_user_name in dataframe:
|
525 |
-
if user['name'] in global_df['hf_user_name'].values:
|
526 |
-
await message.channel.send(f"The HF account {user['name']} is already verified! To change discord accounts or HF accounts, contact <@811235357663297546> or adam@huggingface.co")
|
527 |
-
return
|
528 |
-
|
529 |
-
# check if discord_user_id in dataframe:
|
530 |
-
altered_member_id = "L" + str(member.id) + "L"
|
531 |
-
if altered_member_id in global_df['discord_user_id'].values:
|
532 |
-
|
533 |
-
hf_user_name = global_df.loc[global_df['discord_user_id'] == altered_member_id, 'hf_user_name'].iloc[0]
|
534 |
-
|
535 |
-
if pd.isnull(hf_user_name) or hf_user_name == 'n/a':
|
536 |
-
# empty (no link created yet between discord_user_id and hf_user_name) so we can update
|
537 |
-
global_df.loc[global_df['discord_user_id'] == altered_member_id, 'hf_user_name'] = user['name']
|
538 |
-
global_df.loc[global_df['discord_user_id'] == altered_member_id, 'verified_date'] = verified_date
|
539 |
-
await member.add_roles(role)
|
540 |
-
if role in member.roles:
|
541 |
-
print(f"Updated hf_user_name for id {member.id} | discord_user_name {member} | hf_user_name {user['name']}")
|
542 |
-
await message.channel.send(f"Verification successful! [{member} <---> {user['name']}] π€ {org_link} {invite_message}")
|
543 |
-
await lunar.send(f"Verification successful! [{member} <---> {user['name']}] \nπ€ {org_link} {invite_message}")
|
544 |
-
print(f"Verification successful! [{member} <---> {user['name']}] π€")
|
545 |
-
return
|
546 |
-
else:
|
547 |
-
await message.channel.send(f"The Discord account {member} is already verified! To change discord accounts or HF accounts, contact <@811235357663297546> or adam@huggingface.co")
|
548 |
-
await lunar.send(f"The Discord account {member} is already verified! To change discord accounts or HF accounts, contact <@811235357663297546> or adam@huggingface.co")
|
549 |
-
print(f"The Discord account {member} is already verified! To change discord accounts or HF accounts, contact <@811235357663297546> or adam@huggingface.co")
|
550 |
-
return
|
551 |
-
except Exception as e:
|
552 |
-
print(f"verification Error: {e}")
|
553 |
-
|
554 |
-
# -----------------------------------------------------------------------------------------
|
555 |
-
# If creating new record (edge case)
|
556 |
-
xp = 10
|
557 |
-
discord_exp = "L10L"
|
558 |
-
hub_exp = "L0L"
|
559 |
-
total_exp = "L10L"
|
560 |
-
current_level = calculate_level(xp)
|
561 |
-
|
562 |
-
row_data = [altered_member_id,
|
563 |
-
member.name,
|
564 |
-
discord_exp,
|
565 |
-
current_level,
|
566 |
-
user['name'],
|
567 |
-
"L0L",
|
568 |
-
hub_exp,
|
569 |
-
total_exp,
|
570 |
-
verified_date,
|
571 |
-
likes,
|
572 |
-
models,
|
573 |
-
datasets,
|
574 |
-
spaces,
|
575 |
-
discussions,
|
576 |
-
papers,
|
577 |
-
upvotes]
|
578 |
-
|
579 |
-
global_df.loc[len(global_df.index)] = row_data
|
580 |
-
await member.add_roles(role)
|
581 |
-
if role in member.roles:
|
582 |
-
print(f"New record created for {member}")
|
583 |
-
print("------------------------------------------------------------------------")
|
584 |
await bot.process_commands(message)
|
585 |
except Exception as e:
|
586 |
print(f"on_message Error: {e}")
|
@@ -860,6 +804,85 @@ def create_plot(username, year):
|
|
860 |
|
861 |
return fig
|
862 |
#-------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
863 |
|
864 |
|
865 |
demo = gr.Blocks()
|
@@ -898,6 +921,28 @@ with demo:
|
|
898 |
gr.Markdown("# π How to earn Experience!")
|
899 |
with gr.Row():
|
900 |
gr.DataFrame(get_data2, every=5, interactive=False)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
901 |
with gr.TabItem("π Activity Heatmap", elem_id="activity-heatmap", id=1):
|
902 |
with gr.Row():
|
903 |
username_input = gr.Textbox(label="Enter Username")
|
|
|
1 |
+
import os
|
2 |
+
import re
|
3 |
import csv
|
|
|
4 |
import json
|
5 |
+
import time
|
6 |
+
import random
|
7 |
+
import asyncio
|
8 |
+
import discord
|
9 |
import logging
|
|
|
10 |
import os.path
|
11 |
+
import secrets
|
12 |
+
import gspread
|
13 |
+
import datetime
|
14 |
+
import requests
|
15 |
import threading
|
|
|
|
|
|
|
|
|
16 |
import gradio_client
|
17 |
+
|
18 |
import numpy as np
|
19 |
import pandas as pd
|
20 |
+
import gradio as gr
|
21 |
import plotly.graph_objects as go
|
22 |
|
23 |
+
from tabulate import tabulate
|
24 |
from requests import HTTPError
|
25 |
+
from gradio_client import Client
|
|
|
26 |
from discord import Color, Embed
|
27 |
+
from discord.ui import Button, View
|
28 |
from discord.ext import commands, tasks
|
29 |
+
from datetime import datetime, timedelta
|
30 |
+
from apscheduler.executors.pool import ThreadPoolExecutor
|
31 |
from gspread_formatting.dataframe import format_with_dataframe
|
32 |
+
from apscheduler.schedulers.background import BackgroundScheduler
|
33 |
+
from gspread_dataframe import get_as_dataframe, set_with_dataframe
|
34 |
from huggingface_hub import HfApi, list_liked_repos, list_metrics, list_models
|
|
|
|
|
|
|
35 |
|
36 |
DISCORD_TOKEN = os.environ.get("DISCORD_TOKEN", None)
|
37 |
intents = discord.Intents.all()
|
38 |
bot = commands.Bot(command_prefix='!', intents=intents)
|
39 |
|
40 |
+
GRADIO_APP_URL = "https://huggingface.co/spaces/discord-community/LevelBot"
|
41 |
+
# Dictionary to store user IDs and their corresponding unique strings
|
42 |
+
user_tokens = {}
|
43 |
+
|
44 |
|
45 |
""""""
|
46 |
XP_PER_MESSAGE = 10 # 100k messages = 1M exp = lvl 100
|
|
|
65 |
test_merge = pd.read_csv("https://docs.google.com/spreadsheets/d/1C8aLqgCqLYcMiIFf-P_Aosaa03C_WLIB_UyqvjSdWg8/export?format=csv&gid=0")
|
66 |
|
67 |
|
68 |
+
class DMButton(Button):
|
69 |
+
def __init__(self, label, style):
|
70 |
+
super().__init__(label=label, style=style)
|
71 |
+
|
72 |
+
async def callback(self, interaction: discord.Interaction):
|
73 |
+
# await interaction.user.send(self.message) # this is for DMs, but users may have DMs disabled
|
74 |
+
user_id = interaction.user.id
|
75 |
+
if int(user_id) in user_tokens:
|
76 |
+
del user_tokens[int(user_id)] # always delete all past tokens for a given user when creating new link
|
77 |
+
unique_string = generate_unique_string()
|
78 |
+
user_tokens[user_id] = unique_string
|
79 |
+
unique_link = f"<{GRADIO_APP_URL}?user_id={user_id}&token={unique_string}>"
|
80 |
+
message = f"Login link generated! To complete the verification process:\n- 1 Visit this link,\n- 2 click the 'π€Sign in with Hugging Face' button\n\n{unique_link}"
|
81 |
+
await interaction.response.send_message(message, ephemeral=True)
|
82 |
+
|
83 |
+
|
84 |
+
@bot.command(name='sendbutton')
|
85 |
+
async def send_button(ctx):
|
86 |
+
if ctx.author.id == 811235357663297546:
|
87 |
+
button = DMButton(label="Verify Discord Account", style=discord.ButtonStyle.primary)
|
88 |
+
view = View(timeout=None)
|
89 |
+
view.add_item(button)
|
90 |
+
await ctx.send("Click the button below to generate your verification link:",view=view) #
|
91 |
+
|
92 |
+
|
93 |
@bot.event
|
94 |
async def on_ready():
|
95 |
try:
|
|
|
97 |
await asyncio.sleep(1.1)
|
98 |
print(f'Logged in as {bot.user.name}')
|
99 |
print(f"XP_PER_MESSAGE: {XP_PER_MESSAGE}")
|
100 |
+
|
101 |
+
channel = bot.get_channel(932563860597121054)
|
102 |
+
if channel:
|
103 |
+
try:
|
104 |
+
message = await channel.fetch_message(1269917762327674974)
|
105 |
+
if message:
|
106 |
+
button = DMButton(label="Verify Discord Account", style=discord.ButtonStyle.primary)
|
107 |
+
view = View(timeout=None)
|
108 |
+
view.add_item(button)
|
109 |
+
await message.edit(view=view)
|
110 |
+
print("message edited")
|
111 |
+
except discord.NotFound:
|
112 |
+
print(f"Message with ID {KNOWN_MESSAGE_ID} not found.")
|
113 |
+
except discord.HTTPException as e:
|
114 |
+
print(f"Failed to fetch message with ID {KNOWN_MESSAGE_ID}: {e}")
|
115 |
+
|
116 |
|
117 |
"""import data from google sheets -> HF Space df (doesn't make API call this way, as it's read-only)"""
|
118 |
global_df = test_merge
|
|
|
512 |
|
513 |
@bot.event
|
514 |
async def on_message(message):
|
|
|
515 |
org_link = "https://huggingface.co/organizations/discord-community/share/wPKRAHYbAlaEaCxUxcqVyaaaeZcYagDvqc"
|
516 |
invite_message = "Click to join our community org on the HF Hub!"
|
517 |
try:
|
|
|
523 |
# add check for verification
|
524 |
if message.content.find("!help") != -1:
|
525 |
await message.channel.send(
|
526 |
+
"To verify your π€ account, generate a login link in the verification channel! "
|
527 |
+
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
528 |
await bot.process_commands(message)
|
529 |
except Exception as e:
|
530 |
print(f"on_message Error: {e}")
|
|
|
804 |
|
805 |
return fig
|
806 |
#-------------------------------------------------------------------------------------------------------------------------------
|
807 |
+
async def add_verified_role_to_member(member, role):
|
808 |
+
await member.add_roles(role)
|
809 |
+
|
810 |
+
|
811 |
+
def add_verified_role(member, role):
|
812 |
+
loop = asyncio.get_event_loop()
|
813 |
+
loop.run_until_complete(add_role_to_member(member, role))
|
814 |
+
|
815 |
+
|
816 |
+
async def send_lunar_verification_logs(lunar, member, username)
|
817 |
+
org_link = "https://huggingface.co/organizations/discord-community/share/wPKRAHYbAlaEaCxUxcqVyaaaeZcYagDvqc"
|
818 |
+
invite_message = "Click to join our community org on the HF Hub!"
|
819 |
+
await lunar.send(f"Verification successful! [{member} <---> {username}] \nπ€ {invite_message}\n{org_link} ")
|
820 |
+
|
821 |
+
def send_lunar_verification_logs_def(lunar, member, username)
|
822 |
+
loop = asyncio.get_event_loop()
|
823 |
+
loop.run_until_complete(send_lunar_verification_logs(lunar, member, username))
|
824 |
+
|
825 |
+
def verify_button(profile: gr.OAuthProfile | None, request: gr.Request) -> str:
|
826 |
+
url_str = str(request.url)
|
827 |
+
query_params = parse_qs(urlparse(url_str).query)
|
828 |
+
user_id = query_params.get('user_id', [None])[0]
|
829 |
+
token = query_params.get('token', [None])[0]
|
830 |
+
|
831 |
+
print(f"||| token:{token}||| user_id:{user_id}||| profile:{profile}||| user_tokens:{user_tokens}")
|
832 |
+
|
833 |
+
if user_id is None or token is None:
|
834 |
+
return "# β Invalid link. Generate a new link [here](https://discord.com/channels/879548962464493619/900125909984624713) !"
|
835 |
+
|
836 |
+
if int(user_id) not in user_tokens or user_tokens[int(user_id)] != token:
|
837 |
+
return "# β Invalid or expired link. Generate a new link [here](https://discord.com/channels/879548962464493619/900125909984624713) !"
|
838 |
+
|
839 |
+
if profile is None:
|
840 |
+
return f"# β Not logged in with Hugging Face yet."
|
841 |
+
|
842 |
+
server = bot.get_guild(879548962464493619)
|
843 |
+
role = server.get_role(900063512829755413)
|
844 |
+
member = server.get_member(user_id)
|
845 |
+
verified_date = datetime.now().strftime("%m/%d/%Y, %H:%M:%S")
|
846 |
+
likes = 0
|
847 |
+
models = 0
|
848 |
+
datasets = 0
|
849 |
+
spaces = 0
|
850 |
+
discussions = 0
|
851 |
+
papers = 0
|
852 |
+
upvotes = 0
|
853 |
+
|
854 |
+
# do they have the verified role already?
|
855 |
+
if role in member.roles:
|
856 |
+
return (f" β {member} already has has the '{role}' role! To change discord accounts or HF accounts, contact @lunarflu on discord or adam@huggingface.co")
|
857 |
+
|
858 |
+
|
859 |
+
# check if hf_user_name in dataframe:
|
860 |
+
if profile.username in global_df['hf_user_name'].values:
|
861 |
+
return (f"The HF account {profile.username} is already verified! To change discord accounts or HF accounts, contact @lunarflu or adam@huggingface.co")
|
862 |
+
|
863 |
+
# check if discord_user_id in dataframe:
|
864 |
+
lunar = bot.get_user(811235357663297546)
|
865 |
+
altered_member_id = "L" + str(member.id) + "L"
|
866 |
+
if altered_member_id in global_df['discord_user_id'].values:
|
867 |
+
|
868 |
+
hf_user_name = global_df.loc[global_df['discord_user_id'] == altered_member_id, 'hf_user_name'].iloc[0]
|
869 |
+
|
870 |
+
if pd.isnull(hf_user_name) or hf_user_name == 'n/a':
|
871 |
+
# empty (no link created yet between discord_user_id and hf_user_name) so we can update
|
872 |
+
global_df.loc[global_df['discord_user_id'] == altered_member_id, 'hf_user_name'] = profile.username
|
873 |
+
global_df.loc[global_df['discord_user_id'] == altered_member_id, 'verified_date'] = verified_date
|
874 |
+
add_verified_role(member, role)
|
875 |
+
if role in member.roles:
|
876 |
+
print(f"Updated hf_user_name for id {member.id} | discord_user_name {member} | hf_user_name {user['name']}")
|
877 |
+
return (f" β
Verification successful! [{member} <---> {profile.username}] π€\n{invite_message}\n{org_link} ")
|
878 |
+
send_lunar_verification_logs_def(lunar, member, profile.username)
|
879 |
+
print(f" β
Verification successful! [{member} <---> {profile.username}] π€")
|
880 |
+
else:
|
881 |
+
return (f" β The Discord account {member} is already verified! To change discord accounts or HF accounts, contact @lunarflu or adam@huggingface.co")
|
882 |
+
print(f"The Discord account {member} is already verified! To change discord accounts or HF accounts, contact @lunarflu or adam@huggingface.co")
|
883 |
+
|
884 |
+
# Remove the token after successful verification
|
885 |
+
del user_tokens[int(user_id)]
|
886 |
|
887 |
|
888 |
demo = gr.Blocks()
|
|
|
921 |
gr.Markdown("# π How to earn Experience!")
|
922 |
with gr.Row():
|
923 |
gr.DataFrame(get_data2, every=5, interactive=False)
|
924 |
+
#------------------------------------------------------------------------------
|
925 |
+
with gr.TabItem(" Discord Verification", elem_id="verify-tab", id=2):
|
926 |
+
with gr.Row():
|
927 |
+
login_button = gr.LoginButton()
|
928 |
+
m1 = gr.Markdown()
|
929 |
+
demo.load(verify_button, inputs=None, outputs=m1)
|
930 |
+
|
931 |
+
def check_login_status():
|
932 |
+
try:
|
933 |
+
return login_button.get_session().get("oauth_info", None)
|
934 |
+
except AttributeError:
|
935 |
+
return None
|
936 |
+
|
937 |
+
def check_login_wrapper():
|
938 |
+
session = check_login_status()
|
939 |
+
if session is None:
|
940 |
+
return "Not logged in."
|
941 |
+
else:
|
942 |
+
return f"Logged in as {session.get('username', 'Unknown')}"
|
943 |
+
|
944 |
+
login_button.click(check_login_wrapper, inputs=None, outputs=m1)
|
945 |
+
#------------------------------------------------------------------------------
|
946 |
with gr.TabItem("π Activity Heatmap", elem_id="activity-heatmap", id=1):
|
947 |
with gr.Row():
|
948 |
username_input = gr.Textbox(label="Enter Username")
|