-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathgenerate_analyses.py
More file actions
191 lines (160 loc) · 6.8 KB
/
Copy pathgenerate_analyses.py
File metadata and controls
191 lines (160 loc) · 6.8 KB
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
# Summary: This script generates video analyses using the TwelveLabs Pegasus model.
# It retrieves video files from an S3 bucket, processes each video to generate a
# title, summary, and keywords, and saves the results in a local directory.
# Author: Gary A. Stafford
# Date: 2025-11-01
# License: MIT License
import os
import json
import time
import random
from dotenv import load_dotenv
import boto3
from botocore.config import Config
from utilities import Utilities
from data import VideoAnalysis
load_dotenv() # Loads variables from .env file
AWS_REGION = os.getenv("AWS_REGION", "us-east-1")
S3_VIDEO_STORAGE_BUCKET = os.getenv("S3_VIDEO_STORAGE_BUCKET")
MODEL_ID = "us.twelvelabs.pegasus-1-2-v1:0"
S3_SOURCE_PREFIX = "commercials"
LOCAL_DESTINATION_DIRECTORY = "analyses"
def main() -> None:
config = Config(
retries={
"max_attempts": 5,
"mode": "standard", # Or 'adaptive' for a more sophisticated approach
}
)
bedrock_runtime_client = boto3.client(
service_name="bedrock-runtime", region_name=AWS_REGION, config=config
)
s3_client = boto3.client("s3", region_name=AWS_REGION)
sts = boto3.client("sts")
account_id = sts.get_caller_identity()["Account"]
# Get the list of MP4 files from the specified S3 bucket
video_file_names = Utilities.get_list_of_video_names_from_s3(
s3_client, S3_VIDEO_STORAGE_BUCKET, S3_SOURCE_PREFIX
)
# Wait for the job to complete and then read the output
for video_file_name in video_file_names:
local_file_path = os.path.abspath(
os.path.join(
LOCAL_DESTINATION_DIRECTORY, video_file_name.replace(".mp4", ".json")
)
)
if os.path.exists(local_file_path):
print(f"Skipping {local_file_path}, already processed.")
continue
video_path = (
f"s3://{S3_VIDEO_STORAGE_BUCKET}/{S3_SOURCE_PREFIX}/{video_file_name}"
)
print(f"Generating analysis for video: {video_file_name}")
# Define the prompts for title, summary, and keywords
prompt_summary = "Generate a detailed summary of the video. Consider the visual, audio, textual, spatial, and temporal aspects in the video. Only provide the summary in the response; no pre-text, post-text, or quotation marks."
prompt_title = "Generate a descriptive title for the video. Only provide the title in the response; no pre-text, post-text, or quotation marks."
prompt_keywords = """Extract keywords from the video content as a list of strings, for example: ["keyword1", "keyword2", "keyword3", "keyword4"]. Only provide the list keywords in the response; no pre-text, post-text."""
response_title = generate_video_analysis(
bedrock_runtime_client, account_id, video_path, prompt_title
)
response_summary = generate_video_analysis(
bedrock_runtime_client, account_id, video_path, prompt_summary
)
response_keywords = generate_video_analysis(
bedrock_runtime_client, account_id, video_path, prompt_keywords
)
video_analysis = VideoAnalysis(
videoName=video_file_name,
s3URI=video_path,
title=response_title["message"],
summary=response_summary["message"],
keywords=json.loads(response_keywords["message"]),
dateCreated=time.strftime("%Y-%m-%dT%H:%M:%S %Z", time.gmtime()),
)
# Write the video analysis to a local file
write_video_analysis_to_file(video_analysis, local_file_path)
print(f"Video analysis written to: {local_file_path}")
def generate_video_analysis(
client: boto3.client,
account_id: str,
video_path: str,
prompt: str,
max_retries: int = 5,
) -> dict:
"""Start the video analysis job.
Args:
client (boto3.client): The Boto3 client for the Bedrock service.
account_id (str): The AWS account ID.
video_path (str): The S3 path to the video file.
prompt (str): The prompt to use for the video analysis.
max_retries (int, optional): The maximum number of retry attempts. Defaults to 3.
Raises:
e: An error occurred while starting the video analysis job.
Returns:
dict: The response from the video analysis job.
"""
# Reference: https://docs.aws.amazon.com/bedrock/latest/userguide/model-parameters-pegasus.html
request_body = {
"inputPrompt": prompt,
"mediaSource": {
"s3Location": {
"uri": video_path,
"bucketOwner": account_id,
}
},
"temperature": 0.2,
# "maxOutputTokens": 2048,
# "responseFormat": {
# "type": "json_schema",
# "json_schema": {
# "name": "video_analysis",
# "schema": {
# "type": "object",
# "properties": {
# "summary": {"type": "string"},
# "key_scenes": {"type": "array", "items": {"type": "string"}},
# "duration": {"type": "string"},
# },
# "required": ["summary", "key_scenes"],
# },
# },
# },
}
retries = 0
while True:
try:
response = client.invoke_model(
modelId=MODEL_ID,
body=json.dumps(request_body),
contentType="application/json",
accept="application/json",
)
response_body = json.loads(response["body"].read())
return response_body
except Exception as e:
if "ThrottlingException" in str(e) and retries < max_retries:
retries += 1
backoff_time = (2**retries) + random.uniform(
0, 1
) # Exponential backoff with jitter
print(
f"Throttled. Retrying in {backoff_time:.2f} seconds (attempt {retries})..."
)
time.sleep(backoff_time)
else:
raise e # Re-raise the exception if it's not a retryable error or max retries reached
# method that writes the video analysis response to a local file
def write_video_analysis_to_file(
video_analysis: VideoAnalysis, local_file_path: str
) -> None:
"""Write the video analysis response to a local file.
Args:
video_analysis (VideoAnalysis): The video analysis object containing the response.
local_file_path (str): The local file path where the response will be written.
"""
with open(local_file_path, "w") as f:
f.write(video_analysis.model_dump_json(indent=2))
print(f"Response written to {local_file_path}")
if __name__ == "__main__":
main()
print("Video analysis completed successfully.")