File size: 15,240 Bytes
91336a9
 
 
 
 
 
 
 
 
c3a32d2
91336a9
 
3cfe56d
6990eb1
91336a9
6990eb1
91336a9
6990eb1
 
91336a9
 
 
 
11c497b
6990eb1
91336a9
6990eb1
 
 
 
 
 
 
 
53a5181
 
3cfe56d
4c0c78b
3cfe56d
 
 
 
 
 
 
 
 
 
 
 
4c0c78b
3cfe56d
4c0c78b
3cfe56d
 
 
4c0c78b
3cfe56d
 
 
 
 
 
 
 
 
 
 
 
91336a9
 
 
 
53a5181
 
 
91336a9
 
 
53a5181
 
 
 
 
 
 
91336a9
 
 
 
 
53a5181
 
91336a9
53a5181
 
 
 
91336a9
 
 
 
 
 
53a5181
 
91336a9
53a5181
 
 
 
 
 
 
3cfe56d
403ff6f
53a5181
 
3cfe56d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
53a5181
3cfe56d
 
 
 
eceb1dc
3cfe56d
 
53a5181
 
 
 
c3a32d2
 
 
 
 
 
 
 
 
 
 
 
 
53b3955
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
c3a32d2
 
 
53b3955
3cfe56d
53a5181
 
3cfe56d
 
53a5181
3cfe56d
 
53a5181
3cfe56d
 
53a5181
3cfe56d
 
eceb1dc
 
3cfe56d
 
 
 
403ff6f
3cfe56d
53a5181
3cfe56d
ce67952
 
 
eceb1dc
 
ce67952
 
53a5181
3cfe56d
 
 
 
91336a9
3cfe56d
53a5181
3cfe56d
81dfada
53a5181
a07aca8
c3a32d2
3cfe56d
 
53a5181
3cfe56d
c3a32d2
3cfe56d
 
3a622d5
3cfe56d
 
 
 
53a5181
3cfe56d
 
81dfada
53a5181
3cfe56d
 
53a5181
3cfe56d
 
53a5181
3cfe56d
53a5181
3cfe56d
 
 
53a5181
3cfe56d
 
53a5181
 
 
6990eb1
3cfe56d
 
 
 
 
 
101b77a
53a5181
 
87b9c02
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
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
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)