# %% import random import gradio as gr from News import News from Gemma import GemmaLLM # import matplotlib.pyplot as plt # %% class Cooldown: ... cooldown = Cooldown() ################################## News fetching cooldown in seconds news = News() ########################################## Initialize the News object model = GemmaLLM() ##################################### Initialize the Gemma model # %% with gr.Blocks() as demo: gr.Markdown("# Reading & Quiz Application") ###### ###### State Variables and Components Initialization ###### init = ( ########################################### Initialize the Gradio interface with components and state variables gr.Markdown("## Read Articles"), ## State variables for news articles and quiz, gr.State({}), gr.State([]), gr.State({}), gr.Slider(label="Number of Articles", minimum=1, maximum=10, value=10, step=1), gr.Radio(label="Category (optional)", choices=news.__CATEGORIES__), gr.Button("Get Articles"), gr.Radio(visible=False), gr.Textbox(visible=False), gr.Button(visible=False), gr.Checkbox(visible=False), gr.Textbox(visible=False), gr.Button(visible=False), ## State variables for quiz gr.State([]), gr.State([]), gr.State(), [gr.Radio(visible=False) for _ in range(10)], gr.Button(visible=False), gr.Textbox(visible=False), gr.Button(visible=False), ) ( ################################################## State variables and components for news articles and quiz heading, ## Components for news articles article, articles, descriptions, num_headlines, category, get, headline, description, show, summarize, content, ready, ## Components for quiz answers, response, results, quiz, submit, evaluation, read, ) = init def hide_news(): ################################### Hide news-related components num_headlines = gr.Slider(visible=False) category = gr.Radio(visible=False) get = gr.Button(visible=False) headline = gr.Radio(visible=False) description = gr.Textbox(visible=False) show = gr.Button(visible=False) summarize = gr.Checkbox(visible=False) content = gr.Textbox(visible=False) ready = gr.Button(visible=False) return num_headlines, category, get, headline, description, show, summarize, content, ready def show_news(): ################################### Show news-related components num_headlines = gr.Slider(label="Number of Articles", minimum=1, maximum=10, value=10, step=1, visible=True) category = gr.Radio(label="Category (optional)", choices=news.__CATEGORIES__, visible=True) get = gr.Button("Get Articles", visible=True) return num_headlines, category, get def show_headline(headlines, descriptions): ######## Show news headlines and descriptions headline = gr.Radio(label="Select an Article", choices=headlines, value=headlines[0], interactive=True, visible=True) description = gr.Textbox(label="Article Description", value=descriptions[0], visible=True) show = gr.Button("Show Content", visible=True) return headline, description, show def show_content(content): ######################### Show article content and summary summarize = gr.Checkbox(label="Show Summary?", value=False, interactive=True, visible=True) content = gr.Textbox(label="Content", value=content, visible=True) ready = gr.Button("Begin Quiz", visible=True) return summarize, content, ready def format_mcq(mcq): ############################### Format multiple choice question for quiz if not mcq or not isinstance(mcq, dict): print(f"Multiple choice question object is a {type(mcq)} but should be {type(dict())}.") return "Invalid multiple choice question.", None question = mcq.get('question', 'No question provided.') answer = mcq.get('correct_answer', 'No correct answer provided.') false_answers = mcq.get('false_answers', []) if not isinstance(false_answers, list): print(f"False answers is a {type(false_answers)} but should be {type(list())}.") return "Invalid false answers format.", None options = random.shuffle([answer] + false_answers) return question, options, answer def hide_quiz(): ################################### Hide quiz-related components quiz = [gr.Radio(visible=False) for _ in range(10)] submit = gr.Button(visible=False) evaluation = gr.Textbox(visible=False) read = gr.Button(visible=False) return read, evaluation, submit, *quiz def show_quiz(mcqs): ############################### Show quiz-related components quiz = [(mcq["question"], mcq["false_answers"], mcq["correct_answer"]) for mcq in mcqs] quiz = [(question, random.sample(distractors + [answer], 4), answer) for question, distractors, answer in quiz] questions, options, answers = zip(*quiz) if quiz else ([], [], []) quiz = [gr.Radio(label=f"{i + 1}: {questions[i]}", choices=options[i], visible=True) for i in range(len(mcqs))] quiz += [gr.Radio(visible=False) for _ in range(10 - len(mcqs))] submit = gr.Button("Submit Answers", interactive=bool(answers), visible=True) return submit, list(answers), *quiz def show_eval(eva): ################################ Show evaluation of user's response to the quiz evaluation = gr.Textbox(label="Evaluation", value=eva, visible=True) read = gr.Button("Read Articles", visible=True) return evaluation, read ###### ###### Get and Display News Articles ###### def get_headline(category, num_headlines): ######### Get news headlines based on selected category and number articles = news.get_top_headlines(category=category, num_headlines=num_headlines) headlines, descriptions = zip(*[(article['title'], article.get('description', 'No description available.')) for article in articles]) show = show_headline(headlines, descriptions) descriptions = {h: d for h, d in zip(headlines, descriptions)} return articles, descriptions, *show get.click(get_headline, inputs=[category, num_headlines], outputs=[articles, descriptions, headline, description, show]) def get_description(descriptions, headline): ####### Get description for the selected headline description = "No description available." if not descriptions: print("Descriptions are empty.") elif not headline: print("Headline is empty.") elif not isinstance(descriptions, dict): print(f"Descriptions is a {type(descriptions)} but should be {type(dict())}.") else: description = descriptions.get(headline, description) return description headline.change(get_description, inputs=[descriptions, headline], outputs=[description]) def get_article(articles, headline): ############### Get article for the selected headline headlines = [a['title'] for a in articles] if headline not in headlines: return {} return articles[headlines.index(headline)] show.click(get_article, inputs=[articles, headline], outputs=[article]) def get_content(article): ########################## Get content for the selected article return article, *show_content(article.get("content", "Content not available.")) article.change(get_content, inputs=[article], outputs=[article, summarize, content, ready]) def toggle_summary(articles, article, summarize): ## Toggle between showing summary and full content if not article: print("Selected article is empty.") elif not isinstance(article, dict): print(f"Selected article is a {type(article)} but should be {type(dict())}.") elif not summarize: return article.get("content", "Content not available.") elif "summary" not in article: idx = articles.index(article) articles[idx]["summary"] = model.get_summary(article, 1) article = articles[idx] return article.get("summary", "Summary not available.") summarize.change(toggle_summary, inputs=[articles, article, summarize], outputs=[content]) ###### ###### Quiz Generation and Evaluation ###### def get_quiz(content): ############################# Generate quiz questions from the article content multichoicequests = [] if not content: mcqs = multichoicequests else: mcqs = model.get_questions(content, 3, "Moderate") if not isinstance(mcqs, list): print(f"Multiple choice questions object is a {type(mcqs)} but should be {type(list())}.") elif len(mcqs) == 0: print("Content is empty or no multiple choice questions generated.") for mcq in mcqs: missing = set() if not isinstance(mcq, dict): print(f"Multiple choice question object is {type(mcq)} but should be {type(dict())}.") else: missing = set(['question', 'correct_answer', 'false_answers']) - set(mcq.keys()) if missing: print(f"Multiple choice question object is missing keys: {missing}.") else: multichoicequests.append(mcq) return gr.Markdown("## Quiz"), *hide_news(), *show_quiz(multichoicequests) ready.click(get_quiz, inputs=[content], outputs=[ heading, num_headlines, category, get, headline, description, show, summarize, content, ready, submit, answers, *quiz]) def get_evaluation(answers, *quiz): ################ Evaluate the user's responses to the quiz results, response, evaluation = 0, list(quiz), "" if not answers: return "Answers are empty." elif not quiz: return "Quiz is empty." elif not isinstance(answers, list): return f"Answers is a {type(answers)} but should be {type(list())}." for i, (ans, resp) in enumerate(zip(answers, response)): if ans == resp: results += 1 evaluation += f"\n\t{i + 1}: Correct!" else: evaluation += f"\n\t{i + 1}: Incorrect." evaluation = f"You got {results} out of {len(answers)} correct.\n" + evaluation results /= len(answers) if 0.9 <= results <= 1.0: evaluation = f"Excellent! " + evaluation elif 0.8 <= results < 0.9: evaluation = f"Great job! " + evaluation elif 0.7 <= results < 0.8: evaluation = f"Good effort! " + evaluation elif 0.6 <= results < 0.7: evaluation = f"Keep practicing! " + evaluation elif 0.5 <= results < 0.6: evaluation = f"You can do better! " + evaluation else: evaluation = f"Keep trying! " + evaluation return show_eval(evaluation) submit.click(get_evaluation, inputs=[answers, *quiz], outputs=[evaluation, read]) def read_articles(): ############################### Reset the interface to read articles again return gr.Markdown("## News Articles"), *show_news(), *hide_quiz() read.click(read_articles, outputs=[heading, num_headlines, category, get, read, evaluation, submit, *quiz]) demo.launch() # def visualize_quiz_answers(answers, *quiz_items): # """ # Visualization of correct/incorrect answers from the quiz # """ # if not answers: # return None # correct = 0 # for user_ans, question in zip(answers, quiz_items): # if user_ans == question["correct_answer"]: # correct += 1 # incorrect = len(answers) - correct # fig, ax = plt.subplots() # ax.bar(["Correct", "Incorrect"], [correct, incorrect]) # ax.set_ylabel("Questions") # ax.set_title("Quiz Score Summary") # return fig