import os import re import json import torch import gradio as gr from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig MODEL_ID = os.environ.get("HF_MODEL_ID") CONTACT_EMAIL = "vinothvikas1987@gmail.com" MAX_FREE = 5 SUBJECTS_TOPICS = { "Physics": [ "Physics and Measurement", "Kinematics", "Laws of Motion", "Work, Energy, and Power", "Rotational Motion", "Gravitation", "Properties of Solids and Liquids", "Thermodynamics", "Kinetic Theory of Gases", "Oscillations and Waves", "Electrostatics", "Current Electricity", "Magnetic Effects of Current and Magnetism", "Electromagnetic Induction and Alternating Currents", "Electromagnetic Waves", "Optics", "Dual Nature of Matter and Radiation", "Atoms and Nuclei", "Electronic Devices", "Experimental Skills" ], "Chemistry": [ "Some Basic Concepts of Chemistry", "Structure of Atom", "Classification of Elements and Periodicity in Properties", "Chemical Bonding and Molecular Structure", "States of Matter: Gases and Liquids", "Thermodynamics", "Equilibrium", "Redox Reactions", "Hydrogen", "s-Block Elements", "p-Block Elements", "Organic Chemistry: Basic Principles and Techniques", "Hydrocarbons", "Environmental Chemistry", "Solid State", "Solutions", "Electrochemistry", "Chemical Kinetics", "Surface Chemistry", "Isolation of Elements" ], "Botany": [ "Diversity in the Living World", "Structural Organisation in Plants and Animals", "Cell Structure and Function", "Plant Physiology", "Human Physiology", "Reproduction", "Genetics and Evolution", "Biology and Human Welfare", "Biotechnology", "Ecology and Environment" ], "Zoology": [ "Animal Kingdom", "Structural Organisation in Animals", "Animal Physiology", "Human Physiology", "Reproduction", "Genetics and Evolution", "Biology and Human Welfare", "Biotechnology", "Ecology and Environment" ] } bnb_config = BitsAndBytesConfig( load_in_4bit=True, bnb_4bit_use_double_quant=True, bnb_4bit_quant_type="nf4", bnb_4bit_compute_dtype=torch.bfloat16 ) tokenizer = AutoTokenizer.from_pretrained(MODEL_ID, trust_remote_code=True) model = AutoModelForCausalLM.from_pretrained( MODEL_ID, quantization_config=bnb_config, device_map="auto", trust_remote_code=True ) def generate(subject, topic): prompt = f"Generate a {subject} question on the topic '{topic}' without a diagram." inputs = tokenizer(prompt, return_tensors="pt").to(model.device) outputs = model.generate(**inputs, max_new_tokens=300, temperature=0.7) result = tokenizer.decode(outputs[0], skip_special_tokens=True) json_blocks = re.findall(r'\{.*?\}(?=\{|\Z)', result, re.DOTALL) for block in json_blocks: try: d = json.loads(block) lines = [ f"**Subject:** {d.get('Subject', 'N/A')}", f"**Topic:** {d.get('Topic', 'N/A')}", "", f"**Q{d.get('question_number', '?')}.** {d.get('question_text', '').strip()}", "", "**Options:**" ] for i, opt in enumerate(d.get('options', {}).values(), 1): lines.append(f" {i}. {opt}") lines.append(f"\n**Correct Answer:** Option {d.get('answer', 'N/A')}") return "\n".join(lines) except json.JSONDecodeError: continue return "Could not generate a valid question. Try again." def update_topics(subject): return gr.Dropdown(choices=SUBJECTS_TOPICS[subject], value=SUBJECTS_TOPICS[subject][0]) def on_generate(subject, topic, count): if count >= MAX_FREE: return ( f"**Free limit reached!**\n\n" f"Contact **{CONTACT_EMAIL}** for unlimited access.", count, gr.update(interactive=False) ) result = generate(subject, topic) count += 1 if count >= MAX_FREE: result += ( f"\n\n---\n**Free limit reached!** " f"Email **{CONTACT_EMAIL}** for unlimited access." ) return result, count, gr.update(interactive=False) remaining = MAX_FREE - count result += f"\n\n*{remaining} free question(s) remaining*" return result, count, gr.update(interactive=True) with gr.Blocks(title="NEET Question Generator", theme=gr.themes.Soft()) as demo: gr.Markdown("# NEET Question Generator") gr.Markdown("Select a subject and topic to generate NEET-style MCQs.") state = gr.State(0) with gr.Row(): subject_dd = gr.Dropdown( choices=list(SUBJECTS_TOPICS.keys()), label="Subject", value="Physics" ) topic_dd = gr.Dropdown( choices=SUBJECTS_TOPICS["Physics"], label="Topic" ) subject_dd.change(fn=update_topics, inputs=subject_dd, outputs=topic_dd) btn = gr.Button("Generate Question", variant="primary") output = gr.Markdown() btn.click( fn=on_generate, inputs=[subject_dd, topic_dd, state], outputs=[output, state, btn] ) if __name__ == "__main__": demo.launch()