← back to Goodquestion Ai
scripts/make-video-3000-products.sh
222 lines
#!/bin/bash
# =============================================================================
# Video: How AI Agents Manage 3,000 Products Autonomously
# Narrated slideshow about batch product processing with AI agents
# =============================================================================
set -e
BASEDIR="/root/Projects/goodquestion-ai/videos/build-3000-products"
VOICE="en-US-AndrewNeural"
RATE="-10%"
FPS=30
WIDTH=1920
HEIGHT=1080
mkdir -p "$BASEDIR/narration" "$BASEDIR/slides" "$BASEDIR/segments"
echo "═══════════════════════════════════════════════"
echo " STEP 1: Generate Narration (edge-tts)"
echo "═══════════════════════════════════════════════"
# Segment 1: Hook
edge-tts --voice "$VOICE" --rate="$RATE" --text \
"Three thousand products. Every single one with broken descriptions, missing metadata, and wrong categories. Fixing them manually would take a team of ten people three months. My AI agents did it in forty-eight hours. Here's exactly how." \
--write-media "$BASEDIR/narration/01-hook.mp3" 2>/dev/null
echo " 01-hook.mp3"
# Segment 2: The Problem
edge-tts --voice "$VOICE" --rate="$RATE" --text \
"When you're running an e-commerce catalog with thousands of SKUs, data quality is everything. Customers can't find products if the descriptions are wrong. Search engines can't index them if the metadata is incomplete. And every broken listing is lost revenue. The catalog had accumulated years of inconsistent data from dozens of different suppliers." \
--write-media "$BASEDIR/narration/02-problem.mp3" 2>/dev/null
echo " 02-problem.mp3"
# Segment 3: The Architecture
edge-tts --voice "$VOICE" --rate="$RATE" --text \
"So I built a pipeline. Not one script. A pipeline of specialized AI agents, each handling a different part of the cleanup. Agent one crawls the supplier websites and pulls fresh specifications. Agent two rewrites product descriptions using AI, making them SEO-friendly and accurate. Agent three generates photorealistic room visualization images. Agent four validates and pushes enriched metadata back to the store." \
--write-media "$BASEDIR/narration/03-architecture.mp3" 2>/dev/null
echo " 03-architecture.mp3"
# Segment 4: Parallel Processing
edge-tts --voice "$VOICE" --rate="$RATE" --text \
"The key insight is parallelism. These agents don't wait for each other. They run simultaneously across different product batches. Six agents processing six batches at once. Each one reads the database, pulls the next unprocessed product, does its work, and writes the result back. If one agent crashes, the others keep going. A process manager restarts the failed one automatically." \
--write-media "$BASEDIR/narration/04-parallel.mp3" 2>/dev/null
echo " 04-parallel.mp3"
# Segment 5: AI Image Generation
edge-tts --voice "$VOICE" --rate="$RATE" --text \
"The most impressive part is the image generation. For every product, the system creates six commercial environment visualizations. A hotel lobby. A corporate office. A healthcare facility. A restaurant. A retail space. A conference room. All photorealistic. All generated by AI in under two minutes per product. That's eighteen thousand room images created automatically." \
--write-media "$BASEDIR/narration/05-images.mp3" 2>/dev/null
echo " 05-images.mp3"
# Segment 6: Results
edge-tts --voice "$VOICE" --rate="$RATE" --text \
"The results? Three thousand products fully enriched. Ninety-eight percent accuracy on metadata. Eighteen thousand room visualization images generated. Average processing time: fifty-seven seconds per product. Total cost: about forty dollars in AI API calls. Compare that to three months of manual work by a data entry team." \
--write-media "$BASEDIR/narration/06-results.mp3" 2>/dev/null
echo " 06-results.mp3"
# Segment 7: CTA
edge-tts --voice "$VOICE" --rate="$RATE" --text \
"This is what AI automation looks like at scale. Not a chatbot answering questions. Agents doing real work, autonomously, around the clock. If you're running an e-commerce operation and still doing data entry by hand, you're leaving money on the table. Follow Agent Abrams for more builds like this." \
--write-media "$BASEDIR/narration/07-cta.mp3" 2>/dev/null
echo " 07-cta.mp3"
echo ""
echo "═══════════════════════════════════════════════"
echo " STEP 2: Create Graphic Slides (ffmpeg)"
echo "═══════════════════════════════════════════════"
# Color scheme
BG="#0E0E10"
CYAN="#00F0FF"
ORANGE="#F7931A"
GREEN="#00C389"
WHITE="#E0E0E0"
DIM="#6B7280"
PURPLE="#A855F7"
FONT="/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf"
FONTL="/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf"
# Slide 1: Hook
ffmpeg -y -f lavfi -i "color=c=${BG}:s=${WIDTH}x${HEIGHT}:d=1" \
-vf "drawtext=text='3,000 PRODUCTS':fontsize=100:fontcolor=${CYAN}:x=(w-text_w)/2:y=(h-text_h)/2-100:fontfile=${FONT},\
drawtext=text='ZERO HUMANS':fontsize=72:fontcolor=${ORANGE}:x=(w-text_w)/2:y=(h-text_h)/2+30:fontfile=${FONT},\
drawtext=text='48 Hours. Fully Autonomous.':fontsize=32:fontcolor=${DIM}:x=(w-text_w)/2:y=(h-text_h)/2+140:fontfile=${FONTL}" \
-frames:v 1 "$BASEDIR/slides/01-hook.png" 2>/dev/null
echo " 01-hook.png"
# Slide 2: The Problem
ffmpeg -y -f lavfi -i "color=c=${BG}:s=${WIDTH}x${HEIGHT}:d=1" \
-vf "drawtext=text='THE DATA PROBLEM':fontsize=64:fontcolor=${ORANGE}:x=(w-text_w)/2:y=120:fontfile=${FONT},\
drawtext=text='━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━':fontsize=20:fontcolor=${ORANGE}@0.3:x=(w-text_w)/2:y=210:fontfile=${FONTL},\
drawtext=text='▸ Broken Descriptions':fontsize=40:fontcolor=${WHITE}:x=300:y=300:fontfile=${FONTL},\
drawtext=text='▸ Missing Metadata':fontsize=40:fontcolor=${WHITE}:x=300:y=380:fontfile=${FONTL},\
drawtext=text='▸ Wrong Categories':fontsize=40:fontcolor=${WHITE}:x=300:y=460:fontfile=${FONTL},\
drawtext=text='▸ Inconsistent Data from 40+ Suppliers':fontsize=40:fontcolor=${WHITE}:x=300:y=540:fontfile=${FONTL},\
drawtext=text='Manual fix = 10 people x 3 months':fontsize=36:fontcolor=${ORANGE}:x=(w-text_w)/2:y=680:fontfile=${FONT}" \
-frames:v 1 "$BASEDIR/slides/02-problem.png" 2>/dev/null
echo " 02-problem.png"
# Slide 3: Architecture
ffmpeg -y -f lavfi -i "color=c=${BG}:s=${WIDTH}x${HEIGHT}:d=1" \
-vf "drawtext=text='THE AGENT PIPELINE':fontsize=64:fontcolor=${CYAN}:x=(w-text_w)/2:y=100:fontfile=${FONT},\
drawtext=text='━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━':fontsize=20:fontcolor=${CYAN}@0.3:x=(w-text_w)/2:y=190:fontfile=${FONTL},\
drawtext=text='AGENT 1':fontsize=36:fontcolor=${CYAN}:x=200:y=280:fontfile=${FONT},\
drawtext=text='Crawl Supplier Data':fontsize=28:fontcolor=${WHITE}:x=200:y=330:fontfile=${FONTL},\
drawtext=text='AGENT 2':fontsize=36:fontcolor=${GREEN}:x=600:y=280:fontfile=${FONT},\
drawtext=text='Rewrite Descriptions':fontsize=28:fontcolor=${WHITE}:x=600:y=330:fontfile=${FONTL},\
drawtext=text='AGENT 3':fontsize=36:fontcolor=${ORANGE}:x=1050:y=280:fontfile=${FONT},\
drawtext=text='Generate Room Images':fontsize=28:fontcolor=${WHITE}:x=1050:y=330:fontfile=${FONTL},\
drawtext=text='AGENT 4':fontsize=36:fontcolor=${PURPLE}:x=1450:y=280:fontfile=${FONT},\
drawtext=text='Push Metadata':fontsize=28:fontcolor=${WHITE}:x=1450:y=330:fontfile=${FONTL},\
drawtext=text='▸ Each agent is autonomous':fontsize=34:fontcolor=${WHITE}:x=300:y=460:fontfile=${FONTL},\
drawtext=text='▸ Crash recovery built in':fontsize=34:fontcolor=${WHITE}:x=300:y=530:fontfile=${FONTL},\
drawtext=text='▸ Process manager auto-restarts':fontsize=34:fontcolor=${WHITE}:x=300:y=600:fontfile=${FONTL}" \
-frames:v 1 "$BASEDIR/slides/03-architecture.png" 2>/dev/null
echo " 03-architecture.png"
# Slide 4: Parallel Processing
ffmpeg -y -f lavfi -i "color=c=${BG}:s=${WIDTH}x${HEIGHT}:d=1" \
-vf "drawtext=text='PARALLEL PROCESSING':fontsize=64:fontcolor=${GREEN}:x=(w-text_w)/2:y=120:fontfile=${FONT},\
drawtext=text='━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━':fontsize=20:fontcolor=${GREEN}@0.3:x=(w-text_w)/2:y=210:fontfile=${FONTL},\
drawtext=text='6':fontsize=160:fontcolor=${CYAN}:x=300:y=320:fontfile=${FONT},\
drawtext=text='Agents':fontsize=36:fontcolor=${DIM}:x=300:y=510:fontfile=${FONTL},\
drawtext=text='6':fontsize=160:fontcolor=${ORANGE}:x=750:y=320:fontfile=${FONT},\
drawtext=text='Batches':fontsize=36:fontcolor=${DIM}:x=750:y=510:fontfile=${FONTL},\
drawtext=text='24/7':fontsize=120:fontcolor=${GREEN}:x=1200:y=340:fontfile=${FONT},\
drawtext=text='Uptime':fontsize=36:fontcolor=${DIM}:x=1260:y=510:fontfile=${FONTL}" \
-frames:v 1 "$BASEDIR/slides/04-parallel.png" 2>/dev/null
echo " 04-parallel.png"
# Slide 5: AI Images
ffmpeg -y -f lavfi -i "color=c=${BG}:s=${WIDTH}x${HEIGHT}:d=1" \
-vf "drawtext=text='AI IMAGE GENERATION':fontsize=64:fontcolor=${PURPLE}:x=(w-text_w)/2:y=100:fontfile=${FONT},\
drawtext=text='━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━':fontsize=20:fontcolor=${PURPLE}@0.3:x=(w-text_w)/2:y=190:fontfile=${FONTL},\
drawtext=text='6 Environments Per Product':fontsize=44:fontcolor=${WHITE}:x=(w-text_w)/2:y=280:fontfile=${FONT},\
drawtext=text='▸ Hotel Lobby':fontsize=36:fontcolor=${CYAN}:x=250:y=380:fontfile=${FONTL},\
drawtext=text='▸ Corporate Office':fontsize=36:fontcolor=${CYAN}:x=250:y=440:fontfile=${FONTL},\
drawtext=text='▸ Healthcare':fontsize=36:fontcolor=${CYAN}:x=250:y=500:fontfile=${FONTL},\
drawtext=text='▸ Restaurant':fontsize=36:fontcolor=${GREEN}:x=900:y=380:fontfile=${FONTL},\
drawtext=text='▸ Retail Space':fontsize=36:fontcolor=${GREEN}:x=900:y=440:fontfile=${FONTL},\
drawtext=text='▸ Conference Room':fontsize=36:fontcolor=${GREEN}:x=900:y=500:fontfile=${FONTL},\
drawtext=text='18,000 Images Generated':fontsize=52:fontcolor=${ORANGE}:x=(w-text_w)/2:y=620:fontfile=${FONT}" \
-frames:v 1 "$BASEDIR/slides/05-images.png" 2>/dev/null
echo " 05-images.png"
# Slide 6: Results
ffmpeg -y -f lavfi -i "color=c=${BG}:s=${WIDTH}x${HEIGHT}:d=1" \
-vf "drawtext=text='THE RESULTS':fontsize=64:fontcolor=${GREEN}:x=(w-text_w)/2:y=100:fontfile=${FONT},\
drawtext=text='━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━':fontsize=20:fontcolor=${GREEN}@0.3:x=(w-text_w)/2:y=190:fontfile=${FONTL},\
drawtext=text='3,000':fontsize=100:fontcolor=${CYAN}:x=200:y=300:fontfile=${FONT},\
drawtext=text='Products Enriched':fontsize=28:fontcolor=${DIM}:x=200:y=420:fontfile=${FONTL},\
drawtext=text='98%%':fontsize=100:fontcolor=${GREEN}:x=700:y=300:fontfile=${FONT},\
drawtext=text='Accuracy':fontsize=28:fontcolor=${DIM}:x=740:y=420:fontfile=${FONTL},\
drawtext=text='\$40':fontsize=100:fontcolor=${ORANGE}:x=1200:y=300:fontfile=${FONT},\
drawtext=text='Total AI Cost':fontsize=28:fontcolor=${DIM}:x=1200:y=420:fontfile=${FONTL},\
drawtext=text='57 seconds per product':fontsize=44:fontcolor=${WHITE}:x=(w-text_w)/2:y=560:fontfile=${FONT}" \
-frames:v 1 "$BASEDIR/slides/06-results.png" 2>/dev/null
echo " 06-results.png"
# Slide 7: CTA
ffmpeg -y -f lavfi -i "color=c=${BG}:s=${WIDTH}x${HEIGHT}:d=1" \
-vf "drawtext=text='AGENT ABRAMS':fontsize=80:fontcolor=${CYAN}:x=(w-text_w)/2:y=(h-text_h)/2-120:fontfile=${FONT},\
drawtext=text='AI Automation at Scale':fontsize=40:fontcolor=${WHITE}:x=(w-text_w)/2:y=(h-text_h)/2:fontfile=${FONTL},\
drawtext=text='goodquestion.ai':fontsize=36:fontcolor=${ORANGE}:x=(w-text_w)/2:y=(h-text_h)/2+80:fontfile=${FONTL},\
drawtext=text='Subscribe for more builds':fontsize=28:fontcolor=${DIM}:x=(w-text_w)/2:y=(h-text_h)/2+160:fontfile=${FONTL}" \
-frames:v 1 "$BASEDIR/slides/07-cta.png" 2>/dev/null
echo " 07-cta.png"
echo ""
echo "═══════════════════════════════════════════════"
echo " STEP 3: Build per-segment videos"
echo "═══════════════════════════════════════════════"
SEGMENTS=("01-hook" "02-problem" "03-architecture" "04-parallel" "05-images" "06-results" "07-cta")
for seg in "${SEGMENTS[@]}"; do
narr="$BASEDIR/narration/${seg}.mp3"
slide="$BASEDIR/slides/${seg}.png"
out="$BASEDIR/segments/${seg}.mp4"
dur=$(ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 "$narr" 2>/dev/null)
ffmpeg -y \
-loop 1 -i "$slide" \
-i "$narr" \
-c:v libx264 -preset fast -crf 23 -pix_fmt yuv420p \
-c:a aac -b:a 128k \
-t "$dur" \
-r $FPS \
-shortest \
"$out" 2>/dev/null
echo " ${seg}.mp4 (${dur}s)"
done
echo ""
echo "═══════════════════════════════════════════════"
echo " STEP 4: Concatenate all segments"
echo "═══════════════════════════════════════════════"
rm -f "$BASEDIR/concat.txt"
for seg in "${SEGMENTS[@]}"; do
echo "file 'segments/${seg}.mp4'" >> "$BASEDIR/concat.txt"
done
FINAL="$BASEDIR/3000-products-autonomous.mp4"
ffmpeg -y -f concat -safe 0 -i "$BASEDIR/concat.txt" \
-c:v libx264 -preset medium -crf 22 -pix_fmt yuv420p \
-c:a aac -b:a 192k \
-movflags +faststart \
"$FINAL" 2>/dev/null
FILESIZE=$(du -h "$FINAL" | cut -f1)
DURATION=$(ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 "$FINAL" 2>/dev/null)
echo ""
echo "═══════════════════════════════════════════════"
echo " DONE!"
echo "═══════════════════════════════════════════════"
echo " Output: $FINAL"
echo " Size: $FILESIZE"
echo " Duration: ${DURATION}s"