Upload 6 files
Browse files- README.md +50 -5
- database.py +5 -1
- main.py +15 -233
README.md
CHANGED
|
@@ -1,6 +1,51 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
---
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
--
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Hugging Face Space Pinger Bot 🚀
|
| 2 |
+
|
| 3 |
+
A Telegram bot built with **Pyrogram** and **FastAPI** to keep Hugging Face spaces alive by pinging them sequentially every 5 minutes. The database containing authorized users, admins, and space URLs is automatically created and synced to a Hugging Face dataset for persistent storage.
|
| 4 |
+
|
| 5 |
+
## 🛠️ Required Secret Environment Variables
|
| 6 |
+
|
| 7 |
+
When deploying this bot on Hugging Face Spaces (or any Docker platform), you **MUST** configure the following variables in the Space settings (under **Variables and Secrets**):
|
| 8 |
+
|
| 9 |
+
1. **`API_ID`**: The API ID for your Telegram application (get it from [my.telegram.org](https://my.telegram.org)).
|
| 10 |
+
2. **`API_HASH`**: The API Hash for your Telegram application (get it from [my.telegram.org](https://my.telegram.org)).
|
| 11 |
+
3. **`BOT_TOKEN`**: The Telegram Bot Token generated by [@BotFather](https://t.me/BotFather).
|
| 12 |
+
4. **`ADMIN_ID`**: The numeric Telegram ID of the **Super Admin** (e.g., `123456789`). The Super Admin has highest authority (e.g., can remove admins).
|
| 13 |
+
5. **`HF_TOKEN`**: A Hugging Face User Access Token with **WRITE** permissions (generate it under your Hugging Face account settings at [huggingface.co/settings/tokens](https://huggingface.co/settings/tokens)).
|
| 14 |
+
6. **`HF_DATASET_URL`**: The full URL of your Hugging Face dataset repository (e.g. `https://huggingface.co/datasets/your_username/your_dataset_name` or simply the repository ID like `your_username/your_dataset_name`). The bot will automatically create this dataset if it doesn't already exist and maintain `database.json` within it.
|
| 15 |
+
|
| 16 |
---
|
| 17 |
+
|
| 18 |
+
## 🤖 Available Commands
|
| 19 |
+
|
| 20 |
+
### 💬 Public Commands (Anyone)
|
| 21 |
+
- `/id` - View your Telegram User ID (used to request authorization).
|
| 22 |
+
- `/start` - Displays a simple welcome message.
|
| 23 |
+
- `/help` - Explains what the bot does.
|
| 24 |
+
- `/commands` - List commands matching the caller's authorization level.
|
| 25 |
+
|
| 26 |
+
### 👤 Authorized User Commands
|
| 27 |
+
- `/add <hf_url>` - Register a Hugging Face Space URL. (You can also just send a raw Hugging Face URL directly, and the bot will normalize and register it automatically).
|
| 28 |
+
- `/remove <hf_url>` - Remove a Space URL you registered.
|
| 29 |
+
- `/list_url` - List the Space URLs that *you* registered.
|
| 30 |
+
|
| 31 |
+
### 👮 Admin Commands
|
| 32 |
+
- `/add_user <user_id>` - Authorize a user to register and manage their own URLs.
|
| 33 |
+
- `/remove_user <user_id>` - Deauthorize a user.
|
| 34 |
+
- `/add_admin <user_id>` - Promote a user to Admin.
|
| 35 |
+
- `/list_url` - List **ALL** registered Space URLs in the system along with who registered them.
|
| 36 |
+
- `/list` - List all Admins and Users (excluding the Super Admin).
|
| 37 |
+
|
| 38 |
+
### 👑 Super Admin Commands
|
| 39 |
+
- `/remove_admin <user_id>` - Demote an Admin back to a regular user.
|
| 40 |
+
- `/list` - List the Super Admin, all Admins, and all Users.
|
| 41 |
+
|
| 42 |
+
---
|
| 43 |
+
|
| 44 |
+
## 🐳 Deployment to Hugging Face Spaces
|
| 45 |
+
|
| 46 |
+
1. Create a new Space on Hugging Face: [huggingface.co/new-space](https://huggingface.co/new-space).
|
| 47 |
+
2. Choose **Docker** as the SDK.
|
| 48 |
+
3. Select **Blank** (or any Docker template).
|
| 49 |
+
4. Go to the Space **Settings** page and add the **Secrets** listed above.
|
| 50 |
+
5. Push the repository files (`Dockerfile`, `requirements.txt`, `config.py`, `database.py`, `main.py`) to the Space.
|
| 51 |
+
6. The space will automatically build the Docker image, run the FastAPI web server on port `7860`, launch the Telegram bot, and begin the sequential 5-minute pinger loop.
|
database.py
CHANGED
|
@@ -83,7 +83,11 @@ def init_db():
|
|
| 83 |
|
| 84 |
print("Successfully synced database from Hugging Face.")
|
| 85 |
except Exception as e:
|
| 86 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 87 |
if os.path.exists(LOCAL_PATH):
|
| 88 |
try:
|
| 89 |
with open(LOCAL_PATH, "r", encoding="utf-8") as f:
|
|
|
|
| 83 |
|
| 84 |
print("Successfully synced database from Hugging Face.")
|
| 85 |
except Exception as e:
|
| 86 |
+
err_msg = str(e)
|
| 87 |
+
if "404" in err_msg or "Entry Not Found" in err_msg:
|
| 88 |
+
print("Database file not found in HF dataset. Initializing a new one.")
|
| 89 |
+
else:
|
| 90 |
+
print(f"Error loading database from HF: {err_msg}. Initializing a new one.")
|
| 91 |
if os.path.exists(LOCAL_PATH):
|
| 92 |
try:
|
| 93 |
with open(LOCAL_PATH, "r", encoding="utf-8") as f:
|
main.py
CHANGED
|
@@ -2,7 +2,6 @@ import asyncio
|
|
| 2 |
import os
|
| 3 |
import httpx
|
| 4 |
from fastapi import FastAPI
|
| 5 |
-
from fastapi.responses import HTMLResponse
|
| 6 |
from contextlib import asynccontextmanager
|
| 7 |
from pyrogram import Client, filters
|
| 8 |
import config
|
|
@@ -126,238 +125,10 @@ async def lifespan(app: FastAPI):
|
|
| 126 |
|
| 127 |
app = FastAPI(lifespan=lifespan)
|
| 128 |
|
| 129 |
-
#
|
| 130 |
-
@app.get("/"
|
| 131 |
-
async def
|
| 132 |
-
|
| 133 |
-
own_url = get_own_space_url() or "Not detected (running locally?)"
|
| 134 |
-
|
| 135 |
-
urls_list_html = "".join([f"<li><code>{url}</code></li>" for url in urls])
|
| 136 |
-
if not urls:
|
| 137 |
-
urls_list_html = "<li>No external spaces added yet.</li>"
|
| 138 |
-
|
| 139 |
-
config_status = {
|
| 140 |
-
"Telegram Bot Token": config.BOT_TOKEN is not None,
|
| 141 |
-
"Super Admin ID": config.SUPER_ADMIN_ID is not None,
|
| 142 |
-
"HF Access Token": config.HF_TOKEN is not None,
|
| 143 |
-
"HF Dataset URL": config.HF_DATASET_URL is not None,
|
| 144 |
-
}
|
| 145 |
-
|
| 146 |
-
config_rows = ""
|
| 147 |
-
for name, ok in config_status.items():
|
| 148 |
-
status_badge = '<span class="badge ok">Configured</span>' if ok else '<span class="badge missing">Missing</span>'
|
| 149 |
-
config_rows += f"<tr><td>{name}</td><td>{status_badge}</td></tr>"
|
| 150 |
-
|
| 151 |
-
html_content = f"""
|
| 152 |
-
<!DOCTYPE html>
|
| 153 |
-
<html lang="en">
|
| 154 |
-
<head>
|
| 155 |
-
<meta charset="UTF-8">
|
| 156 |
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| 157 |
-
<title>Hugging Face Space Pinger Dashboard</title>
|
| 158 |
-
<link rel="preconnect" href="https://fonts.googleapis.com">
|
| 159 |
-
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
| 160 |
-
<link href="https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;600;800&family=Space+Grotesk:wght@400;600&display=swap" rel="stylesheet">
|
| 161 |
-
<style>
|
| 162 |
-
:root {{
|
| 163 |
-
--bg: #0b0f19;
|
| 164 |
-
--card-bg: rgba(255, 255, 255, 0.03);
|
| 165 |
-
--card-border: rgba(255, 255, 255, 0.08);
|
| 166 |
-
--primary: #4f46e5;
|
| 167 |
-
--primary-glow: rgba(79, 70, 229, 0.4);
|
| 168 |
-
--success: #10b981;
|
| 169 |
-
--success-glow: rgba(16, 185, 129, 0.4);
|
| 170 |
-
--text-main: #f3f4f6;
|
| 171 |
-
--text-muted: #9ca3af;
|
| 172 |
-
}}
|
| 173 |
-
* {{
|
| 174 |
-
box-sizing: border-box;
|
| 175 |
-
margin: 0;
|
| 176 |
-
padding: 0;
|
| 177 |
-
}}
|
| 178 |
-
body {{
|
| 179 |
-
font-family: 'Outfit', sans-serif;
|
| 180 |
-
background-color: var(--bg);
|
| 181 |
-
color: var(--text-main);
|
| 182 |
-
min-height: 100vh;
|
| 183 |
-
display: flex;
|
| 184 |
-
flex-direction: column;
|
| 185 |
-
justify-content: center;
|
| 186 |
-
align-items: center;
|
| 187 |
-
padding: 2rem;
|
| 188 |
-
background-image:
|
| 189 |
-
radial-gradient(circle at 10% 20%, rgba(79, 70, 229, 0.08) 0%, transparent 40%),
|
| 190 |
-
radial-gradient(circle at 90% 80%, rgba(16, 185, 129, 0.06) 0%, transparent 40%);
|
| 191 |
-
}}
|
| 192 |
-
.container {{
|
| 193 |
-
max-width: 800px;
|
| 194 |
-
width: 100%;
|
| 195 |
-
display: flex;
|
| 196 |
-
flex-direction: column;
|
| 197 |
-
gap: 2rem;
|
| 198 |
-
}}
|
| 199 |
-
header {{
|
| 200 |
-
text-align: center;
|
| 201 |
-
margin-bottom: 1rem;
|
| 202 |
-
}}
|
| 203 |
-
h1 {{
|
| 204 |
-
font-family: 'Space Grotesk', sans-serif;
|
| 205 |
-
font-weight: 800;
|
| 206 |
-
font-size: 2.5rem;
|
| 207 |
-
background: linear-gradient(135deg, #a5b4fc, #818cf8, #6366f1);
|
| 208 |
-
-webkit-background-clip: text;
|
| 209 |
-
-webkit-text-fill-color: transparent;
|
| 210 |
-
margin-bottom: 0.5rem;
|
| 211 |
-
}}
|
| 212 |
-
.subtitle {{
|
| 213 |
-
color: var(--text-muted);
|
| 214 |
-
font-size: 1.1rem;
|
| 215 |
-
}}
|
| 216 |
-
.grid {{
|
| 217 |
-
display: grid;
|
| 218 |
-
grid-template-columns: 1fr 1fr;
|
| 219 |
-
gap: 1.5rem;
|
| 220 |
-
}}
|
| 221 |
-
@media (max-width: 600px) {{
|
| 222 |
-
.grid {{
|
| 223 |
-
grid-template-columns: 1fr;
|
| 224 |
-
}}
|
| 225 |
-
}}
|
| 226 |
-
.card {{
|
| 227 |
-
background: var(--card-bg);
|
| 228 |
-
border: 1px solid var(--card-border);
|
| 229 |
-
border-radius: 16px;
|
| 230 |
-
padding: 1.5rem;
|
| 231 |
-
backdrop-filter: blur(12px);
|
| 232 |
-
box-shadow: 0 8px 32px 0 rgba(0, 0, 0, 0.37);
|
| 233 |
-
transition: transform 0.3s ease, border-color 0.3s ease;
|
| 234 |
-
}}
|
| 235 |
-
.card:hover {{
|
| 236 |
-
transform: translateY(-5px);
|
| 237 |
-
border-color: rgba(99, 102, 241, 0.2);
|
| 238 |
-
}}
|
| 239 |
-
.card-title {{
|
| 240 |
-
font-family: 'Space Grotesk', sans-serif;
|
| 241 |
-
font-size: 1.25rem;
|
| 242 |
-
font-weight: 600;
|
| 243 |
-
margin-bottom: 1rem;
|
| 244 |
-
display: flex;
|
| 245 |
-
align-items: center;
|
| 246 |
-
gap: 0.5rem;
|
| 247 |
-
color: #a5b4fc;
|
| 248 |
-
}}
|
| 249 |
-
.status-badge {{
|
| 250 |
-
display: inline-flex;
|
| 251 |
-
align-items: center;
|
| 252 |
-
gap: 0.5rem;
|
| 253 |
-
padding: 0.5rem 1rem;
|
| 254 |
-
background: rgba(16, 185, 129, 0.1);
|
| 255 |
-
border: 1px solid var(--success);
|
| 256 |
-
color: var(--success);
|
| 257 |
-
border-radius: 9999px;
|
| 258 |
-
font-weight: 600;
|
| 259 |
-
box-shadow: 0 0 15px var(--success-glow);
|
| 260 |
-
animation: pulse 2s infinite;
|
| 261 |
-
}}
|
| 262 |
-
@keyframes pulse {{
|
| 263 |
-
0% {{ box-shadow: 0 0 5px var(--success-glow); }}
|
| 264 |
-
50% {{ box-shadow: 0 0 20px var(--success-glow); }}
|
| 265 |
-
100% {{ box-shadow: 0 0 5px var(--success-glow); }}
|
| 266 |
-
}}
|
| 267 |
-
ul {{
|
| 268 |
-
list-style: none;
|
| 269 |
-
display: flex;
|
| 270 |
-
flex-direction: column;
|
| 271 |
-
gap: 0.75rem;
|
| 272 |
-
}}
|
| 273 |
-
li {{
|
| 274 |
-
background: rgba(255, 255, 255, 0.02);
|
| 275 |
-
border: 1px solid rgba(255, 255, 255, 0.05);
|
| 276 |
-
border-radius: 8px;
|
| 277 |
-
padding: 0.75rem;
|
| 278 |
-
font-size: 0.9rem;
|
| 279 |
-
overflow-x: auto;
|
| 280 |
-
}}
|
| 281 |
-
code {{
|
| 282 |
-
font-family: 'Courier New', Courier, monospace;
|
| 283 |
-
color: #818cf8;
|
| 284 |
-
}}
|
| 285 |
-
table {{
|
| 286 |
-
width: 100%;
|
| 287 |
-
border-collapse: collapse;
|
| 288 |
-
}}
|
| 289 |
-
td {{
|
| 290 |
-
padding: 0.75rem 0;
|
| 291 |
-
border-bottom: 1px solid rgba(255, 255, 255, 0.05);
|
| 292 |
-
}}
|
| 293 |
-
tr:last-child td {{
|
| 294 |
-
border-bottom: none;
|
| 295 |
-
}}
|
| 296 |
-
.badge {{
|
| 297 |
-
display: inline-block;
|
| 298 |
-
padding: 0.25rem 0.5rem;
|
| 299 |
-
border-radius: 4px;
|
| 300 |
-
font-size: 0.8rem;
|
| 301 |
-
font-weight: 600;
|
| 302 |
-
}}
|
| 303 |
-
.badge.ok {{
|
| 304 |
-
background: rgba(16, 185, 129, 0.15);
|
| 305 |
-
color: var(--success);
|
| 306 |
-
}}
|
| 307 |
-
.badge.missing {{
|
| 308 |
-
background: rgba(239, 68, 68, 0.15);
|
| 309 |
-
color: #ef4444;
|
| 310 |
-
}}
|
| 311 |
-
footer {{
|
| 312 |
-
text-align: center;
|
| 313 |
-
color: var(--text-muted);
|
| 314 |
-
font-size: 0.85rem;
|
| 315 |
-
margin-top: 2rem;
|
| 316 |
-
}}
|
| 317 |
-
</style>
|
| 318 |
-
</head>
|
| 319 |
-
<body>
|
| 320 |
-
<div class="container">
|
| 321 |
-
<header>
|
| 322 |
-
<h1>HF Space Pinger</h1>
|
| 323 |
-
<p class="subtitle">Reliable Hugging Face Space keep-alive bot</p>
|
| 324 |
-
</header>
|
| 325 |
-
|
| 326 |
-
<div class="card" style="text-align: center; display: flex; flex-direction: column; align-items: center; gap: 1rem;">
|
| 327 |
-
<div class="card-title">SYSTEM STATUS</div>
|
| 328 |
-
<div>
|
| 329 |
-
<span class="status-badge">
|
| 330 |
-
<span style="display:inline-block; width:8px; height:8px; background:var(--success); border-radius:50%;"></span>
|
| 331 |
-
BOT IS ACTIVE
|
| 332 |
-
</span>
|
| 333 |
-
</div>
|
| 334 |
-
<p style="color: var(--text-muted); margin-top: 0.5rem;">Own Space URL: <code>{own_url}</code></p>
|
| 335 |
-
</div>
|
| 336 |
-
|
| 337 |
-
<div class="grid">
|
| 338 |
-
<div class="card">
|
| 339 |
-
<div class="card-title">📋 Config Settings</div>
|
| 340 |
-
<table>
|
| 341 |
-
{config_rows}
|
| 342 |
-
</table>
|
| 343 |
-
</div>
|
| 344 |
-
|
| 345 |
-
<div class="card">
|
| 346 |
-
<div class="card-title">🔗 Monitored Spaces ({len(urls)})</div>
|
| 347 |
-
<ul>
|
| 348 |
-
{urls_list_html}
|
| 349 |
-
</ul>
|
| 350 |
-
</div>
|
| 351 |
-
</div>
|
| 352 |
-
|
| 353 |
-
<footer>
|
| 354 |
-
Powered by FastAPI, Pyrogram & Hugging Face • Kept awake automatically
|
| 355 |
-
</footer>
|
| 356 |
-
</div>
|
| 357 |
-
</body>
|
| 358 |
-
</html>
|
| 359 |
-
"""
|
| 360 |
-
return html_content
|
| 361 |
|
| 362 |
# ================== PYROGRAM BOT HANDLERS ==================
|
| 363 |
|
|
@@ -366,6 +137,17 @@ async def start_command(client, message):
|
|
| 366 |
if not message.from_user:
|
| 367 |
return
|
| 368 |
log_and_update(message)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 369 |
# Welcomes the user
|
| 370 |
await message.reply_text(
|
| 371 |
"👋 **Hello! Welcome to the Hugging Face Space Pinger Bot.** 🚀\n\n"
|
|
|
|
| 2 |
import os
|
| 3 |
import httpx
|
| 4 |
from fastapi import FastAPI
|
|
|
|
| 5 |
from contextlib import asynccontextmanager
|
| 6 |
from pyrogram import Client, filters
|
| 7 |
import config
|
|
|
|
| 125 |
|
| 126 |
app = FastAPI(lifespan=lifespan)
|
| 127 |
|
| 128 |
+
# Health Check Endpoint
|
| 129 |
+
@app.get("/")
|
| 130 |
+
async def health_check():
|
| 131 |
+
return {"status": "ok", "message": "HF Space Pinger Bot is running successfully."}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 132 |
|
| 133 |
# ================== PYROGRAM BOT HANDLERS ==================
|
| 134 |
|
|
|
|
| 137 |
if not message.from_user:
|
| 138 |
return
|
| 139 |
log_and_update(message)
|
| 140 |
+
|
| 141 |
+
user_id = message.from_user.id
|
| 142 |
+
if not database.is_authorized(user_id):
|
| 143 |
+
await message.reply_text(
|
| 144 |
+
"❌ **Unauthorized User**\n\n"
|
| 145 |
+
f"You are unauthorized to use the bot.\n"
|
| 146 |
+
f"Your ID: `{user_id}`\n\n"
|
| 147 |
+
"Tell an admin to add you."
|
| 148 |
+
)
|
| 149 |
+
return
|
| 150 |
+
|
| 151 |
# Welcomes the user
|
| 152 |
await message.reply_text(
|
| 153 |
"👋 **Hello! Welcome to the Hugging Face Space Pinger Bot.** 🚀\n\n"
|