jyrainer's picture
Update app.py
5f1940c verified
import os
import requests
import uvicorn
import logging
from fastapi import FastAPI, Request, Header, HTTPException
from typing import Optional
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
app = FastAPI()
TEAMS_WEBHOOK_URL = os.getenv("TEAMS_WEBHOOK_URL")
WEBHOOK_SECRET = os.getenv("WEBHOOK_SECRET")
HF_TOKEN = os.getenv("HF_TOKEN")
@app.get("/")
def root():
return {"status": "running"}
def get_commit_info(repo_type, repo_name, head_sha):
type_map = {"model": "models", "dataset": "datasets", "space": "spaces"}
api_type = type_map.get(repo_type, "models")
headers = {}
if HF_TOKEN:
headers["Authorization"] = f"Bearer {HF_TOKEN}"
commit_title = head_sha[:8]
commit_author = "unknown"
parent_sha = None
changed_files = []
# 1) ์ปค๋ฐ‹ ๋ชฉ๋ก์—์„œ ์ปค๋ฐ‹ ๋ฉ”์‹œ์ง€, ์ž‘์„ฑ์ž, ๋ถ€๋ชจ SHA ์กฐํšŒ
try:
commits_url = f"https://huggingface.co/api/{api_type}/{repo_name}/commits/main"
resp = requests.get(commits_url, headers=headers, timeout=10)
if resp.ok:
commits = resp.json()
for i, commit in enumerate(commits):
if commit.get("id", "").startswith(head_sha[:8]):
commit_title = commit.get("title", head_sha[:8])
authors = commit.get("authors", [])
if authors:
commit_author = authors[0].get("user", "unknown")
# ๋ฐ”๋กœ ๋‹ค์Œ์ด ๋ถ€๋ชจ ์ปค๋ฐ‹
if i + 1 < len(commits):
parent_sha = commits[i + 1].get("id")
break
except Exception as e:
logger.error(f"Commits API error: {e}")
# 2) ํ˜„์žฌ ์ปค๋ฐ‹๊ณผ ๋ถ€๋ชจ ์ปค๋ฐ‹์˜ ํŒŒ์ผ ํŠธ๋ฆฌ ๋น„๊ต
if parent_sha:
try:
def get_tree(revision):
tree_url = f"https://huggingface.co/api/{api_type}/{repo_name}/tree/{revision}"
logger.info(f"Fetching tree: {tree_url}")
r = requests.get(tree_url, headers=headers, timeout=10, params={"recursive": "true"})
logger.info(f" Tree status: {r.status_code}")
if r.ok:
return {f.get("path"): f.get("oid") for f in r.json() if f.get("type") == "file"}
return {}
current_files = get_tree(head_sha)
parent_files = get_tree(parent_sha)
# ์ถ”๊ฐ€๋œ ํŒŒ์ผ
for path in current_files:
if path not in parent_files:
changed_files.append(f"๐Ÿ†• {path}")
elif current_files[path] != parent_files[path]:
changed_files.append(f"โœ๏ธ {path}")
# ์‚ญ์ œ๋œ ํŒŒ์ผ
for path in parent_files:
if path not in current_files:
changed_files.append(f"๐Ÿ—‘๏ธ {path}")
except Exception as e:
logger.error(f"Tree compare error: {e}")
return commit_title, commit_author, changed_files
@app.post("/webhook")
async def handle_webhook(
request: Request,
x_webhook_secret: Optional[str] = Header(default=None)
):
if WEBHOOK_SECRET:
if x_webhook_secret != WEBHOOK_SECRET:
raise HTTPException(status_code=403, detail="Invalid secret")
payload = await request.json()
# ์ „์ฒด payload ๋กœ๊น… (๋””๋ฒ„๊น…์šฉ)
logger.info(f"=== WEBHOOK RECEIVED ===")
logger.info(f"Full payload keys: {list(payload.keys())}")
logger.info(f"Event: {payload.get('event')}")
logger.info(f"Repo: {payload.get('repo')}")
event = payload.get("event", {})
repo = payload.get("repo", {})
if event.get("action") == "update" and event.get("scope", "").startswith("repo.content"):
repo_name = repo.get("name", "unknown")
repo_type = repo.get("type", "model")
head_sha = repo.get("headSha", "")
commit_title, commit_author, changed_files = get_commit_info(repo_type, repo_name, head_sha)
if changed_files:
files_text = "\n".join(changed_files[:15])
if len(changed_files) > 15:
files_text += f"\n...์™ธ {len(changed_files) - 15}๊ฐœ ํŒŒ์ผ"
else:
files_text = "(๋ณ€๊ฒฝ ํŒŒ์ผ ์กฐํšŒ ์‹คํŒจ - Space ๋กœ๊ทธ๋ฅผ ํ™•์ธํ•˜์„ธ์š”)"
card = {
"type": "message",
"attachments": [{
"contentType": "application/vnd.microsoft.card.adaptive",
"contentUrl": None,
"content": {
"type": "AdaptiveCard",
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
"version": "1.4",
"body": [
{
"type": "TextBlock",
"text": f"๐Ÿ“ฆ {repo_name}",
"wrap": True, "weight": "Bolder", "size": "Large"
},
{
"type": "FactSet",
"facts": [
{"title": "์ปค๋ฐ‹", "value": commit_title},
{"title": "์ž‘์„ฑ์ž", "value": commit_author},
{"title": "SHA", "value": head_sha[:8]}
]
},
{
"type": "TextBlock",
"text": "**๋ณ€๊ฒฝ๋œ ํŒŒ์ผ:**",
"wrap": True, "spacing": "Medium"
},
{
"type": "TextBlock",
"text": files_text,
"wrap": True, "fontType": "Monospace", "size": "Small"
},
{
"type": "ActionSet",
"actions": [{
"type": "Action.OpenUrl",
"title": "์ปค๋ฐ‹ ๋ณด๊ธฐ",
"url": f"https://huggingface.co/{repo_name}/commit/{head_sha}"
}]
}
]
}
}]
}
resp = requests.post(TEAMS_WEBHOOK_URL, json=card)
return {"sent": True, "teams_status": resp.status_code}
return {"sent": False, "reason": "not a repo content update"}
if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=7860)