gamora commited on
Commit
acbe906
·
1 Parent(s): e7306a2
create_captions.py ADDED
@@ -0,0 +1,111 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import ffmpeg
2
+ import sys
3
+ import re
4
+ import subprocess
5
+ import os
6
+
7
+
8
+
9
+ def time_to_float(time_str):
10
+ # Split the time string into minutes, seconds, and milliseconds
11
+ minutes, seconds = time_str.split(':')
12
+ seconds, milliseconds = seconds.split('.')
13
+
14
+ # Convert to float (total seconds)
15
+ return float(minutes) * 60 + float(seconds) + float(milliseconds) / 1000
16
+
17
+
18
+ def create_caps(steps):
19
+ captions=[]
20
+ video_start=0
21
+ for step in steps:
22
+ print(step)
23
+ start=time_to_float(step['start'])
24
+ end= time_to_float(step['end'])
25
+ description_sentences=step['description'].split(".")
26
+
27
+ print(description_sentences)
28
+
29
+ interval=end/len(description_sentences)
30
+ start_interval=video_start
31
+
32
+ for description_sentence in description_sentences:
33
+ caption=(start_interval,start_interval+interval,description_sentence)
34
+ start_interval+=interval
35
+ captions.append(caption)
36
+ video_start+=end
37
+
38
+ return captions
39
+
40
+
41
+
42
+
43
+ def create_srt(subtitles, output_file):
44
+ with open(output_file, 'w', encoding='utf-8') as f:
45
+ for i, (start, end, text) in enumerate(subtitles, 1):
46
+ start_time = f"{int(start//3600):02d}:{int((start%3600)//60):02d}:{int(start%60):02d},{int((start%1)*1000):03d}"
47
+ end_time = f"{int(end//3600):02d}:{int((end%3600)//60):02d}:{int(end%60):02d},{int((end%1)*1000):03d}"
48
+ f.write(f"{i}\n{start_time} --> {end_time}\n{text}\n\n")
49
+
50
+
51
+
52
+ def add_captions_to_video(input_video,soft_subtitle, subtitles,output_video="output_video_subtitles.mp4",subtitle_language="en"):
53
+ subtitle_file="subtitles.srt"
54
+ create_srt(subtitles,subtitle_file)
55
+
56
+ video_input_stream = ffmpeg.input(input_video)
57
+ subtitle_input_stream = ffmpeg.input(subtitle_file)
58
+ output_video = output_video
59
+ subtitle_track_title = subtitle_file.replace(".srt", "")
60
+
61
+ if soft_subtitle:
62
+ stream = ffmpeg.output(
63
+ video_input_stream, subtitle_input_stream, output_video, **{"c": "copy", "c:s": "mov_text"},
64
+ **{"metadata:s:s:0": f"language={subtitle_language}",
65
+ "metadata:s:s:0": f"title={subtitle_track_title}"}
66
+ )
67
+ ffmpeg.run(stream, overwrite_output=True)
68
+ else:
69
+ subtitle_style = (
70
+ "force_style='FontName=Arial,FontSize=15,PrimaryColour=&H00FFFFFF,"
71
+ "Alignment=2,MarginV=25'"
72
+ )
73
+
74
+ stream = ffmpeg.output(
75
+ video_input_stream,
76
+ output_video,
77
+ **{
78
+ "c:v": "h264_videotoolbox",
79
+ # "q:v": 50, # Specify video codec (H.264)
80
+ "c:a": "copy", # Copy audio stream to avoid re-encoding
81
+ "vf": f"subtitles={subtitle_file}:{subtitle_style}", # Burn subtitles
82
+ "threads": 0
83
+ }
84
+ )
85
+
86
+ print("here")
87
+ ffmpeg.run(stream, overwrite_output=True)
88
+
89
+ return output_video
90
+
91
+
92
+
93
+
94
+
95
+
96
+
97
+ if __name__ == "__main__":
98
+ # Example subtitles
99
+ subtitles = [
100
+ (0, 4, "Hello, this is the first subtitle."),
101
+ (5, 10, "This is the second subtitle.")
102
+ ]
103
+ # create_srt(subtitles, "subtitles.srt")
104
+
105
+ # Input video and subtitle files
106
+ input_video = "/Users/georgia.bucea/products/ShortsAI/21_aug/IMG_8280.MOV"
107
+ subtitle_file = "subtitles.srt"
108
+ output_video = "output_video_subtitles.mp4"
109
+
110
+
111
+ add_captions_to_video(input_video,False,subtitles,output_video,"en")
extract_metadata.py CHANGED
@@ -11,6 +11,7 @@ from grok_analyze import analyze_image_with_grok_f
11
  import json
12
  import random
13
  import string
 
14
  def extract_scenes_scenedetect(video_path, threshold=30.0, min_scene_duration=5.0):
15
 
16
  vid_obj={"type":"video", "path":video_path}
@@ -97,6 +98,7 @@ def extract_scenes_scenedetect(video_path, threshold=30.0, min_scene_duration=5.
97
  return vid_obj
98
 
99
 
 
100
  def get_metadata(all_files):
101
 
102
  all_files_info=[]
@@ -109,26 +111,54 @@ def get_metadata(all_files):
109
  random_string = ''.join(random.choices(string.ascii_lowercase + string.digits, k=8))
110
  file_name = f"all_files_info_{random_string}.json"
111
 
 
 
112
  with open(file_name, "w") as file:
113
  json.dump(all_files_info, file, indent=4)
 
 
114
 
115
  return all_files_info,file_name
116
 
117
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
118
 
119
 
120
  if __name__ == "__main__":
121
- all_files_info=[]
122
- dir_path="/Users/georgia.bucea/products/ShortsAI/21_aug"
123
- all_files=read_files(dir_path)
124
 
125
- for file in all_files:
126
- file_path=dir_path+"/"+file
127
- if file_path.split(".")[-1] in ["MOV","mp4"]:
128
- vid_info=extract_scenes_scenedetect(file_path)
129
- all_files_info.append(vid_info)
 
 
 
 
 
130
 
131
- with open("all_files_info.json", "w") as file:
132
- json.dump(all_files_info, file, indent=4)
 
 
 
 
 
 
 
133
 
134
 
 
 
11
  import json
12
  import random
13
  import string
14
+ import random
15
  def extract_scenes_scenedetect(video_path, threshold=30.0, min_scene_duration=5.0):
16
 
17
  vid_obj={"type":"video", "path":video_path}
 
98
  return vid_obj
99
 
100
 
101
+
102
  def get_metadata(all_files):
103
 
104
  all_files_info=[]
 
111
  random_string = ''.join(random.choices(string.ascii_lowercase + string.digits, k=8))
112
  file_name = f"all_files_info_{random_string}.json"
113
 
114
+
115
+
116
  with open(file_name, "w") as file:
117
  json.dump(all_files_info, file, indent=4)
118
+
119
+ # upload_to_s3(file_name,"bucket","s3key")
120
 
121
  return all_files_info,file_name
122
 
123
 
124
+ def get_scenes_metadata(metadata, no_scenes=10):
125
+
126
+ selected = []
127
+ while len(selected) < no_scenes and metadata: # Pick 3, stop if list empties
128
+ item = random.choice(metadata)
129
+ selected.append(item)
130
+ metadata.remove(item)
131
+
132
+ # print(selected)
133
+ # print(len(selected))
134
+
135
+ return(selected)
136
+
137
+
138
 
139
 
140
  if __name__ == "__main__":
 
 
 
141
 
142
+ with open('/Users/georgia.bucea/products/ShortsAI/all_files_metadata.json', 'r') as file:
143
+ data = json.load(file)
144
+ print(len(data))
145
+ get_scenes_metadata(data)
146
+ # all_files_info=[]
147
+ # # dir_path="/Users/georgia.bucea/products/ShortsAI/21_aug"
148
+ # # all_files=read_files(dir_path)
149
+ # dir_path="/Users/georgia.bucea/products/ShortsAI/16_aug"
150
+ # # all_files2=read_files(dir_path)
151
+ # all_files=read_files(dir_path)
152
 
153
+ # # all_files=all_files+all_files2
154
+ # for file in all_files:
155
+ # file_path=dir_path+"/"+file
156
+ # if file_path.split(".")[-1] in ["MOV","mp4"]:
157
+ # vid_info=extract_scenes_scenedetect(file_path)
158
+ # all_files_info.append(vid_info)
159
+
160
+ # with open("all_files_info_21_aug_16_aug.json", "w") as file:
161
+ # json.dump(all_files_info, file, indent=4)
162
 
163
 
164
+
grok_analyze.py CHANGED
@@ -1,10 +1,14 @@
1
  import os
2
  import base64
 
 
 
3
  from xai_sdk import Client
4
  from xai_sdk.chat import user, image
5
  from dotenv import load_dotenv
6
  import cv2
7
  import json
 
8
  load_dotenv()
9
 
10
  def encode_image_to_base64_f(frame):
@@ -67,13 +71,12 @@ def analyze_image_with_grok_f( frame):
67
  except Exception as e:
68
  return f"Error during API call: {str(e)}"
69
 
70
- def get_story_with_grok(context,current_context):
71
  # Initialize xAI client
72
  api_key = os.getenv("X_AI")
73
  client = Client(
74
  api_key=api_key,
75
  )
76
-
77
  # Create chat session
78
  chat = client.chat.create(model="grok-4-0709") # Use vision-capable model
79
  print(current_context)
@@ -81,13 +84,17 @@ def get_story_with_grok(context,current_context):
81
  # Append user message with base64-encoded image
82
  chat.append(
83
  user(
84
- "Based on the following context, and the phrase: "+current_context+ " generate a random story with no more than 4 scenes. The story should be given as JSON, with the scenes in the following format: path:file_path,start:,end:mdescription. Do not include a title, a main description, or anything else besides the scenes in the story as JSON format. " + str(context),
85
- )
86
- )
 
87
  else:
 
88
  chat.append(
89
  user(
90
- "Based on the following context, generate a random story with no more than 4 scenes. The story should be given as JSON, with the scenes in the following format: path:file_path,start:,end:mdescription. Do not include a title, a main description, or anything else besides the scenes in the story as JSON format. " + str(context),
 
 
91
  )
92
  )
93
 
@@ -95,32 +102,46 @@ def get_story_with_grok(context,current_context):
95
  response = chat.sample()
96
  data= response.content
97
  video_data = json.loads(data)
98
- return video_data
 
99
  except Exception as e:
100
  return f"Error during API call: {str(e)}"
101
 
102
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
103
  def main():
104
- # Your xAI API key
105
- # Path to your image
106
- # image_path = "/Users/georgia.bucea/products/ShortsAI/frames_scenesdetect/scene_0000.jpg"
107
-
108
- # # Verify image path exists
109
- # if not os.path.exists(image_path):
110
- # print(f"Error: Image file not found at {image_path}")
111
- # return
112
-
113
- # print("Analyzing image...")
114
- # analysis = analyze_image_with_grok_f( image_path)
115
- # print("Grok's Analysis:")
116
- # print(analysis)
117
 
118
  context_path="/Users/georgia.bucea/products/ShortsAI/all_files_metadata.json"
119
  with open(context_path, 'r') as file:
120
 
121
  data = json.load(file)
122
  print("here we are")
123
- print(get_story_with_grok(data))
 
 
 
124
 
125
 
126
 
 
1
  import os
2
  import base64
3
+
4
+ from torch.cuda import temperature
5
+
6
  from xai_sdk import Client
7
  from xai_sdk.chat import user, image
8
  from dotenv import load_dotenv
9
  import cv2
10
  import json
11
+ from create_captions import create_caps
12
  load_dotenv()
13
 
14
  def encode_image_to_base64_f(frame):
 
71
  except Exception as e:
72
  return f"Error during API call: {str(e)}"
73
 
74
+ def get_story_with_grok(metadata,current_context,dialog):
75
  # Initialize xAI client
76
  api_key = os.getenv("X_AI")
77
  client = Client(
78
  api_key=api_key,
79
  )
 
80
  # Create chat session
81
  chat = client.chat.create(model="grok-4-0709") # Use vision-capable model
82
  print(current_context)
 
84
  # Append user message with base64-encoded image
85
  chat.append(
86
  user(
87
+ # "Based on the following context, the phrase: "+current_context+ " and the given dialog, generate an engaging random story relevant to the dialog with no more than 4 scenes.The description should be short engaging, relevant to the dialog, with less adjectives, with no more than three short sentences, in present tense and first person. The story should be given as JSON, with the scenes in the following format:scenes:[path:file_path,start:,end:,description:].The path is extracted from the metadata file. Do not include a title, a main description, or anything else besides the scenes in the story as JSON format. The metadata: " + str(metadata) + " And the following dialog: "+ dialog,
88
+ "Based on the following metadata,the phrase: "+current_context+ ", and the given dialog, generate an engaging story with no more than 4 scenes. The story should be given as JSON, with the scenes in the following format:scenes:[path:file_path,start:,end:,description:].The path is extracted from the metadata file. Do not include a title, a main description, or anything else besides the scenes in the story as JSON format. The metadata: " + str(metadata) + " And the following dialog: "+ dialog,
89
+
90
+ ))
91
  else:
92
+ print("here")
93
  chat.append(
94
  user(
95
+ # "Based on the following context and the given dialog, generate an engaging random story with no more than 4 scenes extracted randomly from the given metadata. The description should be short engaging, relevant to the given dialog,with less adjectives. with no more than three short sentences that take into account the transcripted dialog, in present tense and first person. The story should be given as JSON, with the scenes in the following format:scenes:[path:file_path,start:,end:,description:].The path is extracted from the metadata file. Do not include a title, a main description, or anything else besides the scenes in the story as JSON format. The metadata: " + str(metadata) + " And the following dialog: "+ dialog,
96
+ "You are a vlogger, making videos about your life and your adventures. Based on the following metadata and the given dialog, generate an engaging story with no more than 4 scenes related to the metadata. Use less adjectives with short sentences. The story should be given as JSON, with the scenes in the following format:scenes:[path:file_path,start:,end:,description:].The path is extracted from the metadata file. Do not include a title, a main description, or anything else besides the scenes in the story as JSON format. The metadata: " + str(metadata) + " And the following dialog: "+ dialog,
97
+ # "Based on the following metadata and the given dialog, generate an engaging story with all scenes in the metadata. The story should be given as JSON, with the scenes in the following format:scenes:[path:file_path,start:,end:,description:].The path is extracted from the metadata file. Do not include a title, a main description, or anything else besides the scenes in the story as JSON format. The metadata: " + str(metadata) + " And the following dialog: "+ dialog,
98
  )
99
  )
100
 
 
102
  response = chat.sample()
103
  data= response.content
104
  video_data = json.loads(data)
105
+ print(video_data)
106
+ return video_data['scenes']
107
  except Exception as e:
108
  return f"Error during API call: {str(e)}"
109
 
110
 
111
+
112
+ def create_caps_with_grok(steps):
113
+ api_key = os.getenv("X_AI")
114
+ client = Client(
115
+ api_key=api_key,
116
+ )
117
+ # chat = client.chat.create(model="grok-4-0709")
118
+ for step in steps:
119
+ chat = client.chat.create(model="grok-4-0709")
120
+ chat.append(
121
+ user(
122
+ "You are a vlogger, making videos about your life. Based on the following description generate a short caption, with no more than three short sentences, less adjectives, in present tense, first person that is fit for a story. Do not include a title or anython else besides the final caption. the description: "+step["description"],
123
+ ))
124
+ try:
125
+ response = chat.sample()
126
+ data= response.content
127
+ step["description"]=data
128
+ except Exception as e:
129
+ return f"Error during API call: {str(e)}"
130
+ return steps
131
+
132
+
133
+
134
  def main():
 
 
 
 
 
 
 
 
 
 
 
 
 
135
 
136
  context_path="/Users/georgia.bucea/products/ShortsAI/all_files_metadata.json"
137
  with open(context_path, 'r') as file:
138
 
139
  data = json.load(file)
140
  print("here we are")
141
+ steps=get_story_with_grok(data,"")
142
+ print(steps)
143
+ steps=create_caps_with_grok(steps)
144
+ print(steps)
145
 
146
 
147
 
transcripts_editing.py ADDED
@@ -0,0 +1,71 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from dotenv import load_dotenv
2
+ import requests
3
+ import os
4
+ load_dotenv()
5
+
6
+ # Access the variables
7
+ api_key = os.getenv("DEVICE_ID")
8
+
9
+
10
+ def parse_response(data):
11
+
12
+ dialog = []
13
+ for i in range(len(data['memories'])):
14
+ for segment in data['memories'][i]['transcript_segments']:
15
+ speaker = segment['speaker']
16
+ start_time = segment['start']
17
+ end_time = segment['end']
18
+ # Fallback for unexpected speaker IDs
19
+ dialog.append(f"**{speaker}**: {segment['text']}")
20
+
21
+ # Join dialog lines into a markdown string
22
+ dialog_text = "\n\n".join(dialog)
23
+
24
+ return dialog_text
25
+
26
+
27
+
28
+ def fetch_memories(url, headers, cursor=None):
29
+ # Update URL with cursor if provided
30
+ if cursor:
31
+ url = f"{url}&cursor={cursor}"
32
+
33
+ response = requests.get(url, headers=headers)
34
+
35
+ if response.status_code == 200:
36
+ return response.json()
37
+ else:
38
+ print(f"Error: {response.status_code} - {response.text}")
39
+ return None
40
+
41
+ # Initial API setup
42
+
43
+
44
+
45
+ def get_dialog(date="2025-08-21"):
46
+ url = "https://apis.getbuddi.ai/v1/dev/get_memories?date="+date
47
+ headers = {
48
+ "api-key": api_key
49
+ }
50
+
51
+ dialog=""
52
+ # Fetch first batch
53
+ data = fetch_memories(url, headers)
54
+ if data:
55
+ # print("First batch:", data)
56
+
57
+ # Check for next_cursor and fetch subsequent batches
58
+ while 'next_cursor' in data and data['next_cursor']:
59
+ cursor = data['next_cursor']
60
+ print(cursor)
61
+ data = fetch_memories(url, headers, cursor)
62
+ if data:
63
+ dialog=dialog+parse_response(data)
64
+ # print("Next batch:", data)
65
+ else:
66
+ break
67
+ return(dialog)
68
+
69
+
70
+ if __name__ == "__main__":
71
+ print(get_dialog())
upload_to_s3.py CHANGED
@@ -9,6 +9,29 @@ BUCKET = "shortsai-us" # Replace with your bucket name
9
  S3_KEY = "test/IMG_8280.MOV" # S3 path for the file
10
  LOCAL_FILE_PATH = "/Users/georgia.bucea/products/ShortsAI/21_aug/mcp_video-3028_singular_display.MOV" # Replace with your local file path
11
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12
  load_dotenv()
13
 
14
  # Access the variables
@@ -61,7 +84,7 @@ def upload_multiple_files(file_list, bucket):
61
  print(f"Unexpected error: {e}")
62
  return False
63
 
64
- with ThreadPoolExecutor(max_workers=10) as executor:
65
  executor.map(lambda f: upload_to_s3(f[0], bucket, f[1]), file_list)
66
  return uploaded_files
67
 
@@ -70,9 +93,14 @@ if __name__ == "__main__":
70
  # upload_to_s3(LOCAL_FILE_PATH,BUCKET,S3_KEY)
71
  bucket = os.getenv("BUCKET")
72
 
 
 
 
 
 
73
 
74
- file_list = [
75
- ("/Users/georgia.bucea/products/ShortsAI/21_aug/mcp_video-3028_singular_display.MOV", "test/21_aug/mcp_video-3028_singular_display.MOV"),
76
- ]
77
 
78
- uploaded = upload_multiple_files(file_list, bucket)
 
9
  S3_KEY = "test/IMG_8280.MOV" # S3 path for the file
10
  LOCAL_FILE_PATH = "/Users/georgia.bucea/products/ShortsAI/21_aug/mcp_video-3028_singular_display.MOV" # Replace with your local file path
11
 
12
+ import os
13
+
14
+ def list_files_in_folder(folder_path: str) -> list:
15
+ """
16
+ Reads all files in the specified folder (non-recursive, excludes subdirectories).
17
+
18
+ :param folder_path: Path to the folder.
19
+ :return: List of file names.
20
+ """
21
+ try:
22
+ # Check if folder exists
23
+ if not os.path.isdir(folder_path):
24
+ raise ValueError(f"Directory does not exist: {folder_path}")
25
+
26
+ # List all entries in the folder, filter for files only
27
+ files = [f for f in os.listdir(folder_path) if os.path.isfile(os.path.join(folder_path, f))]
28
+ return files
29
+ except Exception as e:
30
+ print(f"Error reading folder: {e}")
31
+ return []
32
+
33
+
34
+
35
  load_dotenv()
36
 
37
  # Access the variables
 
84
  print(f"Unexpected error: {e}")
85
  return False
86
 
87
+ with ThreadPoolExecutor(max_workers=30) as executor:
88
  executor.map(lambda f: upload_to_s3(f[0], bucket, f[1]), file_list)
89
  return uploaded_files
90
 
 
93
  # upload_to_s3(LOCAL_FILE_PATH,BUCKET,S3_KEY)
94
  bucket = os.getenv("BUCKET")
95
 
96
+ folder="/Users/georgia.bucea/products/ShortsAI/16_aug"
97
+
98
+ files=list_files_in_folder("/Users/georgia.bucea/products/ShortsAI/16_aug")
99
+ files=[(folder+ "/"+os.path.basename(path), "testall16/"+os.path.basename(path)) for path in files]
100
+ print(files)
101
 
102
+ # file_list = [
103
+ # ("/Users/georgia.bucea/products/ShortsAI/21_aug/mcp_video-3028_singular_display.MOV", "test/21_aug/mcp_video-3028_singular_display.MOV"),
104
+ # ]
105
 
106
+ uploaded = upload_multiple_files(files, bucket)