Week 13 of 16

Build: Complete the Batch Tool

Add file input, timing, and export to the batch generator.

Day 64 60 minutes Build

Day 64 of 80

Today's Additions

Yesterday's batch generator works but has one limitation: you have to type shots manually. Today you add:

Update batch_generator.py

Add a batch_from_file() function and update main() to support both interactive and file modes:

batch_generator.py — additions Python
# Add these imports at the top:
import time
from pathlib import Path


async def batch_from_file(shots_file, output_file=None):
    """Load shots from a JSON file and batch generate.

    shots_file: path to a JSON array of strings
    ["Wide establishing shot", "Close-up hands", "Aerial reveal"]
    """
    shots_path = Path(shots_file)
    if not shots_path.exists():
        print(f"File not found: {shots_file}")
        return

    with open(shots_path, "r") as f:
        shots = json.load(f)

    if not isinstance(shots, list):
        print("Error: JSON file must contain a list of strings")
        return

    print(f"Loaded {len(shots)} shots from {shots_file}")

    start = time.time()
    results = await batch_generate(shots)
    elapsed = time.time() - start

    successful = [r for r in results if r["status"] == "success"]
    failed = [r for r in results if r["status"] != "success"]

    print(f"\nResults: {len(successful)} successful, {len(failed)} failed")
    print(f"Time: {elapsed:.1f}s ({elapsed/len(results):.2f}s per prompt)")

    # Group results by shot for display and export
    grouped = {}
    for r in successful:
        shot = r["shot"]
        if shot not in grouped:
            grouped[shot] = []
        grouped[shot].append({
            "platform": r["platform"],
            "prompt": r["prompt"],
        })

    # Display
    print()
    for shot, prompts in grouped.items():
        print(f"SHOT: {shot}")
        for p in prompts:
            print(f"  [{p['platform']}] {p['prompt'][:70]}...")
        print()

    # Export to file
    if output_file:
        output = [
            {"shot": shot, "prompts": prompts}
            for shot, prompts in grouped.items()
        ]
        with open(output_file, "w") as f:
            json.dump(output, f, indent=2)
        print(f"Exported to {output_file}")

    return grouped


async def main():
    """Run in interactive or file mode based on command-line args."""
    import sys

    if len(sys.argv) > 1:
        # File mode: python batch_generator.py shots.json [output.json]
        shots_file = sys.argv[1]
        output_file = sys.argv[2] if len(sys.argv) > 2 else "batch_output.json"
        await batch_from_file(shots_file, output_file)
    else:
        # Interactive mode: enter shots manually
        print("=== DVP Batch Prompt Generator ===\n")
        print("Enter shots one per line. Type 'done' when finished.\n")
        print("Tip: you can also run with a shots file:")
        print("  python batch_generator.py my_shots.json output.json\n")

        shots = []
        while True:
            shot = input(f"  Shot {len(shots) + 1} (or 'done'): ")
            if shot.strip().lower() == "done":
                break
            if shot.strip():
                shots.append(shot.strip())

        if not shots:
            print("No shots entered.")
            return

        start = time.time()
        results = await batch_generate(shots)
        elapsed = time.time() - start

        successful = [r for r in results if r["status"] == "success"]
        print(f"\n{len(successful)} of {len(results)} prompts in {elapsed:.1f}s\n")

        for r in results:
            if r["status"] == "success":
                print(f"  [{r['platform']}] {r['shot'][:40]}")
                print(f"  {r['prompt'][:70]}...\n")


if __name__ == "__main__":
    asyncio.run(main())

Test With a Real Shots File

Create my_shots.json:

my_shots.json JSON
[
  "Wide establishing shot, golf course at sunrise, mist rising",
  "Close-up hands gripping club, shallow depth of field",
  "Slow motion golf swing follow-through, backlit",
  "Aerial drone pull-back revealing the full course",
  "Crowd reaction in slow motion, bokeh background"
]

Then run:

python batch_generator.py my_shots.json output.json

You'll generate 15 prompts (5 shots × 3 platforms) in one batch. Open output.json and see the structured results.

End of Day Checklist

Tomorrow

Day 65 adds an async /generate endpoint to your FastAPI app — so you can generate prompts for all platforms from a single API call.