PierreBrunelle's picture
Update app.py
05644d3 verified
import pixeltable as pxt
import os
import openai
import gradio as gr
import getpass
from pixeltable.iterators import FrameIterator
from pixeltable.functions.video import extract_audio
from pixeltable.functions.audio import get_metadata
from pixeltable.functions import openai
# Store OpenAI API Key
if 'OPENAI_API_KEY' not in os.environ:
os.environ['OPENAI_API_KEY'] = getpass.getpass('Enter your OpenAI API key:')
MAX_VIDEO_SIZE_MB = 35
CONCURRENCY_LIMIT = 1
def process_and_generate_post(video_file, social_media_type, progress=gr.Progress()):
progress(0, desc="Initializing...")
# Create a Table, a View, and Computed Columns
pxt.drop_dir('directory', force=True)
pxt.create_dir('directory')
t = pxt.create_table(
'directory.video_table', {
"video": pxt.Video,
"sm_type": pxt.String
}
)
frames_view = pxt.create_view(
"directory.frames",
t,
iterator=FrameIterator.create(video=t.video, fps=1)
)
# Create computed columns to store transformations and persist outputs
t.add_computed_column(audio=extract_audio(t.video, format='mp3'))
t.add_computed_column(metadata=get_metadata(t.audio))
t.add_computed_column(transcription=openai.transcriptions(audio=t.audio, model='whisper-1'))
t.add_computed_column(transcription_text=t.transcription.text)
progress(0.1, desc="Creating UDFs...")
# Custom User-Defined Function (UDF) for Generating Social Media Prompts
@pxt.udf
def prompt(A: str, B: str) -> list[dict]:
system_msg = 'You are an expert in creating social media content and you generate effective post, based on user content. Respect the social media platform guidelines and constraints.'
user_msg = f'A: "{A}" \n B: "{B}"'
return [
{'role': 'system', 'content': system_msg},
{'role': 'user', 'content': user_msg}
]
# Apply the UDF to create a new column
t.add_computed_column(message=prompt(t.sm_type, t.transcription_text))
"""## Generating Responses with OpenAI's GPT Model"""
progress(0.2, desc="Calling LLMs")
# # Generate responses using OpenAI's chat completion API
t.add_computed_column(response=openai.chat_completions(messages=t.message, model='gpt-4o-mini-2024-07-18', max_tokens=500))
## Extract the content of the response
t.add_computed_column(answer=t.response.choices[0].message.content)
if not video_file:
return "Please upload a video file.", None
try:
# Check video file size
video_size = os.path.getsize(video_file) / (1024 * 1024) # Convert to MB
if video_size > MAX_VIDEO_SIZE_MB:
return f"The video file is larger than {MAX_VIDEO_SIZE_MB} MB. Please upload a smaller file.", None
progress(0.4, desc="Inserting video...")
# # Insert a video into the table. Pixeltable supports referencing external data sources like URLs
t.insert([{
"video": video_file,
"sm_type": social_media_type
}])
progress(0.6, desc="Generating posts...")
# Retrieve Social media posts
social_media_post = t.select(t.answer).tail(1)['answer'][0]
# Retrieve Audio
audio = t.select(t.audio).tail(1)['audio'][0]
# Retrieve thumbnails
thumbnails = frames_view.select(frames_view.frame).tail(6)['frame']
progress(0.8, desc="Preparing results...")
# Retrieve Pixeltable Table containing all videos and stored data
df_output = t.select(t.transcription_text).tail(1)['transcription_text'][0]
#Display content
return social_media_post, thumbnails, df_output, audio
except Exception as e:
return f"An error occurred: {str(e)}", None
# Gradio Interface
def gradio_interface():
with gr.Blocks(theme=gr.themes.Base()) as demo:
# Header Section with Logo and Title
gr.Markdown(
"""
<div style="text-align: left; margin-bottom: 20px;">
<img src="https://raw.githubusercontent.com/pixeltable/pixeltable/main/docs/resources/pixeltable-logo-large.png" alt="Pixeltable" style="max-width: 200px; margin-bottom: 20px;" />
<h1 style="margin-bottom: 0.5em;">πŸ“Ή Video to Social Media Post Generator</h1>
<p style="color: #666; margin-bottom: 1em;">Transform your videos into engaging social media content using AI</p>
</div>
"""
)
with gr.Row():
# Left Column - Platform Features
with gr.Column():
with gr.Accordion("🎯 Key Features", open=False):
gr.Markdown(
"""
* πŸŽ₯ **Smart Video Processing**
- Automatic frame extraction
- High-quality audio separation
- Real-time transcription
* πŸ€– **AI-Powered Content**
- Platform-specific post generation
- Engaging caption creation
- Tone & style optimization
* πŸ“Š **Complete Analytics**
- Transcription review
- Thumbnail selection
- Audio verification
"""
)
# Right Column - How It Works
with gr.Column():
with gr.Accordion("πŸ› οΈ How It Works", open=False):
gr.Markdown(
"""
1. πŸ“€ **Upload Your Video**
- Choose your content
- Select target platform
- Start processing
2. πŸ”„ **AI Processing**
- Video analysis
- Content extraction
- Post generation
3. ✨ **Review & Export**
- Preview generated posts
- Select thumbnails
- Copy to clipboard
"""
)
# Main Interface
with gr.Tabs() as tabs:
# Upload Tab
with gr.TabItem("πŸ“€ Upload & Generate", id=0):
with gr.Row():
# Left Column - Input Controls
with gr.Column():
video_input = gr.Video(
label="Upload Your Video",
include_audio=True,
max_length=300,
height='400px',
autoplay=False
)
with gr.Group():
gr.Markdown("### 🎯 Target Platform")
social_media_type = gr.Radio(
choices=[
"X (Twitter)",
"Facebook",
"LinkedIn",
"Instagram"
],
value="X (Twitter)",
label="Select where you want to share:",
interactive=True
)
generate_btn = gr.Button(
"πŸš€ Generate Post",
scale=1,
size="lg",
variant="primary"
)
# Right Column - Output Display
with gr.Column():
output = gr.Textbox(
label="✨ Generated Post",
show_copy_button=True,
lines=4
)
gr.Markdown("### πŸ–ΌοΈ Thumbnail Options")
thumbnail = gr.Gallery(
label="Select your preferred thumbnail",
show_download_button=True,
show_fullscreen_button=True,
height='200px',
object_fit="contain"
)
# Review Tab
with gr.TabItem("πŸ“ Review & Export", id=1):
with gr.Row():
with gr.Column():
df_output = gr.Textbox(
label="πŸ“ Video Transcription",
show_copy_button=True,
lines=8
)
audio = gr.Audio(
label="🎡 Extracted Audio",
show_download_button=True,
type="filepath"
)
# Example Section
gr.Markdown("### πŸ“š Sample Usage")
with gr.Row():
gr.Examples(
examples=[
["example1.mp4", "X (Twitter)"],
["example2.mp4", "LinkedIn"],
["example3.mp4", "Instagram"],
["example4.mp4", "Facebook"]
],
inputs=[video_input, social_media_type],
label="Try with sample videos:",
examples_per_page=5
)
# Footer
gr.HTML(
"""
<div style="text-align: center; margin-top: 2rem; padding-top: 1rem; border-top: 1px solid #ccc;">
<p style="color: #666; font-size: 0.9em;">
Powered by <a href="https://github.com/pixeltable/pixeltable" target="_blank" style="color: #F25022; text-decoration: none;">Pixeltable</a>
| <a href="https://docs.pixeltable.com" target="_blank" style="color: #666;">Documentation</a>
| <a href="https://github.com/pixeltable/pixeltable" target="_blank" style="color: #666;">GitHub</a>
</p>
</div>
"""
)
# Wire up the generate button click event
generate_btn.click(
fn=process_and_generate_post,
inputs=[video_input, social_media_type],
outputs=[output, thumbnail, df_output, audio],
api_name="generate",
show_progress="full",
trigger_mode='once'
)
return demo
# Launch the Gradio interface with production settings
if __name__ == "__main__":
demo = gradio_interface()
demo.launch(
server_name="0.0.0.0", # Allow external access
server_port=7860, # Standard Gradio port
share=False, # Disable sharing in production
show_api=False, # Hide API docs in production
show_error=False, # Hide detailed errors in production
ssl_verify=True, # Enable SSL verification
quiet=True # Reduce console output
)