PierreBrunelle commited on
Commit
b2f0dbe
1 Parent(s): 37b78fd

Simplified the app

Browse files

Relied only on Pixeltable and removed loops

Files changed (1) hide show
  1. app.py +103 -214
app.py CHANGED
@@ -1,239 +1,127 @@
1
- # Import necessary libraries
2
- import gradio as gr
3
  import pixeltable as pxt
4
  import os
 
 
5
  import getpass
6
- from pixeltable.functions.video import extract_audio
7
- from pixeltable.functions import openai as pxop
8
  from pixeltable.iterators import FrameIterator
9
- import openai
10
-
11
-
12
-
13
- # Set up Pixeltable database and table
14
- db_directory = "video_db"
15
- table_name = "video_table"
16
- view_name = 'frames'
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
17
 
18
- # Define constants
19
  MAX_VIDEO_SIZE_MB = 35
20
- GPT_MODEL = "gpt-4o-mini-2024-07-18"
21
- MAX_TOKENS = 500
22
- WHISPER_MODEL = "whisper-1"
23
-
24
- # Set OpenAI API key
25
- if "OPENAI_API_KEY" not in os.environ:
26
- os.environ["OPENAI_API_KEY"] = getpass.getpass("OpenAI API Key:")
27
-
28
- # Clean up existing database and table if they exist
29
- pxt.drop_dir("video_db", force=True)
30
- if table_name in pxt.list_tables():
31
- pxt.drop_table("video_db.video_table")
32
-
33
- # Create or use existing directory and table
34
- if db_directory not in pxt.list_dirs():
35
- pxt.create_dir(db_directory)
36
- else:
37
- print(f"Directory {db_directory} already exists. Using the existing directory.")
38
-
39
- if table_name not in pxt.list_tables():
40
- t = pxt.create_table(
41
- f"{db_directory}.{table_name}",
42
- {
43
- "video": pxt.VideoType(),
44
- "video_filename": pxt.StringType(),
45
- "sm_type": pxt.StringType(),
46
- "sm_post": pxt.StringType(),
47
- },
48
- )
49
- else:
50
- t = pxt.get_table(f"{db_directory}.{table_name}")
51
- print(f"Table {table_name} already exists. Using the existing table.")
52
-
53
- # Function to generate social media post using OpenAI GPT-4 API
54
- def generate_social_media_post(transcript_text, social_media_type):
55
- response = openai.chat.completions.create(
56
- model=GPT_MODEL,
57
- messages=[
58
- {
59
- "role": "system",
60
- "content": f"You are an expert in creating social media content for {social_media_type}.",
61
- },
62
- {
63
- "role": "user",
64
- "content": f"Generate an effective and casual social media post based on this video transcript below. Make it a viral and suitable post for {social_media_type}. Transcript:\n{transcript_text}.",
65
- },
66
- ],
67
- max_tokens=MAX_TOKENS,
68
- )
69
- return response.choices[0].message.content
70
-
71
- # Function to process the uploaded video and generate the post
72
- def process_and_generate_post(video_file, social_media_type):
73
- if video_file:
74
- try:
75
- # Check video file size
76
- video_size = os.path.getsize(video_file) / (1024 * 1024) # Convert to MB
77
- if video_size > MAX_VIDEO_SIZE_MB:
78
- return f"The video file is larger than {MAX_VIDEO_SIZE_MB} MB. Please upload a smaller file."
79
-
80
- video_filename = os.path.basename(video_file)
81
- tr_audio_gen_flag = True
82
- sm_gen_flag = True
83
-
84
- # Check if video already exists in the table
85
- video_df = t.where(t.video_filename == video_filename).tail(1)
86
- if t.select().where(t.video_filename == video_filename).count() >= 1:
87
- tr_audio_gen_flag = False
88
-
89
- # Check if video and social media type combination exists
90
- video_type_df = t.where(
91
- (t.video_filename == video_filename) & (t.sm_type == social_media_type)
92
- ).tail(1)
93
- if video_type_df:
94
- sm_gen_flag = False
95
-
96
- # Insert video into PixelTable if it doesn't exist or if it's a new social media type
97
- if (
98
- (t.count() < 1)
99
- or not (
100
- t.select().where(t.video_filename == video_filename).count() >= 1
101
- )
102
- or (video_df and not video_type_df)
103
- ):
104
- t.insert(
105
- [
106
- {
107
- "video": video_file,
108
- "video_filename": video_filename,
109
- "sm_type": social_media_type,
110
- "sm_post": "",
111
- }
112
- ]
113
- )
114
 
115
- # Extract audio and transcribe if needed
116
- if tr_audio_gen_flag:
117
- if not t.get_column(name="audio"):
118
- t["audio"] = extract_audio(t.video, format="mp3")
119
- else:
120
- t.audio = extract_audio(t.video, format="mp3")
121
-
122
- print("########### processing transcription #############")
123
-
124
- if not t.get_column(name="transcription"):
125
- t["transcription"] = pxop.transcriptions(
126
- t.audio, model=WHISPER_MODEL
127
- )
128
- else:
129
- t.transcription = pxop.transcriptions(t.audio, model=WHISPER_MODEL)
130
-
131
- # Get the current video data
132
- filtered_df = t.where(
133
- (t.video_filename == video_filename) & (t.sm_type == social_media_type)
134
- ).tail(1)
135
-
136
- if len(filtered_df) == 0:
137
- return "No matching video found in the table. Please ensure the video is uploaded correctly and try again."
138
-
139
- cur_video_df = filtered_df[0]
140
- plain_text = cur_video_df["transcription"]["text"]
141
-
142
- # Generate or retrieve social media post
143
- if (
144
- t.select()
145
- .where(
146
- (t.video_filename == video_filename)
147
- & (t.sm_type == social_media_type)
148
- & (t.sm_post != "")
149
- )
150
- .count()
151
- >= 1
152
- ):
153
- print("retrieving existing social media post")
154
- social_media_post = (
155
- t.select(t.sm_post)
156
- .where(
157
- (t.sm_type == social_media_type)
158
- & (t.video_filename == video_filename)
159
- )
160
- .collect()["sm_post"]
161
- )
162
- else:
163
- print("generating new social media post")
164
- social_media_post = generate_social_media_post(
165
- plain_text, social_media_type
166
- )
167
- if sm_gen_flag:
168
- cur_video_df.update({"sm_post": social_media_post})
169
- social_media_post = cur_video_df["sm_post"]
170
 
 
 
 
 
 
171
 
172
- print("######## processing thumbnail ##########")
 
 
 
 
173
 
174
- # images = []
175
- # for frame in FrameIterator(video=video_file, num_frames=4):
176
- # images.append(frame['frame']) # frame['frame'] is a PIL image
177
-
178
- if f"{db_directory}.{view_name}" in pxt.list_tables():
179
- pxt.drop_table(f"{db_directory}.{view_name}")
180
 
181
- frames_view = pxt.create_view(
182
- f"{db_directory}.frames",
183
- t,
184
- iterator=FrameIterator.create(video=t.video, num_frames = 4)
185
- )
186
 
187
- frames = frames_view.select(frames_view.frame).collect()
188
-
189
- return social_media_post, [frame['frame'] for frame in frames]
190
 
191
- except Exception as e:
192
- return f"An error occurred: {e}"
193
- else:
194
- return "Please upload a video file."
195
 
196
  # Gradio Interface
 
 
197
  def gradio_interface():
198
  with gr.Blocks(theme=gr.themes.Glass()) as demo:
199
- # Set up the UI components
200
- gr.Markdown(
201
- """<center><font size=12>Video to Social Media Post Generator</center>"""
202
- )
203
- gr.Markdown(
204
- """<div align="center">
205
- <img src="https://raw.githubusercontent.com/pixeltable/pixeltable/main/docs/source/data/pixeltable-logo-large.png" alt="Pixeltable" width="20%" />
206
- """
207
- )
208
  gr.Markdown(
209
- """<center><font size=6>Data Ops powered by <a href="https://github.com/pixeltable/pixeltable">Pixeltable</a></center>"""
 
 
 
 
 
 
210
  )
211
- gr.Markdown(
212
- """<center>Pixeltable is a Python library providing a declarative interface for multimodal data (text, images, audio, video). It features built-in versioning, lineage tracking, and incremental updates, enabling users to store, transform, index, and iterate on data for their ML workflows. Data transformations, model inference, and custom logic are embedded as computed columns.
213
- </center>"""
214
- )
215
- video_input = gr.Video(label=f"Upload Video File (max {MAX_VIDEO_SIZE_MB} MB):",
216
- include_audio = True,
217
- max_length= 300,
218
- height='400px',
219
- autoplay= True)
220
- social_media_type = gr.Dropdown(
221
- choices=["X (Twitter)", "Facebook", "LinkedIn"],
222
- label="Select Social Media Platform:",
223
- value="X (Twitter)",
224
- )
225
- generate_btn = gr.Button("Generate Post", interactive= True)
226
-
227
- output = gr.Textbox(label="Generated Social Media Post", show_copy_button=True)
228
 
229
- thumbnail = gr.Gallery(label = "Pick your favorite Post Thumbnail", show_download_button= True, show_fullscreen_button= True,
230
- height= '400px')
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
231
 
232
- examples = gr.Examples(
233
- [["example1.mp4"], ["example2.mp4"],["example3.mp4"]], inputs=[video_input]
 
234
  )
235
 
236
- # Connect the generate button to the processing function
237
  generate_btn.click(
238
  fn=process_and_generate_post,
239
  inputs=[video_input, social_media_type],
@@ -243,4 +131,5 @@ def gradio_interface():
243
  return demo
244
 
245
  # Launch the Gradio interface
246
- gradio_interface().launch(show_api=False)
 
 
1
+
 
2
  import pixeltable as pxt
3
  import os
4
+ import openai
5
+ import gradio as gr
6
  import getpass
 
 
7
  from pixeltable.iterators import FrameIterator
8
+ from pixeltable.functions.video import extract_audio
9
+ from pixeltable.functions.audio import get_metadata
10
+ from pixeltable.functions import openai
11
+
12
+ if 'OPENAI_API_KEY' not in os.environ:
13
+ os.environ['OPENAI_API_KEY'] = getpass.getpass('Enter your OpenAI API key:')
14
+
15
+ pxt.drop_dir('directory', force=True)
16
+ pxt.create_dir('directory')
17
+
18
+ t = pxt.create_table(
19
+ 'directory.video_table', {
20
+ "video": pxt.VideoType(nullable=True),
21
+ "sm_type": pxt.StringType(nullable=True),
22
+ }
23
+ )
24
+
25
+ frames_view = pxt.create_view(
26
+ "directory.frames",
27
+ t,
28
+ iterator=FrameIterator.create(video=t.video, num_frames=20)
29
+ )
30
+
31
+ # Create computed columns to store transformations and persist outputs
32
+ t['audio'] = extract_audio(t.video, format='mp3')
33
+ t['metadata'] = get_metadata(t.audio)
34
+ t['transcription'] = openai.transcriptions(audio=t.audio, model='whisper-1')
35
+ t['transcription_text'] = t.transcription.text
36
+
37
+ @pxt.udf
38
+ def prompt(A: str, B: str) -> list[dict]:
39
+ return [
40
+ {'role': 'system', 'content': 'You are an expert in creating social media content and you generate effective post, based on the video transcript and the type of social media asked for. Please respect the limitations in terms of characters and size of each social media platform'},
41
+ {'role': 'user', 'content': f'A: "{A}" \n B: "{B}"'}
42
+ ]
43
+
44
+ t['message'] = prompt(t.sm_type, t.transcription_text)
45
+
46
+ t['response'] = openai.chat_completions(messages=t.message, model='gpt-4o-mini-2024-07-18', max_tokens=500)
47
+ t['answer'] = t.response.choices[0].message.content
48
 
 
49
  MAX_VIDEO_SIZE_MB = 35
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
50
 
51
+ def process_and_generate_post(video_file, social_media_type):
52
+ if not video_file:
53
+ return "Please upload a video file.", None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
54
 
55
+ try:
56
+ # Check video file size
57
+ video_size = os.path.getsize(video_file) / (1024 * 1024) # Convert to MB
58
+ if video_size > MAX_VIDEO_SIZE_MB:
59
+ return f"The video file is larger than {MAX_VIDEO_SIZE_MB} MB. Please upload a smaller file.", None
60
 
61
+ # Insert video in PixelTable
62
+ t.insert([{
63
+ "video": video_file,
64
+ "sm_type": social_media_type
65
+ }])
66
 
67
+ # Retrieve Social media posts
68
+ social_media_post = t.select(t.answer).tail(1)['answer'][0]
 
 
 
 
69
 
70
+ # Retrieve thumbnails
71
+ frames = frames_view.select(frames_view.frame).tail(4)
72
+ thumbnails = [frame['frame'] for frame in frames]
 
 
73
 
74
+ #Display content
75
+ return social_media_post, thumbnails
 
76
 
77
+ except Exception as e:
78
+ return f"An error occurred: {str(e)}", None
 
 
79
 
80
  # Gradio Interface
81
+ import gradio as gr
82
+
83
  def gradio_interface():
84
  with gr.Blocks(theme=gr.themes.Glass()) as demo:
 
 
 
 
 
 
 
 
 
85
  gr.Markdown(
86
+ """
87
+ <center>
88
+ <h1>Video to Social Media Post Generator</h1>
89
+ <img src="https://raw.githubusercontent.com/pixeltable/pixeltable/main/docs/source/data/pixeltable-logo-large.png" alt="Pixeltable" width="20%" />
90
+ <p>Pixeltable is a declarative interface for working with text, images, embeddings, and even video, enabling you to store, transform, index, and iterate on data.</p>
91
+ </center>
92
+ """
93
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
94
 
95
+ with gr.Row():
96
+ with gr.Column():
97
+ video_input = gr.Video(
98
+ label=f"Upload Video File (max {MAX_VIDEO_SIZE_MB} MB):",
99
+ include_audio=True,
100
+ max_length=300,
101
+ height='400px',
102
+ autoplay=True
103
+ )
104
+ social_media_type = gr.Dropdown(
105
+ choices=["X (Twitter)", "Facebook", "LinkedIn", "Instagram"],
106
+ label="Select Social Media Platform:",
107
+ value="X (Twitter)",
108
+ )
109
+ generate_btn = gr.Button("Generate Post")
110
+
111
+ with gr.Column():
112
+ output = gr.Textbox(label="Generated Social Media Post", show_copy_button=True)
113
+ thumbnail = gr.Gallery(
114
+ label="Pick your favorite Post Thumbnail",
115
+ show_download_button=True,
116
+ show_fullscreen_button=True,
117
+ height='400px'
118
+ )
119
 
120
+ gr.Examples(
121
+ examples=[["example1.mp4"], ["example2.mp4"], ["example3.mp4"]],
122
+ inputs=[video_input]
123
  )
124
 
 
125
  generate_btn.click(
126
  fn=process_and_generate_post,
127
  inputs=[video_input, social_media_type],
 
131
  return demo
132
 
133
  # Launch the Gradio interface
134
+ if __name__ == "__main__":
135
+ gradio_interface().launch(show_api=False)