将文本转换为视频的生成已经成为一种趋势,有许多流行的工具可用于此,例如Vadoo、Invideo、Pictory等等。但大多数这些工具都是付费的,当你需要多次修改输出视频时,预算很快就会超出。
所以在本文中,我们将讨论如何免费使用一个开源解决方案[https://github.com/SamurAIGPT/Text-To-Video-AI]将文本转换为视频。如果您只想观看演示,而不想深入了解编码细节,这里有一个教程视频。
现在让我们来谈谈技术方面。以下是根据文本生成一个完整视频的整个过程。
工作流- 使用 OpenAI 从一个主题生成视频剧本
- 使用 edgetts 选择一个声音,并根据上述生成的剧本创建音频
- 使用 whisper 获取上述音频的字幕
- 使用 OpenAI API 为视频剧本生成视觉标签
- 使用 pexels API 根据上述视觉标签获取视频
- 使用 Moviepy 拼接视频、音频和字幕
如果你更喜欢使用高质量的声音,你可以尝试使用Elevenlabs的API而不是edgetts。如果你的系统硬件配置较低,你可以不使用本地的whisper,改用whisper的API。既然整个流程已经很清楚了,现在我们来了解这些步骤是如何完成的。
为视频制作脚本
我们将用以下提示来生成某个主题的视频剧本。因为我们专注于生成一段短视频,我们要求LLM生成一个大约50秒长或140字剧本。此外,我们还要求LLM生成一个有趣且具原创性的剧本。
def generate_script(topic):
prompt = (
"""你是一名擅长制作YouTube Shorts视频的内容创作者,专注于制作事实视频。
你的事实短视频简短精炼,每段视频长度不超过50秒(约140字)。
它们非常引人入胜且具有原创性。当用户请求某种特定的事实短视频时,你会为他们创作。
例如,如果用户请求:
奇怪的事实
你会制作如下内容:
你不知道的奇怪事实:
- 香蕉是浆果,但草莓不是浆果。
- 一朵云的重量可能超过一百万磅。
- 例如水母中的涡鞭水母,从生物学角度来看是永生的。
- 蜂蜜永远不会变质;考古学家在3000多年前的埃及坟墓中发现的蜂蜜仍然可以食用。
- 历史上最短的战争是1896年8月27日英国和桑给巴尔之间的战争,桑给巴尔只抵抗了38分钟就投降了。
- 章鱼拥有三个心脏和蓝色的血液。
你现在需要根据用户的请求类型“事实”来创作最佳的短视频剧本。
要保持内容简短、有趣且独特。
请严格按照如下JSON格式输出,仅提供可解析的JSON对象,键为'script'。
输出示例
{"script": "这里是剧本..."}
"""
)
response = client.chat.completions.create(
model="gpt-4o",
messages=[
{"role": "system", "content": prompt},
{"role": "user", "content": topic}
]
)
content = response.choices[0].message.content
script = json.loads(content)["script"]
return script
脚本完成后,我们会把它交给edgetts来生成语音。接着,我们拿到生成的音频,通过whisper生成带有时间标记的字幕。字幕完成后,接下来,我们就可以开始识别视觉关键词,来找到与字幕相关的视频。
为脚本找一些视觉关键词
我们将使用以下提示来基于输入的字幕识别与输入字幕相关的关键词。我们将使用Pexels API来查找与关键词相关的视频。这些关键词应该由1到2个单词组成,便于搜索,并且这些关键词应该描述一些可视化的元素,这样更便于从Pexels获取视频,这会使在Pexels上的视频搜索更简单。
首先,我们将输入的文字分成每3秒一段的时间段。我们这样做是为了每3秒生成一个新的视频,让内容保持新鲜感。对于每个时间段,我们使用下面的提示来生成三个关键词。这样即使找不到某个关键词的视频,也可以尝试其他两个关键词。
prompt = """# 指令
根据以下视频脚本和时间轴字幕,提取每个时间段中三个具体且明确的关键词,用于搜索背景视频。这些关键词应该简短并捕捉句子的主要内容。它们可以是同义词或相关词。如果字幕模糊或过于笼统,请考虑使用下一个时间轴的字幕以获得更多上下文。如果关键词仅为一个单词,请尽量返回两个单词的关键词,且这两个词具有极强的视觉具体性。如果一个时间段包含两个或多个重要的信息,请将其拆分为较短的时间段,每个时间段用一个关键词。时间段应严格连续,并覆盖整个视频的长度。每个关键词应覆盖2到4秒。输出格式应为JSON,例如:[[[t1, t2], ["关键词1", "关键词2", "关键词3"]], [[t2, t3], ["关键词4", "关键词5", "关键词6"]], ...]。请处理边缘情况,例如重叠的时间段、模糊或笼统的字幕和单个单词的关键词。
例如,如果字幕是'The cheetah is the fastest land animal, capable of running at speeds up to 75 mph',关键词应包括'cheetah running', 'fastest animal', 和'75 mph'。同样,对于'The Great Wall of China is one of the most iconic landmarks in the world',关键词应为'Great Wall of China', 'iconic landmark', 和'China landmark'。
重要指南:
请仅使用英文进行文本查询。
每个查询字符串必须描绘具体的视觉内容。
描绘的内容必须非常具体,如下雨的街道或猫睡觉。
'emotional moment' <= 不好,因为它没有具体的视觉描绘。
'crying child' <= 好,因为它有具体的视觉描绘。
列表中必须始终包含最相关和恰当的查询搜索。
['Car', 'Car driving', 'Car racing', 'Car parked'] <= 不好,因为它包含4个词条。
['Fast car'] <= 好,因为它包含1个词条。
['Un chien', 'une voiture rapide', 'une maison rouge'] <= 不好,因为查询文本不是英文。
"""
现在我们已经为每个时间段生成了视觉关键词。接下来,我们将使用Pexels API查找这些关键词的相关视频。以下是从关键词获取Pexels相关视频的代码示例:
以下是根据关键词在Pexels上查找相关视频的代码示例:
def search_videos(query_string, orientation_landscape=True):
url = "https://api.pexels.com/videos/search"
headers = {
"Authorization": PEXELS_API_KEY
}
params = {
"query": query_string,
"orientation": "landscape" if orientation_landscape else "portrait",
"per_page": 15
}
response = requests.get(url, headers=headers, params=params)
json_data = response.json()
log_response(LOG_TYPE_PEXEL, query_string, response.json())
return json_data
def getBestVideo(query_string, orientation_landscape=True, used_vids=[]):
vids = search_videos(query_string, orientation_landscape)
videos = vids['videos'] # 提取 JSON 中的视频列表
# 过滤并提取宽度和高度为 1920x1080 或 1080x1920 的视频
if orientation_landscape:
filtered_videos = [video for video in videos if video['width'] >= 1920 and video['height'] >= 1080 and video['width']/video['height'] == 16/9]
else:
filtered_videos = [video for video in videos if video['width'] >= 1080 and video['height'] >= 1920 and video['height']/video['width'] == 16/9]
# 按照时长进行升序排序
sorted_videos = sorted(filtered_videos, key=lambda x: abs(15-int(x['duration'])))
# 提取三个符合条件的视频的 URL
for video in sorted_videos:
for video_file in video['video_files']:
if orientation_landscape:
if video_file['width'] == 1920 and video_file['height'] == 1080:
if not (video_file['link'].split('.hd')[0] in used_vids):
return video_file['link']
else:
if video_file['width'] == 1080 and video_file['height'] == 1920:
if not (video_file['link'].split('.hd')[0] in used_vids):
return video_file['link']
print("本次查询未找到符合条件的视频链接:", query_string)
return None
对于每个时间段的3个关键词,我们尝试通过getBestVideo函数来查找视频。如果找不到视频,将返回None。否则,它会过滤结果,以确保我们获得预期的1080p分辨率的视频,并找到时长在15秒以下的最长视频。
你可以用Moviepy将视频、音频和字幕结合在一起
我们现在有了所需的一切,即音频、字幕和相关的视频。我们现在需要将所有这些元素组合在一起,以获得一个包含所有这些元素的最终视频。为此,我们将使用Moviepy库,如下所示。
def download_file(url, filename):
with open(filename, 'wb') as f:
response = requests.get(url)
f.write(response.content)
def search_program(program_name):
try:
search_cmd = "where" if platform.system() == "Windows" else "which"
return subprocess.check_output([search_cmd, program_name]).decode().strip()
except subprocess.CalledProcessError:
return None
def get_program_path(program_name):
program_path = search_program(program_name)
return program_path
def get_output_media(audio_file_path, timed_captions, background_video_data, video_server):
# 输出文件名
OUTPUT_FILE_NAME = "rendered_video.mp4"
magick_path = get_program_path("magick")
print(magick_path)
if magick_path:
os.environ['IMAGEMAGICK_BINARY'] = magick_path
else:
os.environ['IMAGEMAGICK_BINARY'] = '/usr/bin/convert'
visual_clips = []
for (t1, t2), video_url in background_video_data:
# 下载视频文件并
video_filename = tempfile.NamedTemporaryFile(delete=False).name
download_file(video_url, video_filename)
# 使用下载的文件创建 VideoFileClip
video_clip = VideoFileClip(video_filename)
video_clip = video_clip.set_start(t1)
video_clip = video_clip.set_end(t2)
visual_clips.append(video_clip)
audio_clips = []
audio_file_clip = AudioFileClip(audio_file_path)
audio_clips.append(audio_file_clip)
for (t1, t2), text in timed_captions:
text_clip = TextClip(txt=text, fontsize=100, color="white", stroke_width=3, stroke_color="black", method="label")
text_clip = text_clip.set_start(t1)
text_clip = text_clip.set_end(t2)
text_clip = text_clip.set_position(["center", 800])
visual_clips.append(text_clip)
video = CompositeVideoClip(visual_clips)
if audio_clips:
audio = CompositeAudioClip(audio_clips)
video.duration = audio.duration
video.audio = audio
# 视频时长与音频一致
video.write_videofile(OUTPUT_FILE_NAME, codec='libx264', audio_codec='aac', fps=25, preset='veryfast')
# 删除下载的临时视频文件
for (t1, t2), video_url in background_video_data:
video_filename = tempfile.NamedTemporaryFile(delete=False).name
os.remove(video_filename)
return OUTPUT_FILE_NAME
我们需要使用 ImageMagick 在视频上以我们偏好风格叠加字幕,使用 Moviepy 中的 TextClip 函数。现在我们已经准备好了最终输出,并保存为 rendered_video.mp4 文件。
这里有一个简单易运行的Colab笔记本(无需手动安装),还有一个演示视频,如果你不想在系统上手动安装所有这些内容。
Google Colab笔记本如果你想深入了解代码或更喜欢本地运行它,这里有一个 Github 仓库的链接地址。
GitHub - SamurAIGPT/Text-To-Video-AI: 使用 AI 从文本生成视频。通过在 github.com 创建账户来参与 SamurAIGPT/Text-To-Video-AI 的开发…github.com如果你不想写代码的话,并想使用无代码工具,可以试试看这个工具 text to video ai,这个工具。
AI文本转视频 | 使用Vadoo AI生成视频:只需提示、文本和脚本。www.vadoo.tv共同学习,写下你的评论
评论加载中...
作者其他优质文章