agentsclimarketplace

Media generation

Skill S3YED/appie-kit/skills/misc/media-generation

Generate images, video, and talking-head animations via fal.ai and similar APIs. Covers sync-3 lipsync, cost estimation, async queue management, request recovery, and file delivery.From its SKILL.md

Install
npx -y skills add S3YED/appie-kit --skill media-generation

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 6 stars6 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

SKILL.md

6.9 KB, ~1.7k tokens by cl100k_base, as published. Nobody here has run it

AI Media Generation (fal.ai & Similar APIs)

When to Use

  • User wants to create a talking-head video from a photo + audio
  • User asks for image-to-video, lipsync, or face animation
  • Any paid API media generation task (fal.ai, etc.)
  • Uploading/serving generated media files

Principles

Always Estimate Costs Before Running

NEVER fire a paid API call without estimating the cost first. This is the #1 rule from Seyed after the $16 fugu-sync3 incident.

# Sync-3 v3 image-to-video: $0.1333 per output second
# 71s audio = 71 × $0.1333 = ~$9.46

Cost estimation checklist:

  1. Look up the model's pricing (per-second, per-video, per-image)
  2. Calculate: duration × unit_price = estimated_cost
  3. Present to user with balance/remaining info
  4. Only proceed after user confirms

Bulletproof Async Workflow (fal.ai)

The correct sequence for long-running fal.ai jobs is:

1. submit() → get SyncRequestHandle
2. IMMEDIATELY save handle.request_id to disk ← CARDINAL RULE
3. Poll via REST API (GET) until Completed
4. Download result video
5. Compress if needed (Telegram 50MB limit)
6. Clean up temp files

NEVER use subscribe() — it blocks until completion with no request_id fallback. If the client disconnects mid-processing, the result is unrecoverable and credits are wasted.

Request ID Recovery

Even with proper save, if the polling process dies:

  • The saved request_id lets you recover via REST API
  • Use GET on https://queue.fal.run/fal-ai/{app}/requests/{request_id}
  • This returns the full result JSON including video URL
  • The from_request_id() method in fal-client requires an httpx.Client instance (internal) — use raw REST API instead

Supported Models & Pricing

fal.ai — sync-3 Lipsync

ModelEndpointPricingNotes
sync-3 image-to-videofal-ai/sync-lipsync/v3/image-to-video$0.1333/sec outputPhoto + audio → talking video
sync-3 video-to-videofal-ai/sync-lipsync/v3~$0.13/secExisting video + new audio

Input: {"image_url": "...", "audio_url": "..."} (image-to-video variant needs image_url, NOT face_image_url)

Output format: MP4. Result lives at https://v3b.fal.media/... URLs valid ~14 days.

Arbitrary fal.ai Models

All models follow the same queue/submit/workflow pattern. Generic workflow:

from fal_client import submit

handle = submit("fal-ai/{owner}/{model}", arguments={...})
request_id = handle.request_id
# Save request_id immediately!
# Poll via GET https://queue.fal.run/fal-ai/{owner}/{model}/requests/{request_id}

fal.ai File Upload

Use the upload_file() function from fal_client:

from fal_client import upload_file
file_url = upload_file("/path/to/file.jpg")
# Returns: https://v3b.fal.media/files/...

The returned URL is immediately usable in model arguments.

Polling Pattern

Key learning: the status endpoint returns 405 for GET and works with POST. But the result endpoint works with GET:

# Check status (POST)
curl -X POST "https://queue.fal.run/fal-ai/{app}/requests/{id}/status" \
  -H "Authorization: Key $FAL_KEY"

# Get completed result (GET)
curl "https://queue.fal.run/fal-ai/{app}/requests/{id}" \
  -H "Authorization: Key $FAL_KEY"

Important: The {app} in the queue URL may differ from the submit app name.

  • Submit uses: fal-ai/sync-lipsync/v3/image-to-video
  • Queue URL uses: fal-ai/sync-lipsync (without the /v3/image-to-video suffix)

Always check the response_url/status_url from the initial submit response to get the exact queue URL pattern.

File Delivery

Telegram Delivery

Telegram has a 50MB file size limit for bots. Compress with ffmpeg:

ffmpeg -i input.mp4 \
  -c:v libx264 -crf 28 -preset fast \
  -c:a aac -b:a 64k \
  -movflags +faststart \
  output-compressed.mp4

Typical compression: 136MB → ~5.8MB (CRF 28, 71s video). For Telegram delivery, use the MEDIA: prefix.

Google Drive Upload

Requires OAuth setup (rclone or gdrive). The most direct alternative is giving the user the raw fal.ai storage URL (valid ~14 days).

Scripts

Reference: bulletproof-submit.py

A template script for bulletproof fal.ai job submission. Create and modify per task:

import os, json, time
from fal_client import submit

RID_FILE = "/path/to/request-id.txt"

# Submit
handle = submit("fal-ai/{model}", arguments={...})
rid = handle.request_id
with open(RID_FILE, "w") as f: f.write(rid)
print(f"Request ID: {rid}")

# Poll via REST (more reliable than status())
REST_URL = f"https://queue.fal.run/fal-ai/{app}/requests/{rid}"
while True:
    # Use curl or requests here
    # Check if COMPLETED
    # If yes: download video, compress, deliver
    time.sleep(10)

References

Session Learnings (2026-06-23 fugu-sync3)

The fugu-sync3 session produced these verified facts:

  • sync-3 v3 image-to-video expects image_url (NOT face_image_url) + audio_url
  • The correct model path: fal-ai/sync-lipsync/v3/image-to-video
  • Pricing is $0.1333 per output second, shown on the model page as "Your request will cost $X.XX per output second"
  • A 71s video at 30fps generates ~136MB H.264 original, compressible to ~5.8MB at CRF 28
  • Queue polling pattern: POST to status endpoint, GET to result endpoint
  • The fal.ai SDK from_request_id() needs an httpx.Client instance (not a simple public method) — use REST API for recovery instead
  • Video URLs from fal.ai storage are valid for ~14 days
  • Request results expire after approximately 10+ minutes of inactivity — save the video URL immediately

Pitfalls

  • $16 wasted on first attempt — Using subscribe() without request_id fallback made the result unrecoverable when the client timed out.
  • 405 errors on status endpoint — The status endpoint uses POST, not GET. The result endpoint uses GET, not POST.
  • Queue URL vs Submit URL difference — The queue URL may strip subpaths. Check response URLs from the submit call.
  • No charge for server errors — fal.ai doesn't charge for 503/504/timeout errors during queue wait, but DOES charge for completed processing even if the client disconnects.
  • Request ID expiration — Completed request results expire after some time (observed: a 10-minute-old request ID was gone). Save the result URL, not just the request ID.
  • Always save request_id to disk before doing anything else. If the script crashes at any point, the request_id is the only way to recover the result.

What ships with it

Read from the repository

Just SKILL.md. No reference files, no scripts.

Gives 0 of the 12 instructions most media documents skills give in ~1.7k tokens

Counted across 157 of the 158 authors here whose files we hold, read 2026-08-07

  • Provide posting time recommendationsin 7 of 157, across 5 files
  • Track metrics over time to identify trendsin 6 of 157, across 2 files
  • Read marketing context file before startingin 6 of 157, across 5 files
  • Choose platforms based on audience presencein 6 of 157, across 4 files
  • Adapt tone for each platformin 6 of 157, across 4 files
  • Ensure data completeness before analysisin 5 of 157, across 1 file
  • Compare metrics within same time periodsin 5 of 157, across 1 file
  • Account for platform-specific benchmarksin 5 of 157, across 1 file
  • Separate organic and paid metricsin 5 of 157, across 1 file
  • Include context when interpreting resultsin 5 of 157, across 1 file
  • Keep tweets under 280 charactersin 5 of 157, across 3 files
  • Download top-K results with an attribution sidecarin 5 of 157, across 2 files

Said here and by no other author read

  • estimate cost before running api calls
  • present cost estimate to the user
  • proceed only after user confirms cost
  • save handle request_id to disk immediately
  • poll via rest api until job is completed
  • compress output video under 50mb if needed

Grouped from the skills themselves: near-identical wordings counted once, and counted by distinct author, so one author publishing three of these counts once. Length counted with cl100k_base; the agent that loads this file may tokenize it differently.

Keep looking

Skills are one crate of 326,871. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.