Why I built it

A lot of people are vibecoding apps now, but the moment an app needs a feed, someone still has to build the post-enrichment layer before recommendations can work. I built Post Lens so they do not have to start that part from scratch.

A post can have text, one image, a whole carousel, video, and audio. I wanted one backend service that could process all of that consistently instead of wiring together a separate script for every format.

What it does

Send Post Lens some post text and media. It returns versioned JSON with media and text embeddings, plus optional captions, OCR, speech transcripts, hashes, model versions, timings, and clear status values.

For a carousel, every distinct slide contributes to the final media vector. Duplicate slides keep their original position and hash, but the model does not run twice on the same image. For video, Post Lens uses one deterministic frame for the visual embedding and handles the audio separately.

If an optional worker fails, the response can still include the parts that worked instead of throwing everything away.

How I built it

The API is Python and FastAPI. OpenCLIP ViT-L/14 handles media embeddings and multilingual-e5 handles text. Optional Qwen workers handle image captions, OCR, and speech transcription. The larger workers are behind separate dependencies and flags, so the default setup stays smaller.

How I used Codex and GPT-5.6

I used Codex with GPT-5.6 Sol to work through the shared post and carousel contract, implement the API and demo UI, write tests first for the main edge cases, and check ordering, duplicates, failures, and model provenance. I reviewed the decisions and verified the actual output before shipping the public repo.

What was difficult

The main challenge was making the output predictable. Media order, duplicate handling, hashes, model versions, timings, and partial failures all need to stay stable if another backend is going to store the result. The API, single-media flow, carousel flow, and local demo are working now. The optional models still need their downloads and suitable hardware.

Built With

  • fastapi
  • hugging
  • openclip
  • python
  • qwen
Share this project:

Updates