Spaces:
Sleeping
Sleeping
Download main.py from Rolaficus/webhook-handler: direct link, hf CLI and curl.
- Browser
- Download file 3.32 kB
-
https://huggingface.co/spaces/Rolaficus/webhook-handler/resolve/main/main.py
- Command line
-
hf download hf://spaces/Rolaficus/webhook-handler/main.py
-
curl -L -o main.py https://huggingface.co/spaces/Rolaficus/webhook-handler/resolve/main/main.py
3.32 kB
| from fastapi import FastAPI, Request, Header, HTTPException | |
| from pydantic import BaseModel | |
| from typing import Optional, Any, Dict | |
| import requests | |
| import os | |
| app = FastAPI() | |
| # --- Configuration --- | |
| DISCORD_WEBHOOK_URL = os.environ.get("DISCORD_WEBHOOK_URL") | |
| WEBHOOK_SECRET = os.environ.get("WEBHOOK_SECRET") | |
| # --- Models --- | |
| class HFRepo(BaseModel): | |
| type: str | |
| name: str | |
| id: str | |
| url: Dict[str, str] | |
| class HFEvent(BaseModel): | |
| action: str | |
| scope: str | |
| class HFPayload(BaseModel): | |
| repo: HFRepo | |
| event: HFEvent | |
| discussion: Optional[Dict[str, Any]] = None | |
| comment: Optional[Dict[str, Any]] = None | |
| webhook: Optional[Dict[str, Any]] = None | |
| def home(): | |
| return {"status": "Webhook listener is running"} | |
| def handle_webhook( | |
| payload: HFPayload, | |
| x_webhook_secret: Optional[str] = Header(None) | |
| ): | |
| # 1. Security Check | |
| if WEBHOOK_SECRET: | |
| if not x_webhook_secret or x_webhook_secret.strip() != WEBHOOK_SECRET.strip(): | |
| print("Auth Failed") | |
| raise HTTPException(status_code=401, detail="Invalid Secret") | |
| # 2. Build Embed | |
| embed = build_discord_embed(payload) | |
| # 3. Send to Discord | |
| if DISCORD_WEBHOOK_URL: | |
| # Clean the URL just in case | |
| url = DISCORD_WEBHOOK_URL.strip().strip("'").strip('"') | |
| try: | |
| print(f"Sending to Discord: {payload.repo.name} -> {payload.event.action}") | |
| # requests is synchronous and handles DNS/Proxies much better in containers | |
| resp = requests.post(url, json={"embeds": [embed]}, timeout=10) | |
| resp.raise_for_status() | |
| print("Success: Message sent.") | |
| except Exception as e: | |
| print(f"Error sending to Discord: {e}") | |
| return {"message": "Error sending to Discord", "error": str(e)} | |
| return {"message": "Processed"} | |
| def build_discord_embed(data: HFPayload): | |
| # Basic data extraction | |
| repo_name = data.repo.name | |
| repo_url = data.repo.url.get('web', '') | |
| event_scope = data.event.scope | |
| event_action = data.event.action | |
| # Colors | |
| COLOR_BLUE = 0x3498db | |
| COLOR_GREEN = 0x2ecc71 | |
| COLOR_GREY = 0x95a5a6 | |
| color = COLOR_GREY | |
| title = f"Update on {repo_name}" | |
| description = f"Action: {event_action}\nScope: {event_scope}" | |
| # Smart Formatting | |
| if "repo.content" in event_scope: | |
| color = COLOR_BLUE | |
| title = f"New Commit to {repo_name}" | |
| description = f"The repository content has been updated.\n[View Changes]({repo_url})" | |
| elif "discussion" in event_scope: | |
| color = COLOR_GREEN | |
| disc_title = data.discussion.get('title', 'Discussion') if data.discussion else "Discussion" | |
| title = f"Discussion: {disc_title}" | |
| if data.comment: | |
| content = data.comment.get('content', '') | |
| if len(content) > 200: | |
| content = content[:200] + "..." | |
| description = f"**New Comment:**\n{content}\n\n[View Discussion]({repo_url})" | |
| else: | |
| description = f"Discussion status updated: **{event_action}**" | |
| return { | |
| "title": title, | |
| "description": description, | |
| "url": repo_url, | |
| "color": color, | |
| "footer": {"text": "Hugging Face Webhooks"} | |
| } |