feat(ai-create): let users rate the draft the AI produced#193
Open
dantaspaulo wants to merge 2 commits into
Open
feat(ai-create): let users rate the draft the AI produced#193dantaspaulo wants to merge 2 commits into
dantaspaulo wants to merge 2 commits into
Conversation
## Problem
AI creation is one shot: the wizard sends the prompt and the job writes the
copy AND renders the images in a single pass. The user only sees the result
once everything has been generated and the post exists.
That is expensive and frustrating. Images are the costly part of a
generation, so a weak headline, an off-tone caption or a carousel whose
slides arrived in the wrong order all cost a full image render before the
user can react — and fixing it means starting over and paying again.
## Change
Generation is split into two phases with a review step in between.
**Phase A** (`PreparePostContent`) writes only the structured text — the same
generator and humanizer as before, no images — and stores it on a new
`AiPostDraft`. **The review screen** shows that text as editable blocks:
headline, body, caption, photo keywords, and for carousels a card per slide
that can be reordered by dragging. Edits autosave. **Phase B** reuses
`StreamPostCreation` with the approved structure, so it skips text generation
and renders the images from exactly what the user signed off on.
Nothing about the one-shot path changes: `StreamPostCreation` without
`preparedStructured` behaves exactly as before.
## How
- `PostContentComposer` — the "generate then humanize" step extracted from
`StreamPostCreation` verbatim, so both phases share one implementation.
Behaviour is unchanged; this is a pure extraction.
- `AiPostDraft` + `DraftStatus` (`preparing/ready/generating/completed/failed`)
hold the draft between phases. `generate` refuses a draft that is not
`ready`, so a double click cannot create a duplicate post or bill images twice.
- `PostContentPrepared` broadcasts on `user.{id}.ai-draft.{draftId}` when the
text lands; the review screen also polls every 4s so a dropped websocket
cannot strand the user on the skeleton.
- `creationStatus` gives the loading screen the same fallback for phase B.
## Tests
15 tests covering the flow end to end: draft creation and job dispatch, the
cross-workspace social account guard, rendering and authorization of the
review screen, generate persisting the reviewed structure and dispatching
phase B, the replay guard, autosave (persists while `ready`, no-op otherwise),
validation, and `PreparePostContent` marking the draft ready while preserving
the fields the humanizer does not return.
The full suite passes (2638 tests).
There is no signal today for whether an AI generation was actually any good. Publishing tells you nothing — a user can publish something mediocre, or abandon a great draft — so there is no way to tell whether a prompt change or a template tweak made generations better or worse. This adds a small 1-5 star control under the review blocks. Rating is optional, never blocks anything, and answers 204 so the UI can fire and forget. A rating tied to a specific item is idempotent — rating again updates it rather than creating a second row, enforced by a unique index and not just in the application. Standalone ratings stay possible, since NULLs are distinct in a unique index. `rateable_type` is validated against the registered morph aliases, so an arbitrary type cannot blow up later when the relation is resolved. The control follows the WAI-ARIA radiogroup pattern: arrow keys move focus and selection, Enter or click submits. Five feature tests cover recording, auth, the 1-5 bound, the morph-map guard and idempotency.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
There is no signal for whether an AI generation was actually any good. Publishing tells you nothing: a user can publish something mediocre, or abandon a great draft. So there is no way to tell whether a prompt change, a new template or a model swap made generations better or worse.
Change
A small 1–5 star control under the review blocks. It is optional, never blocks anything, and answers
204so the UI can fire and forget.rateable_typeis validated against the registered morph aliases, so an arbitrary type cannot blow up later when the relation is resolved.The table is polymorphic, so the same control can be dropped anywhere else you want a quality signal later.
Tests
Five feature tests: recording, authentication, the 1–5 bound, the morph-map guard, and idempotency. The full suite passes (2643), Pint and ESLint are clean.
Notes
enandpt-BRwritten properly, the other thirteen locales carrying the English strings as an untranslated fallback so the parity test passes.