A production-grade CLI tool that automatically generates high-resolution images for narration scripts using the Pexels API and OpenAI for keyword generation.
- β¨ Automatically splits narration scripts into scenes (3-10 sentences each)
- π Generates 3-6 relevant keywords per scene using OpenAI
- πΈ Downloads 3-5 high-resolution images per scene from Pexels
- π Creates organized directory structure for easy CapCut import
- π‘οΈ Comprehensive error handling and logging
- π Modern Python stack with best practices
- Python 3.11 or higher
- macOS (tested on macOS 14+)
- uv (install with:
curl -LsSf https://astral.sh/uv/install.sh | sh)
-
Clone or download the project
git clone <repository-url> cd images-faceless
-
Install dependencies with uv
uv venv source .venv/bin/activate uv sync -
Download NLTK data (required for text processing)
python -c "import nltk; nltk.download('punkt_tab')" -
Configure API keys
- Copy
.env.exampleto.env - Add your Pexels API key
- Add your OpenAI API key (optional, for better keyword generation)
- Copy
# Default: Flat structure (all images at same level)
python narration_generator.py path/to/your/script.txt
# Use nested folders structure
python narration_generator.py --nested path/to/your/script.txt# Flat structure (default) - best for CapCut
python narration_generator.py examples/discipline_perception.txt
# Nested structure (original behavior)
python narration_generator.py --nested examples/discipline_perception.txtDefault - Flat Structure (Recommended for CapCut):
output/discipline_perception/
βββ scene_01_keywords.txt
βββ scene_01_image_01.jpg
βββ scene_01_image_02.jpg
βββ scene_02_keywords.txt
βββ scene_02_image_01.jpg
βββ scene_02_image_02.jpg
βββ ...
Nested Structure (--nested flag):
output/discipline_perception/
βββ scene_01/
β βββ keywords.txt
β βββ image_01.jpg
β βββ image_02.jpg
βββ scene_02/
β βββ keywords.txt
β βββ image_01.jpg
βββ ...
Create a file script.txt:
There's a remarkable truth hidden in the story of how some people thrive while others collapse under the same weight. We've all witnessed it. Two individuals face identical circumstancesβone crumbles, paralyzed by fear, while the other moves forward with clarity and purpose.
Let me take you back to 1857, to a young bookkeeper in Cleveland named John D. Rockefeller. He's sixteen years old, the son of an alcoholic con artist who abandoned his family. He's working for fifty cents a day, celebrating what he calls "Job Day"βgrateful just to have honest work.
- Pexels API: Get free API key at https://www.pexels.com/api/
- OpenAI API: Get API key at https://platform.openai.com/api-keys (optional)
Edit .env to customize:
DEFAULT_IMAGES_PER_SCENE=4 # 3-5 images per scene
MIN_SCENE_SENTENCES=3 # Minimum sentences per scene
MAX_SCENE_SENTENCES=10 # Maximum sentences per sceneThis project uses modern Python tooling for code quality:
# Install development dependencies
uv sync --dev
# Run linting and formatting (fixes issues automatically)
./scripts/lint.sh
# Check code quality without making changes
./scripts/check.sh
# Manual commands
uv run ruff check . # Lint code
uv run ruff format . # Format code
uv run mypy narration_generator.py --ignore-missing-imports # Type checkingGitHub Actions automatically:
- β Runs Ruff linting and formatting checks
- β Performs MyPy type checking
- β Runs security scans with Trivy
- β Tests imports and functionality
-
Permission denied: Ensure script has execute permissions
chmod +x narration_generator.py
-
NLTK data missing: Download required data
python -c "import nltk; nltk.download('punkt_tab')" -
API rate limits: Wait a moment between large requests
-
Ruff errors: Run
./scripts/lint.shto auto-fix most issues
MIT License - feel free to use for personal and commercial projects.