@deenruv/replicate-simple-bg-plugin 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/LICENSE +23 -0
  2. package/README.md +54 -0
  3. package/dist/plugin-server/constants.d.ts +13 -0
  4. package/dist/plugin-server/constants.js +122 -0
  5. package/dist/plugin-server/entities/replicate-simple-bg.d.ts +11 -0
  6. package/dist/plugin-server/entities/replicate-simple-bg.js +49 -0
  7. package/dist/plugin-server/extensions/replicate-simple-bg.extension.d.ts +1 -0
  8. package/dist/plugin-server/extensions/replicate-simple-bg.extension.js +105 -0
  9. package/dist/plugin-server/graphql/generated-admin-types.d.ts +5807 -0
  10. package/dist/plugin-server/graphql/generated-admin-types.js +1030 -0
  11. package/dist/plugin-server/index.d.ts +5 -0
  12. package/dist/plugin-server/index.js +40 -0
  13. package/dist/plugin-server/resolvers/replicate-simple-bg-admin.resolver.d.ts +51 -0
  14. package/dist/plugin-server/resolvers/replicate-simple-bg-admin.resolver.js +105 -0
  15. package/dist/plugin-server/services/replicate-simple-bg.service.d.ts +45 -0
  16. package/dist/plugin-server/services/replicate-simple-bg.service.js +254 -0
  17. package/dist/plugin-server/types.d.ts +29 -0
  18. package/dist/plugin-server/types.js +2 -0
  19. package/dist/plugin-server/zeus/const.d.ts +6 -0
  20. package/dist/plugin-server/zeus/const.js +3714 -0
  21. package/dist/plugin-server/zeus/index.d.ts +18885 -0
  22. package/dist/plugin-server/zeus/index.js +1101 -0
  23. package/dist/plugin-server/zeus/typedDocumentNode.d.ts +3 -0
  24. package/dist/plugin-server/zeus/typedDocumentNode.js +13 -0
  25. package/dist/plugin-ui/components/FileUpload.d.ts +11 -0
  26. package/dist/plugin-ui/components/FileUpload.js +50 -0
  27. package/dist/plugin-ui/components/RoomStyleSelect.d.ts +7 -0
  28. package/dist/plugin-ui/components/RoomStyleSelect.js +19 -0
  29. package/dist/plugin-ui/components/RoomTypeSelect.d.ts +7 -0
  30. package/dist/plugin-ui/components/RoomTypeSelect.js +21 -0
  31. package/dist/plugin-ui/components/index.d.ts +1 -0
  32. package/dist/plugin-ui/components/index.js +1 -0
  33. package/dist/plugin-ui/constants.d.ts +1 -0
  34. package/dist/plugin-ui/constants.js +15 -0
  35. package/dist/plugin-ui/graphql/mutations.d.ts +22 -0
  36. package/dist/plugin-ui/graphql/mutations.js +21 -0
  37. package/dist/plugin-ui/graphql/queries.d.ts +87 -0
  38. package/dist/plugin-ui/graphql/queries.js +32 -0
  39. package/dist/plugin-ui/graphql/selectors.d.ts +43 -0
  40. package/dist/plugin-ui/graphql/selectors.js +38 -0
  41. package/dist/plugin-ui/index.d.ts +1 -0
  42. package/dist/plugin-ui/index.js +33 -0
  43. package/dist/plugin-ui/locales/en/index.d.ts +67 -0
  44. package/dist/plugin-ui/locales/en/index.js +2 -0
  45. package/dist/plugin-ui/locales/en/simpleBg.json +66 -0
  46. package/dist/plugin-ui/locales/pl/index.d.ts +67 -0
  47. package/dist/plugin-ui/locales/pl/index.js +2 -0
  48. package/dist/plugin-ui/locales/pl/simpleBg.json +66 -0
  49. package/dist/plugin-ui/pages/ReplicatePage.d.ts +2 -0
  50. package/dist/plugin-ui/pages/ReplicatePage.js +282 -0
  51. package/dist/plugin-ui/pages/ReplicateProductSidebar.d.ts +2 -0
  52. package/dist/plugin-ui/pages/ReplicateProductSidebar.js +186 -0
  53. package/dist/plugin-ui/translation-ns.d.ts +1 -0
  54. package/dist/plugin-ui/translation-ns.js +1 -0
  55. package/dist/plugin-ui/tsconfig.json +18 -0
  56. package/dist/plugin-ui/types.d.ts +35 -0
  57. package/dist/plugin-ui/types.js +15 -0
  58. package/dist/plugin-ui/zeus/const.d.ts +6 -0
  59. package/dist/plugin-ui/zeus/const.js +3711 -0
  60. package/dist/plugin-ui/zeus/index.d.ts +18885 -0
  61. package/dist/plugin-ui/zeus/index.js +1093 -0
  62. package/dist/plugin-ui/zeus/scalars.d.ts +18 -0
  63. package/dist/plugin-ui/zeus/scalars.js +25 -0
  64. package/dist/plugin-ui/zeus/typedDocumentNode.d.ts +3 -0
  65. package/dist/plugin-ui/zeus/typedDocumentNode.js +9 -0
  66. package/package.json +53 -0
@@ -0,0 +1,2 @@
1
+ import badges from "./simpleBg.json";
2
+ export default [badges];
@@ -0,0 +1,66 @@
1
+ {
2
+ "input": "Wejście",
3
+ "output": "Wyjście",
4
+ "run_model": "Uruchom Model",
5
+ "upload_furniture_image": "Prześlij zdjęcie mebla",
6
+ "original_room": "Oryginalny Pokój",
7
+ "choose_room_type_and_theme": "Wybierz pomieszczenie i styl pokoju",
8
+ "select_room_type": "Wybierz pomieszczenie",
9
+ "select_room_theme": "Wybierz styl",
10
+ "generated_room": "Wygenerowany Pokój",
11
+ "loading": "Oczekiwanie na wynik... (ok. 2min)",
12
+ "download_image": "Pobierz Obraz",
13
+ "bedroom": "Sypialnia",
14
+ "living_room": "Salon",
15
+ "dining_room": "Jadalnia",
16
+ "kitchen": "Kuchnia",
17
+ "bathroom": "Łazienka",
18
+ "office": "Biuro",
19
+ "modern": "Nowoczesny",
20
+ "summer": "Letni",
21
+ "professional": "Profesjonalny",
22
+ "tropical": "Tropikalny",
23
+ "coastal": "Nadmorski",
24
+ "vintage": "Vintage",
25
+ "industrial": "Industrialny",
26
+ "neoclassic": "Neoklasyczny",
27
+ "choose_file": "Wybierz plik",
28
+ "no_file_chosen": "Nie wybrano pliku",
29
+ "previous_predictions": "Poprzednie Predykcje",
30
+ "starting": "W trakcie",
31
+ "preprocessing": "Przetwarzanie",
32
+ "succeeded": "Zakończono",
33
+ "failed": "Niepowodzenie",
34
+ "generate_new_background": "Wygeneruj nowe tło",
35
+ "no_room_style": "Brak stylu pomieszczenia",
36
+ "no_room_type": "Brak rodzaju pomieszczenia",
37
+ "no_file": "Brak pliku",
38
+ "refresh": "Odśwież liste",
39
+ "status": "Status",
40
+ "room_type": "Rodzaj pokoju",
41
+ "room_style": "Styl pokoju",
42
+ "prediction": "Predykcja",
43
+ "prediction_details": "Szczególy predykcji",
44
+ "generating_asset": "Generenowanie zdjęcia..",
45
+ "asset_assigned": "Zdjęcie przypisane do produktu",
46
+ "prompt_placeholder": "Czy chcesz coś zmienić? Opisz to tutaj!",
47
+ "prompt": "Zapytanie",
48
+ "error": {
49
+ "loading": "Trwa generowanie zdjęcia.."
50
+ },
51
+ "modal": {
52
+ "title": "Predykcja",
53
+ "choose_room_type": "Wybierz pomieszczenie",
54
+ "choose_room_theme": "Wybierz styl",
55
+ "generate_new": "Wygeneruj nowy",
56
+ "close": "Wyjdź",
57
+ "add_to_product": "Dodaj do produktu",
58
+ "assign_prediction_to_product": "Przypisz predykcję do produktu",
59
+ "product_name": "Nazwa",
60
+ "product_sku": "SKU",
61
+ "product_action": "Akcja",
62
+ "product_assign": "Przypisz",
63
+ "run_model_again": "Uruchom model ponownie",
64
+ "input_prompt": "Czy chcesz coś zmienić? Opisz to tutaj!"
65
+ }
66
+ }
@@ -0,0 +1,2 @@
1
+ import React from "react";
2
+ export declare const ReplicatePage: () => React.JSX.Element;
@@ -0,0 +1,282 @@
1
+ "use client";
2
+ import { apiClient, apiUploadClient, Button, Card, CardContent, CardFooter, CardHeader, CardTitle, cn, DialogProductPicker, Label, PageBlock, ScrollArea, useLazyQuery, useMutation, useQuery, useTranslation, } from "@deenruv/react-ui-devkit";
3
+ import { useEffect, useMemo, useRef, useState } from "react";
4
+ import { translationNS } from "../translation-ns.js";
5
+ import { getPredictionSimpleBGIDQuery, getSimpleBgItemQuery, getSimpleBgPredictionsQuery, getSimpleBgRoomOptions, } from "../graphql/queries.js";
6
+ import { SortOrder } from "../zeus/index.js";
7
+ import React from "react";
8
+ import { FileUpload } from "../components/FileUpload.js";
9
+ import { getPredictionAssetMutation, startGenerateSimpleBgMutation, } from "../graphql/mutations.js";
10
+ import { $ } from "@deenruv/admin-types";
11
+ import { Loader2 } from "lucide-react";
12
+ import { useSearchParams } from "react-router-dom";
13
+ import { toast } from "sonner";
14
+ import { RoomStyleSelect } from "../components/RoomStyleSelect.js";
15
+ import { RoomTypeSelect } from "../components/RoomTypeSelect.js";
16
+ export const ReplicatePage = () => {
17
+ const { t } = useTranslation(translationNS);
18
+ const [uploadState, setUploadState] = useState({
19
+ file: null,
20
+ room_style_enum: undefined,
21
+ room_type_enum: undefined,
22
+ });
23
+ const { data } = useQuery(getSimpleBgRoomOptions);
24
+ const [getPredictionID] = useLazyQuery(getPredictionSimpleBGIDQuery);
25
+ const [searchParams, setSearchParams] = useSearchParams();
26
+ const predictionEntityID = searchParams.get("predictionId");
27
+ const [getPredictionItem, { data: predictionItem }] = useLazyQuery(getSimpleBgItemQuery);
28
+ const [loading, setLoading] = useState(false);
29
+ const [uploadLoading, setUploadLoading] = useState(false);
30
+ const [startGenerateSimpleBg] = useMutation(startGenerateSimpleBgMutation);
31
+ const [predictions, setPredictions] = useState();
32
+ const [getReplicatePredictions, { loading: loadingPredictions }] = useLazyQuery(getSimpleBgPredictionsQuery);
33
+ const [getPredictionAsset] = useMutation(getPredictionAssetMutation);
34
+ const [page, setPage] = useState(1);
35
+ const [filters] = useState({
36
+ sort: { finishedAt: SortOrder.DESC },
37
+ filter: { status: { eq: "succeeded" } },
38
+ });
39
+ useEffect(() => {
40
+ getReplicatePredictions({
41
+ options: {
42
+ ...filters,
43
+ take: page * 10,
44
+ skip: (page - 1) * 10,
45
+ },
46
+ }).then((res) => {
47
+ setPredictions((prev) => [...(prev || []), ...res.getSimpleBgPredictions.items].filter((p, i, a) => a.findIndex((t) => t.id === p.id) === i));
48
+ });
49
+ }, []);
50
+ const intervalRef = useRef(null);
51
+ useEffect(() => {
52
+ if (predictionEntityID &&
53
+ predictionItem?.getSimpleBgItem.status !== "succeeded") {
54
+ setLoading(true);
55
+ intervalRef.current = setInterval(() => {
56
+ getPredictionID({
57
+ prediction_simple_bg_entity_id: predictionEntityID,
58
+ }).then((res) => {
59
+ const predictionID = res.getSimpleBgID;
60
+ if (predictionID) {
61
+ getPredictionItem({ id: predictionID });
62
+ }
63
+ });
64
+ }, 5000);
65
+ }
66
+ return () => {
67
+ if (intervalRef.current) {
68
+ clearInterval(intervalRef.current);
69
+ intervalRef.current = null;
70
+ }
71
+ };
72
+ }, [predictionEntityID]);
73
+ useEffect(() => {
74
+ if (predictionItem?.getSimpleBgItem.status === "succeeded" &&
75
+ intervalRef.current) {
76
+ clearInterval(intervalRef.current);
77
+ intervalRef.current = null;
78
+ setLoading(false);
79
+ setPage(1);
80
+ getReplicatePredictions({
81
+ options: { ...filters, take: 10, skip: 0 },
82
+ }).then((res) => {
83
+ setPredictions(res.getSimpleBgPredictions.items);
84
+ });
85
+ }
86
+ }, [predictionItem?.getSimpleBgItem.status]);
87
+ const getReplicateItem = async (id) => {
88
+ const scrollToElement = document.getElementById("scrollto");
89
+ if (scrollToElement) {
90
+ scrollToElement.scrollIntoView({
91
+ behavior: "smooth",
92
+ block: "start",
93
+ });
94
+ }
95
+ await getPredictionItem({ id });
96
+ };
97
+ const generateSimpleBg = async () => {
98
+ try {
99
+ const { file, room_style_enum, room_type_enum } = uploadState;
100
+ switch (true) {
101
+ case !room_style_enum: {
102
+ toast.error(t("no_room_style"));
103
+ break;
104
+ }
105
+ case !room_type_enum: {
106
+ toast.error(t("no_room_type"));
107
+ break;
108
+ }
109
+ case !file: {
110
+ toast.error(t("no_file"));
111
+ break;
112
+ }
113
+ default: {
114
+ setUploadLoading(true);
115
+ const { createAssets } = await apiUploadClient("mutation")({
116
+ createAssets: [
117
+ { input: $("input", "[CreateAssetInput!]!") },
118
+ {
119
+ __typename: true,
120
+ "...on Asset": { id: true, source: true },
121
+ "...on MimeTypeError": {
122
+ fileName: true,
123
+ mimeType: true,
124
+ errorCode: true,
125
+ message: true,
126
+ },
127
+ },
128
+ ],
129
+ }, { variables: { input: [{ file }] } });
130
+ const asset = createAssets[0];
131
+ if (!asset || asset.__typename !== "Asset")
132
+ throw new Error("Cannot upload image");
133
+ const response = await startGenerateSimpleBg({
134
+ input: {
135
+ assetId: asset.id,
136
+ roomStyle: room_style_enum,
137
+ roomType: room_type_enum,
138
+ },
139
+ });
140
+ setSearchParams({ predictionId: response.startGenerateSimpleBg });
141
+ }
142
+ }
143
+ }
144
+ catch {
145
+ }
146
+ finally {
147
+ setUploadLoading(false);
148
+ }
149
+ };
150
+ const uploadButtonDisabled = useMemo(() => !uploadState.file ||
151
+ !uploadState.room_style_enum ||
152
+ !uploadState.room_type_enum, [uploadState.file, uploadState.room_style_enum, uploadState.room_type_enum]);
153
+ return (React.createElement(PageBlock, null,
154
+ React.createElement("div", { className: "flex justify-between gap-4" },
155
+ React.createElement(Card, { className: "w-full h-full" },
156
+ React.createElement(CardHeader, null,
157
+ React.createElement(CardTitle, null, t("input"))),
158
+ React.createElement(CardContent, null,
159
+ React.createElement("div", { className: "flex flex-col gap-4" },
160
+ React.createElement(RoomTypeSelect, { roomTypes: data?.getSimpleBgOptions.roomTypes, selectedValue: uploadState.room_type_enum, onValueChange: (newValue) => setUploadState((prev) => ({
161
+ ...prev,
162
+ room_type_enum: newValue,
163
+ })) }),
164
+ React.createElement(RoomStyleSelect, { selectedValue: uploadState.room_style_enum, roomThemes: data?.getSimpleBgOptions.roomThemes, onSelect: (value) => setUploadState((prev) => ({
165
+ ...prev,
166
+ room_style_enum: value,
167
+ })) }),
168
+ React.createElement("div", null,
169
+ React.createElement(Label, { className: "block text-sm font-medium mb-2" }, t("upload_image")),
170
+ React.createElement(FileUpload, { value: uploadState.file, onChange: (file) => {
171
+ setUploadState((prev) => ({
172
+ ...prev,
173
+ file,
174
+ }));
175
+ } })))),
176
+ React.createElement(CardFooter, { className: "flex justify-end items-center w-full" },
177
+ React.createElement(Button, { className: "relative", type: "button", onClick: generateSimpleBg, disabled: uploadButtonDisabled || uploadLoading || loading },
178
+ React.createElement("span", { className: cn("transition-opacity", uploadLoading && "opacity-0") }, t("run_model")),
179
+ uploadLoading && (React.createElement("div", { className: "absolute inset-0 flex items-center justify-center" },
180
+ React.createElement(Loader2, { className: "animate-spin", size: 16, strokeWidth: 2 })))))),
181
+ React.createElement(Card, { className: "w-full h-[500px]" },
182
+ React.createElement(CardHeader, null,
183
+ React.createElement("div", { className: "flex w-full flex-row items-center justify-between" },
184
+ React.createElement(CardTitle, null, t("previous_predictions")))),
185
+ React.createElement(CardContent, null,
186
+ React.createElement(ScrollArea, { className: "h-[350px] pr-4", id: "scrollable" }, predictions?.length === 0 ? (React.createElement("div", { className: "flex items-center justify-center h-full" },
187
+ React.createElement("p", { className: "text-muted-foreground" }, t("no_predictions")))) : (React.createElement("div", { className: "flex flex-col gap-2" }, predictions?.map((prediction) => (React.createElement(Card, { key: prediction.id, className: cn("flex items-center justify-between p-2 cursor-pointer", predictionItem?.getSimpleBgItem.id === prediction.id
188
+ ? "bg-primary text-primary-foreground"
189
+ : "hover:bg-secondary hover:text-secondary-foreground", loading ? "pointer-events-none" : ""), onClick: async () => {
190
+ if (loading)
191
+ return;
192
+ await getReplicateItem(prediction.id);
193
+ } },
194
+ prediction.id,
195
+ " - ",
196
+ prediction.status,
197
+ " -",
198
+ " ",
199
+ prediction.finishedAt))))))),
200
+ React.createElement(CardFooter, { className: "flex justify-end items-center w-full" },
201
+ React.createElement(Button, { type: "button", disabled: loadingPredictions || loading, onClick: () => {
202
+ setPage((prev) => prev + 1);
203
+ getReplicatePredictions({
204
+ options: {
205
+ ...filters,
206
+ take: page * 10,
207
+ skip: (page - 1) * 10,
208
+ },
209
+ }).then((res) => {
210
+ const scrollableElement = document.getElementById("scrollable");
211
+ if (scrollableElement) {
212
+ scrollableElement.scrollTop = 0;
213
+ }
214
+ setPredictions((prev) => [
215
+ ...(prev || []),
216
+ ...res.getSimpleBgPredictions.items,
217
+ ].filter((p, i, a) => a.findIndex((t) => t.id === p.id) === i));
218
+ });
219
+ } }, t("refresh"))))),
220
+ React.createElement(Card, { className: "w-full mt-4" },
221
+ React.createElement(CardHeader, null,
222
+ React.createElement("div", { className: "flex w-full flex-row items-center justify-between" },
223
+ React.createElement(CardTitle, null, t("output")))),
224
+ React.createElement(CardContent, null, loading ? (React.createElement("div", { className: "flex flex-col gap-2 items-center justify-center h-[350px] w-full" },
225
+ React.createElement(Loader2, { className: "animate-spin text-primary", size: 24, strokeWidth: 2 }),
226
+ React.createElement("p", { className: "text-muted-foreground" }, t("loading")))) : predictionItem?.getSimpleBgItem?.image ? (React.createElement("div", { className: "h-[450px] w-full flex justify-between items-start gap-8" },
227
+ React.createElement("div", { className: "relative w-full h-full overflow-hidden rounded-lg" },
228
+ React.createElement("img", { className: "absolute inset-0 w-full h-full object-cover rounded-md", src: predictionItem.getSimpleBgItem.image || "/placeholder.svg", alt: "Generated Room" })),
229
+ React.createElement(Card, { className: "w-full h-full flex-col flex justify-between" },
230
+ React.createElement("div", { className: "flex flex-col gap-2" },
231
+ React.createElement(CardHeader, null,
232
+ React.createElement(CardTitle, null, t("prediction_details"))),
233
+ React.createElement(CardContent, null,
234
+ predictionItem.getSimpleBgItem.roomType && (React.createElement("div", null,
235
+ React.createElement("p", { className: "text-sm font-semibold" },
236
+ t("room_type"),
237
+ ":"),
238
+ React.createElement("p", { className: "text-sm text-muted-foreground" }, predictionItem.getSimpleBgItem.roomType))),
239
+ predictionItem.getSimpleBgItem.roomStyle && (React.createElement("div", null,
240
+ React.createElement("p", { className: "text-sm font-semibold" },
241
+ t("room_style"),
242
+ ":"),
243
+ React.createElement("p", { className: "text-sm text-muted-foreground" }, predictionItem.getSimpleBgItem.roomStyle))),
244
+ predictionItem.getSimpleBgItem.status && (React.createElement("div", null,
245
+ React.createElement("p", { className: "text-sm font-semibold" },
246
+ t("status"),
247
+ ":"),
248
+ React.createElement("p", { className: "text-sm text-muted-foreground" }, predictionItem.getSimpleBgItem.status))))),
249
+ React.createElement(CardFooter, null,
250
+ React.createElement(DialogProductPicker, { initialValue: "", mode: "product", onSubmit: async ({ productId }) => {
251
+ const response = await apiClient("query")({
252
+ product: [{ id: productId }, { assets: { id: true } }],
253
+ });
254
+ const asset = await getPredictionAsset({
255
+ input: {
256
+ predictionId: predictionEntityID ?? "",
257
+ productId,
258
+ },
259
+ });
260
+ const assetIds = response.product?.assets
261
+ .map((asset) => asset.id)
262
+ .concat(asset.getPredictionAsset.id);
263
+ const { updateProduct } = await apiClient("mutation")({
264
+ updateProduct: [
265
+ { input: { id: productId, assetIds } },
266
+ { id: true },
267
+ ],
268
+ });
269
+ // toast(
270
+ // <div className="flex gap-2 items-center">
271
+ // <p className="text-sm font-semibold">
272
+ // {t("prediction_assigned")}
273
+ // </p>
274
+ // <Link to={Routes.products.to(updateProduct.id)}>
275
+ // {t("view_product")}
276
+ // </Link>
277
+ // </div>,
278
+ // );
279
+ } }))))) : (React.createElement("div", { className: "flex items-center justify-center h-[350px]" },
280
+ React.createElement("p", { className: "text-muted-foreground" }, t("no_output")))))),
281
+ React.createElement("div", { id: "scrollto", className: "h-[50px]" })));
282
+ };
@@ -0,0 +1,2 @@
1
+ import React from "react";
2
+ export declare const ReplicateProductSidebar: React.FC;
@@ -0,0 +1,186 @@
1
+ import React, { useState, useRef, useEffect } from "react";
2
+ import { Card, CardHeader, Button, useDetailView, useMutation, Dialog, useTranslation, CardContent, cn, useQuery, DialogContent, DialogHeader, DialogTitle, CardTitle, useLazyQuery, Textarea, } from "@deenruv/react-ui-devkit";
3
+ import { translationNS } from "../translation-ns";
4
+ import { getPredictionAssetMutation, startGenerateSimpleBgMutation, } from "../graphql/mutations.js";
5
+ import { ChevronDown, Image, Loader2 } from "lucide-react";
6
+ import { getPredictionSimpleBGIDQuery, getSimpleBgItemQuery, getSimpleBgRoomOptions, } from "../graphql/queries.js";
7
+ import { toast } from "sonner";
8
+ import { RoomStyleSelect } from "../components/RoomStyleSelect.js";
9
+ import { RoomTypeSelect } from "../components/RoomTypeSelect.js";
10
+ export const ReplicateProductSidebar = () => {
11
+ const { t } = useTranslation(translationNS);
12
+ const { id: productId, entity, markAsDirty, form: { base: { state, setField }, }, } = useDetailView("products-detail-view");
13
+ const [form, setForm] = useState({ roomType: undefined, roomStyle: undefined, prompt: null });
14
+ const { data } = useQuery(getSimpleBgRoomOptions);
15
+ const [getPredictionItem, { data: predictionItem, setData: setPredictionItem },] = useLazyQuery(getSimpleBgItemQuery);
16
+ const [getPredictionID] = useLazyQuery(getPredictionSimpleBGIDQuery);
17
+ const [getPredictionAsset] = useMutation(getPredictionAssetMutation);
18
+ const [startGenerateSimpleBg, { loading: gettingInitialID }] = useMutation(startGenerateSimpleBgMutation);
19
+ const [predictionEntityID, setPredictionEntityID] = useState(null);
20
+ const [loading, setLoading] = useState(false);
21
+ const [isDialogVisible, setIsDialogVisible] = useState(false);
22
+ const [isOpen, setIsOpen] = useState(true);
23
+ const [height, setHeight] = useState(undefined);
24
+ const contentRef = useRef(null);
25
+ const intervalRef = useRef(null);
26
+ useEffect(() => {
27
+ if (predictionEntityID &&
28
+ predictionItem?.getSimpleBgItem.status !== "succeeded") {
29
+ setLoading(true);
30
+ intervalRef.current = setInterval(() => {
31
+ getPredictionID({
32
+ prediction_simple_bg_entity_id: predictionEntityID,
33
+ }).then((res) => {
34
+ const predictionID = res.getSimpleBgID;
35
+ if (predictionID) {
36
+ getPredictionItem({ id: predictionID });
37
+ }
38
+ });
39
+ }, 5000);
40
+ }
41
+ return () => {
42
+ if (intervalRef.current) {
43
+ clearInterval(intervalRef.current);
44
+ intervalRef.current = null;
45
+ }
46
+ };
47
+ }, [predictionEntityID]);
48
+ useEffect(() => {
49
+ if (predictionItem?.getSimpleBgItem.status === "succeeded" &&
50
+ intervalRef.current) {
51
+ clearInterval(intervalRef.current);
52
+ intervalRef.current = null;
53
+ setIsDialogVisible(true);
54
+ setLoading(false);
55
+ }
56
+ }, [predictionItem?.getSimpleBgItem.status]);
57
+ const handleClose = () => {
58
+ if (loading) {
59
+ toast.error(t("error.loading"));
60
+ return;
61
+ }
62
+ setIsDialogVisible(false);
63
+ setPredictionEntityID(null);
64
+ setForm({ roomType: undefined, roomStyle: undefined, prompt: null });
65
+ };
66
+ useEffect(() => {
67
+ if (contentRef.current) {
68
+ setHeight(isOpen ? contentRef.current.scrollHeight : 0);
69
+ }
70
+ }, [isOpen, contentRef.current, data?.getSimpleBgOptions]);
71
+ const runModel = async () => {
72
+ const assetId = entity?.featuredAsset?.id;
73
+ if (assetId) {
74
+ const { roomStyle, roomType, prompt } = form;
75
+ const response = await startGenerateSimpleBg({
76
+ input: { assetId, roomType, roomStyle, prompt },
77
+ });
78
+ const id = response.startGenerateSimpleBg;
79
+ if (!id) {
80
+ toast.error(t("error.start_model_run"));
81
+ return;
82
+ }
83
+ setPredictionEntityID(id);
84
+ }
85
+ };
86
+ const assignPredictionToProduct = async () => {
87
+ if (!productId || !predictionEntityID)
88
+ return;
89
+ const asset = await getPredictionAsset({
90
+ input: { predictionId: predictionEntityID, productId: productId },
91
+ });
92
+ if (!asset || !entity)
93
+ return;
94
+ const newAsset = asset.getPredictionAsset;
95
+ if (state.assetIds?.value) {
96
+ setField("assetIds", [...state.assetIds.value, newAsset.id]);
97
+ }
98
+ markAsDirty();
99
+ setIsDialogVisible(false);
100
+ setPredictionEntityID(null);
101
+ setForm({ roomType: undefined, roomStyle: undefined, prompt: null });
102
+ setLoading(false);
103
+ toast.success(t("success.asset_assigned"));
104
+ };
105
+ return (React.createElement(React.Fragment, null,
106
+ React.createElement("div", { className: "w-full flex flex-col gap-4" },
107
+ React.createElement(Card, { className: "overflow-hidden rounded-lg border bg-card border-l-orange-200 duration-200 hover:shadow h-full border-l-4" },
108
+ React.createElement(CardHeader, { className: "p-4 flex flex-row items-center justify-between cursor-pointer select-none", onClick: () => setIsOpen(!isOpen) },
109
+ React.createElement("div", { className: "flex items-center gap-2" },
110
+ React.createElement(Image, { className: "w-5 h-5 text-white/70" }),
111
+ React.createElement("span", { className: "font-semibold tracking-tight text-lg" }, t("generate_new_background"))),
112
+ React.createElement(ChevronDown, { className: cn("h-5 w-5 text-white/70 transition-transform duration-300 ease-in-out", isOpen && "transform -rotate-180") })),
113
+ React.createElement("div", { ref: contentRef, style: { height: height !== undefined ? `${height}px` : undefined }, className: cn("transition-all duration-300 ease-in-out p-2", !isOpen && "opacity-0") },
114
+ React.createElement(CardContent, { className: "pt-0 pb-4 px-4" },
115
+ React.createElement("div", { className: "flex flex-col gap-4" },
116
+ React.createElement(RoomStyleSelect, { selectedValue: form.roomStyle, roomThemes: data?.getSimpleBgOptions.roomThemes, onSelect: (value) => setForm((prev) => ({
117
+ ...prev,
118
+ roomStyle: value,
119
+ })) }),
120
+ React.createElement(RoomTypeSelect, { roomTypes: data?.getSimpleBgOptions.roomTypes, selectedValue: form.roomType, onValueChange: (newValue) => {
121
+ setForm((prev) => ({
122
+ ...prev,
123
+ roomType: newValue,
124
+ }));
125
+ } }),
126
+ React.createElement(Button, { className: "mt-2 relative", disabled: (!form.roomType || !form.roomStyle || loading) &&
127
+ !isDialogVisible, onClick: runModel },
128
+ React.createElement("span", { className: cn("transition-opacity", loading && "opacity-0") }, t("run_model")),
129
+ loading && (React.createElement("div", { className: "absolute inset-0 flex items-center gap-2 justify-center" },
130
+ React.createElement(Loader2, { className: "animate-spin", size: 16, strokeWidth: 2 }),
131
+ React.createElement("span", null, t("generating_asset")))))))))),
132
+ React.createElement(Dialog, { open: isDialogVisible, onOpenChange: handleClose },
133
+ React.createElement(DialogContent, { className: "w-full lg:max-w-[900px] xl:max-w-[1100px] h-[600px] grid-rows-[auto_1fr_auto]", onInteractOutside: (e) => e.preventDefault() },
134
+ React.createElement(DialogHeader, null,
135
+ React.createElement(DialogTitle, null, t("modal.title"))),
136
+ React.createElement("div", { className: "w-full h-full relative grid md:grid-cols-[1fr_auto] gap-2" },
137
+ React.createElement("div", { className: "flex flex-col gap-2 h-full" },
138
+ React.createElement("div", { className: "relative w-full min-h-[300px] grow overflow-hidden rounded-lg" }, predictionItem?.getSimpleBgItem.image ? (React.createElement("img", { className: "absolute inset-0 w-full h-full object-contain rounded-md", src: predictionItem?.getSimpleBgItem.image, alt: "Generated Room" })) : (React.createElement("div", { className: "absolute inset-0 flex items-center justify-center" },
139
+ React.createElement(Image, { className: "w-10 h-10 text-muted-foreground" }))))),
140
+ React.createElement("div", { className: "flex flex-col gap-2 w-[300px]" },
141
+ React.createElement(Card, { className: "w-full h-full flex-col flex justify-between" },
142
+ React.createElement("div", { className: "flex flex-col gap-2 h-full" },
143
+ React.createElement(CardHeader, null,
144
+ React.createElement(CardTitle, null, t("prediction_details"))),
145
+ React.createElement(CardContent, { className: "flex flex-col justify-between h-full" },
146
+ React.createElement("div", { className: "flex flex-col gap-2 h-full" },
147
+ React.createElement("div", { className: "flex flex-col gap-1" },
148
+ React.createElement("p", { className: "text-sm font-semibold" },
149
+ t("room_type"),
150
+ ":"),
151
+ React.createElement("p", { className: "text-sm text-muted-foreground" }, t(form.roomType?.toLowerCase() ||
152
+ predictionItem?.getSimpleBgItem.roomType ||
153
+ ""))),
154
+ React.createElement("div", { className: "flex flex-col gap-1" },
155
+ React.createElement("p", { className: "text-sm font-semibold" },
156
+ t("room_style"),
157
+ ":"),
158
+ React.createElement("p", { className: "text-sm text-muted-foreground" }, t(form.roomStyle?.toLowerCase() ||
159
+ predictionItem?.getSimpleBgItem.roomStyle ||
160
+ ""))),
161
+ React.createElement("div", { className: "flex flex-col gap-1" },
162
+ React.createElement("p", { className: "text-sm font-semibold" },
163
+ t("status"),
164
+ ":"),
165
+ React.createElement("p", { className: "text-sm text-muted-foreground" }, t(form.roomType?.toLowerCase() ||
166
+ predictionItem?.getSimpleBgItem.status ||
167
+ ""))),
168
+ React.createElement("div", { className: "flex flex-col gap-1" },
169
+ React.createElement("p", { className: "text-sm font-semibold" },
170
+ t("prompt"),
171
+ ":"),
172
+ React.createElement(Textarea, { className: "w-full h-24 resize-none", value: form.prompt || "", onChange: (e) => setForm((prev) => ({
173
+ ...prev,
174
+ prompt: e.target.value,
175
+ })), placeholder: t("modal.prompt_placeholder"), disabled: loading })),
176
+ React.createElement("div", { className: "w-full h-full flex flex-col justify-end" },
177
+ React.createElement(Button, { variant: "secondary", onClick: async () => {
178
+ setPredictionEntityID(null);
179
+ setPredictionItem(null);
180
+ await runModel();
181
+ }, disabled: loading || gettingInitialID }, loading ? (React.createElement("div", { className: "flex items-center gap-2" },
182
+ React.createElement(Loader2, { className: "animate-spin", size: 16, strokeWidth: 2 }),
183
+ t("generating_asset"))) : (t("modal.run_model_again")))))))),
184
+ React.createElement("div", { className: "flex justify-end" },
185
+ React.createElement(Button, { onClick: assignPredictionToProduct, disabled: !predictionItem?.getSimpleBgItem.image }, t("modal.assign_prediction_to_product")))))))));
186
+ };
@@ -0,0 +1 @@
1
+ export declare const translationNS: string;
@@ -0,0 +1 @@
1
+ export const translationNS = Symbol("replicate-simple-bg-plugin").toString();
@@ -0,0 +1,18 @@
1
+ {
2
+ "compilerOptions": {
3
+ "module": "ESNext",
4
+ "moduleResolution": "node",
5
+ "target": "ES2020",
6
+ "jsx": "react",
7
+ "outDir": "../../dist/plugin-ui",
8
+ "importHelpers": true,
9
+ "declaration": true,
10
+ "resolveJsonModule": true,
11
+ "skipLibCheck": true,
12
+ "strict": true,
13
+ "noImplicitAny": true,
14
+ "esModuleInterop": true,
15
+ "allowSyntheticDefaultImports": true
16
+ },
17
+ "include": ["./**/*.tsx", "./**/*.json", "./**/*.ts"]
18
+ }
@@ -0,0 +1,35 @@
1
+ /// <reference types="react" />
2
+ import { z } from "zod";
3
+ export declare const formSchema: z.ZodObject<{
4
+ file: z.ZodUnion<[z.ZodType<File, z.ZodTypeDef, File>, z.ZodNull]>;
5
+ room_type_enum: z.ZodString;
6
+ room_style_enum: z.ZodString;
7
+ prompt: z.ZodNullable<z.ZodOptional<z.ZodString>>;
8
+ }, "strip", z.ZodTypeAny, {
9
+ file: File | null;
10
+ room_style_enum: string;
11
+ room_type_enum: string;
12
+ prompt?: string | null | undefined;
13
+ }, {
14
+ file: File | null;
15
+ room_style_enum: string;
16
+ room_type_enum: string;
17
+ prompt?: string | null | undefined;
18
+ }>;
19
+ export type FormValues = z.infer<typeof formSchema>;
20
+ export declare const useReplicateForm: () => import("react-hook-form").UseFormReturn<{
21
+ file: File | null;
22
+ room_style_enum: string;
23
+ room_type_enum: string;
24
+ prompt?: string | null | undefined;
25
+ }, any, {
26
+ file: File | null;
27
+ room_style_enum: string;
28
+ room_type_enum: string;
29
+ prompt?: string | null | undefined;
30
+ }>;
31
+ export interface CustomFileInputProps {
32
+ onChange: (event: React.ChangeEvent<HTMLInputElement>) => void;
33
+ accept?: string;
34
+ className?: string;
35
+ }
@@ -0,0 +1,15 @@
1
+ import { z } from "zod";
2
+ import { zodResolver } from "@hookform/resolvers/zod";
3
+ import { useForm } from "react-hook-form";
4
+ export const formSchema = z.object({
5
+ file: z.union([z.instanceof(File), z.null()]),
6
+ room_type_enum: z.string().min(1),
7
+ room_style_enum: z.string().min(1),
8
+ prompt: z.string().optional().nullable(),
9
+ });
10
+ export const useReplicateForm = () => {
11
+ // zodResolver type constraint mismatches due to zod v3/v4 compat layer;
12
+ // cast through unknown to bridge the incompatible ZodType definitions.
13
+ const resolver = zodResolver(formSchema);
14
+ return useForm({ resolver });
15
+ };
@@ -0,0 +1,6 @@
1
+ export declare const AllTypesProps: Record<string, any>;
2
+ export declare const ReturnTypes: Record<string, any>;
3
+ export declare const Ops: {
4
+ query: "Query";
5
+ mutation: "Mutation";
6
+ };