Add image generation workbench#4701
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
WalkthroughAdds an image generation workbench: backend support (new PlaygroundImage handler, relay-mode mapping, model allowlists, middleware group handling) and a full frontend feature (types, API wrapper, UI component, routing, sidebar integration, and i18n strings). Also standardizes frontend ApiRequestConfig typing and replaces inline untyped request option casts. ChangesImage Generation Workbench
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Tip 💬 Introducing Slack Agent: The best way for teams to turn conversations into code.Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.
Built for teams:
One agent for your entire SDLC. Right inside Slack. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 4
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
web/default/src/i18n/locales/en.json (1)
1976-2000: 🛠️ Refactor suggestion | 🟠 Major | 🏗️ Heavy liftUse hierarchical i18n keys for the new image workbench strings.
These newly added entries use raw English sentence keys, which makes key evolution and cross-locale consistency harder. Please move these to semantic keys (e.g.,
imageWorkbench.status.completed,imageWorkbench.form.outputFormat, etc.) and update call sites accordingly.♻️ Suggested key shape
- "Image generation completed.": "Image generation completed.", - "Image generation failed.": "Image generation failed.", - "Output format": "Output format", + "imageWorkbench.status.completed": "Image generation completed.", + "imageWorkbench.status.failed": "Image generation failed.", + "imageWorkbench.form.outputFormat": "Output format",As per coding guidelines,
web/default/src/i18n/**/*.{ts,tsx,json}: "Use hierarchical and semantically clear translation key names such asdashboard.overview.titleand maintain naming consistency".🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@web/default/src/i18n/locales/en.json` around lines 1976 - 2000, Replace the raw English sentence keys in this JSON (e.g., "Image generation completed.", "Image input", "Generating image...", etc.) with hierarchical semantic keys (suggested: imageWorkbench.status.completed, imageWorkbench.status.failed, imageWorkbench.workspace.title, imageWorkbench.input.label, imageWorkbench.input.price, imageWorkbench.output.label, imageWorkbench.output.price, imageWorkbench.preview.title, imageWorkbench.ratio.label, imageWorkbench.tools.toVideo, imageWorkbench.tokens.label, imageWorkbench.generate.description, imageWorkbench.generate.relayFlow, imageWorkbench.generate.costsExplanation, imageWorkbench.form.promptPlaceholder, imageWorkbench.errors.noData, imageWorkbench.errors.generationFailed, imageWorkbench.form.outputFormat, imageWorkbench.recent.title, imageWorkbench.recent.hint, imageWorkbench.generating.label, imageWorkbench.emptyState.message, imageWorkbench.relay.note) and then update all call sites that reference the old literal English keys to use these new keys (search for the original strings in UI components and change i18n lookup calls to the corresponding imageWorkbench.* keys).
🧹 Nitpick comments (3)
web/default/src/i18n/locales/zh.json (1)
1976-2000: 🏗️ Heavy liftUse hierarchical i18n keys for new image-workbench strings
The new entries use sentence-literal keys; this should be namespaced (e.g.,
imageWorkbench.status.completed,imageWorkbench.help.relayBilling) to match the required i18n key strategy and keep this module maintainable as it grows.As per coding guidelines, "Use hierarchical and semantically clear translation key names such as
dashboard.overview.titleand maintain naming consistency".🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@web/default/src/i18n/locales/zh.json` around lines 1976 - 2000, Current literal sentence keys (e.g., "Image generation completed.", "Generate images with relay billing.", "Image Workspace", "Please enter an image prompt.", etc.) should be replaced with hierarchical, namespaced keys and kept with the same translations; for example map UI strings to keys like imageWorkbench.status.completed, imageWorkbench.status.failed, imageWorkbench.ui.workspace, imageWorkbench.input.placeholder, imageWorkbench.billing.relayInfo, imageWorkbench.recent.title, imageWorkbench.preview.label, imageWorkbench.format.output and so on—update each corresponding key in the JSON to the new dotted names and keep the existing Chinese values, ensuring naming consistency and grouping all image-workbench strings under the imageWorkbench namespace.web/default/src/features/image-workbench/types.ts (1)
23-33: ⚡ Quick winNarrow
GeneratedImage.outputFormatto a union instead ofstring.Using a broad
stringweakens compile-time validation and allows invalid persisted values. Reuse explicit output format unions across request/state types.♻️ Suggested typing cleanup
+export type ImageOutputFormat = 'png' | 'jpeg' | 'webp' + export type ImageWorkbenchRequest = { model: string group?: string prompt: string n: number size: string quality: string response_format: 'b64_json' | 'url' - output_format?: 'png' | 'jpeg' | 'webp' + output_format?: ImageOutputFormat } @@ export type GeneratedImage = { @@ - outputFormat: string + outputFormat: ImageOutputFormat createdAt: string }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@web/default/src/features/image-workbench/types.ts` around lines 23 - 33, Replace the loose string type for GeneratedImage.outputFormat with the shared explicit union type used elsewhere (e.g., the OutputFormat or ImageFormat union used in request/state types); update the GeneratedImage type to reference that union instead of string so persisted values are validated at compile time and consistent across request and state types.controller/playground.go (1)
63-108: ⚡ Quick winExtract a shared helper to avoid the ~90% duplication between
PlaygroundandPlaygroundImage.The two handlers differ only in the relay format, token-name prefix, and a single
c.Set("relay_mode", ...)line. Keeping them separate means any future change to the shared logic (error handling,userCache, token construction) must be applied in two places.♻️ Proposed refactor
+func playgroundRelay( + c *gin.Context, + relayFormat types.RelayFormatType, + tokenPrefix string, +) { + var newAPIError *types.NewAPIError + defer func() { + if newAPIError != nil { + c.JSON(newAPIError.StatusCode, gin.H{"error": newAPIError.ToOpenAIError()}) + } + }() + + useAccessToken := c.GetBool("use_access_token") + if useAccessToken { + newAPIError = types.NewError( + errors.New("暂不支持使用 access token"), + types.ErrorCodeAccessDenied, + types.ErrOptionWithSkipRetry(), + ) + return + } + + relayInfo, err := relaycommon.GenRelayInfo(c, relayFormat, nil, nil) + if err != nil { + newAPIError = types.NewError(err, types.ErrorCodeInvalidRequest, types.ErrOptionWithSkipRetry()) + return + } + + userId := c.GetInt("id") + userCache, err := model.GetUserCache(userId) + if err != nil { + newAPIError = types.NewError(err, types.ErrorCodeQueryDataError, types.ErrOptionWithSkipRetry()) + return + } + userCache.WriteContext(c) + + tempToken := &model.Token{ + UserId: userId, + Name: fmt.Sprintf("%s-%s", tokenPrefix, relayInfo.UsingGroup), + Group: relayInfo.UsingGroup, + } + _ = middleware.SetupContextForToken(c, tempToken) + Relay(c, relayFormat) +} func Playground(c *gin.Context) { - var newAPIError *types.NewAPIError - defer func() { ... }() - // ... identical body ... - Relay(c, types.RelayFormatOpenAI) + playgroundRelay(c, types.RelayFormatOpenAI, "playground") } func PlaygroundImage(c *gin.Context) { c.Set("relay_mode", relayconstant.RelayModeImagesGenerations) - var newAPIError *types.NewAPIError - defer func() { ... }() - // ... identical body ... - Relay(c, types.RelayFormatOpenAIImage) + playgroundRelay(c, types.RelayFormatOpenAIImage, "image-workbench") }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@controller/playground.go` around lines 63 - 108, Extract the shared logic in PlaygroundImage and Playground into a helper like runPlayground(c *gin.Context, relayFormat string, tokenPrefix string, relayMode string) that performs the access-token check, calls relaycommon.GenRelayInfo(c, relayFormat, ...), fetches userCache via model.GetUserCache, calls userCache.WriteContext(c), constructs the temp token Name with fmt.Sprintf("%s-%s", tokenPrefix, relayInfo.UsingGroup), calls middleware.SetupContextForToken(c, tempToken), sets c.Set("relay_mode", relayMode) and finally calls Relay(c, relayFormat); have both PlaygroundImage and Playground call this helper with types.RelayFormatOpenAIImage / "image-workbench" / relayconstant.RelayModeImagesGenerations and the other handler pass its respective relayFormat, tokenPrefix and relayMode, and surface any errors from GenRelayInfo or GetUserCache back as types.NewError consistent with existing error handling.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@web/default/src/features/image-workbench/api.ts`:
- Around line 7-9: Create a central extended request config type in lib/api.ts
that extends AxiosRequestConfig and adds the custom flags (skipErrorHandler,
skipBusinessError, disableDuplicate), export that type, then replace the unsafe
cast in features/image-workbench/api.ts (the api.post call using "as
Record<string, unknown>") to use the new exported type; also update any other
API calls that rely on those interceptor flags to import and use this extended
config so the custom properties are properly typed across the codebase.
In `@web/default/src/features/image-workbench/index.tsx`:
- Around line 102-111: persistHistory currently attempts to store full
GeneratedImage objects (including large b64_json image data) into localStorage
which will trigger QuotaExceededError and is silently swallowed; change
persistHistory to persist only a lightweight metadata object (fields like
prompt, model, size, quality, createdAt, id, outputFormat) and exclude
src/b64_json, and if thumbnails are needed add code that generates and stores a
small low-resolution data URL via canvas resizing before saving; update any code
that reads history to expect the reduced shape and retain the full image
elsewhere (e.g., server or indexedDB) or regenerate on demand.
- Around line 156-169: The fallback group option strings in the useMemo for
groupOptions are hard-coded ('Auto' and 'Circuit Breaker') and must be wrapped
with the i18n t() function; update the component to obtain t from
useTranslation() (if not already present) and replace the label and desc values
in the DEFAULT_GROUP fallback object to use t('imageWorkbench.auto') and
t('imageWorkbench.circuitBreaker') (or appropriate keys), and ensure those keys
are added to the locale files so translations work on language change; keep the
rest of the logic around groupsData, DEFAULT_GROUP, and useMemo unchanged.
- Around line 470-523: The CardContent contains a two-level nested ternary using
isGenerating ? ... : resultImages.length === 0 ? ... : ..., which violates the
nested-ternary guideline; refactor by extracting the JSX into a small render
helper or assign the conditional block to a variable (e.g., renderImageContent
or imageContent) above the component's return, and inside that helper use clear
if/else or early returns to handle the three cases (isGenerating, empty
resultImages, and populated resultImages) while keeping references to
resultImages.map, image.id, image.src, image.prompt, and downloadImage unchanged
so the button behavior and badges remain intact.
---
Outside diff comments:
In `@web/default/src/i18n/locales/en.json`:
- Around line 1976-2000: Replace the raw English sentence keys in this JSON
(e.g., "Image generation completed.", "Image input", "Generating image...",
etc.) with hierarchical semantic keys (suggested:
imageWorkbench.status.completed, imageWorkbench.status.failed,
imageWorkbench.workspace.title, imageWorkbench.input.label,
imageWorkbench.input.price, imageWorkbench.output.label,
imageWorkbench.output.price, imageWorkbench.preview.title,
imageWorkbench.ratio.label, imageWorkbench.tools.toVideo,
imageWorkbench.tokens.label, imageWorkbench.generate.description,
imageWorkbench.generate.relayFlow, imageWorkbench.generate.costsExplanation,
imageWorkbench.form.promptPlaceholder, imageWorkbench.errors.noData,
imageWorkbench.errors.generationFailed, imageWorkbench.form.outputFormat,
imageWorkbench.recent.title, imageWorkbench.recent.hint,
imageWorkbench.generating.label, imageWorkbench.emptyState.message,
imageWorkbench.relay.note) and then update all call sites that reference the old
literal English keys to use these new keys (search for the original strings in
UI components and change i18n lookup calls to the corresponding imageWorkbench.*
keys).
---
Nitpick comments:
In `@controller/playground.go`:
- Around line 63-108: Extract the shared logic in PlaygroundImage and Playground
into a helper like runPlayground(c *gin.Context, relayFormat string, tokenPrefix
string, relayMode string) that performs the access-token check, calls
relaycommon.GenRelayInfo(c, relayFormat, ...), fetches userCache via
model.GetUserCache, calls userCache.WriteContext(c), constructs the temp token
Name with fmt.Sprintf("%s-%s", tokenPrefix, relayInfo.UsingGroup), calls
middleware.SetupContextForToken(c, tempToken), sets c.Set("relay_mode",
relayMode) and finally calls Relay(c, relayFormat); have both PlaygroundImage
and Playground call this helper with types.RelayFormatOpenAIImage /
"image-workbench" / relayconstant.RelayModeImagesGenerations and the other
handler pass its respective relayFormat, tokenPrefix and relayMode, and surface
any errors from GenRelayInfo or GetUserCache back as types.NewError consistent
with existing error handling.
In `@web/default/src/features/image-workbench/types.ts`:
- Around line 23-33: Replace the loose string type for
GeneratedImage.outputFormat with the shared explicit union type used elsewhere
(e.g., the OutputFormat or ImageFormat union used in request/state types);
update the GeneratedImage type to reference that union instead of string so
persisted values are validated at compile time and consistent across request and
state types.
In `@web/default/src/i18n/locales/zh.json`:
- Around line 1976-2000: Current literal sentence keys (e.g., "Image generation
completed.", "Generate images with relay billing.", "Image Workspace", "Please
enter an image prompt.", etc.) should be replaced with hierarchical, namespaced
keys and kept with the same translations; for example map UI strings to keys
like imageWorkbench.status.completed, imageWorkbench.status.failed,
imageWorkbench.ui.workspace, imageWorkbench.input.placeholder,
imageWorkbench.billing.relayInfo, imageWorkbench.recent.title,
imageWorkbench.preview.label, imageWorkbench.format.output and so on—update each
corresponding key in the JSON to the new dotted names and keep the existing
Chinese values, ensuring naming consistency and grouping all image-workbench
strings under the imageWorkbench namespace.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: f0aa6afd-37d6-4c26-81bb-2fef1c84436b
📒 Files selected for processing (20)
common/model.gocommon/model_test.gocontroller/playground.gomiddleware/distributor.gorelay/channel/openai/constant.gorelay/constant/relay_mode.gorouter/relay-router.goweb/default/src/features/image-workbench/api.tsweb/default/src/features/image-workbench/index.tsxweb/default/src/features/image-workbench/types.tsweb/default/src/features/profile/components/sidebar-modules-card.tsxweb/default/src/features/system-settings/maintenance/config.tsweb/default/src/features/system-settings/maintenance/sidebar-modules-section.tsxweb/default/src/hooks/use-sidebar-config.tsweb/default/src/hooks/use-sidebar-data.tsweb/default/src/i18n/locales/en.jsonweb/default/src/i18n/locales/zh.jsonweb/default/src/i18n/static-keys.tsweb/default/src/routeTree.gen.tsweb/default/src/routes/_authenticated/image-workbench/index.tsx
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@web/default/src/lib/api.ts`:
- Line 2: Run the project's type checker (bun run typecheck) and fix all
TypeScript errors until typecheck passes; specifically, in the module that
imports AxiosRequestConfig ensure the imported symbol (AxiosRequestConfig) is
either used in function signatures or removed, correct any incorrect
parameter/return types on the API functions that rely on that config, and add
explicit typing or casts where necessary so the file compiles cleanly with the
project's tsconfig/type rules.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: d8962282-8173-44c7-b30d-3bd21126922a
📒 Files selected for processing (11)
web/default/src/features/auth/hooks/use-oauth-login.tsweb/default/src/features/auth/reset-password-confirm/index.tsxweb/default/src/features/channels/api.tsweb/default/src/features/channels/hooks/use-channel-upstream-updates.tsweb/default/src/features/image-workbench/api.tsweb/default/src/features/models/api.tsweb/default/src/features/playground/api.tsweb/default/src/features/system-settings/general/channel-affinity/api.tsweb/default/src/features/wallet/api.tsweb/default/src/lib/api.tsweb/default/src/routes/oauth/$provider.tsx
✅ Files skipped from review due to trivial changes (2)
- web/default/src/features/wallet/api.ts
- web/default/src/routes/oauth/$provider.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
- web/default/src/features/image-workbench/api.ts
Summary
Verification
Notes
Summary by CodeRabbit
New Features
Tests