fmmkii commited on
Commit
52cdd17
·
1 Parent(s): 73d0db3

Updated app.py

Browse files
.gitignore ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ /.streamlit
2
+ script_history.json
3
+ /__pycache__
DOCS.md ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Documentation
2
+ ### 1. Initial Setup and Requirements
3
+
4
+ The original boilerplate simply performs only script generating task. The libraries used for this boilerplate includes Langchain, DuckDuckGo, and dotenv.
5
+ ### 2. Very Noticeable Changes
6
+
7
+ Instead of just simply performing YouTube script generation, I had decided to utilize mutimodal technologies for this project that includes out of the box features including thumbnail generation and creative consultation. This may help improve usability and utility of this project as this may help induce creativity in content creation.
8
+
9
+ Instead of using the text completion model of the original, I had rather used the ChatOpenAI library instead for richer and straightforward responses using the model GPT-4o mini. For image generation, I have also utilized Dall-E 3, one of the few image generation models provided by OpenAI. This accurately generates images based on style, albeit limitations including options for aspect ratio.
10
+
11
+ Instead of DuckDuckGo due to unpredictable API limits, we will be using Serpo API for fetching Google Search Results, providing quality search results. This also has a limit of 2500 requests for free tier, which is a limitation but this project is made for personal use in mind.
12
+
13
+ Storing scripts using **json** provides an organized access to scripts and files which can be stored an prepared later for future use.
14
+
15
+ To store secrets, we will use Streamlit instead as being modular and quick to set-up rather than dotenv.
16
+ ### 3. Every Python File Explained
17
+
18
+ This project utilizes multiple python files. The **app.py** is where the main application resides. Following that includes the **scriptgen.py (Script Generation)**, **imggen.py (Image Generation)**, **tweaker.py (Creative Consultant)**, and the **secretary.py (Script Secretary)**.
19
+
20
+ The **scriptgen.py** is where the the interface of the script generation resides. This is also associated with the **generate_script.py** where the loading and the rest of the script generation logic resides. For every script that is generated, this will be saved on a **.json** file storing the script metadata for later use and will be loaded on other tools such as Image Generation and Creative Consultant.
21
+
22
+ The **imggen.py** contains the interface and the logic of the image generation. This can be used independently for image generation if the **Other** option is selected and can be customized with styles.
23
+
24
+ The **tweaker.py** is where the creative consultant resides. This only accepts prompts related to its job and gives the user a way to fine-tune scripts with the model. The user has an option to clear the conversation if needed.
25
+
26
+ Lastly is the **secretary.py** that enables the user to download or delete scripts if needed. This reads the **.json** file and lists them in an orderly manner, giving the users some reference of the generated scripts.
27
+ ### 4. Some Bugs and Quirks and Concerns
28
+
29
+ Being a pre-trained model, OpenAI has filters turned on by default preventing generation of harmful content. This is not a bug but still considered a quirk of their models.
30
+ ### 5. What Can we Add?
31
+
32
+ Implementing a text-to-video model can be possible however since this requires a lot of computing and monetary needs, this may not be possible for now.
33
+ ### 6. Closing Statements
34
+
35
+ This can be tweaked, changed, modified, or customized for better use, so feel free to experiment this app!
36
+
37
+
app.py CHANGED
@@ -1,26 +1,32 @@
1
  import streamlit as st
2
 
3
- scriptgen = st.Page("scriptgen.py", title="Script Generator", default=True)
4
- imggen = st.Page("imggen.py", title="Image Generator")
5
- tweaker = st.Page("tweaker.py", title="Creative Consultant")
6
 
7
- replicate_api = st.secrets['REPLICATE_API_TOKEN']
 
 
 
 
 
 
 
8
 
9
  # Sidebar for API Key input and options
10
  with st.sidebar:
11
  # Retrieve API Key from Streamlit secrets or prompt for input
12
- if 'REPLICATE_API_TOKEN' in st.secrets:
13
- if not (replicate_api.startswith('r8_') and len(replicate_api) == 40):
14
- replicate_api = st.text_input('Enter your Replicate API token:', type='password')
15
  st.warning('Invalid or no API key! Please try again')
16
  else:
17
- st.success('Try asking now!')
18
  else:
19
- replicate_api = st.text_input('Enter your Replicate API token:', type='password')
20
 
21
  pg = st.navigation(
22
  {
23
- "": [scriptgen, imggen, tweaker]
 
24
  }
25
  )
26
 
 
1
  import streamlit as st
2
 
3
+ st.set_page_config(layout='wide', page_icon='✨')
 
 
4
 
5
+ scriptgen = st.Page("scriptgen.py", title="Script Generator", icon='📃')
6
+ imggen = st.Page("imggen.py", title="Thumbnail Generator", icon='🖼️')
7
+ tweaker = st.Page("tweaker.py", title="Creative Consultant", icon='🎬')
8
+ jsonbase = st.Page("secretary.py", title = "Script Secretary", icon='📚')
9
+ manual = st.Page("manual.py", title="Manual", icon="👓", default= True)
10
+ docs = st.Page("docs.py", title="Documentation", icon= '📑')
11
+
12
+ api_key = st.secrets['OPENAI_API_KEY']
13
 
14
  # Sidebar for API Key input and options
15
  with st.sidebar:
16
  # Retrieve API Key from Streamlit secrets or prompt for input
17
+ if 'OPENAI_API_KEY' in st.secrets:
18
+ if not (api_key.startswith('sk-proj')):
19
+ api_key = st.text_input('Enter your OpenAI API token:', type='password')
20
  st.warning('Invalid or no API key! Please try again')
21
  else:
22
+ st.success('API Key Recognized!')
23
  else:
24
+ api_key = st.text_input('Enter your OpenAI API token:', type='password')
25
 
26
  pg = st.navigation(
27
  {
28
+ "Others":[manual, docs],
29
+ "Tools": [scriptgen, imggen, tweaker, jsonbase]
30
  }
31
  )
32
 
docs.py ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+
3
+ def read_markdown_file(file_path):
4
+ with open(file_path, "r") as file:
5
+ return file.read()
6
+
7
+ docs = read_markdown_file('DOCS.md')
8
+ st.markdown(docs)
generate_script.py CHANGED
@@ -1,41 +1,31 @@
1
- from langchain_community.llms import Replicate
2
  from langchain.chains import LLMChain
3
  from langchain.prompts import PromptTemplate
4
- from langchain_community.tools import DuckDuckGoSearchRun
5
  import os
6
 
7
- def generate_script(prompt, video_length, creativity, replicate_api):
8
  """
9
  Generate a YouTube video title and script based on the provided prompt, duration, and creativity level.
10
-
11
- Parameters:
12
- prompt (str): Topic of the video.
13
- video_length (float): Desired duration of the video in minutes.
14
- creativity (float): Creativity level (0.0 to 1.0).
15
- replicate_api (str): Replicate API Key for authentication.
16
-
17
- Returns:
18
- tuple: Generated title, script, and search data.
19
  """
20
- # Ensure the Replicate API key is set
21
- if not replicate_api:
22
- raise ValueError("Replicate API Key is missing.")
23
- os.environ["REPLICATE_API_TOKEN"] = replicate_api
24
 
25
- # Initialize the LLM with the Replicate model
26
- llm = Replicate(
27
- model="meta/meta-llama-3-8b-instruct",
28
- input={
29
- "top_k": 0,
30
- "top_p": 0.95,
31
- "prompt": prompt,
32
- "max_tokens": 4096,
33
- "temperature": 0.7,
34
- "length_penalty": 1,
35
- "max_new_tokens": 4096,
36
- "presence_penalty": 0,
37
- "log_performance_metrics": False
38
- },
 
 
 
39
  )
40
 
41
  # Define the title generation prompt
@@ -43,7 +33,7 @@ def generate_script(prompt, video_length, creativity, replicate_api):
43
  input_variables=["topic"],
44
  template="Generate a YouTube video title for the topic '{topic}'."
45
  )
46
- title_chain = LLMChain(llm=llm, prompt=title_template, verbose=True)
47
 
48
  # Define the script generation prompt
49
  script_template = PromptTemplate(
@@ -53,24 +43,20 @@ def generate_script(prompt, video_length, creativity, replicate_api):
53
  "Incorporate the following research information: {search_data}."
54
  )
55
  )
56
- script_chain = LLMChain(llm=llm, prompt=script_template, verbose=True)
57
 
58
- # Fetch relevant search data using DuckDuckGo
59
- search_tool = DuckDuckGoSearchRun()
60
- search_data = search_tool.run(prompt)
61
 
62
- # Generate the video title
63
  title = title_chain.run({"topic": prompt})
64
 
65
- # Save the generated title to a file
66
- with open("generated_title.txt", "w") as file:
67
- file.write(title)
68
-
69
- # Generate the video script
70
  script = script_chain.run({
71
  "title": title,
72
  "duration": video_length,
73
- "search_data": search_data
74
  })
75
 
76
  return title, script, search_data
 
1
+ from langchain_openai import ChatOpenAI
2
  from langchain.chains import LLMChain
3
  from langchain.prompts import PromptTemplate
4
+ from langchain_community.utilities import GoogleSerperAPIWrapper
5
  import os
6
 
7
+ def generate_script(prompt, video_length, creativity, openai_api_key, serper_api_key):
8
  """
9
  Generate a YouTube video title and script based on the provided prompt, duration, and creativity level.
 
 
 
 
 
 
 
 
 
10
  """
 
 
 
 
11
 
12
+ # Ensure the OpenAI API key is set
13
+ if not openai_api_key:
14
+ raise ValueError("OpenAI API Key is missing.")
15
+ os.environ["OPENAI_API_KEY"] = openai_api_key
16
+
17
+ # Ensure the Serper API key is set
18
+ if not serper_api_key:
19
+ raise ValueError("Serper API Key is missing.")
20
+ os.environ["SERPER_API_KEY"] = serper_api_key
21
+
22
+ # Initialize the LLM
23
+ llm = ChatOpenAI(
24
+ model='gpt-4o-mini',
25
+ temperature=creativity,
26
+ max_tokens=None,
27
+ timeout=None,
28
+ max_retries=2
29
  )
30
 
31
  # Define the title generation prompt
 
33
  input_variables=["topic"],
34
  template="Generate a YouTube video title for the topic '{topic}'."
35
  )
36
+ title_chain = LLMChain(llm=llm, prompt=title_template, verbose=False)
37
 
38
  # Define the script generation prompt
39
  script_template = PromptTemplate(
 
43
  "Incorporate the following research information: {search_data}."
44
  )
45
  )
46
+ script_chain = LLMChain(llm=llm, prompt=script_template, verbose=False)
47
 
48
+ # Fetch relevant search data using Google Serper
49
+ search_tool = GoogleSerperAPIWrapper()
50
+ search_data = search_tool.results(prompt)
51
 
52
+ # Generate the video title ONCE
53
  title = title_chain.run({"topic": prompt})
54
 
55
+ # Generate the video script using the title
 
 
 
 
56
  script = script_chain.run({
57
  "title": title,
58
  "duration": video_length,
59
+ "search_data": search_data,
60
  })
61
 
62
  return title, script, search_data
generated_title.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ "10 Reasons Why AirPods Are the Ultimate Must-Have Tech!"
imggen.py CHANGED
@@ -1,50 +1,118 @@
1
  import streamlit as st
2
- import replicate
3
  import time
4
  from dotenv import load_dotenv
5
  import os
6
  import requests
7
  from io import BytesIO
8
  from PIL import Image
9
- import random
10
 
11
  # Load environment variables
12
  load_dotenv()
13
 
14
- # Check for a title from the script generator
15
- try:
16
- with open("generated_title.txt", "r") as file:
17
- title = file.read().strip()
18
- prompt = title # Use the title as the default prompt
19
- except FileNotFoundError:
20
- st.warning("No title found! Please run the script generator first.")
21
- prompt = "" # Set an empty prompt if no title is available
 
 
 
 
 
 
 
22
 
23
  # Retrieve the API key
24
- replicate_api = st.secrets.get('REPLICATE_API_TOKEN') or os.getenv("REPLICATE_API_TOKEN")
25
 
26
- if not replicate_api:
27
  st.error("API Key not provided! Please add it to Streamlit secrets or the .env file.")
28
  else:
29
- os.environ['REPLICATE_API_TOKEN'] = replicate_api # Set the API key for Replicate
30
 
31
  # Initialize session state for image history
32
  if "image_history" not in st.session_state:
33
  st.session_state.image_history = []
34
 
35
- # Streamlit UI setup
36
- st.title("AI Image Generator")
37
- prompt = st.text_input("Enter a prompt for the image", value=prompt) # Use the title as the default value
38
- styles = st.multiselect("Image artstyle", ['Impressionism', 'Cubism', 'Surrealism', 'Baroque', 'Art Noveau', 'Cyberpunk', 'Synthwave', 'Anime', 'Pixel Art', 'Low Poly', 'Dark Fantasy', 'Space Opera', 'Steampunk', 'Fantasy', 'Abstract','Glitch Art', 'Kawaii','Pop Art'])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
39
 
40
- with st.sidebar:
41
- st.title("Options")
42
- aspect_ratio = st.selectbox("Aspect Ratio", ("16:9", "4:3", "3:2", "1:1", "21:9"))
43
- seed = st.number_input("Seed (leave empty for random)", min_value=0, step=1, format="%d")
44
- quality = st.slider("Quality", min_value=0, max_value=100, value=90, step=1)
45
- strength = st.slider("Prompt Strength", min_value=0.0, max_value=1.0, value=0.9, step=0.01)
46
- steps = st.slider("Sampling Steps", min_value=1, max_value=28, value=28, step=1)
47
- cfg = st.slider("Similarity", min_value=0.0, max_value=20.0, value= 3.5, step=0.1)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
48
 
49
  # Function to convert image URL to PNG buffer
50
  def get_image_buffer(image_url):
@@ -58,62 +126,25 @@ def get_image_buffer(image_url):
58
  else:
59
  return None
60
 
61
- # Handle image generation
62
- if st.button("Generate Image"):
63
- seed = int(seed) if seed else random.randint(0, 99999)
64
 
65
- if not prompt:
66
- st.error("Please enter a prompt!")
67
- else:
68
- with st.spinner('Generating image...'):
69
- start_time = time.time()
70
- try:
71
- # Replicate API call
72
- output = replicate.run(
73
- "stability-ai/stable-diffusion-3",
74
- input={
75
- "cfg": cfg,
76
- "steps": steps,
77
- "prompt": f"With this context of the prompt: {prompt}, make me a video thumbnail with these artstyles: {styles}",
78
- "aspect_ratio": aspect_ratio,
79
- "output_format": "png",
80
- "output_quality": quality,
81
- "negative_prompt": "bad quality, worse quality, deformed",
82
- "prompt_strength": strength,
83
- "seed": seed
84
- }
85
- )
86
- # Display output and elapsed time
87
- if output:
88
- image_url = output[0]
89
- st.image(image_url, caption="Generated Image", use_container_width=True)
90
- end_time = time.time()
91
- elapsed_time = end_time - start_time
92
- st.write(f"Image Generated in {elapsed_time:.2f} seconds")
93
-
94
- # Save to session state
95
- st.session_state.image_history.append((image_url, prompt))
96
- else:
97
- st.error("No output received. Please try again!")
98
- except Exception as e:
99
- st.error(f"An error occurred: {str(e)}")
100
-
101
- # Display image history
102
- with st.expander("Show Prompt History"):
103
- if st.session_state.image_history:
104
- for idx, (image_url, image_prompt) in enumerate(reversed(st.session_state.image_history)):
105
- st.subheader(f"Image {len(st.session_state.image_history) - idx}")
106
- st.text(f"Prompt: {image_prompt}")
107
- st.image(image_url, use_container_width=True)
108
-
109
- # Generate download button for each image
110
- buffer = get_image_buffer(image_url)
111
- if buffer:
112
- st.download_button(
113
- label="Download Image",
114
- data=buffer,
115
- file_name=f"generated_image_{len(st.session_state.image_history) - idx}.png",
116
- mime="image/png"
117
- )
118
- else:
119
- st.write("No images generated yet.")
 
1
  import streamlit as st
2
+ from openai import OpenAI
3
  import time
4
  from dotenv import load_dotenv
5
  import os
6
  import requests
7
  from io import BytesIO
8
  from PIL import Image
9
+ import json
10
 
11
  # Load environment variables
12
  load_dotenv()
13
 
14
+ # Initialize OpenAI client
15
+ client = OpenAI()
16
+
17
+ # Load script history
18
+ history_file = "script_history.json"
19
+
20
+
21
+ def load_script_history():
22
+ if os.path.exists(history_file):
23
+ with open(history_file, "r") as file:
24
+ return json.load(file)
25
+ return []
26
+
27
+
28
+ script_history = load_script_history()
29
 
30
  # Retrieve the API key
31
+ api_key = st.secrets.get('OPENAI_API_KEY') or os.getenv("OPENAI_API_KEY")
32
 
33
+ if not api_key:
34
  st.error("API Key not provided! Please add it to Streamlit secrets or the .env file.")
35
  else:
36
+ os.environ['OPENAI_API_KEY'] = api_key # Set the API key for OpenAI
37
 
38
  # Initialize session state for image history
39
  if "image_history" not in st.session_state:
40
  st.session_state.image_history = []
41
 
42
+ # Main title
43
+ st.title("Thumbnail Generator 🖼️")
44
+ st.subheader('Create thumbnails with AI images for your video!')
45
+
46
+ # Define layout with two columns
47
+ left_col, right_col = st.columns(2, border= True)
48
+
49
+ with left_col:
50
+ st.subheader('Input 👇')
51
+ # Generate script titles from history
52
+ script_titles = [f"Script {idx + 1}: {item['title']}" for idx, item in enumerate(script_history)]
53
+
54
+ # Add an "Other" option for custom prompts
55
+ script_titles_with_other = script_titles + ["Other"]
56
+
57
+ # Select a script or choose "Other"
58
+ selected_option = st.selectbox(
59
+ "Choose a script to make a thumbnail or write one:",
60
+ range(len(script_titles_with_other)),
61
+ format_func=lambda x: script_titles_with_other[x]
62
+ )
63
 
64
+ # Set the prompt based on the selection
65
+ if script_titles_with_other[selected_option] == "Other":
66
+ prompt = st.text_input("Enter your custom script prompt:")
67
+ else:
68
+ prompt = script_titles_with_other[selected_option]
69
+
70
+ # Choose art styles
71
+ styles = st.multiselect(
72
+ "Image artstyle",
73
+ [
74
+ 'Realism', 'Impressionism','Cubism', 'Surrealism', 'Baroque', 'Art Noveau', 'Cyberpunk',
75
+ 'Synthwave', 'Anime', 'Pixel Art', 'Low Poly', 'Dark Fantasy', 'Space Opera',
76
+ 'Steampunk', 'Fantasy', 'Abstract', 'Glitch Art', 'Kawaii', 'Pop Art'
77
+ ],
78
+ max_selections=3
79
+ )
80
+
81
+ # Sidebar options
82
+ with st.sidebar:
83
+ st.title("Options")
84
+ size = st.selectbox("Size", ("1024x1024", "1024x1792", "1792x1024"))
85
+ quality = st.selectbox("Quality", ("standard", "hd"))
86
+
87
+ # Handle image generation
88
+ if st.button("Generate Image"):
89
+ if not prompt:
90
+ st.error("Please enter a prompt!")
91
+ else:
92
+ with st.spinner('Generating image...'):
93
+ start_time = time.time()
94
+ try:
95
+ # Call the OpenAI API to generate images
96
+ output = client.images.generate(
97
+ model="dall-e-3",
98
+ prompt=f"{prompt}. Apply these styles if provided: {', '.join(styles)}" if styles else prompt,
99
+ quality=quality,
100
+ size=size,
101
+ n=1
102
+ )
103
+ # Access the URL from the response
104
+ if output and hasattr(output, 'data'):
105
+ image_url = output.data[0].url # Get the first image URL
106
+ right_col.image(image_url, caption="Generated Image", use_container_width=True)
107
+ elapsed_time = time.time() - start_time
108
+ right_col.write(f"Image Generated in {elapsed_time:.2f} seconds")
109
+
110
+ # Save to session state
111
+ st.session_state.image_history.append((image_url, prompt))
112
+ else:
113
+ right_col.error("No output received. Please try again!")
114
+ except Exception as e:
115
+ right_col.error(f"An error occurred: {str(e)}")
116
 
117
  # Function to convert image URL to PNG buffer
118
  def get_image_buffer(image_url):
 
126
  else:
127
  return None
128
 
 
 
 
129
 
130
+ with right_col:
131
+ st.subheader('Output ✨')
132
+ # Display image history
133
+ with st.expander("Show Prompt History"):
134
+ if st.session_state.image_history:
135
+ for idx, (image_url, image_prompt) in enumerate(reversed(st.session_state.image_history)):
136
+ st.subheader(f"Image {len(st.session_state.image_history) - idx}")
137
+ st.text(f"Prompt: {image_prompt}")
138
+ st.image(image_url, use_container_width=True)
139
+
140
+ # Generate download button for each image
141
+ buffer = get_image_buffer(image_url)
142
+ if buffer:
143
+ st.download_button(
144
+ label="Download Image",
145
+ data=buffer,
146
+ file_name=f"generated_image_{len(st.session_state.image_history) - idx}.png",
147
+ mime="image/png"
148
+ )
149
+ else:
150
+ st.write("No images generated yet.")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
manual.py ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+
3
+ st.header("Welcome to ImaGen Creator Toolkit! ✨")
4
+ st.write('''Powered with OpenAI, this toolkit helps you create scripts and thumbnails for your next YouTube video.
5
+ ''')
6
+
7
+ st.subheader("1. Things you need before you begin")
8
+ st.markdown("Please make sure you have your **OpenAI API Key** ready to be able to use this toolkit. If none provided, you may be prompted to enter the **API Key**. You may visit the OpenAI for you to retrieve your **API Key**." )
9
+ st.info("Please take note that using the API also requires additional payment")
10
+
11
+ st.subheader('2. Script Generator')
12
+ st.markdown('The **Script Generator** lets the user prompt to create a script. Below this lets you estimate the timeframe for your script. Simply press **Generate Script** then an output of your script will be ready.')
13
+ st.image('resources/scriptgen.png')
14
+ st.markdown('Some advanced options include **Creativity**. The lower the values, the more on-point the topic will be.')
15
+
16
+ st.subheader('3. Thumbnail Generator')
17
+ st.markdown('The **Thumbnail Generator** makes you create images based on the titles of your pre-made scripts alongside with **Styles** that helps you configure a particular style. You may opt creating one without the script by selecting **Others** on the select box. To start creating, simply press **Generate Image**.')
18
+ st.image('resources/imggen.png')
19
+ st.markdown('Some advanced options include the **Image Size** limited by the model and the the **Quality**. For higher quality outputs, you can choose the **hd** option or upscale the image size.')
20
+ st.info('Note that it does not support widescreen (16:9), so you need to manually edit it after.')
21
+
22
+ st.subheader('4. Creative Consultant')
23
+ st.markdown("The **Creative Consultant** is a chatbot that gives you advice on your scripts or helps you tweak some changes of the generated scripts. On the sidebar contains options for you to select scripts for it to look over. Ask the consultant nearly everything unless it's all about coding or some matters.")
24
+ st.image("resources/tweaker.png")
25
+
26
+ st.subheader("5. Script Secretary")
27
+ st.markdown("The **Script Secretary** manages all of your saved scripts. It gives you an option to **Download** the script as the text file or **Delete** them entirely. ")
28
+ st.image("resources/secretary.png")
requirements.txt CHANGED
@@ -1,7 +1,7 @@
1
  streamlit
2
  langchain_community
 
3
  langchain
4
  replicate
5
  openai
6
- duckduckgo_search
7
  python-dotenv
 
1
  streamlit
2
  langchain_community
3
+ langchain_openai
4
  langchain
5
  replicate
6
  openai
 
7
  python-dotenv
resources/imggen.png ADDED
resources/scriptgen.png ADDED
resources/secretary.png ADDED
resources/tweaker.png ADDED
scriptgen.py CHANGED
@@ -2,52 +2,98 @@ import streamlit as st
2
  from dotenv import load_dotenv
3
  from generate_script import generate_script
4
  import os
 
 
 
 
5
 
6
  # Load environment variables from .env file
7
  load_dotenv()
8
 
9
- # Streamlit app title and subtitle
10
- st.title("YouTube-Inator")
11
- st.subheader("Make fun stuff with YouTube-Inator!")
12
-
13
- with st.sidebar:
14
- st.title("Options")
15
- creativity = st.slider("Set creativity level:", min_value=0.0, max_value=1.0, value=0.5)
16
-
17
-
18
- # Input fields for video generation parameters
19
- prompt = st.text_input("Provide the topic of the video:", placeholder="e.g., How to bake a cake")
20
- video_length = st.number_input("Specify length in minutes", min_value=1.0, step=0.5, value= 10.0)
21
-
22
- # Button to generate the video script
23
- generate_script_button = st.button("Generate Script")
24
-
25
- # Generate script on button click
26
- if generate_script_button:
27
- if not replicate_api:
28
- st.error("Please provide a valid API Key.")
29
- else:
30
- # Set the API Key in the environment variable for use by other modules
31
- os.environ["REPLICATE_API_TOKEN"] = replicate_api
32
-
33
- try:
34
- # Generate the video script using the utility function
35
- with st.spinner("Generating your script..."):
36
- title, script, search_data = generate_script(prompt, video_length, creativity, replicate_api)
37
-
38
- # Display the results
39
- st.success("Script generated successfully!")
40
- st.subheader(f"Title: {title}")
41
- st.write(f"Script: {script}")
42
-
43
- # Display additional search data
44
- with st.expander("Show search data for the script"):
45
- st.write(search_data)
46
-
47
- except Exception as e:
48
- # Handle any errors that occur during script generation
49
- st.error(f"An error occurred. Try again {e}")
50
- with st.expander("Expand to see details"):
51
- st.write(f'{e}')
52
-
53
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2
  from dotenv import load_dotenv
3
  from generate_script import generate_script
4
  import os
5
+ import json
6
+
7
+ # File to store script history
8
+ history_file = "script_history.json"
9
 
10
  # Load environment variables from .env file
11
  load_dotenv()
12
 
13
+ st.title("Script Generator 📃")
14
+ st.subheader("Create your script with just a single prompt!")
15
+
16
+ # Retrieve API key from secrets or environment variables
17
+ api_key = st.secrets.get("OPENAI_API_KEY") or os.getenv("OPENAI_API_KEY")
18
+ serper_api_key = st.secrets.get("SERPER_API_KEY") or os.getenv("SERPER_API_KEY")
19
+
20
+ if not api_key:
21
+ st.error("Please provide a valid API Key in Streamlit secrets or .env file.")
22
+ else:
23
+ os.environ["OPENAI_API_KEY"] = api_key
24
+
25
+ # Function to load history from file
26
+ def load_history():
27
+ if os.path.exists(history_file):
28
+ with open(history_file, "r") as file:
29
+ return json.load(file)
30
+ return []
31
+
32
+ # Function to save history to file
33
+ def save_history(history):
34
+ with open(history_file, "w") as file:
35
+ json.dump(history, file, indent=4)
36
+
37
+ # Load history from JSON file
38
+ script_history = load_history()
39
+
40
+ # Layout with two columns
41
+ col1, col2 = st.columns(2, border= True)
42
+
43
+ # Left column for inputs
44
+ with col1:
45
+ st.subheader("Input 👇")
46
+ prompt = st.text_input("Provide the topic of the video:", placeholder="e.g., How to bake a cake")
47
+ video_length = st.number_input("Specify length in minutes", min_value=1.0, step=0.5, value=10.0)
48
+
49
+ with st.sidebar:
50
+ st.title("Options")
51
+ creativity = st.slider("Set creativity level:", min_value=0.0, max_value=1.0, value=0.5)
52
+
53
+ # Button to generate the video script
54
+ generate_script_button = st.button("Generate Script")
55
+
56
+ # Right column for results
57
+ with col2:
58
+ st.subheader("Output ✨")
59
+
60
+ if generate_script_button:
61
+ if not prompt:
62
+ st.error("Please provide a topic for the video.")
63
+ else:
64
+ try:
65
+ # Generate the video script using the utility function
66
+ with st.spinner("Generating your script..."):
67
+ title, script, search_data = generate_script(prompt, video_length, creativity, api_key, serper_api_key)
68
+
69
+ # Display the results
70
+ st.success("Script generated successfully!")
71
+ st.subheader(f"Title: {title}")
72
+ st.write(f"Script: {script}")
73
+
74
+ # Save the new script directly to the JSON file
75
+ new_entry = {
76
+ "title": title,
77
+ "script": script,
78
+ "search_data": search_data,
79
+ }
80
+ script_history.append(new_entry)
81
+ save_history(script_history)
82
+
83
+ # Add a download button for the generated script
84
+ st.download_button(
85
+ label="Download Script",
86
+ data=script,
87
+ file_name="generated_script.txt",
88
+ mime="text/plain",
89
+ )
90
+
91
+ # Display additional search data
92
+ with st.expander("Show search data for the script"):
93
+ st.write(search_data)
94
+
95
+ except Exception as e:
96
+ # Handle any errors that occur during script generation
97
+ st.error("An error occurred. Try again.")
98
+ with st.expander("Expand to see details"):
99
+ st.write(f"{e}")
secretary.py ADDED
@@ -0,0 +1,62 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import json
3
+ import os
4
+
5
+ # Load script history
6
+ history_file = "script_history.json"
7
+
8
+ def load_script_history():
9
+ if os.path.exists(history_file):
10
+ with open(history_file, "r") as file:
11
+ return json.load(file)
12
+ return []
13
+
14
+ def save_script_history(history):
15
+ with open(history_file, "w") as file:
16
+ json.dump(history, file, indent=4)
17
+
18
+ # Load the script history
19
+ script_history = load_script_history()
20
+
21
+ st.title("Script Secretary 📚")
22
+ st.header('Manage saved scripts in history.')
23
+
24
+ # Display entries and provide delete/download functionality
25
+ if script_history:
26
+ for idx, entry in enumerate(script_history):
27
+ # Add an expander for each script
28
+ with st.expander(entry.get("title","")):
29
+ # Display script content in a read-only text area
30
+ st.text_area(
31
+ "Script Content",
32
+ value=entry.get("script", ""),
33
+ height=150,
34
+ disabled=True,
35
+ key=f"text_area_{idx}" # Unique key for each text area
36
+ )
37
+
38
+ # Add a button to download the script as a text file
39
+ st.download_button(
40
+ label="Download Script",
41
+ data=entry["script"],
42
+ file_name=f"{entry.get("title","")}.txt",
43
+ mime="text/plain"
44
+ )
45
+
46
+ # Add a delete button for each entry
47
+ if st.button(f"Delete Script", key=f"delete_{idx}"):
48
+ # Delete the selected entry
49
+ del script_history[idx]
50
+ save_script_history(script_history)
51
+ st.success(f"Script {idx + 1} deleted!")
52
+ st.rerun() # Refresh the page to reflect the deletion
53
+ else:
54
+ st.info("No script history found!")
55
+
56
+ # Add a button to clear all history
57
+ with st.sidebar:
58
+ if script_history and st.button("Clear All Scripts"):
59
+ script_history = []
60
+ save_script_history(script_history)
61
+ st.success("All script history cleared!")
62
+ st.rerun()
tweaker.py CHANGED
@@ -1,97 +1,124 @@
1
  import streamlit as st
2
- from langchain_community.llms import Replicate
 
 
3
  from langchain.chains import ConversationChain
4
  from langchain.memory import ConversationSummaryMemory
5
  from langchain.prompts import ChatPromptTemplate
6
- import os
7
 
8
- # Setting page title and header
9
- st.title("Creative Consultant")
10
- st.subheader("Make fun stuff with YouTube-Inator!")
11
-
12
- # Sidebar for API key input and summarisation
13
- with st.sidebar:
14
- # Button to summarise the conversation
15
- summarise_button = st.button("Summarise the conversation", key="summarise_button")
16
-
17
- # Check if the summarise button was clicked
18
- if summarise_button:
19
- if st.session_state.get('conversation') and st.session_state['conversation'].memory:
20
- # Generate the summary
21
- summary = st.session_state['conversation'].memory.buffer
22
- st.session_state['summary'] = summary # Store in session state
23
- st.write("Summary:\n\n" + summary)
24
- else:
25
- # Handle case where no conversation memory exists
26
- summary = "No conversation to summarise leh!"
27
- st.write(summary)
28
-
29
- # Add a download button if a summary exists
30
- if st.session_state.get('summary'):
31
- st.download_button(
32
- label="Download Summary",
33
- data=st.session_state['summary'],
34
- file_name="conversation_summary.txt",
35
- mime="text/plain",
36
- )
 
 
 
 
 
 
 
37
 
38
- # Initialize conversation state if not already done
39
- if 'conversation' not in st.session_state:
40
- st.session_state['conversation'] = None
41
- if 'messages' not in st.session_state:
42
- st.session_state['messages'] = []
43
- if 'REPLICATE_API_TOKEN' not in st.session_state:
44
- st.session_state['REPLICATE_API_TOKEN'] = ''
45
-
46
- # Function to get response from OpenAI model
47
- def get_response(user_input, replicate_api):
48
- if st.session_state['conversation'] is None:
49
- llm = Replicate(
50
- model=("meta/meta-llama-3-8b-instruct"),
51
- model_kwargs={
52
- "temperature": 0.01,
53
- "top_p": 0.9,
54
- "max_length": 128,
55
- },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
56
  )
57
- st.session_state['conversation'] = ConversationChain(
58
  llm=llm,
59
  verbose=True,
60
  memory=ConversationSummaryMemory(llm=llm),
 
61
  )
62
- # Call the conversation chain
63
- response_dict = st.session_state['conversation'].invoke(input=user_input)
64
-
65
- # Extract the response field only
66
- return response_dict.get("response", "No response generated leh!")
67
-
68
- # Function to get user input
69
- def get_text():
70
- chat_input = st.chat_input("Say Hello")
71
- return chat_input
72
 
73
  # Display chat history
74
- if st.session_state.messages:
75
- for msg in st.session_state.messages:
76
- with st.chat_message(msg["role"]):
77
- st.markdown(msg["content"])
78
 
79
- # Get user input
80
- user_input = get_text()
81
 
82
  if user_input:
 
 
 
 
 
83
  try:
84
- # Get the response from the LLM
85
- response = get_response(user_input, st.session_state['REPLICATE_API_TOKEN'])
86
-
87
- # Append the user message to session state
88
- st.session_state.messages.append({"role": "user", "content": user_input})
89
- with st.chat_message("user"):
90
- st.markdown(user_input)
91
-
92
- # Append and display the LLM response
93
- st.session_state.messages.append({"role": "LLM", "content": response})
94
- with st.chat_message("LLM"):
 
 
 
 
 
 
 
 
95
  st.markdown(response)
96
 
97
  except Exception as e:
 
1
  import streamlit as st
2
+ import json
3
+ import os
4
+ from langchain_openai import ChatOpenAI
5
  from langchain.chains import ConversationChain
6
  from langchain.memory import ConversationSummaryMemory
7
  from langchain.prompts import ChatPromptTemplate
 
8
 
9
+ st.title('Creative Consultant 🎬')
10
+ st.subheader('Ask content creation tips or help tweak your premade script!')
11
+
12
+ # Load script history from `scriptgen.py`
13
+ history_file = "script_history.json"
14
+
15
+ def load_script_history():
16
+ if os.path.exists(history_file):
17
+ with open(history_file, "r") as file:
18
+ return json.load(file)
19
+ return []
20
+
21
+ # Initialize session state
22
+ if "messages" not in st.session_state:
23
+ st.session_state.messages = [
24
+ {"role": "assistant", "content": "Hey there! I'm here to help you improve or tweak your scripts. Feel free to ask me anything related to content creation!"}
25
+ ]
26
+ if "conversation" not in st.session_state:
27
+ st.session_state["conversation"] = None
28
+ if "OPENAI_API_KEY" not in st.session_state:
29
+ st.session_state["OPENAI_API_KEY"] = ""
30
+
31
+ def clear_chat_history():
32
+ st.session_state.messages = [{"role": "assistant", "content": "Chat history cleared. What would you like help with next?"}]
33
+
34
+
35
+
36
+ # Load generated scripts from history
37
+ script_history = load_script_history()
38
+
39
+ # Sidebar for script selection
40
+ if script_history:
41
+ st.sidebar.header("Previously Generated Scripts")
42
+ script_titles = [f"Script {idx + 1}: {item['title']}" for idx, item in enumerate(script_history)]
43
+ selected_script_idx = st.sidebar.selectbox("Choose a script to tweak:", range(len(script_titles)), format_func=lambda x: script_titles[x])
44
+ selected_script = script_history[selected_script_idx]
45
 
46
+ # Display the selected script
47
+ st.sidebar.text_area("Script Content", value=selected_script["script"], height=200, disabled=True)
48
+ else:
49
+ st.sidebar.info("No scripts available. Please generate scripts using the Script Generator.")
50
+
51
+ st.sidebar.button('Clear Chat History', on_click=clear_chat_history)
52
+
53
+ # Prompt template for the Creative Consultant
54
+ prompt_template = ChatPromptTemplate.from_template(
55
+ """
56
+ You are a Creative Consultant focused on improving video scripts and YouTube content.
57
+ You provide detailed feedback and actionable suggestions to make the scripts more engaging, concise, or tailored to the target audience.
58
+
59
+ This is the conversation history:
60
+ {history}
61
+
62
+ This is the user's new question or statement:
63
+ {input}
64
+
65
+ Provide specific recommendations or edits based on the selected script. Ensure your feedback remains within the scope of content creation and creativity.
66
+ """
67
+ )
68
+
69
+ # Function to get response from the LLM
70
+ def get_response(user_input):
71
+ if st.session_state["conversation"] is None:
72
+ llm = ChatOpenAI(
73
+ model='gpt-4o-mini',
74
+ temperature=0.1,
75
+ max_tokens=512,
76
+ timeout=None,
77
+ max_retries=2
78
  )
79
+ st.session_state["conversation"] = ConversationChain(
80
  llm=llm,
81
  verbose=True,
82
  memory=ConversationSummaryMemory(llm=llm),
83
+ prompt=prompt_template
84
  )
85
+ response_dict = st.session_state["conversation"].invoke(input=user_input)
86
+ return response_dict.get("response", "No response generated.")
 
 
 
 
 
 
 
 
87
 
88
  # Display chat history
89
+ for message in st.session_state.messages:
90
+ with st.chat_message(message["role"]):
91
+ st.markdown(message["content"])
 
92
 
93
+ # User input
94
+ user_input = st.chat_input("Ask for feedback or tweaks on your selected script...")
95
 
96
  if user_input:
97
+ # Append user input to session state and display it
98
+ st.session_state.messages.append({"role": "user", "content": user_input})
99
+ with st.chat_message("user"):
100
+ st.markdown(user_input)
101
+
102
  try:
103
+ # Use the selected script as context for the assistant's response
104
+ if script_history:
105
+ user_input_with_context = f"""
106
+ The user selected the following script for feedback:
107
+ Title: {selected_script['title']}
108
+ Script Content: {selected_script['script']}
109
+
110
+ User's query: {user_input}
111
+ """
112
+ else:
113
+ user_input_with_context = user_input
114
+
115
+ # Generate the assistant's response
116
+ with st.spinner():
117
+ response = get_response(user_input_with_context)
118
+ st.session_state.messages.append({"role": "assistant", "content": response})
119
+
120
+ # Display assistant's response
121
+ with st.chat_message("assistant"):
122
  st.markdown(response)
123
 
124
  except Exception as e: