NotestoVid / main.py
Rahul-Sainy's picture
corrected update for coquitts
af3de47 verified
import streamlit as st
import os
import time
import json
from pydub import AudioSegment
from pydub.playback import play
import google.generativeai as genai
import narration
import img
import vid
import requests
import base64
import urllib.parse
import uuid
from dotenv import load_dotenv
load_dotenv()
# Title and description
st.set_page_config(
page_title="Educational Video Generator",
page_icon="logo.png",
layout="centered",
initial_sidebar_state="auto",
)
# Define themes
themes = {
"blue": {
"primaryColor": "#007B83",
"backgroundColor": "#F5F5F5",
"secondaryBackgroundColor": "#E0E0E0",
"textColor": "#333333",
"font": "sans serif",
},
"Dark": {
"primaryColor": "#2D2D2D",
"backgroundColor": "#121212",
"secondaryBackgroundColor": "#242424",
"textColor": "#FFFFFF",
"font": "sans serif",
},
}
ms = st.session_state
if "themes" not in ms:
ms.themes = {
"current_theme": "light",
"refreshed": True,
"light": {
"theme.base": "light",
"theme.backgroundColor": "#fefae0",
"theme.primaryColor": "#fcd303",
"theme.secondaryBackgroundColor": "#E0E0E0",
"theme.textColor": "#262730",
"theme.font": "sans serif",
"button_face": "🌜",
},
"dark": {
"theme.base": "light",
"theme.backgroundColor": "#121212",
"theme.primaryColor": "#2D2D2D",
"theme.secondaryBackgroundColor": "#242424",
"theme.textColor": "#FFFFFF",
"button_face": "🌞",
},
}
def ChangeTheme():
previous_theme = ms.themes["current_theme"]
tdict = (
ms.themes["light"]
if ms.themes["current_theme"] == "light"
else ms.themes["dark"]
)
for vkey, vval in tdict.items():
if vkey.startswith("theme"):
st._config.set_option(vkey, vval)
ms.themes["refreshed"] = False
if previous_theme == "dark":
ms.themes["current_theme"] = "light"
elif previous_theme == "light":
ms.themes["current_theme"] = "dark"
btn_face = (
ms.themes["light"]["button_face"]
if ms.themes["current_theme"] == "light"
else ms.themes["dark"]["button_face"]
)
# Create a row of columns. Adjust the number inside the list to change the width ratio of the buttons if needed.
col1, col2, col3, col4 = st.columns(4)
# Place each button in its own column
with col1:
st.button(f"Change Theme: {btn_face}", on_click=ChangeTheme)
with col2:
st.link_button("Contact Us 📱","https://collegitesai.web.app/contactus")
with col3:
st.link_button("Report Issue 🚨","https://collegitesai.web.app/contactus")
with col4:
st.link_button("Share Idea 💡","https://collegitesai.web.app/contactus")
# Separator and centered text remain unchanged
st.markdown("---")
if ms.themes["refreshed"] == False:
ms.themes["refreshed"] = True
st.rerun()
# Header with title and description
st.title(":movie_camera: Educational Video Generator")
# Initialize instruction visibility in session state
if "instruction_visibility" not in st.session_state:
st.session_state.instruction_visibility = False
if "examples_visibility" not in st.session_state:
st.session_state.examples_visibility = False
st.markdown(
"""
Welcome to the **Educational Video Generator**! Create personalized educational videos effortlessly. Select a prompt, provide source material, and watch your custom video come to life with detailed explanations and visuals.
"""
)
# Button to toggle instructions visibility
if st.button("Show/Hide Instructions :bookmark_tabs:"):
st.session_state.instruction_visibility = (
not st.session_state.instruction_visibility
)
# Display instructions if visibility is True
if st.session_state.instruction_visibility:
st.markdown(
"""
### How it Works:
1. **Select a Prompt**: Choose a topic or concept for your video.
2. **Provide Source Material**: Input text or documents to base your video on.
3. **Generate Your Video**: Sit back and let our system create a professional educational video for you.
### Features:
- Customizable video length and style
- Real-time visualizations and annotations
- Export options for sharing or embedding
Ready to start? Try it out now!
"""
)
# Button to toggle examples visibility
if st.button("Show/Hide Examples :clapper:"):
st.session_state.examples_visibility = not st.session_state.examples_visibility
if st.session_state.examples_visibility:
st.markdown("### Examples:")
col1, col2 = st.columns(2)
with col1:
st.markdown("#### Example 1:")
st.video("https://www.youtube.com/watch?v=5q6ZOv_i-mE")
with col2:
st.markdown("#### Example 2:")
st.video("https://www.youtube.com/watch?v=dbnHg5o5rvQ")
# Prompt options
prompt_options = [
{
"title": "Last Minute Exam preapration Video for College Students",
"short_description": "Create a video to help Indian college students grasp key concepts for exams.",
"prompt": "You are creating an educational video for Indian college students to quickly grasp and retain key concepts for exams so create a complete explanatory video. The video will provide detailed explanations, supported by visuals and clear narration for each line in Hindi words. Follow these guidelines:",
},
{
"title": "Comprehensive Study Review: Key Concepts and Definitions",
"short_description": "Create a video summarizing key concepts and definitions for effective exam preparation.",
"prompt": "You are creating a study review video summarizing key concepts and definitions from provided notes. Each slide should focus on a specific concept or term, providing clear explanations and examples where applicable. Use visuals and bilingual narration to aid understanding and retention.",
},
{
"title": "Analytical Overview: Critical Analysis of Provided Topics",
"short_description": "Develop a video providing a critical analysis of topics covered in the provided notes.",
"prompt": "Produce educational content offering a critical analysis of topics from provided notes. Each slide should analyze a specific topic or issue, presenting insights, perspectives, and supporting evidence. Include visual aids and bilingual narration for clarity and depth.",
},
{
"title": "Practical Applications: Real-world Examples and Case Studies",
"short_description": "Craft a video demonstrating practical applications of theories or concepts from the provided notes.",
"prompt": "Create instructional slides showcasing practical applications of theories or concepts from provided notes. Each slide should feature real-world examples, case studies, or scenarios illustrating the application of knowledge. Use visuals and clear bilingual narration to enhance comprehension.",
},
{
"title": "Step-by-Step Guide: Detailed Procedures or Processes",
"short_description": "Generate a video providing a step-by-step guide to procedures or processes outlined in the provided notes.",
"prompt": "Develop educational slides offering a detailed step-by-step guide to procedures or processes from provided notes. Each slide should break down a specific procedure, method, or workflow, explaining each step clearly. Utilize diagrams, flowcharts, and bilingual narration for thorough understanding.",
},
{
"title": "Comparative Analysis: Contrasting Perspectives or Theories",
"short_description": "Produce a video comparing and contrasting different perspectives or theories discussed in the provided notes.",
"prompt": "You are creating study slides for comparative analysis based on provided notes. Each slide should compare and contrast different perspectives, theories, or approaches to a topic. Provide visual aids and bilingual narration to elucidate differences and similarities effectively.",
},
]
# Function to read input_prompt from file or user selection
def get_input_prompt():
selected_prompt = st.radio(
"Select a prompt option",
[option["title"] for option in prompt_options] + ["Custom"],
)
if selected_prompt == "Custom":
return st.text_area("Enter your own prompt", height=200)
else:
for option in prompt_options:
if option["title"] == selected_prompt:
st.text_area(
"Prompt details: " + option["short_description"],
value=option["prompt"],
height=130,
disabled=True,
)
return option["prompt"]
return None
# Function to configure the generative AI model
def configure_model():
api_key = os.environ.get("GEMINI_API_KEY")
genai.configure(api_key=api_key)
return genai.GenerativeModel(
model_name="gemini-1.5-flash",
generation_config={
"temperature": 0.4,
"top_p": 1,
"top_k": 32,
"max_output_tokens": 8192,
},
safety_settings=[
{
"category": "HARM_CATEGORY_HARASSMENT",
"threshold": "BLOCK_MEDIUM_AND_ABOVE",
},
{
"category": "HARM_CATEGORY_HATE_SPEECH",
"threshold": "BLOCK_MEDIUM_AND_ABOVE",
},
{
"category": "HARM_CATEGORY_SEXUALLY_EXPLICIT",
"threshold": "BLOCK_MEDIUM_AND_ABOVE",
},
{
"category": "HARM_CATEGORY_DANGEROUS_CONTENT",
"threshold": "BLOCK_MEDIUM_AND_ABOVE",
},
],
)
# Function to generate the script content
def generate_script(model, prompt_option, source_material):
input_prompt = f"""
{prompt_option}
Follow these guidelines and format strictly as we are scrapping the text form your response:
    Title
    Content: Use bullet points for clarity, use only english language for slide content.
    Image Description: For AI image search; avoid referencing real people, sexual content, or celebrities.
    Narration: Provide a narration in Hindi Devanagari script. Use simple Hindi language and mix with english words do not use too deep hindi words instead use english words.
    Image Descriptions: Ensure they complement the content.
    Format:
    Slide Number, Title, and Content in square brackets.
    Separate image description and narration.
    !in a line use single #(hash symbol) only, for slide number and title . stick to the example format strictly.
    !important to generate each thing mentioned in the example, do not skip anything
   
    Slide Structure Example:
    # Slide [Slide Number]: [Title]
   
    [Slide Content]
   
    - Point 1
    - Point 2
    - Point n
   
    [Image Description: Description of a fitting image related to content]
   
    *Narration: [Hindi narration in Devanagari script]
   
    and so on..... generate the content until all topics covered
   
    ## Continue generating content in this format for all topics
    ## !important narration should be in Hindi Devanagari script only and contnet and title in englsih only
    ```
**Key improvements:**
* **Clearer narration instruction:** Directly specifies "Provide a narration in Hindi Devanagari script."
* **Removed redundant information:** Removed the Hinglish and phonetics references as they are not necessary for generating Devanagari text.
* **Simplified format:** Removed unnecessary details and focused on the essential requirements.
"""
response = model.generate_content(input_prompt + source_material)
return (
response.text.replace("’", "'")
.replace("`", "'")
.replace("…", "...")
.replace("“", '"')
.replace("”", '"')
)
# Function to save text to a file
def save_text_to_file(text, path):
with open(path, "w", encoding="utf-8") as f:
f.write(text)
# Function to save JSON data to a file
def save_json_to_file(data, path):
with open(path, "w", encoding="utf-8") as f:
json.dump(data, f, ensure_ascii=False)
# Function to upload video to GitHub
def upload_to_github(video_path):
# Extract the folder ID from the URL
folder_id = str(uuid.uuid4())
# Replace with your GitHub repository details
# Load values from environment variables
repo_owner = os.environ.get("REPO_OWNER")
repo_name = os.environ.get("REPO_NAME")
github_token = os.environ.get("GITHUB_TOKEN")
print(repo_owner, repo_name, github_token)
github_file_path = f"videos/{folder_id}/short.mp4"
print(f"GitHub File Path: {github_file_path}") # For debugging
# GitHub API URL
url = f"https://api.github.com/repos/{repo_owner}/{repo_name}/contents/{github_file_path}"
print(f"GitHub API URL: {url}") # For debugging
headers = {
"Authorization": f"token {github_token}",
"Accept": "application/vnd.github.v3+json",
}
# Local file path for reading the video file
local_file_path = urllib.parse.urlparse(video_path).path
# Read video file as binary data
with open(local_file_path, "rb") as f:
content = f.read()
# Base64 encode the content
encoded_content = base64.b64encode(content).decode("utf-8")
# Prepare data for API request
data = {"message": "Upload generated video", "content": encoded_content}
# Make API request to create the file
response = requests.put(url, headers=headers, json=data)
if response.status_code in [200, 201]:
print("File uploaded successfully to GitHub.")
response_data = response.json()
download_url = response_data["content"]["download_url"]
print(f"Download URL: {download_url}")
# os.remove(video_path) # Be cautious with automatically removing files
return download_url
else:
print(f"Failed to upload file: {response.content}")
return None
# Main function to generate the video
def generate_video(source_material, prompt_option, selected_bg):
short_id = str(int(time.time())) # Generate a unique ID
output_file = "short.mp4"
basedir = os.path.join("videos", short_id)
os.makedirs(basedir, exist_ok=True)
model = configure_model()
with st.spinner("Generating script..."):
response_text = generate_script(model, prompt_option, source_material)
save_text_to_file(response_text, os.path.join(basedir, "response.txt"))
with st.spinner("Parsing response..."):
data, narrations = narration.parse(response_text)
# Now 'parsed_data' will be a list containing dictionaries for text and image information
print(narrations)
st.markdown("### Generated Narration:")
st.text(narrations)
save_json_to_file(data, os.path.join(basedir, "data.json"))
with st.spinner("Generating narration..."):
narration.create(data, os.path.join(basedir, "narrations"))
with st.spinner("Generating images..."):
img.create(data, os.path.join(basedir, "images"))
with st.spinner("Generating video..."):
vid.create(narrations, data, basedir, output_file, selected_bg)
# Upload video directly to GitHub
video_path = os.path.abspath(os.path.join(basedir, output_file))
video_path = video_path.replace("%5C", "/")
print(video_path)
giturl = upload_to_github(video_path)
return giturl
# User inputs
input_prompt = get_input_prompt()
st.subheader("Enter the Notes👇🏻")
source_material = st.text_area("Your source material", height=200)
# Initialize session state for selected_bg if it doesn't exist
if "selected_bg" not in st.session_state:
st.session_state.selected_bg = "Option 1"
bg_options = {
"Option 1": "pptbgs/0.png",
"Option 2": "pptbgs/1.png",
"Option 3": "pptbgs/2.png",
"Option 4": "pptbgs/3.png",
"Option 5": "pptbgs/4.png",
"Option 6": "pptbgs/5.png",
}
## Display Background Image Options
col1, col2, col3 = st.columns(3)
with col1:
st.image(bg_options["Option 1"], use_column_width=True)
if st.button("Select Option 1", key="option1"):
st.session_state.selected_bg = "Option 1"
with col2:
st.image(bg_options["Option 2"], use_column_width=True)
if st.button("Select Option 2", key="option2"):
st.session_state.selected_bg = "Option 2"
with col3:
st.image(bg_options["Option 3"], use_column_width=True)
if st.button("Select Option 3", key="option3"):
st.session_state.selected_bg = "Option 3"
col4, col5, col6 = st.columns(3)
with col4:
st.image(bg_options["Option 4"], use_column_width=True)
if st.button("Select Option 4", key="option4"):
st.session_state.selected_bg = "Option 4"
with col5:
st.image(bg_options["Option 5"], use_column_width=True)
if st.button("Select Option 5", key="option5"):
st.session_state.selected_bg = "Option 5"
with col6:
st.image(bg_options["Option 6"], use_column_width=True)
if st.button("Select Option 6", key="option6"):
st.session_state.selected_bg = "Option 6"
## Display Selected Background Image
# st.write(f"Selected Background Image: {st.session_state.selected_bg}")
# Display the selected image
# Display the selected image within an expander
with st.expander(
f"Selected Background Image: {st.session_state.selected_bg}", expanded=False
):
image_path = bg_options[st.session_state.selected_bg]
st.image(image_path, caption=st.session_state.selected_bg, use_column_width=True)
selected_bg_path = bg_options[st.session_state.selected_bg]
# Adding an image to visualize the concept
if st.button("Generate Video :movie_camera:") and source_material:
st.text("Generating video...")
print(selected_bg_path)
video_path = generate_video(source_material, input_prompt, selected_bg_path)
st.success("Video generated successfully!")
st.markdown(f'Download your video [here]({video_path.replace("%5C", "/")})')
st.balloons()
audio = AudioSegment.from_file("success_sound.wav", format="wav")
play(audio)
st.image("logo.png", use_column_width=True)