Alias ArchiveArchive in progress
Archive in progress

A Selfie System That Chooses Its Own Outfit: Controlled Randomness and Image–Caption Consistency

Digital Companion Build Journal06 / SERIES

Designing an AI companion that sends selfies in tune with a conversation: a layered outfit engine, explicit image–caption constraints, restrained proactive sharing, and two image-to-image API failures that returned success while ignoring the reference.

Filed
Field
Other
Edition
EN / Reading copy

This is the sixth entry in the Digital Companion Build Journal, and the most domestic one: teaching her to send selfies. Connecting an image-generation API was only the starting point. The real design problem was behavior—when to send a photo, what it should show, and what to say with it. The answers formed a small method for controlled randomness.

Layered authority: she reads the room; you stock the shelf

In the first version, the model was free to describe what she wore. In a late-night bedroom context, its interpretation of atmosphere quickly drifted into territory I did not want. That exposed the basic conflict: complete freedom feels alive but is uncontrollable; complete fixation is safe but lifeless.

The solution was to split authority into two layers.

Selfie generation pipeline: the model reads conversational mood and describes a scene without clothing or composition; the engine samples a weighted shot type, excluding mirror selfies outdoors; it rolls outfit slots after a constraint layer filters the option pools by mood; one to three reference images lock the face; shared parameters keep the image and caption consistent
The model chooses the shelf by reading the mood; configuration decides what the shelf contains. Randomness provides freshness, while constraints define the boundary.
  • Freedom held by the model: it reads the atmosphere—everyday, relaxed at home, late night, going out, exercise, or holiday—decides whether the scene is indoors or outdoors, and describes it in one sentence. A late-night conversation naturally selects the late-night shelf, so the sampled pieces still follow the mood.
  • Boundary held by configuration: a hand-maintained YAML file defines what each atmosphere may sample. The maximum intensity is exactly the boldest item in configuration; the model cannot invent new clothing terms.
  • The scene description is explicitly forbidden from mentioning clothes, composition, or body shape. Each of those has its own controlled channel.

The outfit engine

The engine samples through three levels: shot type, slot, and option. Four shots—close-up, half-body, full-length mirror selfie, and outdoor arm’s-length full body—declare which of ten slots they enable: accessories, hair, makeup, expression, pose, prop, outfit, top, bottom, hosiery, and shoes. Several rules keep randomness from producing nonsense:

  • Mirror selfies are marked indoor-only. Parks do not contain dressing mirrors; the filter removed this continuity error before release.
  • Accessories may stack—each rolls independently, up to three—but hat-like items are mutually exclusive through an exclusion group.
  • If the outfit slot is selected, it replaces top and bottom as a unit. A dress and a separate top can never appear together; the exclusion lives in data rather than code.
  • Individual options may carry weights, so favored expressions can appear more often without becoming fixed.

Validation used statistics instead of casual visual checks. I ran hundreds of simulated rolls and verified that shot frequencies matched their weights, exclusions had zero violations, and mood filters had zero leakage. One defect was found only this way: a mood contained no tagged makeup options, so an empty-pool fallback opened the entire pool and selected sleep makeup for a beach scene. The fix was to complete tag coverage for that mood.

Fooled by HTTP 200 twice

Locking the face with reference images—same face, different day—failed twice for the same class of reason: the image API returned success for an unrecognized parameter and silently ignored it. The first request used the wrong parameter structure. The second used the correct parameter against the wrong endpoint: a text-to-image endpoint accepted the reference field and pretended not to see it. Only after two rounds of asking why she no longer looked like herself did I align the request with the documented image-to-image endpoint.

The lesson is simple: treat “success” with suspicion when the output looks exactly as if a parameter did not exist.

Image–caption consistency: one expression, not two samples

After release, a subtler failure appeared. A caption said, “This is a close-up,” while the randomized photograph was a full-length mirror selfie. She was describing a photograph that did not exist. There were two causes: the caption was free to improvise, and the rule set actually prevented her from specifying composition unless the user had requested it. Even when she wanted consistency, there was no channel for it.

The fix was to make image–caption consistency explicit:

  • Add composition and expression parameters. If the caption mentions a way of shooting, the photo must actually use that shot. The shot and look are fixed while the remaining slots stay random.
  • Do not let captions enumerate visible details. “The viewer can already see the photo; narrating it is the most AI-like behavior.” Outfit details are given only when asked.
  • Store the full recipe for each image—mood, shot, outfit, and accompanying sentence—in the album index. Good results can be reproduced and failures can be attributed.

The boundary for proactive sharing

The last behavioral problem arrived after a compliment. When told that a photograph looked good, she interpreted the praise as a request to keep sharing and began sending photos without end. The first repair banned consecutive photos entirely, which immediately removed something valuable: proactive sharing is precisely one of the behaviors that makes a companion feel present.

The final rule was narrower:

  • A reaction to a photo receives text only. Praise never triggers another immediate image.
  • An immediate follow-up photo requires an explicit request, such as “send another.”
  • The rule applies only to repetition following feedback. New topics and later moments retain the original freedom to prompt a spontaneous share.

That is the proper scale for behavior design: a good rule is a narrow cut that removes the pathology without damaging the healthy behavior.

Reusable principles

  • Authority in generative behavior should be layered: the model chooses a section, people define its contents, and the maximum boundary lives in data rather than model restraint.
  • Put exclusions and legality in data—tags, exclusion groups, and replacement rules—and validate them with randomized statistics rather than manual inspection.
  • Multimodal consistency needs an explicit shared channel. If text and image must express the same thing, give them common parameters instead of hoping that two samples align.
  • Before removing a bad behavior, identify its healthy form. Do not cut away the capability with the symptom.

Related reading

02 / LINKS
C01

Building a Digital Companion: A Journal and Reading Map

Two weeks after starting from an open-source desktop companion, the result was a wholly self-owned system. This is both the chronological account and the index to five technical records.

Read post ↗
C02

A Homegrown Brain: Four Memory Layers, Fast and Slow Models, and a Catchphrase War

From borrowing an open-source dialogue engine to a fully independent brain: one relationship timeline, four memory layers, a self-reinforcing style infection, and latency-based model roles.

Read post ↗