import gradio as gr import requests import re import boto3 import os import json from gradio.components import Textbox from openai import OpenAI from pathlib import Path import replicate from datasets.filesystems import S3FileSystem import s3fs api_key= os.getenv('OPENAI_API_KEY') client = OpenAI(api_key=api_key) # Set your API keys and configurations here aws_access_key_id = os.getenv('AWS_ACCESS_KEY_ID') aws_secret_access_key = os.getenv('AWS_SECRET_ACCESS_KEY') aws_default_region = os.getenv('AWS_DEFAULT_REGION') REPLICATE_API_TOKEN = os.getenv('REPLICATE_API_TOKEN') # Initialize OpenAI and S3 clients # client = OpenAI(api_key=api_key) # s3 = boto3.client( # 's3', # aws_access_key_id=aws_access_key_id, # aws_secret_access_key=aws_secret_access_key, # region_name=aws_default_region # ) print("Clients initialized") content_creation_prompt = """ [You are a teacher and a video creator and you create animated educational videos based on SLOs(Student learning outcomes) for students who don't really have a nag for the conventional ways of learning. You make sure that your video lessons are very very interesting and at the same time they still have all the teaching material that you want to incorporate. You have to make sure that the teaching material is logically incorporated within the stories, scenarios, or small daily life examples so that I can make an animated video out of it. As a creative assistant you are the best creative person out there and you have more than 30 years of experience. As a learning assistant you are better than the best of the teachers out there, you always know how to teach the given topic in a super easy manner and break it down so that your target audience can easily learn it. As a learning assistant you have more than 30 years of experience. As a creative assistant you will make sure that you come up with good ideas for the script and that you will incorporate all the teaching material into the story in a logical and creative manner and as a learning assistant you will make sure that you come up with good learning material and you will also make sure that creative assistant incorporates them in the story without being wrong about them. Please remember that whatever you create together is more about demonstration and less about telling. Please remember this film writing rule all the times Show don’t tell. You will be given an SLO. And at this point you will have two options and you will have to choose one. You have two options either proceed with story based learning or proceed with a short explainer video style. Whatever option you choose please remember to make it relevant to the Pakistani audience. Whatever option you may choose you have to make sure that you incorporate all the teaching material in that video. If you proceed with story based learning the story will always start with a big idea on that SLO. In the story based learning, the creative assistant will generate a big story idea around the given SLO. ( What is the big idea?: well Big idea of any video lesson is that one scene around which the whole story revolves, for instance in the SLO “Understand centripetal acceleration”, the big idea is showing a scene with a daredevil doing a loop de loop and not falling inwards. Why is this a big idea? Because a kid will see the potential crisis, and when the daredevil successfully completes the stunt, they will understand the concept of centripetal acceleration. Well, it's all about creating that "aha" moment. When a kid sees the daredevil in action, they get how centripetal acceleration works.) You have to add scenarios, examples, diagrams, explanations, or any other better option that you might have to suggest. Make sure the big idea has an element of conflict to it. Which the main protagonist has to face. The big idea should also be very relevant to the target audience. You will keep in mind that you have to demonstrate more than you talk about it. Skip the above step if a short explainer video is chosen. The explainer video includes multiple examples, and short scenarios directly told to the target audience through a narrator. Short explainer videos can have very minimal visual design. Either way you will keep in mind that you have to demonstrate more than you talk about it. If the short explainer video is chosen then the topic does not need a story around it. In Fact Creative assistant will keep this video simple enough and will generate ideas for it without adding a story. It will certainly have a narrative but no complete story. It is always encouraged to start by asking questions. You have to add scenarios, examples, diagrams, explanations, or any other better option that you might have to suggest. These scripts are relatively shorter and more concise and to the point. Important thing to notice is that this format is short, simple, crisp, to the point, and very very visual. short explainer videos can have very minimal visual design Your output will be in a script format. Timestamps would be mentioned, write voiceovers and provide prompts for static visuals from the story. You must give 10 scenes at all times. Each scene must provide three Visual prompt statements and each statement must be labeled as VISUAL PROMPT, Do not number them. Prompts for visuals would always be labeled as VISUAL PROMPT. PLEASE MAKE SURE THAT YOU WRITE VOICEOVERS IN SUCH A WAY THAT THEY DO NOT EXCEED 9 SECONDS IN DURATION .Mention Timestamps for each scene. PLEASE ALWAYS MENTION VOICE OVERS AS V.O AND PROMPTS FOR VISUALS AS VISUAL PROMPT. ALSO MENTION THE SCENE NUMBERS. If the user gives you an SLO that is half or broken or does not make any sense, you must fix it and improve it and show it to the user that this is how you fixed it. You must always ask for the grade for which you have to keep the difficult level for. You can never use magic, themes or stories in any of the formats whatsoever. "Generate a detailed prompt for a static animated image. The prompt should vividly describe a scene that includes the following elements: 1. **Setting**: Specify a unique and engaging environment, such as forest, a futuristic city, an underwater kingdom, a space station, or a historical setting like a medieval marketplace. 2. **Key Features**: Include specific details about the landscape, architecture, and any notable features of the setting. For instance, glowing plants, futuristic buildings, coral palaces, spaceships, or market stalls. 3. **Atmosphere and Lighting**: Describe the time of day and the overall atmosphere, highlighting elements like lighting (bioluminescent, neon, sunlight filtering through water, etc.) and mood (mystical, bustling, serene, etc.). 4. **Characters and Lifeforms**: Mention any characters, creatures, or life forms present in the scene, whether they are people, animals, mythical beings, or aliens. Describe their appearance and activities. 5. **Additional Elements**: Add any extra details that will bring the scene to life, such as specific actions occurring, types of objects present, or interactions between characters. The prompt should be detailed and evoke a clear and vivid image of the scene, allowing for a diverse and imaginative interpretation when visualized.] """ creatmote_api_key = os.getenv('CREATOMATE_API_KEY') bucket_name = os.getenv('BUCKET_NAME') folder_name = os.getenv('FOLDER_NAME') def generate_voiceover(line, index, bucket_name, folder_name, aws_access_key_id, aws_secret_access_key): try: print(f"Starting generate_voiceover for line {index + 1}") # Initialize the S3FileSystem with AWS credentials s3_fs = s3fs.S3FileSystem(key=aws_access_key_id, secret=aws_secret_access_key) print("S3FileSystem initialized") # Generate a unique file name for each line file_name = f"vo_line_{index + 1}.mp3" print(f"Generated file name: {file_name}") # Generate voiceover using OpenAI print("Generating voiceover using OpenAI") response = client.audio.speech.create( model="tts-1", voice="alloy", input=line ) # Write the audio content to a local file speech_file_path = Path(file_name) with open(speech_file_path, 'wb') as f: f.write(response.content) print(f"Voiceover written to file {file_name}") # Upload the file to S3 s3_path = f"{bucket_name}/{folder_name}/{file_name}" print(f"Uploading {file_name} to S3 path {s3_path}") with open(speech_file_path, 'rb') as f: s3_fs.put(str(speech_file_path), s3_path) # Corrected the order of arguments here print(f"Successfully uploaded {file_name} to S3") # Generate and return the S3 URL for the uploaded file s3_url = f'https://{bucket_name}.s3.amazonaws.com/{folder_name}/{file_name}' print(f"S3 URL for the uploaded file: {s3_url}") return s3_url except Exception as e: print(f"An error occurred in generate_voiceover: {e}") raise def generate_image(visual_prompt, API_KEY, ENDPOINT,generated_image_urls): print("Generating image for visual prompt") # Create the Request Payload payload = { "model": "dall-e-3", "prompt": f"<{visual_prompt.strip()}>", "n": 1, "size": "1024x1024" } # Make the POST Request headers = { 'Authorization': f'Bearer {API_KEY}', 'Content-Type': 'application/json' } response = requests.post(ENDPOINT, json=payload, headers=headers) print("POST request sent to OpenAI for image generation") # Handle the Response if response.status_code == 200: image_url = response.json()['data'][0]['url'] print(f"Image URL {len(generated_image_urls)+1}: {image_url}") return image_url else: error_message = f"Error in image generation: {response.status_code}, {response.text}" print(error_message) raise Exception(error_message) def generate_videos_from_images(image_urls): generated_video_urls = [] input_params = { "video_length": "25_frames_with_svd_xt", "sizing_strategy": "maintain_aspect_ratio", "frames_per_second": 6, "motion_bucket_id": 127, "cond_aug": 0.02, "decoding_t": 14, # "seed": your_seed_value (optional) } for i, image_url in enumerate(image_urls): try: response = requests.get(image_url) if response.status_code == 200: image_path = f"image_{i}.jpg" with open(image_path, "wb") as file: file.write(response.content) with open(image_path, "rb") as image_file: input_params["input_image"] = image_file output = replicate.run( "stability-ai/stable-video-diffusion:3f0457e4619daac51203dedb472816fd4af51f3149fa7a9e0b5ffcf1b8172438", input=input_params ) generated_video_urls.append(output) print(f"Generated Video URL {i + 1}: {output}") else: print(f"Error downloading image {i + 1}: {response.status_code}, {response.text}") except Exception as e: print(f"An error occurred while generating video from image {i + 1}: {e}") return generated_video_urls def generate_video(slo): print(f"Starting video generation for SLO: {slo}") # Step 1: Script Generation combined_prompt = f"{content_creation_prompt}\n\nBased on the following Student Learning Objective (SLO): '{slo}', generate a detailed script for an educational video." print("Generating script...") script_response = client.chat.completions.create(model="gpt-4", messages=[{"role": "user", "content": combined_prompt}]) script_text = script_response.choices[0].message.content print(f"Script generated: {script_text}") # Step 2: Image Generation print("Generating images...") pattern = r'^VISUAL PROMPT:(.*)$' visual_prompts = re.findall(pattern, script_text, re.MULTILINE) for idx, prompt in enumerate(visual_prompts): print(f"Visual Prompt {idx+1}: {prompt.strip()}") generated_image_urls = [] API_KEY = api_key ENDPOINT = 'https://api.openai.com/v1/images/generations' for visual_prompt in visual_prompts: image_url = generate_image(visual_prompt, API_KEY, ENDPOINT,generated_image_urls) generated_image_urls.append(image_url) print(f"Image generated and added to list: {image_url}") # Step 3: Generate Videos from Images print("Generating videos from images...") generated_video_urls = generate_videos_from_images(generated_image_urls) for idx, url in enumerate(generated_video_urls): print(f"Generated Video URL {idx+1}: {url}") # Step 4: Voiceover Generation and Upload to AWS S3 print("Generating voiceovers and uploading to AWS S3...") pattern_vo = r'^V\.O:\s*(.*?)$' vo_lines = re.findall(pattern_vo, script_text, re.MULTILINE) s3_voiceover_urls = [] for i, line in enumerate(vo_lines): s3_url = generate_voiceover(line, i, bucket_name, folder_name, aws_access_key_id, aws_secret_access_key) s3_voiceover_urls.append(s3_url) print(f"Voiceover for line {i + 1} uploaded to S3: {s3_url}") # Step 5: Video Compilation with Creatomate print("Compiling video with Creatomate...") # print(f"Payload for video compilation: {payload}") modifications = {f'Visual prompt-{i+1}': url for i, url in enumerate(generated_video_urls)} for index, audio_url in enumerate(s3_voiceover_urls): modifications[f"vo_line_{index+1}"] = audio_url payload = { 'template_id': '57b15295-36c7-4d47-b114-2f2e00cf9e67', 'modifications': modifications, } render_url = 'https://api.creatomate.com/v1/renders' headers = { 'Authorization': f'Bearer {creatmote_api_key}', 'Content-Type': 'application/json' } try: response = requests.post(render_url, data=json.dumps(payload), headers=headers) response.raise_for_status() print("POST request sent to Creatomate for video compilation") response_data = response.json() print("Response JSON:", response_data) if response_data and isinstance(response_data, list) and len(response_data) > 0: video_url = response_data[0].get('url', 'No URL found in the response') print(f"Video URL: {video_url}") else: print("No valid data in Creatomate response") video_url = 'No valid data in response' except requests.RequestException as error: error_message = f"An error occurred: {str(error)}" print(error_message) return error_message print("Video generation process completed") return video_url iface = gr.Interface( fn=generate_video, inputs=gr.Textbox(label="Enter Student Learning Objective (SLO)"), outputs=gr.Textbox(label="Generated Video URL") ) print("Gradio interface set up!") iface.queue().launch(share=False)