Updated app.py
Browse files- .gitignore +3 -0
- DOCS.md +37 -0
- app.py +16 -10
- docs.py +8 -0
- generate_script.py +28 -42
- generated_title.txt +1 -0
- imggen.py +114 -83
- manual.py +28 -0
- requirements.txt +1 -1
- resources/imggen.png +0 -0
- resources/scriptgen.png +0 -0
- resources/secretary.png +0 -0
- resources/tweaker.png +0 -0
- scriptgen.py +91 -45
- secretary.py +62 -0
- tweaker.py +104 -77
.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 |
-
|
| 4 |
-
imggen = st.Page("imggen.py", title="Image Generator")
|
| 5 |
-
tweaker = st.Page("tweaker.py", title="Creative Consultant")
|
| 6 |
|
| 7 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 '
|
| 13 |
-
if not (
|
| 14 |
-
|
| 15 |
st.warning('Invalid or no API key! Please try again')
|
| 16 |
else:
|
| 17 |
-
st.success('
|
| 18 |
else:
|
| 19 |
-
|
| 20 |
|
| 21 |
pg = st.navigation(
|
| 22 |
{
|
| 23 |
-
"":
|
|
|
|
| 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
|
| 2 |
from langchain.chains import LLMChain
|
| 3 |
from langchain.prompts import PromptTemplate
|
| 4 |
-
from langchain_community.
|
| 5 |
import os
|
| 6 |
|
| 7 |
-
def generate_script(prompt, video_length, creativity,
|
| 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 |
-
#
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
|
| 29 |
-
|
| 30 |
-
|
| 31 |
-
|
| 32 |
-
"
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
|
| 36 |
-
|
| 37 |
-
|
| 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=
|
| 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=
|
| 57 |
|
| 58 |
-
# Fetch relevant search data using
|
| 59 |
-
search_tool =
|
| 60 |
-
search_data = search_tool.
|
| 61 |
|
| 62 |
-
# Generate the video title
|
| 63 |
title = title_chain.run({"topic": prompt})
|
| 64 |
|
| 65 |
-
#
|
| 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
|
| 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
|
| 10 |
|
| 11 |
# Load environment variables
|
| 12 |
load_dotenv()
|
| 13 |
|
| 14 |
-
#
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 22 |
|
| 23 |
# Retrieve the API key
|
| 24 |
-
|
| 25 |
|
| 26 |
-
if not
|
| 27 |
st.error("API Key not provided! Please add it to Streamlit secrets or the .env file.")
|
| 28 |
else:
|
| 29 |
-
os.environ['
|
| 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 |
-
#
|
| 36 |
-
st.title("
|
| 37 |
-
|
| 38 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 39 |
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
|
| 45 |
-
|
| 46 |
-
|
| 47 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
-
|
| 66 |
-
|
| 67 |
-
|
| 68 |
-
|
| 69 |
-
|
| 70 |
-
|
| 71 |
-
|
| 72 |
-
|
| 73 |
-
|
| 74 |
-
|
| 75 |
-
|
| 76 |
-
|
| 77 |
-
|
| 78 |
-
|
| 79 |
-
"
|
| 80 |
-
|
| 81 |
-
"
|
| 82 |
-
"
|
| 83 |
-
|
| 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 |
-
|
| 10 |
-
st.
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
|
| 29 |
-
|
| 30 |
-
|
| 31 |
-
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
|
| 36 |
-
|
| 37 |
-
|
| 38 |
-
|
| 39 |
-
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
|
| 45 |
-
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
|
| 49 |
-
|
| 50 |
-
|
| 51 |
-
|
| 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 |
-
|
|
|
|
|
|
|
| 3 |
from langchain.chains import ConversationChain
|
| 4 |
from langchain.memory import ConversationSummaryMemory
|
| 5 |
from langchain.prompts import ChatPromptTemplate
|
| 6 |
-
import os
|
| 7 |
|
| 8 |
-
|
| 9 |
-
st.
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
|
| 29 |
-
|
| 30 |
-
|
| 31 |
-
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
|
| 36 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 37 |
|
| 38 |
-
#
|
| 39 |
-
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
|
| 45 |
-
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
|
| 49 |
-
|
| 50 |
-
|
| 51 |
-
|
| 52 |
-
|
| 53 |
-
|
| 54 |
-
|
| 55 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 56 |
)
|
| 57 |
-
st.session_state[
|
| 58 |
llm=llm,
|
| 59 |
verbose=True,
|
| 60 |
memory=ConversationSummaryMemory(llm=llm),
|
|
|
|
| 61 |
)
|
| 62 |
-
|
| 63 |
-
response_dict
|
| 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 |
-
|
| 75 |
-
|
| 76 |
-
|
| 77 |
-
st.markdown(msg["content"])
|
| 78 |
|
| 79 |
-
#
|
| 80 |
-
user_input =
|
| 81 |
|
| 82 |
if user_input:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 83 |
try:
|
| 84 |
-
#
|
| 85 |
-
|
| 86 |
-
|
| 87 |
-
|
| 88 |
-
|
| 89 |
-
|
| 90 |
-
|
| 91 |
-
|
| 92 |
-
|
| 93 |
-
|
| 94 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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:
|