|
1 |
| -import yaml |
2 |
| -import logging |
3 |
| -from moviepy.editor import VideoFileClip, AudioFileClip, CompositeVideoClip |
4 |
| -import random |
5 | 1 | import asyncio
|
6 |
| -from openai import OpenAI |
7 |
| -import os |
8 |
| - |
9 |
| -# Set up logging |
10 |
| -logging.basicConfig(level=logging.INFO) |
11 |
| - |
12 |
| -from src.ImageHandler import ImageHandler |
13 |
| -from src.AIShortGenerator import AIShortGenerator |
14 |
| - |
15 |
| -def load_config(file_path): |
16 |
| - """Load the YAML configuration file.""" |
17 |
| - try: |
18 |
| - with open(file_path, 'r') as file: |
19 |
| - config = yaml.safe_load(file) |
20 |
| - return config |
21 |
| - except FileNotFoundError: |
22 |
| - logging.error(f"Config file {file_path} not found.") |
23 |
| - raise |
24 |
| - except Exception as e: |
25 |
| - logging.error(f"Error loading config file: {e}") |
26 |
| - raise |
27 |
| - |
28 |
| -def load_prompt(file_path): |
29 |
| - """Load the YAML prompt template file.""" |
30 |
| - try: |
31 |
| - with open(file_path, 'r') as file: |
32 |
| - prompt_template_file = yaml.safe_load(file) |
33 |
| - return prompt_template_file |
34 |
| - except FileNotFoundError: |
35 |
| - logging.error(f"Prompt file {file_path} not found.") |
36 |
| - raise |
37 |
| - except Exception as e: |
38 |
| - logging.error(f"Error loading prompt file: {e}") |
39 |
| - raise |
40 |
| - |
41 |
| -config = load_config('config.yaml') |
42 |
| - |
43 |
| -# Accessing configuration values |
44 |
| -openai_api_key = os.getenv('OPENAI_API_KEY', config['api_keys']['OPENAI_API_KEY']) |
45 |
| -pexels_api_key = os.getenv('PEXELS_API_KEY', config['api_keys']['PEXELS_API_KEY']) |
46 |
| - |
47 |
| -openai = OpenAI(api_key=openai_api_key) |
48 |
| - |
49 |
| -def gpt_summary_of_script(video_script): |
50 |
| - try: |
51 |
| - completion = openai.chat.completions.create( |
52 |
| - model="gpt-3.5-turbo-0125", |
53 |
| - temperature=0.25, |
54 |
| - max_tokens=250, |
55 |
| - messages=[ |
56 |
| - {"role": "user", "content": f"Summarize the following video script; it is very important that you keep it to one line. \n Script: {video_script}"} |
57 |
| - ] |
58 |
| - ) |
59 |
| - logging.info("Script generated successfully.") |
60 |
| - return completion.choices[0].message.content |
61 |
| - except Exception as e: |
62 |
| - logging.error(f"Error generating script summary: {e}") |
63 |
| - return "" # Return an empty string on error |
64 |
| - |
65 |
| -async def generate_video(video_topic='', video_url='', video_script='', video_script_type='based_on_topic'): |
66 |
| - """Generate a video based on the provided topic or ready-made script. |
67 |
| -
|
68 |
| - Args: |
69 |
| - video_topic (str): The topic of the video if script type is 'based_on_topic'. |
70 |
| - video_url (str): The URL of the video to download. |
71 |
| - video_script (str): The ready-made script if script type is 'ready_made_script'. |
72 |
| - video_script_type (str): The type of script generation ('based_on_topic' or 'ready_made_script'). |
73 |
| -
|
74 |
| - Returns: |
75 |
| - dict: A dictionary with the status of the video generation and a message. |
76 |
| - """ |
77 |
| - try: |
78 |
| - # Ensure the script type is provided |
79 |
| - if not video_script_type: |
80 |
| - raise ValueError("The video script type must be provided.") |
81 |
| - |
82 |
| - # Handle the different cases for script generation |
83 |
| - if video_script_type == 'ready_made_script': |
84 |
| - if not video_script: |
85 |
| - raise ValueError("For 'ready_made_script', the video script should not be null.") |
86 |
| - if len(video_script) > 400: |
87 |
| - raise ValueError("The video script exceeds the 400 character limit.") |
88 |
| - |
89 |
| - elif video_script_type == 'based_on_topic': |
90 |
| - if not video_topic: |
91 |
| - raise ValueError("For 'based_on_topic', the video topic should not be null.") |
92 |
| - # video_script = generate_script_from_topic(video_topic) # You'd need to implement this |
93 |
| - |
94 |
| - else: |
95 |
| - raise ValueError("Invalid video script type. It must be either 'ready_made_script' or 'based_on_topic'.") |
96 |
| - |
97 |
| - # Load prompt template |
98 |
| - prompt_template = load_prompt('prompt_templates/reddit_thread.yaml') |
99 |
| - |
100 |
| - logging.info(f"Starting video generation process for: {video_script_type}") |
101 |
| - ai_short_gen = AIShortGenerator(openai_api_key) |
102 |
| - image_handler = ImageHandler(pexels_api_key, openai_api_key) |
103 |
| - |
104 |
| - video_path = ai_short_gen.download_video(video_url) |
105 |
| - if not video_path: |
106 |
| - logging.error("Failed to download video.") |
107 |
| - return {"status": "error", "message": "No video path provided."} |
108 |
| - |
109 |
| - script = video_script if video_script_type == 'ready_made_script' else await ai_short_gen.generate_script(video_topic, prompt_template) |
110 |
| - if not script: |
111 |
| - logging.error("Failed to generate script.") |
112 |
| - return {"status": "error", "message": "Failed to generate script."} |
113 |
| - |
114 |
| - audio_path = await ai_short_gen.generate_voice(script) |
115 |
| - if not audio_path: |
116 |
| - logging.error("Failed to generate audio.") |
117 |
| - return {"status": "error", "message": "Failed to generate audio."} |
118 |
| - |
119 |
| - audio_clip = AudioFileClip(str(audio_path)) |
120 |
| - audio_length = audio_clip.duration |
121 |
| - audio_clip.close() |
122 |
| - |
123 |
| - video_length = VideoFileClip(video_path).duration |
124 |
| - max_start_time = video_length - audio_length |
125 |
| - |
126 |
| - if max_start_time <= 0: |
127 |
| - logging.error("Calculated start time is invalid.") |
128 |
| - return {"status": "error", "message": "Calculated start time is invalid."} |
129 |
| - |
130 |
| - start_time = random.uniform(0, max_start_time) |
131 |
| - end_time = start_time + audio_length |
132 |
| - |
133 |
| - cut_video_path = ai_short_gen.cut_video(video_path, start_time, end_time) |
134 |
| - if not cut_video_path: |
135 |
| - logging.error("Failed to cut video.") |
136 |
| - return {"status": "error", "message": "Failed to cut video."} |
137 |
| - |
138 |
| - subtitles_path = ai_short_gen.generate_subtitles(audio_path) |
139 |
| - logging.info(f"Subtitles generated successfully.") |
140 |
| - |
141 |
| - video_context = video_script if video_script_type == 'ready_made_script' else video_topic |
142 |
| - image_paths = image_handler.get_images_from_subtitles(subtitles_path, video_context) |
143 |
| - logging.info(f"Downloaded images successfully.") |
144 |
| - |
145 |
| - clip = ai_short_gen.add_audio_and_captions_to_video(cut_video_path, audio_path, subtitles_path) |
146 |
| - ai_short_gen.add_images_to_video(clip, image_paths) |
147 |
| - |
148 |
| - # Cleanup: Ensure temporary files are removed |
149 |
| - cleanup_files([audio_path, cut_video_path, subtitles_path]) |
150 |
| - |
151 |
| - return {"status": "success", "message": "Video generated successfully."} |
152 |
| - |
153 |
| - except Exception as e: |
154 |
| - logging.error(f"Error in video generation: {e}") |
155 |
| - return {"status": "error", "message": f"Error in video generation: {str(e)}"} |
156 |
| - |
157 |
| - |
158 |
| -def cleanup_files(file_paths): |
159 |
| - """Delete temporary files to clean up the workspace.""" |
160 |
| - for file_path in file_paths: |
161 |
| - try: |
162 |
| - if os.path.exists(file_path): |
163 |
| - os.remove(file_path) |
164 |
| - logging.info(f"Deleted temporary file: {file_path}") |
165 |
| - else: |
166 |
| - logging.warning(f"File not found: {file_path}") |
167 |
| - except Exception as e: |
168 |
| - logging.error(f"Error deleting file {file_path}: {e}") |
| 2 | +from src.generateVideo import generate_video |
| 3 | +import yaml |
169 | 4 |
|
| 5 | +with open('./config.yaml', 'r') as file: |
| 6 | + config = yaml.safe_load(file) |
170 | 7 |
|
171 | 8 | # Example usage
|
172 |
| -video_url = config['assets']['YOUTUBE_URL'] |
| 9 | +video_path_or_url = config['assets']['VIDEO_PATH_OR_URL'] |
| 10 | +video_url = config['assets']['VIDEO_YOUTUBE_URL'] |
| 11 | +video_path = config['assets']['VIDEO_PATH'] |
173 | 12 | video_topic = config['video_parameters']['VIDEO_TOPIC']
|
174 | 13 | video_script = config['video_parameters']['VIDEO_SCRIPT']
|
175 | 14 | video_script_type = config['video_parameters']['VIDEO_SCRIPT_TYPE']
|
176 | 15 |
|
177 |
| -asyncio.run(generate_video(video_topic=video_topic, |
178 |
| - video_url=video_url, |
179 |
| - video_script=video_script, |
180 |
| - video_script_type=video_script_type)) |
| 16 | +asyncio.run(generate_video( |
| 17 | + video_path_or_url=video_path_or_url, |
| 18 | + video_path=video_path, |
| 19 | + video_url=video_url, |
| 20 | + video_topic=video_topic, |
| 21 | + video_script=video_script, |
| 22 | + video_script_type=video_script_type)) |
0 commit comments