Spaces:
Running
Running
Jeff Myers II
Replaced Gemma for OpenAI API and commented out visualize_quiz_answers (seems to be breaking the script).
54e639b
# %% | |
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 | |