Spaces:
Build error
Build error
| 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() |