File size: 3,315 Bytes
5506351
 
79eb0b7
 
5506351
 
 
 
79eb0b7
 
 
5506351
79eb0b7
5506351
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
79eb0b7
5506351
 
 
 
79eb0b7
 
 
 
5506351
79eb0b7
5506351
 
 
 
79eb0b7
 
 
123ce06
79eb0b7
 
 
 
 
123ce06
79eb0b7
123ce06
5506351
 
 
 
79eb0b7
5506351
 
 
 
 
79eb0b7
 
 
 
 
 
5506351
79eb0b7
5506351
79eb0b7
 
 
5506351
79eb0b7
5506351
79eb0b7
 
 
 
5506351
 
123ce06
 
 
79eb0b7
5506351
79eb0b7
5506351
 
 
 
 
 
79eb0b7
5506351
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
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

@app.get("/")
def home():
    return {"status": "Webhook listener is running"}

@app.post("/webhook")
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"}
    }