certification-app / criteria.py
burtenshaw
style response message
9350e9c
import os
from typing import Dict, List, Optional, NamedTuple, Tuple
from datetime import datetime
from datasets import load_dataset
from huggingface_hub import HfApi
# Environment variables and constants
EXAM_DATASET_ID = os.getenv(
"EXAM_DATASET_ID", "agents-course/unit_1_quiz_student_responses"
)
CERTIFICATE_MODELS_DIR = os.getenv("CERTIFICATE_MODELS_DIR", "./certificate_models")
CERTIFICATE_PATH = os.path.join(CERTIFICATE_MODELS_DIR, "certificate.png")
PASSING_THRESHOLD = float(os.getenv("PASSING_THRESHOLD", "0.8")) # 80%
MIN_QUESTIONS = int(os.getenv("MIN_QUESTIONS", "1"))
class CertificateResult(NamedTuple):
"""Stores the result of a certificate check"""
message: str
certificate_path: Optional[str]
pass_percentage: float
passed: bool
results_df: Optional[object] = None
def get_user_results(username: str) -> List[Dict]:
"""
Get user's quiz results from the dataset.
Args:
username: The Hugging Face username to check
Returns:
List of user's quiz results
"""
try:
user_results = load_dataset(path=EXAM_DATASET_ID, split=username)
results = user_results.to_list()
print(f"Found {len(results)} results for user {username}")
return results
except Exception as e:
print(f"Error in get_user_results: {str(e)}")
raise
def calculate_pass_percentage(results: List[Dict]) -> Tuple[float, int]:
"""
Calculate the user's pass percentage and number of questions from their results.
The dataset structure has:
- is_correct: bool indicating if answer was correct
- grade: float64 indicating overall grade
- datetime: string of attempt timestamp
Args:
results: List of quiz results
Returns:
Tuple of (highest grade achieved, number of questions answered)
"""
try:
if not results:
return 0.0, 0
# Group results by datetime to get distinct attempts
attempts = {}
for result in results:
timestamp = result["datetime"]
if timestamp not in attempts:
attempts[timestamp] = {
"correct": 0,
"total": 0,
"grade": result.get("grade", 0.0),
}
attempts[timestamp]["total"] += 1
if result["is_correct"]:
attempts[timestamp]["correct"] += 1
# Find the best attempt
best_attempt = max(
attempts.values(),
key=lambda x: x["grade"]
if x["grade"] is not None
else (x["correct"] / x["total"] if x["total"] > 0 else 0),
)
# If grade is available, use it; otherwise calculate from correct/total
if best_attempt["grade"] is not None and best_attempt["grade"] > 0:
pass_percentage = float(best_attempt["grade"])
else:
pass_percentage = (
best_attempt["correct"] / best_attempt["total"]
if best_attempt["total"] > 0
else 0.0
)
return pass_percentage, best_attempt["total"]
except Exception as e:
print(f"Error in calculate_pass_percentage: {str(e)}")
raise
def has_passed(pass_percentage: float, num_questions: int) -> bool:
"""
Check if user has passed based on percentage and minimum questions.
Args:
pass_percentage: User's highest quiz score
num_questions: Number of questions answered
Returns:
Boolean indicating if user passed
"""
return pass_percentage >= PASSING_THRESHOLD and num_questions >= MIN_QUESTIONS
def get_certificate_result(
pass_percentage: float, num_questions: int
) -> CertificateResult:
"""
Determine if user passed and create appropriate message.
Args:
pass_percentage: User's highest quiz score
num_questions: Number of questions answered
Returns:
CertificateResult with pass status and details
"""
passed = has_passed(pass_percentage, num_questions)
if passed:
message = """
Congratulations, you successfully completed the course! πŸŽ‰ \n
You can download your certificate below ⬇️
"""
return CertificateResult(
message=message,
certificate_path=CERTIFICATE_PATH,
pass_percentage=pass_percentage,
passed=True,
)
else:
return CertificateResult(
message="""
You haven't completed all the requirements yet. \n
Keep trying! πŸ’ͺ
""",
certificate_path=None,
pass_percentage=pass_percentage,
passed=False,
)
def check_certification(username: str) -> CertificateResult:
"""
Check if a user has completed the certification requirements.
Args:
username: The Hugging Face username to check
Returns:
CertificateResult containing pass status and details
"""
try:
# Get user's quiz results
results = get_user_results(username)
if not results:
return CertificateResult(
message="No quiz results found. Please complete the quiz first.",
certificate_path=None,
pass_percentage=0.0,
passed=False,
)
# Calculate pass percentage and get appropriate certificate result
pass_percentage, num_questions = calculate_pass_percentage(results)
return get_certificate_result(pass_percentage, num_questions)
except Exception as e:
error_msg = """
There was an error checking your certification status.
Please try again later or contact support if the issue persists.
"""
return CertificateResult(
message=error_msg,
certificate_path=None,
pass_percentage=0.0,
passed=False,
)