fix(generators/ideas.py): fix typo in variable name 'existing_ideas'

feat(generators/montage.py): add check to skip slide if it already exists
feat(generators/montage.py): add support for DEEPL_ACCESS_KEY and UNSPLASH_ACCESS_KEY environment variables
feat(generators/speak.py): add support for Johanne voice
feat(generators/speak.py): add emotion parameter to generate_voice function
feat(generators/uploader.py): add success message and authorization prompt message to run_local_server method
fix(main.py): check if credits is None before writing to meta.txt file
feat(prompts/marp.md): change theme to gaia and add lead and invert classes
This commit is contained in:
Paillat
2023-05-25 21:47:11 +02:00
parent 32c14a01ca
commit 25f578f48c
6 changed files with 90 additions and 58 deletions

View File

@@ -20,7 +20,10 @@ async def generate_ideas(path, subject):
except: except:
ides_json = [] ides_json = []
ideas = "There are no existing ideas." ideas = "There are no existing ideas."
prmpt = prmpt.replace('[existing ideas]', ideas) exuisting_ideas = ""
for idea in ides_json:
exuisting_ideas += f"{idea['title']}\n"
prmpt = prmpt.replace('[existing ideas]', exuisting_ideas)
print(prmpt) print(prmpt)
response = await openai.ChatCompletion.acreate( response = await openai.ChatCompletion.acreate(
model="gpt-3.5-turbo", model="gpt-3.5-turbo",

View File

@@ -9,12 +9,12 @@ from generators.speak import generate_voice, voices
from moviepy.video.VideoClip import ImageClip from moviepy.video.VideoClip import ImageClip
from moviepy.editor import VideoFileClip, concatenate_videoclips, CompositeAudioClip, concatenate_audioclips from moviepy.editor import VideoFileClip, concatenate_videoclips, CompositeAudioClip, concatenate_audioclips
from moviepy.audio.io.AudioFileClip import AudioFileClip from moviepy.audio.io.AudioFileClip import AudioFileClip
from moviepy.audio.fx.all import volumex, audio_fadein, audio_fadeout from moviepy.audio.fx.all import volumex, audio_fadein, audio_fadeout # type: ignore
from dotenv import load_dotenv from dotenv import load_dotenv
load_dotenv() load_dotenv()
unsplash_access = os.getenv("UNSPLASH_ACCESS_KEY") unsplash_access = os.getenv("UNSPLASH_ACCESS_KEY") or "UNSPLASH_ACCESS_KEY"
unsplash_url = "https://api.unsplash.com/photos/random/?client_id=" + unsplash_access + "&query=" unsplash_url = "https://api.unsplash.com/photos/random/?client_id=" + unsplash_access + "&query="
deepl_access = os.getenv("DEEPL_ACCESS_KEY") deepl_access = os.getenv("DEEPL_ACCESS_KEY") or "DEEPL_ACCESS_KEY"
translator = deepl.Translator(deepl_access) translator = deepl.Translator(deepl_access)
def prepare(path): def prepare(path):
@@ -36,6 +36,9 @@ def prepare(path):
if not os.path.exists(audio_path): if not os.path.exists(audio_path):
generate_voice(audio_path, script[i]['spoken'], choosen_voice) generate_voice(audio_path, script[i]['spoken'], choosen_voice)
if "image" in script[i]: if "image" in script[i]:
if os.path.exists(path + "/slides/assets/slide" + str(i) + ".md"):
#skip this slide
continue
if not os.path.exists(path + "/slides/assets"): if not os.path.exists(path + "/slides/assets"):
os.mkdir(path + "/slides/assets") os.mkdir(path + "/slides/assets")
url= unsplash_url + script[i]['image'] url= unsplash_url + script[i]['image']
@@ -48,16 +51,29 @@ def prepare(path):
with open(path + "/slides/slide" + str(i) + ".md", 'w', encoding='utf-8') as f: with open(path + "/slides/slide" + str(i) + ".md", 'w', encoding='utf-8') as f:
f.write(content) f.write(content)
elif "markdown" in script[i]: elif "markdown" in script[i]:
if os.path.exists(path + "/slides/slide" + str(i) + ".md"):
#skip this slide
continue
with open(path + "/slides/slide" + str(i) + ".md", 'w', encoding='utf-8') as f: with open(path + "/slides/slide" + str(i) + ".md", 'w', encoding='utf-8') as f:
f.write(marp + "\n\n" + script[i]['markdown']) f.write(marp + "\n\n" + script[i]['markdown'])
elif "huge" in script[i]: elif "huge" in script[i]:
#use fit #use fit
if os.path.exists(path + "/slides/slide" + str(i) + ".md"):
#skip this slide
continue
with open(path + "/slides/slide" + str(i) + ".md", 'w', encoding='utf-8') as f: with open(path + "/slides/slide" + str(i) + ".md", 'w', encoding='utf-8') as f:
f.write(marp + "\n\n# <!-- fit --> " + script[i]['huge']) f.write(marp + "\n\n# <!-- fit --> " + script[i]['huge'])
else: else:
pass if os.path.exists(path + "/slides/slide" + str(i) + ".md"):
#skip this slide
continue
with open(path + "/slides/slide" + str(i) + ".md", 'w', encoding='utf-8') as f:
f.write(marp + "\n\n") # blank slide
for i in range(len(script)): for i in range(len(script)):
marrkdown_path = "./" + path + "/slides/slide" + str(i) + ".md" marrkdown_path = "./" + path + "/slides/slide" + str(i) + ".md"
if os.path.exists(f"./{path}/slides/slide{i}.png"):
#skip this slide
continue
command = f"marp.exe {marrkdown_path} -o {path}/slides/slide{i}.png --allow-local-files" command = f"marp.exe {marrkdown_path} -o {path}/slides/slide{i}.png --allow-local-files"
os.system(command) os.system(command)
return script return script
@@ -79,6 +95,7 @@ def subs(length, total, text, srt, index):
return srt return srt
def mount(path, script): def mount(path, script):
if not os.path.exists(path + "/montage.mp4"):
num_slides = len(os.listdir(path + "/audio")) num_slides = len(os.listdir(path + "/audio"))
clips = [] clips = []
srt = pysrt.SubRipFile() srt = pysrt.SubRipFile()
@@ -118,3 +135,5 @@ def mount(path, script):
music_credit = f.read() music_credit = f.read()
f.close() f.close()
return music_credit return music_credit
else:
return None

View File

@@ -8,17 +8,23 @@ fakenames = {
"Alexander": "p230", "Alexander": "p230",
"Benjamin": "p240", "Benjamin": "p240",
"Amelia": "p270", "Amelia": "p270",
"Katherine": "p273" "Katherine": "p273",
"Johanne": "p347",
} }
voices = ["Alexander", "Benjamin", "Amelia", "Katherine"] voices = ["Alexander", "Benjamin", "Amelia", "Katherine", "Johanne"]
# Init TTS # Init TTS
def generate_voice(path, text, speaker="Alexander"): def generate_voice(path, text, speaker="Alexander"):
try: model = model_best_multi
tts = TTS(model_best_multi, gpu=True)
except:
tts = TTS(model_best_multi, gpu=False)
speaker = fakenames[speaker] if speaker in fakenames else speaker speaker = fakenames[speaker] if speaker in fakenames else speaker
tts.tts_to_file(text=text, file_path=path, speaker=speaker, speed=1) print(f"Generating voice for {model} with speaker {speaker}")
try:
tts = TTS(model, gpu=True)
except:
tts = TTS(model, gpu=False)
tts.tts_to_file(text=text, file_path=path, speaker=speaker, speed=1, emotion="Happy")
if __name__ == "__main__":
generate_voice("test/test.mp3", "This is a test. I like the words python, django and flask. Betty bought a bit of butter but the butter was bitter. So she bought some better butter to make the bitter butter better.")

View File

@@ -26,7 +26,7 @@ RETRIABLE_EXCEPTIONS = (httplib2.HttpLib2Error, IOError, client.NotConnected,
RETRIABLE_STATUS_CODES = [500, 502, 503, 504] RETRIABLE_STATUS_CODES = [500, 502, 503, 504]
CLIENT_SECRETS_FILE = 'env/client_secret.json' CLIENT_SECRETS_FILE = ''
#SCOPES = ['https://www.googleapis.com/auth/youtube.upload', 'https://www.googleapis.com/upload/youtube/v3/thumbnails/set', 'https://www.googleapis.com/auth/youtube.force-ssl'] #SCOPES = ['https://www.googleapis.com/auth/youtube.upload', 'https://www.googleapis.com/upload/youtube/v3/thumbnails/set', 'https://www.googleapis.com/auth/youtube.force-ssl']
SCOPES = ['https://www.googleapis.com/auth/youtube'] SCOPES = ['https://www.googleapis.com/auth/youtube']
@@ -38,6 +38,7 @@ VALID_PRIVACY_STATUSES = ('public', 'private', 'unlisted')
# Authorize the request and store authorization credentials. # Authorize the request and store authorization credentials.
def get_authenticated_service(credentialsPath=""): def get_authenticated_service(credentialsPath=""):
CLIENT_SECRETS_FILE=f'{credentialsPath}/client_secret.json'
if os.path.exists(f'{credentialsPath}/credentials.json'): if os.path.exists(f'{credentialsPath}/credentials.json'):
with open(f'{credentialsPath}/credentials.json') as json_file: with open(f'{credentialsPath}/credentials.json') as json_file:
data = json.load(json_file) data = json.load(json_file)
@@ -52,7 +53,7 @@ def get_authenticated_service(credentialsPath=""):
else: else:
flow = InstalledAppFlow.from_client_secrets_file( flow = InstalledAppFlow.from_client_secrets_file(
CLIENT_SECRETS_FILE, SCOPES) CLIENT_SECRETS_FILE, SCOPES)
credentials = flow.run_local_server() credentials = flow.run_local_server(success_message="Heyy, yippie, you're authenticated ! You can close this window now !", authorization_prompt_message="Please authorize this app to upload videos on your YouTube account !")
with open(f'{credentialsPath}/credentials.json', 'w') as outfile: with open(f'{credentialsPath}/credentials.json', 'w') as outfile:
outfile.write(credentials.to_json()) outfile.write(credentials.to_json())
return build(API_SERVICE_NAME, API_VERSION, credentials=credentials) return build(API_SERVICE_NAME, API_VERSION, credentials=credentials)

View File

@@ -53,6 +53,7 @@ async def main():
script = prepare(path) script = prepare(path)
credits = mount(path, script) credits = mount(path, script)
description = f"{idea['description']}\n\nMusic credits: {credits}" description = f"{idea['description']}\n\nMusic credits: {credits}"
if credits != None:
with open(path + "/meta.txt", 'w', encoding='utf-8') as f: with open(path + "/meta.txt", 'w', encoding='utf-8') as f:
f.write(description) f.write(description)
f.close() f.close()

View File

@@ -1,6 +1,8 @@
--- ---
marp: true marp: true
theme: default theme: gaia
class: invert class:
- lead
- invert
backgroundImage: url(https://images.unsplash.com/photo-1651604454911-fdfb0edde727) backgroundImage: url(https://images.unsplash.com/photo-1651604454911-fdfb0edde727)
--- ---