Research Paper Video Generation Pipeline
A reusable media pipeline for converting long-form research audio into structured transcript chunks, visual prompts, generated images, and a synchronized video.
Problem
Making research videos by hand requires transcription, chunking, visual planning, image generation, and video assembly.
Outcome
A scriptable pipeline that stores transcript segments in SQLite, generates visual prompts, creates images, and assembles a video with FFmpeg.
Implementation evidence
The solution is backed by inspectable code
This solves automated research-video assembly: transcribe audio, chunk the transcript, summarize each chunk into a visual concept, generate images, and merge the images with audio.
Code
import json
import sqlite3
DB_NAME = "transcriptions.db"
def create_tables():
conn = sqlite3.connect(DB_NAME)
cursor = conn.cursor()
cursor.execute("""
CREATE TABLE IF NOT EXISTS transcriptions (
id INTEGER PRIMARY KEY AUTOINCREMENT,
text TEXT,
language TEXT
)
""")
cursor.execute("""
CREATE TABLE IF NOT EXISTS segments (
id INTEGER PRIMARY KEY AUTOINCREMENT,
transcription_id INTEGER,
start REAL,
end REAL,
text TEXT,
tokens TEXT,
confidence REAL,
words TEXT,
FOREIGN KEY (transcription_id) REFERENCES transcriptions(id) ON DELETE CASCADE
)
""")
conn.commit()
conn.close()
def insert_transcription(data):
conn = sqlite3.connect(DB_NAME)
cursor = conn.cursor()
cursor.execute(
"INSERT INTO transcriptions (text, language) VALUES (?, ?)",
(data.get("text", ""), data.get("language", "")),
)
transcription_id = cursor.lastrowid
for segment in data.get("segments", []):
cursor.execute(
"""
INSERT INTO segments (transcription_id, start, end, text, tokens, confidence, words)
VALUES (?, ?, ?, ?, ?, ?, ?)
""",
(
transcription_id,
segment.get("start", 0),
segment.get("end", 0),
segment.get("text", ""),
json.dumps(segment.get("tokens", [])),
segment.get("confidence", 0),
json.dumps(segment.get("words", [])),
),
)
conn.commit()
conn.close()
return transcription_id
def get_text_chunks(transcription_id, max_chunk_duration=7.0):
conn = sqlite3.connect(DB_NAME)
cursor = conn.cursor()
cursor.execute(
"""
SELECT start, end, text
FROM segments
WHERE transcription_id = ?
ORDER BY start ASC
""",
(transcription_id,),
)
segments = cursor.fetchall()
conn.close()
chunks, current = [], []
current_start = current_end = current_duration = None
for start, end, text in segments:
duration = end - start
if not current:
current_start, current_end, current_duration = start, end, duration
current.append(text)
continue
if current_duration + duration > max_chunk_duration:
chunks.append({"start": current_start, "end": current_end, "text": " ".join(current)})
current, current_start, current_end, current_duration = [text], start, end, duration
else:
current.append(text)
current_end = end
current_duration += duration
if current:
chunks.append({"start": current_start, "end": current_end, "text": " ".join(current)})
return chunks
import subprocess
def assemble_video(image_files, audio_file, output_movie="paper_video.mp4"):
with open("image_list.txt", "w", encoding="utf-8") as f:
for filepath, start, end in image_files:
f.write(f"file '{filepath}'\n")
f.write(f"duration {max(end - start, 1)}\n")
subprocess.run([
"ffmpeg", "-f", "concat", "-safe", "0", "-i", "image_list.txt",
"-vf", "scale=1280:720", "-c:v", "libx264", "-pix_fmt", "yuv420p",
"temp_video.mp4",
], check=True)
subprocess.run([
"ffmpeg", "-i", "temp_video.mp4", "-i", audio_file,
"-c:v", "copy", "-c:a", "aac", "-shortest", output_movie,
], check=True)
Usage
- Transcribe audio with Whisper or
whisper-timestamped. - Insert the transcription JSON with
insert_transcription. - Chunk segments with
get_text_chunks. - Generate summaries and image prompts for each chunk.
- Generate images and call
assemble_video.
Requirements
The article uses Whisper, Ollama, Stable Diffusion WebUI, SQLite, Pillow, and FFmpeg.
Source
The article points to the implementation repository: ernanhughes/wave_to_text.
Full explanation
For the end-to-end walkthrough and image generation steps, read: Creating AI-Powered Paper Videos: From Research to YouTube.