diff --git a/.gitignore b/.gitignore index 54cf5da9..48064e20 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,7 @@ wheels/ # working directory .working_dir/ .test/ + +# other +.DS_Store +.tool-versions diff --git a/configs/idea-example.yaml b/configs/idea-example.yaml new file mode 100644 index 00000000..10f245b6 --- /dev/null +++ b/configs/idea-example.yaml @@ -0,0 +1,7 @@ +idea: | + If a cat and a dog are best friends, what would happen when they meet a new cat? + +user_requirement: | + For children, do not exceed 3 scenes. Each scene should be no more than 5 shots. + +style: Cartoon diff --git a/configs/script-example.yaml b/configs/script-example.yaml new file mode 100644 index 00000000..9d45fbca --- /dev/null +++ b/configs/script-example.yaml @@ -0,0 +1,17 @@ +script: | + EXT. SCHOOL GYM - DAY + A group of students are practicing basketball in the gym. The gym is large and open, with a basketball hoop at one end and a large crowd of spectators at the other end. John (18, male, tall, athletic) is the star player, and he is practicing his dribble and shot. Jane (17, female, short, athletic) is the assistant coach, and she is helping John with his practice. The other students are watching the practice and cheering for John. + John: (dribbling the ball) I'm going to score a basket! + Jane: (smiling) Good job, John! + John: (shooting the ball) Yes! + John:(The shot misses. He seems frustrated.) Argh! My follow-through feels off today. + Jane:(Walks over, analytical.) Your elbow is drifting out. Remember, straight as an arrow. + John:(Nods, taking the ball again.) Straight as an arrow... Let me try again. + (John takes another shot. This time, the ball swishes through the net perfectly.) + Jane:(Clapping.) There it is! Perfect form! That's the shot we need for the championship. + John:(Retrieving the ball, smiling with renewed confidence.) Thanks, Coach Jane. I just needed you to point it out. One more time? + +user_requirement: | + Fast-paced with no more than 15 shots. + +style: Anime Style diff --git a/main_idea2video.py b/main_idea2video.py index 09fe7a55..72513300 100644 --- a/main_idea2video.py +++ b/main_idea2video.py @@ -1,22 +1,89 @@ import asyncio +import argparse +import yaml +from pathlib import Path from pipelines.idea2video_pipeline import Idea2VideoPipeline -# SET YOUR OWN IDEA, USER REQUIREMENT, AND STYLE HERE -idea = \ -""" -If a cat and a dog are best friends, what would happen when they meet a new cat? -""" -user_requirement = \ -""" -For children, do not exceed 3 scenes. Each scene should be no more than 5 shots. -""" -style = "Cartoon" +def load_from_file(file_path: str) -> dict: + """Load idea, user_requirement, and style from a YAML file.""" + with open(file_path, 'r') as f: + data = yaml.safe_load(f) + + required_fields = ['idea', 'user_requirement', 'style'] + for field in required_fields: + if field not in data: + raise ValueError( + f"Missing required field '{field}' in {file_path}") + + return data + + +def parse_args(): + parser = argparse.ArgumentParser( + description='Generate video from an idea using AI', + formatter_class=argparse.RawDescriptionHelpFormatter, + epilog=""" +Examples: + # Using command-line arguments: + python main_idea2video.py -i "A woman exercising" -u "3 scenes max" -s "Realistic" + + # Using a YAML file: + python main_idea2video.py -f configs/idea-example.yaml -c configs/myidea2video.yaml + + # YAML file format: + idea: | + Your idea here + Can span multiple lines + user_requirement: | + Your requirements here + style: Realistic, warm feel + """ + ) + + parser.add_argument('-f', '--file', type=str, + help='Path to YAML file containing idea, user_requirement, and style') + parser.add_argument('-i', '--idea', type=str, + help='The main idea for the video') + parser.add_argument('-u', '--user-requirement', type=str, + help='User requirements (e.g., number of scenes, shots)') + parser.add_argument('-s', '--style', type=str, + help='Video style (e.g., "Realistic, warm feel")') + parser.add_argument('-c', '--config', type=str, default='configs/idea2video.yaml', + help='Path to pipeline configuration file (default: configs/idea2video.yaml)') + + args = parser.parse_args() + + # Validate arguments + if args.file: + if any([args.idea, args.user_requirement, args.style]): + parser.error( + "Cannot use --file with --idea, --user-requirement, or --style") + return args + else: + if not all([args.idea, args.user_requirement, args.style]): + parser.error( + "Must provide either --file or all of: --idea, --user-requirement, --style") + return args async def main(): - pipeline = Idea2VideoPipeline.init_from_config(config_path="configs/idea2video.yaml") + args = parse_args() + + # Load parameters from file or command-line arguments + if args.file: + data = load_from_file(args.file) + idea = data['idea'] + user_requirement = data['user_requirement'] + style = data['style'] + else: + idea = args.idea + user_requirement = args.user_requirement + style = args.style + + pipeline = Idea2VideoPipeline.init_from_config(config_path=args.config) await pipeline(idea=idea, user_requirement=user_requirement, style=style) + if __name__ == "__main__": asyncio.run(main()) diff --git a/main_script2video.py b/main_script2video.py index cd6cf7bc..f2d88218 100644 --- a/main_script2video.py +++ b/main_script2video.py @@ -1,32 +1,88 @@ import asyncio +import argparse +import yaml +from pathlib import Path from pipelines.script2video_pipeline import Script2VideoPipeline -# SET YOUR OWN SCRIPT, USER REQUIREMENT, AND STYLE HERE -script = \ -""" -EXT. SCHOOL GYM - DAY -A group of students are practicing basketball in the gym. The gym is large and open, with a basketball hoop at one end and a large crowd of spectators at the other end. John (18, male, tall, athletic) is the star player, and he is practicing his dribble and shot. Jane (17, female, short, athletic) is the assistant coach, and she is helping John with his practice. The other students are watching the practice and cheering for John. -John: (dribbling the ball) I'm going to score a basket! -Jane: (smiling) Good job, John! -John: (shooting the ball) Yes! -John:(The shot misses. He seems frustrated.) Argh! My follow-through feels off today. -Jane:(Walks over, analytical.) Your elbow is drifting out. Remember, straight as an arrow. -John:(Nods, taking the ball again.) Straight as an arrow... Let me try again. -(John takes another shot. This time, the ball swishes through the net perfectly.) -Jane:(Clapping.) There it is! Perfect form! That's the shot we need for the championship. -John:(Retrieving the ball, smiling with renewed confidence.) Thanks, Coach Jane. I just needed you to point it out. One more time? -""" -user_requirement = \ -""" -Fast-paced with no more than 15 shots. -""" -style = "Anime Style" +def load_from_file(file_path: str) -> dict: + """Load script, user_requirement, and style from a YAML file.""" + with open(file_path, 'r') as f: + data = yaml.safe_load(f) + required_fields = ['script', 'user_requirement', 'style'] + for field in required_fields: + if field not in data: + raise ValueError( + f"Missing required field '{field}' in {file_path}") + + return data + + +def parse_args(): + parser = argparse.ArgumentParser( + description='Generate video from a script using AI', + formatter_class=argparse.RawDescriptionHelpFormatter, + epilog=""" +Examples: + # Using command-line arguments: + python main_script2video.py -S "EXT. GYM - DAY..." -u "15 shots max" -s "Anime Style" + + # Using a YAML file: + python main_script2video.py -f configs/script-example.yaml + + # YAML file format: + script: | + EXT. GYM - DAY + Your script here + Can span multiple lines + user_requirement: | + Your requirements here + style: Anime Style + """ + ) + + parser.add_argument('-f', '--file', type=str, + help='Path to YAML file containing script, user_requirement, and style') + parser.add_argument('-S', '--script', type=str, + help='The script for the video') + parser.add_argument('-u', '--user-requirement', type=str, + help='User requirements (e.g., number of shots, pacing)') + parser.add_argument('-s', '--style', type=str, + help='Video style (e.g., "Anime Style")') + parser.add_argument('-c', '--config', type=str, default='configs/script2video.yaml', + help='Path to pipeline configuration file (default: configs/script2video.yaml)') + + args = parser.parse_args() + + # Validate arguments + if args.file: + if any([args.script, args.user_requirement, args.style]): + parser.error( + "Cannot use --file with --script, --user-requirement, or --style") + return args + else: + if not all([args.script, args.user_requirement, args.style]): + parser.error( + "Must provide either --file or all of: --script, --user-requirement, --style") + return args async def main(): - pipeline = Script2VideoPipeline.init_from_config(config_path="configs/script2video.yaml") + args = parse_args() + + # Load parameters from file or command-line arguments + if args.file: + data = load_from_file(args.file) + script = data['script'] + user_requirement = data['user_requirement'] + style = data['style'] + else: + script = args.script + user_requirement = args.user_requirement + style = args.style + + pipeline = Script2VideoPipeline.init_from_config(config_path=args.config) await pipeline(script=script, user_requirement=user_requirement, style=style)