Shorts / shortGPT /engine /content_short_engine.py
HashScripts's picture
Upload 167 files
b293d47 verified
import datetime
import os
import re
import shutil
from abc import abstractmethod
from shortGPT.audio import audio_utils
from shortGPT.audio.audio_duration import get_asset_duration
from shortGPT.audio.voice_module import VoiceModule
from shortGPT.config.asset_db import AssetDatabase
from shortGPT.config.languages import Language
from shortGPT.editing_framework.editing_engine import (EditingEngine,
EditingStep)
from shortGPT.editing_utils import captions, editing_images
from shortGPT.editing_utils.handle_videos import extract_random_clip_from_video
from shortGPT.engine.abstract_content_engine import AbstractContentEngine
from shortGPT.gpt import gpt_editing, gpt_translate, gpt_yt
class ContentShortEngine(AbstractContentEngine):
def __init__(self, short_type: str, background_video_name: str, background_music_name: str, voiceModule: VoiceModule, short_id="",
num_images=None, watermark=None, language: Language = Language.ENGLISH,):
super().__init__(short_id, short_type, language, voiceModule)
if not short_id:
if (num_images):
self._db_num_images = num_images
if (watermark):
self._db_watermark = watermark
self._db_background_video_name = background_video_name
self._db_background_music_name = background_music_name
self.stepDict = {
1: self._generateScript,
2: self._generateTempAudio,
3: self._speedUpAudio,
4: self._timeCaptions,
5: self._generateImageSearchTerms,
6: self._generateImageUrls,
7: self._chooseBackgroundMusic,
8: self._chooseBackgroundVideo,
9: self._prepareBackgroundAssets,
10: self._prepareCustomAssets,
11: self._editAndRenderShort,
12: self._addYoutubeMetadata
}
@abstractmethod
def _generateScript(self):
self._db_script = ""
def _generateTempAudio(self):
if not self._db_script:
raise NotImplementedError("generateScript method must set self._db_script.")
if (self._db_temp_audio_path):
return
self.verifyParameters(text=self._db_script)
script = self._db_script
if (self._db_language != Language.ENGLISH.value):
self._db_translated_script = gpt_translate.translateContent(script, self._db_language)
script = self._db_translated_script
self._db_temp_audio_path = self.voiceModule.generate_voice(
script, self.dynamicAssetDir + "temp_audio_path.wav")
def _speedUpAudio(self):
if (self._db_audio_path):
return
self.verifyParameters(tempAudioPath=self._db_temp_audio_path)
self._db_audio_path = audio_utils.speedUpAudio(
self._db_temp_audio_path, self.dynamicAssetDir+"audio_voice.wav")
def _timeCaptions(self):
self.verifyParameters(audioPath=self._db_audio_path)
whisper_analysis = audio_utils.audioToText(self._db_audio_path)
self._db_timed_captions = captions.getCaptionsWithTime(
whisper_analysis)
def _generateImageSearchTerms(self):
self.verifyParameters(captionsTimed=self._db_timed_captions)
if self._db_num_images:
self._db_timed_image_searches = gpt_editing.getImageQueryPairs(
self._db_timed_captions, n=self._db_num_images)
def _generateImageUrls(self):
if self._db_timed_image_searches:
self._db_timed_image_urls = editing_images.getImageUrlsTimed(
self._db_timed_image_searches)
def _chooseBackgroundMusic(self):
self._db_background_music_url = AssetDatabase.get_asset_link(self._db_background_music_name)
def _chooseBackgroundVideo(self):
self._db_background_video_url = AssetDatabase.get_asset_link(
self._db_background_video_name)
self._db_background_video_duration = AssetDatabase.get_asset_duration(
self._db_background_video_name)
def _prepareBackgroundAssets(self):
self.verifyParameters(
voiceover_audio_url=self._db_audio_path,
video_duration=self._db_background_video_duration,
background_video_url=self._db_background_video_url, music_url=self._db_background_music_url)
if not self._db_voiceover_duration:
self.logger("Rendering short: (1/4) preparing voice asset...")
self._db_audio_path, self._db_voiceover_duration = get_asset_duration(
self._db_audio_path, isVideo=False)
if not self._db_background_trimmed:
self.logger("Rendering short: (2/4) preparing background video asset...")
self._db_background_trimmed = extract_random_clip_from_video(
self._db_background_video_url, self._db_background_video_duration, self._db_voiceover_duration, self.dynamicAssetDir + "clipped_background.mp4")
def _prepareCustomAssets(self):
self.logger("Rendering short: (3/4) preparing custom assets...")
pass
def _editAndRenderShort(self):
self.verifyParameters(
voiceover_audio_url=self._db_audio_path,
video_duration=self._db_background_video_duration,
music_url=self._db_background_music_url)
outputPath = self.dynamicAssetDir+"rendered_video.mp4"
if not (os.path.exists(outputPath)):
self.logger("Rendering short: Starting automated editing...")
videoEditor = EditingEngine()
videoEditor.addEditingStep(EditingStep.ADD_VOICEOVER_AUDIO, {
'url': self._db_audio_path})
videoEditor.addEditingStep(EditingStep.ADD_BACKGROUND_MUSIC, {'url': self._db_background_music_url,
'loop_background_music': self._db_voiceover_duration,
"volume_percentage": 0.11})
videoEditor.addEditingStep(EditingStep.CROP_1920x1080, {
'url': self._db_background_trimmed})
videoEditor.addEditingStep(EditingStep.ADD_SUBSCRIBE_ANIMATION, {'url': AssetDatabase.get_asset_link('subscribe animation')})
if self._db_watermark:
videoEditor.addEditingStep(EditingStep.ADD_WATERMARK, {
'text': self._db_watermark})
caption_type = EditingStep.ADD_CAPTION_SHORT_ARABIC if self._db_language == Language.ARABIC.value else EditingStep.ADD_CAPTION_SHORT
for timing, text in self._db_timed_captions:
videoEditor.addEditingStep(caption_type, {'text': text.upper(),
'set_time_start': timing[0],
'set_time_end': timing[1]})
if self._db_num_images:
for timing, image_url in self._db_timed_image_urls:
videoEditor.addEditingStep(EditingStep.SHOW_IMAGE, {'url': image_url,
'set_time_start': timing[0],
'set_time_end': timing[1]})
videoEditor.renderVideo(outputPath, logger= self.logger if self.logger is not self.default_logger else None)
self._db_video_path = outputPath
def _addYoutubeMetadata(self):
if not os.path.exists('videos/'):
os.makedirs('videos')
self._db_yt_title, self._db_yt_description = gpt_yt.generate_title_description_dict(self._db_script)
now = datetime.datetime.now()
date_str = now.strftime("%Y-%m-%d_%H-%M-%S")
newFileName = f"videos/{date_str} - " + \
re.sub(r"[^a-zA-Z0-9 '\n\.]", '', self._db_yt_title)
shutil.move(self._db_video_path, newFileName+".mp4")
with open(newFileName+".txt", "w", encoding="utf-8") as f:
f.write(
f"---Youtube title---\n{self._db_yt_title}\n---Youtube description---\n{self._db_yt_description}")
self._db_video_path = newFileName+".mp4"
self._db_ready_to_upload = True