File size: 7,847 Bytes
b3081c2 |
1 2 3 4 5 6 7 8 9 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 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 |
import os
import uuid
import shutil
from image_generator import ImageGenerator
from moviepy.editor import ImageClip, concatenate_videoclips,AudioFileClip
from function_wrap_center import add_text_to_image
from gtts import gTTS
from structured_output import StructuredOutputExtractor
from pydantic import BaseModel, Field
class YoutubeShortGenerator:
def __init__(self):
self.video_title = None
self.result = None
self.media_dir = 'generated_media'
self.generated_video_dir = None
self.image_dir = None
self.audio_clips_dir = None
self.video_path = None
os.makedirs(self.media_dir,exist_ok=True)
def title_to_keywords(self, title):
# Define your data extraction model here
class TopN(BaseModel):
title: str = Field(description="the title of the youtube video")
title_image_prompt: str = Field(description="highly detailed and descriptive image prompt for the background image of Title")
items: list[str] = Field(description="top n number of requested items")
items_image_prompts: list[str] = Field(description="highly detailed and descriptive image prompts for each item ")
# Assuming StructuredOutputExtractor is defined and functional
extractor = StructuredOutputExtractor(response_schema=TopN)
result = extractor.extract(title)
self.result = result
# create main directory for saving video related content i.e images, audio_clips
video_title = self.result.title
unique_id = uuid.uuid4().hex
folder_path = f"{self.media_dir}/generated_{video_title}_{unique_id}"
self.generated_video_dir = folder_path
return self
def generate_images(self):
if not self.result:
print("No data available. Call title_to_keywords first.")
return self
print(self.result,'inside generate_images()')
generator = ImageGenerator() # Your custom image generator
folder_path = f"{self.generated_video_dir}/generated_images" # Append unique ID
os.makedirs(folder_path, exist_ok=True) # Ensure directory is created
self.image_dir = folder_path
# Generate Title Image
# generator.generate_image(self.result.title_image_prompt, path=f"{folder_path}/title.png")
print("Title Prompt: ",self.result.title_image_prompt)
# generate images using stable-diffusion-turbo
generator.generate_image(self.result.title_image_prompt, path=f"{folder_path}/title.png")
print("Generating Images...")
image_prompts = self.result.items_image_prompts
print("items image prompts: ", image_prompts)
image_prompts = reversed(image_prompts)
print("Image Prompts: ", image_prompts) # Placeholder for actual image processing
# Generate and save images
for index, image_prompt in enumerate(image_prompts):
# generate images using stable-diffusion-turbo
generator.generate_image(image_prompt, f"{folder_path}/{index}.png" )
print(f"Image {index} saved.")
return self # Return self for further chaining if needed
def overlay_text_to_images(self):
if not self.result:
print("No data available. Call title_to_keywords first.")
return self
title_text = self.result.title
text_items = reversed(self.result.items)
print("text_items ",text_items)
# add text to title image
add_text_to_image(text=title_text,image_path=f"{self.image_dir}/title.png", save_to=f"{self.image_dir}/title.png")
# add text to other images
for index, text in enumerate(text_items):
image_path = f"{self.image_dir}/{index}.png"
add_text_to_image(text=text,image_path=image_path,is_title=False, save_to=image_path)
return self
def generate_audio_clips(self):
if not self.result:
print("No data available. Call title_to_keywords first.")
return self
print("Generating Title Audio...")
overlay_title = self.result.title
print("Title: ", overlay_title)
print("Generating Audio Clips...")
overlay_text_items = reversed(self.result.items)
print("Overlay Text: ", overlay_text_items) # Placeholder for actual text processing
folder_path = f"{self.generated_video_dir}/generated_audio_clips" # Append unique ID
self.audio_clips_dir = folder_path
os.makedirs(folder_path, exist_ok=True) # Ensure directory is created
# Generate title Audio
title_tts = gTTS(text=overlay_title)
title_tts.save(f"{folder_path}/title.mp3")
print(f"Title Audio clip title.mp3 saved.")
# Generate and save audio clips
for index, text_overlay in enumerate(overlay_text_items):
tts = gTTS(text=text_overlay) # Generate audio clip
tts.save(f"{folder_path}/{index}.mp3") # Save the audio as MP3
print(f"Audio clip {index} saved.")
return self # Return self for further chaining if needed
def make_video(self):
# Ensure title is included and sorted properly
audio_files = sorted(os.listdir(self.audio_clips_dir), key=lambda x: (x != "title.mp3", int(x.split(".")[0]) if x != "title.mp3" else -1))
image_files = sorted(os.listdir(self.image_dir), key=lambda x: (x != "title.png", int(x.split(".")[0]) if x != "title.png" else -1))
print("Sorted audio files:", audio_files)
print("Sorted image files:", image_files)
# Initialize audio clips
audio_clips = [AudioFileClip(os.path.join(self.audio_clips_dir, audio)) for audio in audio_files]
# Initialize image clips with matching durations
image_clips = [ImageClip(os.path.join(self.image_dir, image)).set_duration(audio.duration)
for image, audio in zip(image_files, audio_clips)]
# Attach audio to images
image_clips_with_audio = [image.set_audio(audio) for image, audio in zip(image_clips, audio_clips)]
# Concatenate all video clips
video_clip = concatenate_videoclips(image_clips_with_audio, method="compose")
# Save the final video
video_clip.write_videofile(
os.path.join(self.generated_video_dir, 'final_video.mp4'),
codec='libx264',
fps=24
)
self.remove_directory(self.image_dir)
self.remove_directory(self.audio_clips_dir)
existing_videos = sorted(
[os.path.join(self.media_dir, d) for d in os.listdir(self.media_dir)
if os.path.isdir(os.path.join(self.media_dir, d))],
key=os.path.getctime # Sort by creation time (oldest first)
)
if len(existing_videos) > 5:
for old_video_dir in existing_videos[:-5]: # Keep last 5, delete the rest
if old_video_dir != self.generated_video_dir: # Ensure we don't delete the current video
self.remove_directory(old_video_dir)
@staticmethod
def remove_directory(dir_path):
"""
Remove the specified directory and all its contents.
"""
if os.path.isdir(dir_path):
shutil.rmtree(dir_path)
print(f"{dir_path} and its contents have been removed.")
else:
print(f"{dir_path} does not exist or is not a directory.")
if __name__ == '__main__':
yt_short_generator = YoutubeShortGenerator()
result = yt_short_generator.title_to_keywords("top 3 Marvel Superheroes").generate_images().overlay_text_to_images().generate_audio_clips().make_video()
|