Spaces:
Sleeping
Sleeping
import gradio as gr | |
from groq import Groq | |
import os | |
from PIL import Image, ImageDraw, ImageFont | |
from datetime import datetime | |
import json | |
import tempfile | |
# Initialize Groq client | |
client = Groq( | |
api_key=os.getenv("GROQ_API_KEY") | |
) | |
class QuizApp: | |
def __init__(self): | |
self.current_questions = [] | |
self.user_data = {} | |
def generate_questions(self, text, num_questions): | |
prompt = f"""Create {num_questions} multiple choice questions based on this text: | |
{text} | |
Each question should: | |
1. Have a clear, concise question text | |
2. Have exactly 4 options | |
3. Have only one correct answer | |
4. Be educational and test understanding | |
Return the questions in this JSON format: | |
[ | |
{{ | |
"question": "Question text?", | |
"options": [ | |
"Correct answer", | |
"Wrong answer 1", | |
"Wrong answer 2", | |
"Wrong answer 3" | |
], | |
"correct_answers": [0] | |
}} | |
] | |
Only return the JSON array, no other text.""" | |
try: | |
response = client.chat.completions.create( | |
messages=[ | |
{"role": "system", "content": "You are a quiz generator that creates clear, single-choice questions."}, | |
{"role": "user", "content": prompt} | |
], | |
model="llama-3.2-3b-preview", | |
temperature=0.5, | |
max_tokens=2048, | |
top_p=0.9 | |
) | |
response_text = response.choices[0].message.content.strip() | |
# Remove any markdown formatting | |
response_text = response_text.replace("```json", "").replace("```", "").strip() | |
questions = json.loads(response_text) | |
if isinstance(questions, list): | |
self.current_questions = questions | |
else: | |
self.current_questions = questions.get("questions", []) | |
# Validate question format | |
for q in self.current_questions: | |
if not all(key in q for key in ["question", "options", "correct_answers"]): | |
raise ValueError("Invalid question format") | |
if len(q["options"]) != 4: | |
raise ValueError("Each question must have exactly 4 options") | |
return json.dumps(self.current_questions, indent=2) | |
except Exception as e: | |
print(f"Error generating questions: {e}") | |
return json.dumps([{ | |
"question": "Error generating questions. Please try again.", | |
"options": ["Error", "Error", "Error", "Error"], | |
"correct_answers": [0] | |
}]) | |
def calculate_score(self, answers): | |
try: | |
answers = json.loads(answers) if isinstance(answers, str) else answers | |
total = len(self.current_questions) | |
correct = 0 | |
for q, a in zip(self.current_questions, answers): | |
if set(a) == set(q["correct_answers"]): | |
correct += 1 | |
return (correct / total) * 100 | |
except Exception as e: | |
print(f"Error calculating score: {e}") | |
return 0 | |
def generate_certificate(self, name, score, course_name, company_logo=None, participant_photo=None): | |
try: | |
# Create certificate with a light blue background | |
certificate = Image.new('RGB', (1200, 800), '#F0F8FF') | |
draw = ImageDraw.Draw(certificate) | |
# Load fonts | |
try: | |
title_font = ImageFont.truetype("arial.ttf", 60) | |
text_font = ImageFont.truetype("arial.ttf", 40) | |
subtitle_font = ImageFont.truetype("arial.ttf", 30) | |
except: | |
print("Using default font as Arial not found") | |
title_font = ImageFont.load_default() | |
text_font = ImageFont.load_default() | |
subtitle_font = ImageFont.load_default() | |
# Add decorative border | |
draw.rectangle([20, 20, 1180, 780], outline='#4682B4', width=3) | |
# Draw certificate content | |
draw.text((600, 100), "CertifyMe AI", font=title_font, fill='#4682B4', anchor="mm") | |
draw.text((600, 160), "Certificate of Achievement", font=subtitle_font, fill='#4682B4', anchor="mm") | |
draw.text((600, 300), "This is to certify that", font=text_font, fill='black', anchor="mm") | |
draw.text((600, 380), name, font=text_font, fill='#4682B4', anchor="mm") | |
draw.text((600, 460), "has successfully completed", font=text_font, fill='black', anchor="mm") | |
draw.text((600, 540), course_name, font=text_font, fill='#4682B4', anchor="mm") | |
draw.text((600, 620), f"with a score of {score:.1f}%", font=text_font, fill='black', anchor="mm") | |
# Add date | |
current_date = datetime.now().strftime("%B %d, %Y") | |
draw.text((600, 700), current_date, font=text_font, fill='black', anchor="mm") | |
# Add logo if provided | |
if company_logo is not None: | |
try: | |
logo = Image.open(company_logo) | |
logo = logo.resize((150, 150)) | |
certificate.paste(logo, (50, 50)) | |
except Exception as e: | |
print(f"Error adding logo: {e}") | |
# Add photo if provided | |
if participant_photo is not None: | |
try: | |
photo = Image.open(participant_photo) | |
photo = photo.resize((150, 150)) | |
certificate.paste(photo, (1000, 50)) | |
except Exception as e: | |
print(f"Error adding photo: {e}") | |
# Save certificate | |
temp_file = tempfile.NamedTemporaryFile(delete=False, suffix='.png') | |
certificate.save(temp_file.name) | |
return temp_file.name | |
except Exception as e: | |
print(f"Error generating certificate: {e}") | |
return None | |
def create_quiz_app(): | |
quiz_app = QuizApp() | |
with gr.Blocks(title="CertifyMe AI", theme=gr.themes.Soft()) as demo: | |
current_tab = gr.State(0) | |
current_questions = gr.State([]) | |
user_answers = gr.State([]) | |
gr.Markdown(""" | |
# 🎓 CertifyMe AI | |
### Transform Your Knowledge into Recognized Achievements | |
""") | |
with gr.Tabs() as tabs: | |
# Step 1: Profile Setup (remains largely the same) | |
with gr.Tab("📋 Step 1: Profile Setup", id=0) as tab1: | |
# ... (previous profile setup code remains the same) | |
# Step 2: Take Assessment (completely revised) | |
with gr.Tab("📝 Step 2: Take Assessment", id=1) as tab2: | |
def format_questions(questions_json): | |
try: | |
questions = json.loads(questions_json) if isinstance(questions_json, str) else questions_json | |
return questions | |
except: | |
return [] | |
def display_questions(questions): | |
with gr.Group() as quiz_container: | |
answers = [] | |
for i, q in enumerate(questions): | |
gr.Markdown(f"### Question {i+1}") | |
gr.Markdown(q["question"]) | |
radio = gr.Radio( | |
choices=q["options"], | |
label="Select your answer", | |
value=None, | |
visible=True | |
) | |
answers.append(radio) | |
return quiz_container | |
def process_answers(answers): | |
processed = [] | |
for i, ans in enumerate(answers): | |
if ans is not None: | |
processed.append([i]) | |
return processed | |
questions_display = gr.JSON(visible=False) # Hidden JSON storage | |
quiz_area = gr.Group(visible=False) # Container for dynamic quiz content | |
submit_btn = gr.Button("Submit Assessment", variant="primary", visible=False) | |
score_display = gr.Number(label="Your Score", visible=False) | |
# Update the question display when questions are generated | |
questions_display.change( | |
fn=lambda q: ( | |
gr.Group(visible=True), | |
gr.Button(visible=True), | |
format_questions(q) | |
), | |
inputs=[questions_display], | |
outputs=[quiz_area, submit_btn, current_questions] | |
) | |
# Step 3: Get Certified | |
with gr.Tab("🎓 Step 3: Get Certified", id=2) as tab3: | |
gr.Markdown(""" | |
### Certification | |
- Your certificate will be generated automatically if you score 80% or above | |
- The certificate includes your name, score, and completion date | |
- Company logo and photo will be included if provided | |
- You can download your certificate once it's generated | |
""") | |
course_name = gr.Textbox( | |
label="Certification Title", | |
value="Professional Assessment Certification" | |
) | |
certificate_display = gr.Image(label="Your Certificate") | |
# Helper functions for tab navigation | |
def generate_and_switch_tab(text, num_questions): | |
questions = quiz_app.generate_questions(text, num_questions) | |
return questions, 1, gr.Markdown(visible=True), gr.Button(visible=True) | |
def calculate_score(selected_answers, questions): | |
correct = 0 | |
total = len(questions) | |
for q, ans in zip(questions, selected_answers): | |
if set(ans) == set(q["correct_answers"]): | |
correct += 1 | |
score = (correct / total) * 100 if total > 0 else 0 | |
return score, 2 | |
# Event handlers | |
generate_btn.click( | |
fn=generate_and_switch_tab, | |
inputs=[text_input, num_questions], | |
outputs=[questions_display, current_tab, quiz_area, submit_btn] | |
).then( | |
fn=lambda tab: gr.Tabs(selected=tab), | |
inputs=[current_tab], | |
outputs=[tabs] | |
) | |
submit_btn.click( | |
fn=calculate_score, | |
inputs=[user_answers, current_questions], | |
outputs=[score_display, current_tab] | |
).then( | |
fn=lambda tab: gr.Tabs(selected=tab), | |
inputs=[current_tab], | |
outputs=[tabs] | |
) | |
# Certificate generation remains the same | |
score_display.change( | |
fn=lambda score, user_name, course, logo, photo: ( | |
quiz_app.generate_certificate(user_name, score, course, logo, photo) | |
if score >= 80 else None | |
), | |
inputs=[score_display, name, course_name, company_logo, participant_photo], | |
outputs=certificate_display | |
) | |
return demo | |
# Main execution remains the same | |
if __name__ == "__main__": | |
if not os.getenv("GROQ_API_KEY"): | |
print("Please set your GROQ_API_KEY environment variable") | |
exit(1) | |
demo = create_quiz_app() | |
demo.launch() |