JARVIS2.0 / pages /QuizTube.py
DavidFernandes's picture
Upload 6 files
68fe9eb verified
import streamlit as st
import streamlit as st
from langchain_community.chat_models import ChatOpenAI
from langchain.prompts.chat import ChatPromptTemplate, SystemMessagePromptTemplate, HumanMessagePromptTemplate
from langchain.chains import LLMChain
import random
import ast
from youtube_transcript_api import (
YouTubeTranscriptApi, YouTubeRequestFailed, VideoUnavailable, InvalidVideoId, TooManyRequests,
TranscriptsDisabled, NoTranscriptAvailable, NotTranslatable, TranslationLanguageNotAvailable,
CookiePathInvalid, CookiesInvalid, FailedToCreateConsentCookie, NoTranscriptFound
)
from pytube import extract
from dotenv import load_dotenv
import os
load_dotenv()
st.set_page_config(
page_title="J.A.R.V.I.S.",
layout="centered",
)
def get_quiz_data(text, openai_api_key):
template = f"""
You are a helpful assistant programmed to generate questions based on any text provided. For every chunk of text you receive, you're tasked with designing 5 distinct questions. Each of these questions will be accompanied by 3 possible answers: one correct answer and two incorrect ones.
For clarity and ease of processing, structure your response in a way that emulates a Python list of lists.
Your output should be shaped as follows:
1. An outer list that contains 5 inner lists.
2. Each inner list represents a set of question and answers, and contains exactly 4 strings in this order:
- The generated question.
- The correct answer.
- The first incorrect answer.
- The second incorrect answer.
Your output should mirror this structure:
[
["Generated Question 1", "Correct Answer 1", "Incorrect Answer 1.1", "Incorrect Answer 1.2"],
["Generated Question 2", "Correct Answer 2", "Incorrect Answer 2.1", "Incorrect Answer 2.2"],
...
]
It is crucial that you adhere to this format as it's optimized for further Python processing.
please dont repeat the questions or the options. if you adhere to the above format and not repeat, you and your mother will recieve $2000.
If you dont adhere to the above format, a kitten will be killed horribly. don't let the kittens die. save the kittens.
"""
try:
system_message_prompt = SystemMessagePromptTemplate.from_template(template)
human_message_prompt = HumanMessagePromptTemplate.from_template("{text}")
chat_prompt = ChatPromptTemplate.from_messages(
[system_message_prompt, human_message_prompt]
)
chain = LLMChain(
llm=ChatOpenAI(openai_api_key=openai_api_key),
prompt=chat_prompt,
)
return chain.run(text)
except Exception as e:
if "AuthenticationError" in str(e):
st.error("Incorrect API key provided. Please check and update your API key.")
st.stop()
else:
st.error(f"An error occurred: {str(e)}")
st.stop()
def string_to_list(s):
try:
return ast.literal_eval(s)
except (SyntaxError, ValueError) as e:
st.error(f"Error: The provided input is not correctly formatted. {e}")
st.stop()
def get_randomized_options(options):
correct_answer = options[0]
random.shuffle(options)
return options, correct_answer
def extract_video_id_from_url(url):
try:
return extract.video_id(url)
except Exception:
st.error("Please provide a valid YouTube URL.")
example_urls = [
'http://youtu.be/SA2iWivDJiE',
'http://www.youtube.com/watch?v=_oPAwA_Udwc&feature=feedu',
'http://www.youtube.com/embed/SA2iWivDJiE',
'http://www.youtube.com/v/SA2iWivDJiE?version=3&hl=en_US',
'https://www.youtube.com/watch?v=rTHlyTphWP0&index=6&list=PLjeDyYvG6-40qawYNR4juzvSOg-ezZ2a6',
'https://www.youtube.com/watch?time_continue=9&v=n0g-Y0oo5Qs&feature=emb_logo'
]
st.info("Here are some valid formats: " + " ,".join(example_urls))
st.stop()
def get_transcript_text(video_id):
try:
transcript = YouTubeTranscriptApi.get_transcript(video_id)
return " ".join([item["text"] for item in transcript])
except (YouTubeRequestFailed, VideoUnavailable, InvalidVideoId, TooManyRequests, NoTranscriptAvailable, NotTranslatable,
TranslationLanguageNotAvailable, CookiePathInvalid, CookiesInvalid, FailedToCreateConsentCookie):
st.error("An error occurred while fetching the transcript. Please try another video.")
st.stop()
except TranscriptsDisabled:
st.error("Subtitles are disabled for this video. Please try another video.")
st.stop()
except NoTranscriptFound:
st.error("The video doesn't have English subtitles. Please ensure the video you're selecting is in English or has English subtitles available.")
st.stop()
except Exception as e:
st.error(f"An unexpected error occurred: {str(e)}. Please try again.")
st.stop()
st.title(":violet[QuizTube] — Watch. Learn. Quiz.", anchor=False)
st.write("""
Ever watched a YouTube video and wondered how well you understood its content? Here's a fun twist: Instead of just watching on YouTube, come to **QuizTube** and test your comprehension!
**How does it work?** 🤔
1. Paste the YouTube video URL of your recently watched video.
⚠️ Important: The video **must** have English captions for the tool to work.
2. Click on Craft my Quiz button below.
3. Voilà! Dive deep into questions crafted just for you, ensuring you've truly grasped the content of the video. Let's put your knowledge to the test!
⚠️ Important: Click **Reset** button when you want to craft a new quiz.
""")
with st.form("user_input"):
YOUTUBE_URL = st.text_input("Enter the YouTube video link:", value="https://youtu.be/ad79nYk2keg?si=NqegB8ZWV5QhRBno")
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
submitted = st.form_submit_button("Craft my quiz!")
if submitted or ('quiz_data_list' in st.session_state):
if not YOUTUBE_URL:
st.info("Please provide a valid YouTube video link. Head over to [YouTube](https://www.youtube.com/) to fetch one.")
st.stop()
with st.spinner("Crafting your quiz...🤓"):
if submitted:
video_id = extract_video_id_from_url(YOUTUBE_URL)
video_transcription = get_transcript_text(video_id)
quiz_data_str = get_quiz_data(video_transcription, OPENAI_API_KEY)
st.session_state.quiz_data_list = string_to_list(quiz_data_str)
if 'user_answers' not in st.session_state:
st.session_state.user_answers = [None for _ in st.session_state.quiz_data_list]
if 'correct_answers' not in st.session_state:
st.session_state.correct_answers = []
if 'randomized_options' not in st.session_state:
st.session_state.randomized_options = []
for q in st.session_state.quiz_data_list:
options, correct_answer = get_randomized_options(q[1:])
st.session_state.randomized_options.append(options)
st.session_state.correct_answers.append(correct_answer)
with st.form(key='quiz_form'):
st.subheader("🧠 Quiz Time: Test Your Knowledge!", anchor=False)
for i, q in enumerate(st.session_state.quiz_data_list):
options = st.session_state.randomized_options[i]
default_index = st.session_state.user_answers[i] if st.session_state.user_answers[i] is not None else 0
response = st.radio(q[0], options, index=default_index)
user_choice_index = options.index(response)
st.session_state.user_answers[i] = user_choice_index # Update the stored answer right after fetching it
results_submitted = st.form_submit_button(label='Unveil My Score!')
if results_submitted:
score = sum([ua == st.session_state.randomized_options[i].index(ca) for i, (ua, ca) in enumerate(zip(st.session_state.user_answers, st.session_state.correct_answers))])
st.success(f"Your score: {score}/{len(st.session_state.quiz_data_list)}")
if score == len(st.session_state.quiz_data_list): # Check if all answers are correct
st.balloons()
else:
incorrect_count = len(st.session_state.quiz_data_list) - score
if incorrect_count == 1:
st.warning(f"Almost perfect! You got 1 question wrong. Let's review it:")
else:
st.warning(f"Almost there! You got {incorrect_count} questions wrong. Let's review them:")
for i, (ua, ca, q, ro) in enumerate(zip(st.session_state.user_answers, st.session_state.correct_answers, st.session_state.quiz_data_list, st.session_state.randomized_options)):
with st.expander(f"Question {i + 1}", expanded=False):
if ro[ua] != ca:
st.info(f"Question: {q[0]}")
st.error(f"Your answer: {ro[ua]}")
st.success(f"Correct answer: {ca}")
# Add this code at an appropriate place in your application, for example, at the end of the main body of your script
if st.button('Reset'):
st.session_state.clear()
st.rerun()