File size: 8,030 Bytes
4195ac0 44daadf 4195ac0 bcb4808 e15fe43 4195ac0 0a7c017 35b9d7e 732c892 4195ac0 5bb2ded 4195ac0 2ee56f9 e15fe43 4195ac0 5bb2ded 4195ac0 5bb2ded 4195ac0 6e9feb9 4195ac0 5bb2ded 660c675 a13afb6 4195ac0 660c675 a13afb6 4195ac0 a13afb6 4195ac0 d9d8e75 4195ac0 35b9d7e 5bb2ded e15fe43 5bb2ded e15fe43 5bb2ded 4195ac0 5bb2ded 4195ac0 fce60a3 4195ac0 5bb2ded 9b1ede4 4195ac0 570b457 660c675 e15fe43 4195ac0 48db6cb 5bb2ded 48db6cb 29dd10e 48db6cb 0640418 48db6cb 5bb2ded 4195ac0 e084787 4195ac0 e15fe43 35b9d7e 4195ac0 f9b68ce e15fe43 4195ac0 5bb2ded |
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 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 |
import gradio as gr
from datasets import load_dataset, Dataset
from datetime import datetime
from datetime import date
import requests
import tempfile
import asyncio
from huggingface_hub import upload_file
from functools import partial
import io
import os
from PIL import Image, ImageDraw, ImageFont
from huggingface_hub import login
login(token=os.environ["HUGGINGFACE_TOKEN"])
# Constants
SCORES_DATASET = "agents-course/unit4-students-scores"
CERTIFICATES_DATASET = "agents-course/course-certificates-of-excellence"
THRESHOLD_SCORE = 30
CERTIFYING_ORG_LINKEDIN_ID = os.getenv("CERTIFYING_ORG_LINKEDIN_ID", "000000")
COURSE_TITLE = os.getenv("COURSE_TITLE", "Hugging Face Agents Course")
# Function to check user score
def check_user_score(username):
score_data = load_dataset(SCORES_DATASET, split="train", download_mode="force_redownload")
matches = [row for row in score_data if row["username"] == username]
return matches[0] if matches else None
# Function to check if certificate entry exists
def has_certificate_entry(username):
cert_data = load_dataset(CERTIFICATES_DATASET, split="train", download_mode="force_redownload")
print(username)
return any(row["username"] == username for row in cert_data)
# Function to add certificate entry
def add_certificate_entry(username, name, score):
# Load current dataset
ds = load_dataset(CERTIFICATES_DATASET, split="train", download_mode="force_redownload")
# Remove any existing entry with the same username
filtered_rows = [row for row in ds if row["username"] != username]
# Append the updated/new entry
new_entry = {
"username": username,
"score": score,
"timestamp": datetime.now().isoformat()
}
filtered_rows.append(new_entry)
# Rebuild dataset and push
updated_ds = Dataset.from_list(filtered_rows)
updated_ds.push_to_hub(CERTIFICATES_DATASET)
# Function to generate certificate PDF
def generate_certificate(name, score):
"""Generate certificate image and PDF."""
certificate_path = os.path.join(
os.path.dirname(__file__), "templates", "certificate.png"
)
im = Image.open(certificate_path)
d = ImageDraw.Draw(im)
name_font = ImageFont.truetype("Quattrocento-Regular.ttf", 100)
date_font = ImageFont.truetype("Quattrocento-Regular.ttf", 48)
name = name.title()
d.text((1000, 740), name, fill="black", anchor="mm", font=name_font)
d.text((1480, 1170), str(date.today()), fill="black", anchor="mm", font=date_font)
pdf = im.convert("RGB")
pdf.save("certificate.pdf")
return im, "certificate.pdf"
async def upload_certificate_to_hub(username: str, certificate_img) -> str:
"""Upload certificate to the dataset hub and return the URL asynchronously."""
# Save image to temporary file
with tempfile.NamedTemporaryFile(suffix=".png", delete=False) as tmp:
certificate_img.save(tmp.name)
try:
# Run upload in a thread pool since upload_file is blocking
loop = asyncio.get_event_loop()
upload_func = partial(
upload_file,
path_or_fileobj=tmp.name,
path_in_repo=f"certificates/{username}/{date.today()}.png",
repo_id="agents-course/final-certificates",
repo_type="dataset",
token=os.getenv("HF_TOKEN"),
)
await loop.run_in_executor(None, upload_func)
# Construct the URL to the image
cert_url = (
f"https://huggingface.co/datasets/agents-course/final-certificates/"
f"resolve/main/certificates/{username}/{date.today()}.png"
)
# Clean up temp file
os.unlink(tmp.name)
return cert_url
except Exception as e:
print(f"Error uploading certificate: {e}")
os.unlink(tmp.name)
return None
def create_linkedin_button(username: str, cert_url: str | None) -> str:
"""Create LinkedIn 'Add to Profile' button HTML."""
current_year = date.today().year
current_month = date.today().month
# Use the dataset certificate URL if available, otherwise fallback to default
certificate_url = cert_url or "https://huggingface.co/agents-course-finishers"
linkedin_params = {
"startTask": "CERTIFICATION_NAME",
"name": COURSE_TITLE,
"organizationName": "Hugging Face",
"organizationId": CERTIFYING_ORG_LINKEDIN_ID,
"issueYear": str(current_year),
"issueMonth": str(current_month),
"certUrl": certificate_url,
"certId": username, # Using username as cert ID
}
# Build the LinkedIn button URL
base_url = "https://www.linkedin.com/profile/add?"
params = "&".join(
f"{k}={requests.utils.quote(v)}" for k, v in linkedin_params.items()
)
button_url = base_url + params
message = f"""
<a href="{button_url}" target="_blank" style="display: block; margin: 0 auto; width: fit-content;">
<img src="https://download.linkedin.com/desktop/add2profile/buttons/en_US.png"
alt="LinkedIn Add to Profile button"
style="height: 40px; width: auto; display: block;" />
</a>
"""
return message
# Main function to handle certificate generation
async def handle_certificate(name, profile: gr.OAuthProfile):
if profile is None:
return "You must be logged in with your Hugging Face account.", None
username = profile.username
user_score = check_user_score(username)
if not user_score:
return "You need to complete Unit 4 first.", None, None, None
score = user_score["score"]
if score < THRESHOLD_SCORE:
return f"Your score is {score}. You need at least {THRESHOLD_SCORE} to pass.", None, None
certificate_image, certificate_pdf = generate_certificate(name, score)
add_certificate_entry(username, name, score)
# Start certificate upload asynchronously
gr.Info("Uploading your certificate...")
cert_url = await upload_certificate_to_hub(username, certificate_image)
if cert_url is None:
gr.Warning("Certificate upload failed, but you still passed!")
cert_url = "https://huggingface.co/agents-course"
linkedin_button = create_linkedin_button(username, cert_url)
return "Congratulations! Here's your certificate:", certificate_image, gr.update(value=linkedin_button, visible=True), certificate_pdf
# Gradio interface
with gr.Blocks() as demo:
gr.Markdown("# π Agents Course - Get Your Final Certificate")
gr.Markdown("Welcome! Follow the steps below to receive your official certificate:")
gr.Markdown("β οΈ **Note**: Due to high demand, you might experience occasional bugs. If something doesn't work, please try again after a moment!")
with gr.Group():
gr.Markdown("## β
How it works")
gr.Markdown("""
1. **Sign in** with your Hugging Face account using the button below.
2. **Enter your full name** (this will appear on the certificate).
3. Click **'Get My Certificate'** to check your score and download your certificate.
""")
gr.Markdown("---")
gr.Markdown("π **Note**: You must have completed [Unit 4](https://huggingface.co/learn/agents-course/unit4/introduction) and your Agent must have scored **above 30** to get your certificate.")
gr.LoginButton()
with gr.Row():
name_input = gr.Text(label="Enter your name (this will appear on the certificate)")
generate_btn = gr.Button("Get my certificate")
output_text = gr.Textbox(label="Result")
linkedin_btn = gr.HTML(visible=False)
cert_image = gr.Image(label="Your Certificate")
cert_file = gr.File(label="Download Certificate (PDF)", file_types=[".pdf"])
generate_btn.click(
fn=handle_certificate,
inputs=[name_input],
outputs=[output_text, cert_image, linkedin_btn, cert_file]
)
demo.launch()
|