import pandas as pd import json import gradio as gr from pathlib import Path from ragatouille import RAGPretrainedModel from tempfile import NamedTemporaryFile from sentence_transformers import CrossEncoder import numpy as np from time import perf_counter from backend.semantic_search import table, retriever import os # Add Groq imports from phi.agent import Agent from phi.model.groq import Groq VECTOR_COLUMN_NAME = "vector" TEXT_COLUMN_NAME = "text" proj_dir = Path.cwd() # Set up logging import logging logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) # Replace Qwen client with Groq Agent setup api_key = os.getenv("GROQ_API_KEY") if not api_key: gr.Warning("GROQ_API_KEY not found. Set it in 'Repository secrets'.") logger.error("GROQ_API_KEY not found.") api_key = "" # Fallback to empty string, but this will fail without a key else: os.environ["GROQ_API_KEY"] = api_key # Initialize Groq Agent for quiz generation quiz_agent = Agent( name="Quiz Generation Assistant", role="You are an expert quiz generator for educational content", instructions=[ "You are an expert quiz generator specializing in creating educational quizzes.", "Create exactly 10 multiple choice questions with 4 options each.", "Base questions strictly on the provided documents.", "Return the response in the exact JSON format requested.", "Ensure questions match the specified difficulty level.", "Make sure all questions are clear and unambiguous." ], model=Groq(id="llama3-70b-8192", api_key=api_key), markdown=False ) def system_instructions(question_difficulty, topic, documents_str): return f"""You are a great teacher and your task is to create 10 questions with 4 choices with {question_difficulty} difficulty about the topic request "{topic}" only from the below given documents: {documents_str} Create questions and answers in JSON format with the following structure: - Questions as "Q1": "question text" to "Q10": "question text" - Four choices as "Q1:C1": "choice 1" to "Q1:C4": "choice 4" for each question - Answers as "A1": "Q1:C#" to "A10": "Q10:C#" where # is the correct choice number Example format: {{ "Q1": "What is photosynthesis?", "Q1:C1": "Process of breathing", "Q1:C2": "Process of making food using sunlight", "Q1:C3": "Process of reproduction", "Q1:C4": "Process of excretion", "A1": "Q1:C2" }} Provide complete JSON with all 10 questions, their choices, and answers.""" # RAG setup RAG_db = gr.State() quiz_data = None def json_to_excel(output_json): # Initialize list for DataFrame data = [] gr.Warning('Generating Shareable file link..', duration=30) for i in range(1, 11): # Assuming there are 10 questions question_key = f"Q{i}" answer_key = f"A{i}" question = output_json.get(question_key, '') correct_answer_key = output_json.get(answer_key, '') correct_answer = correct_answer_key.split(':')[-1].replace('C', '').strip() if correct_answer_key else '' # Extract options option_keys = [f"{question_key}:C{i}" for i in range(1, 6)] options = [output_json.get(key, '') for key in option_keys] # Add data row data.append([ question, # Question Text "Multiple Choice", # Question Type options[0], # Option 1 options[1], # Option 2 options[2] if len(options) > 2 else '', # Option 3 options[3] if len(options) > 3 else '', # Option 4 options[4] if len(options) > 4 else '', # Option 5 correct_answer, # Correct Answer 30, # Time in seconds '' # Image Link ]) # Create DataFrame df = pd.DataFrame(data, columns=[ "Question Text", "Question Type", "Option 1", "Option 2", "Option 3", "Option 4", "Option 5", "Correct Answer", "Time in seconds", "Image Link" ]) temp_file = NamedTemporaryFile(delete=False, suffix=".xlsx") df.to_excel(temp_file.name, index=False) return temp_file.name # Define a colorful theme colorful_theme = gr.themes.Default( primary_hue="cyan", # Set a bright cyan as primary color secondary_hue="yellow", # Set a bright magenta as secondary color neutral_hue="purple" # Optionally set a neutral color ) with gr.Blocks(title="Quiz Maker", theme=colorful_theme) as QUIZBOT: # Create a single row for the HTML and Image with gr.Row(): with gr.Column(scale=2): gr.Image(value='logo.png', height=200, width=200) with gr.Column(scale=6): gr.HTML("""

ADWITIYA Customs Manual Quizbot

Generative AI-powered Capacity building for Training Officers

⚠️ NACIN Faculties create quiz from any topic dynamically for classroom evaluation after their sessions ! ⚠️
""") topic = gr.Textbox(label="Enter the Topic for Quiz", placeholder="Write any topic/details from Customs Manual") with gr.Row(): difficulty_radio = gr.Radio(["easy", "average", "hard"], label="How difficult should the quiz be?") model_radio = gr.Radio(choices=[ '(ACCURATE) BGE reranker', '(HIGH ACCURATE) ColBERT'], value='(ACCURATE) BGE reranker', label="Embeddings", info="First query to ColBERT may take a little time") generate_quiz_btn = gr.Button("Generate Quiz!🚀") quiz_msg = gr.Textbox() question_radios = [gr.Radio(visible=False) for _ in range(10)] @generate_quiz_btn.click(inputs=[difficulty_radio, topic, model_radio], outputs=[quiz_msg] + question_radios + [gr.File(label="Download Excel")]) def generate_quiz(question_difficulty, topic, cross_encoder): top_k_rank = 10 documents = [] gr.Warning('Generating Quiz may take 1-2 minutes. Please wait.', duration=60) if cross_encoder == '(HIGH ACCURATE) ColBERT': gr.Warning('Retrieving using ColBERT.. First-time query will take 2 minute for model to load.. please wait',duration=100) RAG = RAGPretrainedModel.from_pretrained("colbert-ir/colbertv2.0") RAG_db.value = RAG.from_index('.ragatouille/colbert/indexes/cbseclass10index') documents_full = RAG_db.value.search(topic, k=top_k_rank) documents = [item['content'] for item in documents_full] else: document_start = perf_counter() query_vec = retriever.encode(topic) doc1 = table.search(query_vec, vector_column_name=VECTOR_COLUMN_NAME).limit(top_k_rank) documents = table.search(query_vec, vector_column_name=VECTOR_COLUMN_NAME).limit(top_k_rank).to_list() documents = [doc[TEXT_COLUMN_NAME] for doc in documents] query_doc_pair = [[topic, doc] for doc in documents] if cross_encoder == '(ACCURATE) BGE reranker': cross_encoder1 = CrossEncoder('BAAI/bge-reranker-base') cross_scores = cross_encoder1.predict(query_doc_pair) sim_scores_argsort = list(reversed(np.argsort(cross_scores))) documents = [documents[idx] for idx in sim_scores_argsort[:top_k_rank]] formatted_prompt = system_instructions(question_difficulty, topic, '\n'.join(documents)) print('Formatted Prompt:', formatted_prompt) try: # Use Groq Agent instead of Qwen client response = quiz_agent.run(formatted_prompt) response_text = response.content if hasattr(response, 'content') else str(response) print("Agent Response:", response_text) # Extract JSON from response start_index = response_text.find('{') end_index = response_text.rfind('}') cleaned_response = response_text[start_index:end_index + 1] if start_index != -1 and end_index != -1 else '' print('Cleaned Response:', cleaned_response) output_json = json.loads(cleaned_response) # Assign the extracted JSON to quiz_data for use in the comparison function global quiz_data quiz_data = output_json # Generate the Excel file excel_file = json_to_excel(output_json) question_radio_list = [] for question_num in range(1, 11): question_key = f"Q{question_num}" answer_key = f"A{question_num}" question = output_json.get(question_key) answer = output_json.get(output_json.get(answer_key)) if not question or not answer: continue choice_keys = [f"{question_key}:C{i}" for i in range(1, 5)] choice_list = [output_json.get(choice_key, "Choice not found") for choice_key in choice_keys] radio = gr.Radio(choices=choice_list, label=question, visible=True, interactive=True) question_radio_list.append(radio) return ['Quiz Generated!'] + question_radio_list + [excel_file] except json.JSONDecodeError as e: print(f"Failed to decode JSON: {e}") return ['Error generating quiz. Please try again.'] + [gr.Radio(visible=False) for _ in range(10)] + [None] except Exception as e: print(f"Error in quiz generation: {e}") return ['Error generating quiz. Please try again.'] + [gr.Radio(visible=False) for _ in range(10)] + [None] check_button = gr.Button("Check Score") score_textbox = gr.Markdown() @check_button.click(inputs=question_radios, outputs=score_textbox) def compare_answers(*user_answers): user_answer_list = list(user_answers) answers_list = [] for question_num in range(1, 20): answer_key = f"A{question_num}" answer = quiz_data.get(quiz_data.get(answer_key)) if not answer: break answers_list.append(answer) score = sum(1 for item in user_answer_list if item in answers_list) if score > 7: message = f"### Excellent! You got {score} out of 10!" elif score > 5: message = f"### Good! You got {score} out of 10!" else: message = f"### You got {score} out of 10! Don't worry. You can prepare well and try better next time!" return message QUIZBOT.queue() QUIZBOT.launch(debug=True) # import pandas as pd # import json # import gradio as gr # from pathlib import Path # from ragatouille import RAGPretrainedModel # from gradio_client import Client # from tempfile import NamedTemporaryFile # from sentence_transformers import CrossEncoder # import numpy as np # from time import perf_counter # from sentence_transformers import CrossEncoder # from backend.semantic_search import table, retriever # import os # VECTOR_COLUMN_NAME = "vector" # TEXT_COLUMN_NAME = "text" # proj_dir = Path.cwd() # # Set up logging # import logging # logging.basicConfig(level=logging.INFO) # logger = logging.getLogger(__name__) # # Replace Mixtral client with Qwen Client # #client = Client("Qwen/Qwen1.5-110B-Chat-demo") # # Step 2: Initialize the client for the Qwen3 Demo space # hf_token=os.getenv('HUGGING_FACE_HUB_TOKEN') # client = Client("Qwen/Qwen3-Demo",hf_token=hf_token) # settings = { # "model": "qwen3-235b-a22b", # "sys_prompt": "You are a helpful and harmless assistant.", # "thinking_budget": 38 # } # def system_instructions(question_difficulty, topic, documents_str): # return f""" [INST] You are a great teacher and your task is to create 10 questions with 4 choices with {question_difficulty} difficulty about the topic request "{topic}" only from the below given documents, {documents_str}. Then create answers. Index in JSON format, the questions as "Q#":"" to "Q#":"", the four choices as "Q#:C1":"" to "Q#:C4":"", and the answers as "A#":"Q#:C#" to "A#":"Q#:C#". Example: 'A10':'Q10:C3' [/INST]""" # # RA # RAG_db = gr.State() # quiz_data = None # def json_to_excel(output_json): # # Initialize list for DataFrame # data = [] # gr.Warning('Generating Shareable file link..', duration=30) # for i in range(1, 11): # Assuming there are 10 questions # question_key = f"Q{i}" # answer_key = f"A{i}" # question = output_json.get(question_key, '') # correct_answer_key = output_json.get(answer_key, '') # #correct_answer = correct_answer_key.split(':')[-1] if correct_answer_key else '' # correct_answer = correct_answer_key.split(':')[-1].replace('C', '').strip() if correct_answer_key else '' # # Extract options # option_keys = [f"{question_key}:C{i}" for i in range(1, 6)] # options = [output_json.get(key, '') for key in option_keys] # # Add data row # data.append([ # question, # Question Text # "Multiple Choice", # Question Type # options[0], # Option 1 # options[1], # Option 2 # options[2] if len(options) > 2 else '', # Option 3 # options[3] if len(options) > 3 else '', # Option 4 # options[4] if len(options) > 4 else '', # Option 5 # correct_answer, # Correct Answer # 30, # Time in seconds # '' # Image Link # ]) # # Create DataFrame # df = pd.DataFrame(data, columns=[ # "Question Text", # "Question Type", # "Option 1", # "Option 2", # "Option 3", # "Option 4", # "Option 5", # "Correct Answer", # "Time in seconds", # "Image Link" # ]) # temp_file = NamedTemporaryFile(delete=False, suffix=".xlsx") # df.to_excel(temp_file.name, index=False) # return temp_file.name # # Define a colorful theme # colorful_theme = gr.themes.Default( # primary_hue="cyan", # Set a bright cyan as primary color # secondary_hue="yellow", # Set a bright magenta as secondary color # neutral_hue="purple" # Optionally set a neutral color # ) # #with gr.Blocks(title="Quiz Maker", theme=gr.themes.Default(primary_hue="green", secondary_hue="green")) as QUIZBOT: # with gr.Blocks(title="Quiz Maker", theme=colorful_theme) as QUIZBOT: # # Create a single row for the HTML and Image # with gr.Row(): # with gr.Column(scale=2): # gr.Image(value='logo.png', height=200, width=200) # with gr.Column(scale=6): # gr.HTML(""" #
#

ADWITIYA Customs Manual Quizbot

#

Generative AI-powered Capacity building for Training Officers

# ⚠️ NACIN Faculties create quiz from any topic dynamically for classroom evaluation after their sessions ! ⚠️ #
# """) # topic = gr.Textbox(label="Enter the Topic for Quiz", placeholder="Write any topic/details from Customs Manual") # with gr.Row(): # difficulty_radio = gr.Radio(["easy", "average", "hard"], label="How difficult should the quiz be?") # model_radio = gr.Radio(choices=[ '(ACCURATE) BGE reranker', '(HIGH ACCURATE) ColBERT'], # value='(ACCURATE) BGE reranker', label="Embeddings", # info="First query to ColBERT may take a little time") # generate_quiz_btn = gr.Button("Generate Quiz!🚀") # quiz_msg = gr.Textbox() # question_radios = [gr.Radio(visible=False) for _ in range(10)] # @generate_quiz_btn.click(inputs=[difficulty_radio, topic, model_radio], outputs=[quiz_msg] + question_radios + [gr.File(label="Download Excel")]) # def generate_quiz(question_difficulty, topic, cross_encoder): # top_k_rank = 10 # documents = [] # gr.Warning('Generating Quiz may take 1-2 minutes. Please wait.', duration=60) # if cross_encoder == '(HIGH ACCURATE) ColBERT': # gr.Warning('Retrieving using ColBERT.. First-time query will take 2 minute for model to load.. please wait',duration=100) # RAG = RAGPretrainedModel.from_pretrained("colbert-ir/colbertv2.0") # RAG_db.value = RAG.from_index('.ragatouille/colbert/indexes/cbseclass10index') # documents_full = RAG_db.value.search(topic, k=top_k_rank) # documents = [item['content'] for item in documents_full] # else: # document_start = perf_counter() # query_vec = retriever.encode(topic) # doc1 = table.search(query_vec, vector_column_name=VECTOR_COLUMN_NAME).limit(top_k_rank) # documents = table.search(query_vec, vector_column_name=VECTOR_COLUMN_NAME).limit(top_k_rank).to_list() # documents = [doc[TEXT_COLUMN_NAME] for doc in documents] # query_doc_pair = [[topic, doc] for doc in documents] # # if cross_encoder == '(FAST) MiniLM-L6v2': # # cross_encoder1 = CrossEncoder('cross-encoder/ms-marco-MiniLM-L-6-v2') # if cross_encoder == '(ACCURATE) BGE reranker': # cross_encoder1 = CrossEncoder('BAAI/bge-reranker-base') # cross_scores = cross_encoder1.predict(query_doc_pair) # sim_scores_argsort = list(reversed(np.argsort(cross_scores))) # documents = [documents[idx] for idx in sim_scores_argsort[:top_k_rank]] # formatted_prompt = system_instructions(question_difficulty, topic, '\n'.join(documents)) # print(' Formatted Prompt : ' ,formatted_prompt) # try: # #response = client.predict(query=formatted_prompt, history=[], system="You are a helpful assistant.", api_name="/model_chat") # # Step 3: Define the input message and model settings # response = client.predict( # input_value=formatted_prompt, # settings_form_value=settings, # api_name="/add_message" # ) # # Step 5: Extract the assistant's final text response from the chat history # chat_history = response[1] # response[1] contains the updated chat history # assistant_response = None # # Loop through the messages in reverse to find the most recent assistant message # for message in reversed(chat_history["value"]): # if message["role"] == "assistant": # # Find the text content part # for content_item in message["content"]: # if content_item["type"] == "text": # assistant_response = content_item["content"] # break # if assistant_response: # break # # Step 6: Print only the assistant's natural language response # if assistant_response: # print("Assistant Response:") # print(assistant_response) # else: # print("No assistant response found in the chat history.") # #response1 = response[1][0][1] # response1=assistant_response # # Extract JSON # start_index = response1.find('{') # end_index = response1.rfind('}') # cleaned_response = response1[start_index:end_index + 1] if start_index != -1 and end_index != -1 else '' # print('Cleaned Response :',cleaned_response) # output_json = json.loads(cleaned_response) # # Assign the extracted JSON to quiz_data for use in the comparison function # global quiz_data # quiz_data = output_json # # Generate the Excel file # excel_file = json_to_excel(output_json) # question_radio_list = [] # for question_num in range(1, 11): # question_key = f"Q{question_num}" # answer_key = f"A{question_num}" # question = output_json.get(question_key) # answer = output_json.get(output_json.get(answer_key)) # if not question or not answer: # continue # choice_keys = [f"{question_key}:C{i}" for i in range(1, 5)] # choice_list = [output_json.get(choice_key, "Choice not found") for choice_key in choice_keys] # radio = gr.Radio(choices=choice_list, label=question, visible=True, interactive=True) # question_radio_list.append(radio) # return ['Quiz Generated!'] + question_radio_list + [excel_file] # except json.JSONDecodeError as e: # print(f"Failed to decode JSON: {e}") # check_button = gr.Button("Check Score") # score_textbox = gr.Markdown() # @check_button.click(inputs=question_radios, outputs=score_textbox) # def compare_answers(*user_answers): # user_answer_list = list(user_answers) # answers_list = [] # for question_num in range(1, 20): # answer_key = f"A{question_num}" # answer = quiz_data.get(quiz_data.get(answer_key)) # if not answer: # break # answers_list.append(answer) # score = sum(1 for item in user_answer_list if item in answers_list) # if score > 7: # message = f"### Excellent! You got {score} out of 10!" # elif score > 5: # message = f"### Good! You got {score} out of 10!" # else: # message = f"### You got {score} out of 10! Don't worry. You can prepare well and try better next time!" # return message # QUIZBOT.queue() # QUIZBOT.launch(debug=True)