sayakpaul HF Staff commited on
Commit
1beb20f
·
verified ·
1 Parent(s): f62d0f5

Upload 5 files

Browse files
.gitattributes CHANGED
@@ -33,3 +33,6 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ Quattrocento-Bold.ttf filter=lfs diff=lfs merge=lfs -text
37
+ Quattrocento-Regular.ttf filter=lfs diff=lfs merge=lfs -text
38
+ templates/certificate.png filter=lfs diff=lfs merge=lfs -text
Quattrocento-Bold.ttf ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:fec2ad7660d0729c6c43031331c1bb9345509f08b4a90e968fd3e51fa87e6b8c
3
+ size 153980
Quattrocento-Regular.ttf ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:ccb5e43e18fd65db55eb919b9e32220a20772c3a22812386cd12012d10c4f6b4
3
+ size 147732
app.py ADDED
@@ -0,0 +1,214 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json
2
+ import os
3
+ import tempfile
4
+ import uuid
5
+ from datetime import date, datetime
6
+ from pathlib import Path
7
+ from typing import Any
8
+
9
+ import gradio as gr
10
+ from PIL import Image, ImageDraw, ImageFont
11
+ from datasets import load_dataset
12
+ from huggingface_hub import upload_file
13
+
14
+
15
+ BASE_DIR = Path(__file__).resolve().parent
16
+ TEMPLATE_PATH = BASE_DIR / "templates" / "certificate.png"
17
+ REGULAR_FONT_PATH = BASE_DIR / "Quattrocento-Regular.ttf"
18
+
19
+ VALIDATION_DATASET_ID = "diffusers/mvp-candidates"
20
+ PUSH_TOKEN = os.getenv("VALIDATION_DATASET_TOKEN")
21
+
22
+ CERTIFICATES_DATASET_REPO = "diffusers/mvp-certificates"
23
+ CERTIFICATES_DATASET_SUBDIR = Path("certificates")
24
+ CERTIFICATES_METADATA_SUBDIR = Path("metadata")
25
+
26
+
27
+ def _normalize_username(value: Any) -> str:
28
+ return str(value or "").strip().lower()
29
+
30
+
31
+ def _normalize_pr(value: Any) -> str:
32
+ return str(value or "").strip()
33
+
34
+ dataset = load_dataset(VALIDATION_DATASET_ID, split="train")
35
+ _VALIDATION_INDEX = {
36
+ (
37
+ _normalize_username(record.get("github_username")),
38
+ _normalize_pr(record.get("pr_number")),
39
+ ): record
40
+ for record in dataset
41
+ }
42
+
43
+ def generate_certificate(name: str, output_path: str | os.PathLike[str] | None = None):
44
+ """Generate certificate image and PDF."""
45
+
46
+ im = Image.open(TEMPLATE_PATH)
47
+ d = ImageDraw.Draw(im)
48
+
49
+ name_font = ImageFont.truetype(str(REGULAR_FONT_PATH), 100)
50
+ date_font = ImageFont.truetype(str(REGULAR_FONT_PATH), 48)
51
+
52
+ formatted_name = name.title()
53
+ d.text((1000, 740), formatted_name, fill="black", anchor="mm", font=name_font)
54
+ d.text((1480, 1170), str(date.today()), fill="black", anchor="mm", font=date_font)
55
+
56
+ pdf_path = Path(output_path) if output_path else BASE_DIR / "certificate.pdf"
57
+ pdf_path.parent.mkdir(parents=True, exist_ok=True)
58
+
59
+ pdf = im.convert("RGB")
60
+ pdf.save(pdf_path)
61
+
62
+ return im, str(pdf_path)
63
+
64
+
65
+ def _require_validation_record(github_username: str, pr_number: str) -> dict[str, Any]:
66
+ key = (_normalize_username(github_username), _normalize_pr(pr_number))
67
+ record = _VALIDATION_INDEX.get(key)
68
+ if record is None:
69
+ raise gr.Error(
70
+ "No matching submission was found. Make sure the PR was accepted and "
71
+ "your GitHub handle is correct."
72
+ )
73
+ return record
74
+
75
+
76
+ def _build_metadata(
77
+ *,
78
+ github_username: str,
79
+ pr_number: str,
80
+ profile: gr.OAuthProfile,
81
+ record: dict[str, Any],
82
+ display_name: str,
83
+ ) -> dict[str, Any]:
84
+ return {
85
+ "github_username": github_username.strip(),
86
+ "pr_number": pr_number,
87
+ "issued_at": datetime.now().isoformat() + "Z",
88
+ "display_name": display_name,
89
+ "huggingface": {
90
+ "username": profile.username,
91
+ "name": profile.name,
92
+ "profile_url": profile.profile,
93
+ "avatar": profile.picture,
94
+ },
95
+ "validation_record": record,
96
+ }
97
+
98
+
99
+ def _upload_certificate(
100
+ pdf_path: Path, metadata: dict[str, Any], token: str | None = None
101
+ ) -> str:
102
+ if not CERTIFICATES_DATASET_REPO:
103
+ raise gr.Error(
104
+ "Set CERTIFICATES_DATASET_REPO so the app knows where to store certificates."
105
+ )
106
+ issued_at = datetime.now().strftime("%Y%m%dT%H%M%S")
107
+ unique_suffix = uuid.uuid4().hex[:8]
108
+ pdf_filename = f"certificate-{issued_at}-{unique_suffix}.pdf"
109
+ metadata_filename = pdf_filename.replace(".pdf", ".json")
110
+
111
+ pdf_remote_path = CERTIFICATES_DATASET_SUBDIR / pdf_filename
112
+ metadata_remote_path = CERTIFICATES_METADATA_SUBDIR / metadata_filename
113
+
114
+ with tempfile.TemporaryDirectory() as tmpdir:
115
+ metadata_path = Path(tmpdir) / metadata_filename
116
+ metadata_path.write_text(json.dumps(metadata, indent=2), encoding="utf-8")
117
+
118
+ upload_file(
119
+ path_or_fileobj=str(pdf_path),
120
+ path_in_repo=str(pdf_remote_path),
121
+ repo_id=CERTIFICATES_DATASET_REPO,
122
+ repo_type="dataset",
123
+ token=PUSH_TOKEN
124
+ )
125
+ upload_file(
126
+ path_or_fileobj=str(metadata_path),
127
+ path_in_repo=str(metadata_remote_path),
128
+ repo_id=CERTIFICATES_DATASET_REPO,
129
+ repo_type="dataset",
130
+ token=PUSH_TOKEN
131
+ )
132
+
133
+ return (
134
+ "https://huggingface.co/datasets/"
135
+ f"{CERTIFICATES_DATASET_REPO}/resolve/main/{pdf_remote_path}"
136
+ )
137
+
138
+
139
+ def issue_certificate(
140
+ github_username: str,
141
+ pr_number: str,
142
+ name: str,
143
+ profile: gr.OAuthProfile | None,
144
+ ) -> str:
145
+ if not github_username.strip() or not pr_number:
146
+ raise gr.Error("Both GitHub username and PR number are required.")
147
+
148
+ if not name.strip():
149
+ raise gr.Error("Please provide the full name for the certificate.")
150
+
151
+ if profile is None:
152
+ raise gr.Error("Please sign in with your Hugging Face account to continue.")
153
+
154
+ record = _require_validation_record(github_username, pr_number)
155
+
156
+ normalized_pr = _normalize_pr(pr_number)
157
+ sanitized_username = _normalize_username(github_username).replace("/", "-")
158
+
159
+ with tempfile.TemporaryDirectory() as tmpdir:
160
+ pdf_path = Path(tmpdir) / f"{sanitized_username}-pr{normalized_pr}.pdf"
161
+ _, generated_pdf_path = generate_certificate(name, output_path=str(pdf_path))
162
+ pdf_path = Path(generated_pdf_path)
163
+
164
+ metadata = _build_metadata(
165
+ github_username=github_username,
166
+ pr_number=normalized_pr,
167
+ profile=profile,
168
+ record=record,
169
+ display_name=name.title(),
170
+ )
171
+
172
+ certificate_url = _upload_certificate(
173
+ pdf_path=pdf_path,
174
+ metadata=metadata,
175
+ )
176
+
177
+ return f"[Open certificate ↗]({certificate_url})"
178
+
179
+
180
+ with gr.Blocks(title="MVP Certificate Generator") as demo:
181
+ gr.Markdown(
182
+ """
183
+ # MVP Certificate Generator
184
+
185
+ Sign in with your Hugging Face account, verify your merged PR, and mint a certificate.
186
+ """
187
+ )
188
+
189
+ gr.LoginButton()
190
+
191
+ with gr.Row():
192
+ github_username_input = gr.Textbox(
193
+ label="GitHub Username",
194
+ placeholder="huggingface",
195
+ autofocus=True,
196
+ )
197
+ pr_number_input = gr.Textbox(label="PR Number", placeholder="42")
198
+ name_input = gr.Textbox(label="Name on Certificate", placeholder="Jane Doe")
199
+
200
+ generate_button = gr.Button("Generate certificate", variant="primary")
201
+ certificate_output = gr.Markdown(
202
+ value="_Certificate link will appear here after successful verification._",
203
+ elem_id="certificate-link-output",
204
+ )
205
+
206
+ generate_button.click(
207
+ fn=issue_certificate,
208
+ inputs=[github_username_input, pr_number_input, name_input],
209
+ outputs=certificate_output,
210
+ )
211
+
212
+
213
+ if __name__ == "__main__":
214
+ demo.launch()
templates/certificate.png ADDED

Git LFS Details

  • SHA256: a743716c7f0003a31b8c66bc7ea3caf6bebdd8fe33aa7f762cbcbde3645c0b41
  • Pointer size: 131 Bytes
  • Size of remote file: 146 kB