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()