import streamlit as st import PyPDF2 import json from xai_sdk import Client from xai_sdk.chat import user, system from langchain_text_splitters import RecursiveCharacterTextSplitter from dotenv import load_dotenv import os import random load_dotenv() # .env file se API key load kar sakte ho (optional) st.set_page_config(page_title="PDF เคธเฅ‡ Pro Quiz Generator", page_icon="๐Ÿง ", layout="wide") st.title("๐Ÿ“„ PDF เคธเฅ‡ High-Quality Quiz Generator (50 เคคเค• Questions)") st.markdown("Upload PDF โ†’ Grok se accurate MCQs banaye โ†’ Quiz attempt karo aur score dekho!") # Sidebar with st.sidebar: st.header("Settings") api_key = st.text_input("xAI Grok API Key", type="password", value=os.getenv("XAI_API_KEY", "")) model = st.selectbox("Grok Model", ["grok-beta", "grok-4"], index=0) # Latest models check kar lena docs se num_questions = st.slider("Kitne questions chahiye?", 5, 50, 15, step=5) difficulty = st.selectbox("Difficulty Level", ["Easy", "Medium", "Hard", "Mixed"], index=2) if not api_key: st.warning("API key daalo sidebar mein. https://console.x.ai se milega.") st.stop() # PDF Upload uploaded_file = st.file_uploader("PDF file daalo (.pdf)", type="pdf") if uploaded_file and st.button("๐Ÿš€ Quiz Generate Karo", type="primary"): if not api_key: st.error("API key missing hai!") st.stop() with st.spinner("PDF padh raha hoon + questions bana raha hoon... (1-2 min lagega)"): # PDF โ†’ Text try: reader = PyPDF2.PdfReader(uploaded_file) full_text = "" for page in reader.pages: text = page.extract_text() or "" full_text += text + "\n\n" if len(full_text.strip()) < 200: st.error("PDF mein readable text bahut kam hai (scanned image PDF ho sakta hai). OCR tool use karo pehle.") st.stop() except Exception as e: st.error(f"PDF padhne mein problem: {e}") st.stop() # Text ko chunks mein baanto (context limit ke liye) splitter = RecursiveCharacterTextSplitter( chunk_size=12000, # ~3000-4000 tokens safe chunk_overlap=1500, length_function=len ) chunks = splitter.split_text(full_text) st.info(f"PDF ko {len(chunks)} chunks mein baanta gaya.") # Grok client client = Client(api_key=api_key) all_mcqs = [] questions_per_chunk = max(3, num_questions // len(chunks) + 1) progress_bar = st.progress(0) status_text = st.empty() for i, chunk in enumerate(chunks): status_text.text(f"Processing chunk {i+1}/{len(chunks)}...") prompt = f""" You are an expert quiz creator and educator. From the given content, create exactly **{questions_per_chunk}** high-quality MCQs. Rules (strictly follow): - Questions factual, clear, and based ONLY on the provided text. - Each has exactly 4 options (A, B, C, D). - Only ONE correct answer. - Options should be plausible but only one 100% correct. - Vary difficulty: {difficulty} level (make some tricky if medium/hard). - No duplicates with previous questions. - Output **ONLY valid JSON array**, nothing else. No explanation, no markdown. Format: [ {{ "question": "Question text?", "A": "Option A here", "B": "Option B here", "C": "Option C here", "D": "Option D here", "correct": "A", // only A/B/C/D "explanation": "Short explanation why this is correct (1-2 sentences)" }} ] Content: {chunk} """ try: chat = client.chat.create(model=model) chat.append(system("You are a precise quiz generator. Respond with ONLY the requested JSON array. No other text.")) chat.append(user(prompt)) response = chat.sample() content = response.content.strip() # JSON try parse mcqs = json.loads(content) if isinstance(mcqs, list): all_mcqs.extend(mcqs) except Exception as e: st.warning(f"Chunk {i+1} mein error: {e}. Skipping...") progress_bar.progress((i + 1) / len(chunks)) status_text.text("Done!") # Limit to desired number all_mcqs = all_mcqs[:num_questions] if not all_mcqs: st.error("Koi bhi question generate nahi hua. Prompt ya API check karo.") st.stop() # Shuffle questions random.shuffle(all_mcqs) st.session_state.mcqs = all_mcqs st.session_state.user_answers = [None] * len(all_mcqs) st.session_state.score = 0 st.success(f"**{len(all_mcqs)} high-quality questions ready!** Ab quiz attempt karo โ†“") # ---------------- Quiz Mode ---------------- if 'mcqs' in st.session_state and st.session_state.mcqs: st.subheader("๐Ÿง  Quiz Time โ€“ Attempt Karo!") score = 0 for idx, q in enumerate(st.session_state.mcqs): st.markdown(f"**Q{idx+1}:** {q.get('question', 'N/A')}") options = ["A", "B", "C", "D"] choice = st.radio( "Choose answer:", options, format_func=lambda x: f"{x}) {q.get(x, 'N/A')}", key=f"q_{idx}", index=None if st.session_state.user_answers[idx] is None else options.index(st.session_state.user_answers[idx]) ) if choice: st.session_state.user_answers[idx] = choice # Show explanation only after attempt (optional toggle) if st.toggle("Explanation dikhao", key=f"exp_{idx}", value=False): st.info(q.get("explanation", "No explanation available.")) if st.button("๐Ÿ“Š Submit Quiz & See Score", type="primary"): score = sum(1 for i, ans in enumerate(st.session_state.user_answers) if ans == st.session_state.mcqs[i].get("correct")) st.balloons() st.success(f"**Your Score: {score} / {len(st.session_state.mcqs)}** ({score/len(st.session_state.mcqs)*100:.1f}%)") # Show correct answers with st.expander("Detailed Answers & Explanations"): for i, q in enumerate(st.session_state.mcqs): user_ans = st.session_state.user_answers[i] correct = q["correct"] st.write(f"**Q{i+1}:** {q['question']}") st.write(f"Your answer: **{user_ans or 'Not attempted'}**") st.write(f"Correct: **{correct}** โ†’ {q.get('A','')} / {q.get('B','')} / {q.get('C','')} / {q.get('D','')}") st.info(f"Explanation: {q.get('explanation','')}") st.markdown("---") # Download JSON st.download_button( "Download Quiz (JSON)", json.dumps(st.session_state.mcqs, ensure_ascii=False, indent=2), file_name="my_generated_quiz.json", mime="application/json" ) st.markdown("---") st.caption("Made with โค๏ธ using Grok API + Streamlit | Questions improve karne ke liye prompt tweak kar sakte ho")