shorts-maker / app.py
walter2161's picture
Update app.py
885cebe verified
import gradio as gr
import json
import requests
import random
import subprocess
import os
from gtts import gTTS
from moviepy.editor import VideoFileClip, AudioFileClip, concatenate_videoclips
# Function to fetch portrait videos from Pexels
def get_pexels_video(keyword):
headers = {"Authorization": "P310n0wKAlr05spr9UrtHeQXqouRlCL7r1jT6RQD55I1FIqyZt4fx7SL"}
params = {
"query": keyword,
"per_page": 10,
"orientation": "portrait",
"size": "large",
"min_width": 1080,
"min_height": 1920,
}
response = requests.get("https://api.pexels.com/videos/search", headers=headers, params=params)
if response.status_code == 200:
videos = response.json()['videos']
portrait_videos = [video for video in videos if video['width'] < video['height']] # Check for portrait videos
if portrait_videos:
selected_video = random.choice(portrait_videos)
return selected_video['video_files'][0]['link']
else:
print(f"No portrait video found on Pexels for {keyword}")
return None
else:
print("Failed to fetch video from Pexels")
return None
# Function to generate voiceover using gTTS
def generate_voiceover(text, filename, speed=1.0):
tts = gTTS(text=text, lang='pt', slow=False)
tts.save(filename)
# Function to generate video content and create data.json
def generate_video_content(topic):
api_key = "AIzaSyAtVhAjcUi7tHYnYZTWA4_L2ExvsAeupQY"
url = f"https://generativelanguage.googleapis.com/v1beta/models/gemini-1.0-pro:generateContent?key={api_key}"
payload = {
"contents": [
{
"role": "user",
"parts": [
{
"text": f"Create a short one-minute video on {topic} and the keyword under each scene will be used for pexels search query, so give a precise keyword for each scene and create very short scenes. Give upto 15 related tags. Give response in this json format and give just the json: {{ \"title\": \"\", \"description\": \"\", \"video\": [ {{ \"scene\": \"\", \"keyword\": \"\", \"voiceover\": \"\" }} ], \"tags\": [\"\", \"\", \"\"] }}"
}
]
}
],
"generationConfig": {
"temperature": 0.9,
"topK": 1,
"topP": 1,
"maxOutputTokens": 2048,
"stopSequences": []
},
"safetySettings": [
{
"category": "HARM_CATEGORY_HARASSMENT",
"threshold": "BLOCK_NONE"
},
{
"category": "HARM_CATEGORY_HATE_SPEECH",
"threshold": "BLOCK_NONE"
},
{
"category": "HARM_CATEGORY_SEXUALLY_EXPLICIT",
"threshold": "BLOCK_NONE"
},
{
"category": "HARM_CATEGORY_DANGEROUS_CONTENT",
"threshold": "BLOCK_NONE"
}
]
}
headers = {
'Content-Type': 'application/json'
}
response = requests.post(url, headers=headers, json=payload)
if response.status_code == 200:
try:
with open("data.json", "w") as f:
f.write(response.json()["candidates"][0]["content"]["parts"][0]["text"])
print("Data saved successfully as data.json")
except KeyError:
print("Error: Could not find the desired data in the response")
else:
print("Error occurred while fetching data")
# Function to concatenate videos using FFmpeg
def concatenate_videos_ffmpeg(scene_videos, output_filename):
# Write scene_videos to temporary files
temp_filenames = []
for i, video_clip in enumerate(scene_videos):
temp_filename = f'temp_video_{i}.mp4'
video_clip.write_videofile(temp_filename, codec="libx264", audio_codec="aac", temp_audiofile="temp-audio.m4a", remove_temp=True, verbose=False)
temp_filenames.append(temp_filename)
# Create a text file containing the list of videos to concatenate
with open('video_list.txt', 'w') as f:
for temp_filename in temp_filenames:
f.write(f"file '{temp_filename}'\n")
# Use FFmpeg to concatenate the videos without resizing
subprocess.run(['ffmpeg', '-f', 'concat', '-safe', '0', '-i', 'video_list.txt', '-vf', 'scale=1080:1920', '-c:a', 'aac', '-b:a', '256k', '-c:v', 'libx264', '-preset', 'medium', output_filename])
# Clean up the video list file and temporary video files
os.remove('video_list.txt')
for temp_filename in temp_filenames:
os.remove(temp_filename)
def process_video(topic):
generate_video_content(topic)
with open('data.json', 'r') as f:
data = json.load(f)
title = data.get('title', '')
description = data.get('description', '')
tags = ", ".join(data.get('tags', []))
scene_info = []
for scene in data['video']:
voiceover_text = scene['voiceover']
voiceover_filename = f"{scene['scene']}_voiceover.mp3"
generate_voiceover(voiceover_text, voiceover_filename)
voiceover_duration = AudioFileClip(voiceover_filename).duration
scene_info.append({'scene': scene['scene'], 'voiceover_filename': voiceover_filename, 'voiceover_duration': voiceover_duration, 'keyword': scene['keyword']})
# Step 3: Fetch videos from Pexels based on portrait orientation
for scene in scene_info:
video_urls = [get_pexels_video(scene['keyword']) for _ in range(3)] # Fetch 3 videos for each scene
video_filenames = []
for video_url in video_urls:
if video_url:
# Download video file locally
video_filename = f"{scene['scene']}_video_{len(video_filenames)}.mp4"
with open(video_filename, 'wb') as f:
f.write(requests.get(video_url).content)
video_filenames.append(video_filename)
scene['video_filenames'] = video_filenames
# Step 4: Create Scene Videos without resizing
scene_videos = []
for scene in scene_info:
video_clips = []
for video_filename in scene['video_filenames']:
video_clip = VideoFileClip(video_filename)
video_clips.append(video_clip)
concatenated_clip = concatenate_videoclips(video_clips)
# Trim the concatenated clip to match the voiceover duration
concatenated_clip = concatenated_clip.subclip(0, scene['voiceover_duration'])
# Add audio to video clip
concatenated_clip = concatenated_clip.set_audio(AudioFileClip(scene['voiceover_filename']))
scene_videos.append(concatenated_clip)
final_filename = title + '.mp4'
concatenate_videos_ffmpeg(scene_videos, final_filename)
# Clean up downloaded files
for scene in scene_info:
os.remove(scene['voiceover_filename'])
for video_filename in scene['video_filenames']:
os.remove(video_filename)
return final_filename, title, description, tags
iface = gr.Interface(
fn=process_video,
inputs="text",
outputs=["video", "text", "text", "text"],
css="footer {visibility: hidden}",
description="Generate a free short video just with a word or topic. Best for YouTube, Reels and TikTok. This is a prototype. If you want better software, please inbox or email me at aheedsajid@gmail.com and do like this space. [Click here to Donate](https://nowpayments.io/donation/aheed) <b>Want to make long landscape videos?</b> [Click here](https://huggingface.co/spaces/aheedsajid/invideo-clone)",
title="Text to Short Video - Invideo AI Clone"
)
iface.launch()