docs-combiner 0.1.14 → 0.1.16
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.
- package/dist/renderer.js +965 -394
- package/dist/renderer.js.map +1 -1
- package/package.json +1 -1
package/dist/renderer.js
CHANGED
|
@@ -3056,29 +3056,6 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
3056
3056
|
|
|
3057
3057
|
/***/ }),
|
|
3058
3058
|
|
|
3059
|
-
/***/ "./node_modules/@mui/icons-material/esm/InfoOutlined.js":
|
|
3060
|
-
/*!**************************************************************!*\
|
|
3061
|
-
!*** ./node_modules/@mui/icons-material/esm/InfoOutlined.js ***!
|
|
3062
|
-
\**************************************************************/
|
|
3063
|
-
/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
|
|
3064
|
-
|
|
3065
|
-
"use strict";
|
|
3066
|
-
__webpack_require__.r(__webpack_exports__);
|
|
3067
|
-
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
|
3068
|
-
/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__)
|
|
3069
|
-
/* harmony export */ });
|
|
3070
|
-
/* harmony import */ var _utils_createSvgIcon_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./utils/createSvgIcon.js */ "./node_modules/@mui/material/esm/utils/createSvgIcon.js");
|
|
3071
|
-
/* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react/jsx-runtime */ "./node_modules/react/jsx-runtime.js");
|
|
3072
|
-
"use client";
|
|
3073
|
-
|
|
3074
|
-
|
|
3075
|
-
|
|
3076
|
-
/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ((0,_utils_createSvgIcon_js__WEBPACK_IMPORTED_MODULE_0__["default"])(/*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_1__.jsx)("path", {
|
|
3077
|
-
d: "M11 7h2v2h-2zm0 4h2v6h-2zm1-9C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2m0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8"
|
|
3078
|
-
}), 'InfoOutlined'));
|
|
3079
|
-
|
|
3080
|
-
/***/ }),
|
|
3081
|
-
|
|
3082
3059
|
/***/ "./node_modules/@mui/icons-material/esm/KeyboardArrowDown.js":
|
|
3083
3060
|
/*!*******************************************************************!*\
|
|
3084
3061
|
!*** ./node_modules/@mui/icons-material/esm/KeyboardArrowDown.js ***!
|
|
@@ -100879,50 +100856,53 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
100879
100856
|
/* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/Card/Card.js");
|
|
100880
100857
|
/* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/CardContent/CardContent.js");
|
|
100881
100858
|
/* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/Stack/Stack.js");
|
|
100882
|
-
/* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/
|
|
100883
|
-
/* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/
|
|
100884
|
-
/* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/
|
|
100885
|
-
/* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/
|
|
100859
|
+
/* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/TextField/TextField.js");
|
|
100860
|
+
/* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/FormHelperText/FormHelperText.js");
|
|
100861
|
+
/* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/CircularProgress/CircularProgress.js");
|
|
100862
|
+
/* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/Alert/Alert.js");
|
|
100886
100863
|
/* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/Divider/Divider.js");
|
|
100887
|
-
/* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/
|
|
100888
|
-
/* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_18__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/
|
|
100889
|
-
/* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_19__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/
|
|
100890
|
-
/* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_20__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/
|
|
100891
|
-
/* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_21__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/
|
|
100892
|
-
/* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_22__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/
|
|
100893
|
-
/* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_23__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/
|
|
100894
|
-
/* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_24__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/
|
|
100895
|
-
/* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_25__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/
|
|
100896
|
-
/* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_26__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/
|
|
100897
|
-
/* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_27__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/
|
|
100898
|
-
/* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_28__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/
|
|
100864
|
+
/* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/Accordion/Accordion.js");
|
|
100865
|
+
/* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_18__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/AccordionSummary/AccordionSummary.js");
|
|
100866
|
+
/* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_19__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/AccordionDetails/AccordionDetails.js");
|
|
100867
|
+
/* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_20__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/Button/Button.js");
|
|
100868
|
+
/* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_21__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/FormControlLabel/FormControlLabel.js");
|
|
100869
|
+
/* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_22__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/Checkbox/Checkbox.js");
|
|
100870
|
+
/* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_23__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/InputAdornment/InputAdornment.js");
|
|
100871
|
+
/* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_24__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/Tooltip/Tooltip.js");
|
|
100872
|
+
/* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_25__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/FormControl/FormControl.js");
|
|
100873
|
+
/* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_26__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/InputLabel/InputLabel.js");
|
|
100874
|
+
/* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_27__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/Select/Select.js");
|
|
100875
|
+
/* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_28__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/MenuItem/MenuItem.js");
|
|
100899
100876
|
/* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_29__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/ToggleButtonGroup/ToggleButtonGroup.js");
|
|
100900
100877
|
/* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_30__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/ToggleButton/ToggleButton.js");
|
|
100901
100878
|
/* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_31__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/Paper/Paper.js");
|
|
100902
|
-
/* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_32__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/
|
|
100903
|
-
/* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_33__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/
|
|
100904
|
-
/* harmony import */ var
|
|
100905
|
-
/* harmony import */ var
|
|
100906
|
-
/* harmony import */ var
|
|
100907
|
-
/* harmony import */ var
|
|
100908
|
-
/* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_38__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/
|
|
100909
|
-
/* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_39__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/
|
|
100910
|
-
/* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_40__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/
|
|
100911
|
-
/* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_41__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/
|
|
100912
|
-
/* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_42__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/
|
|
100913
|
-
/* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_43__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/
|
|
100914
|
-
/* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_44__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/
|
|
100915
|
-
/* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_45__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/
|
|
100916
|
-
/* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_46__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/
|
|
100917
|
-
/* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_47__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/
|
|
100918
|
-
/* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_48__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/
|
|
100919
|
-
/* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_49__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/
|
|
100920
|
-
/* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_50__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/
|
|
100921
|
-
/* harmony import */ var
|
|
100922
|
-
/* harmony import */ var
|
|
100923
|
-
/* harmony import */ var
|
|
100924
|
-
/* harmony import */ var
|
|
100925
|
-
/* harmony import */ var
|
|
100879
|
+
/* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_32__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/Dialog/Dialog.js");
|
|
100880
|
+
/* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_33__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/DialogTitle/DialogTitle.js");
|
|
100881
|
+
/* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_34__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/DialogContent/DialogContent.js");
|
|
100882
|
+
/* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_35__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/DialogActions/DialogActions.js");
|
|
100883
|
+
/* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_36__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/styles/createTheme.js");
|
|
100884
|
+
/* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_37__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/styles/ThemeProvider.js");
|
|
100885
|
+
/* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_38__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/AccountBalance.js");
|
|
100886
|
+
/* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_39__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/AttachMoney.js");
|
|
100887
|
+
/* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_40__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/AutoAwesome.js");
|
|
100888
|
+
/* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_41__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/Brightness4.js");
|
|
100889
|
+
/* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_42__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/Brightness7.js");
|
|
100890
|
+
/* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_43__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/CheckCircle.js");
|
|
100891
|
+
/* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_44__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/CloudDownload.js");
|
|
100892
|
+
/* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_45__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/ContentCopy.js");
|
|
100893
|
+
/* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_46__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/DeleteOutline.js");
|
|
100894
|
+
/* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_47__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/ExpandMore.js");
|
|
100895
|
+
/* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_48__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/Login.js");
|
|
100896
|
+
/* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_49__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/Logout.js");
|
|
100897
|
+
/* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_50__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/NoteAdd.js");
|
|
100898
|
+
/* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_51__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/Replay.js");
|
|
100899
|
+
/* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_52__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/Settings.js");
|
|
100900
|
+
/* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_53__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/Visibility.js");
|
|
100901
|
+
/* harmony import */ var _PromptManagerDialog__WEBPACK_IMPORTED_MODULE_54__ = __webpack_require__(/*! ./PromptManagerDialog */ "./src/PromptManagerDialog.tsx");
|
|
100902
|
+
/* harmony import */ var _promptOverrides__WEBPACK_IMPORTED_MODULE_55__ = __webpack_require__(/*! ./promptOverrides */ "./src/promptOverrides.ts");
|
|
100903
|
+
/* harmony import */ var xlsx__WEBPACK_IMPORTED_MODULE_56__ = __webpack_require__(/*! xlsx */ "./node_modules/xlsx/xlsx.mjs");
|
|
100904
|
+
/* harmony import */ var jszip__WEBPACK_IMPORTED_MODULE_57__ = __webpack_require__(/*! jszip */ "./node_modules/jszip/dist/jszip.min.js");
|
|
100905
|
+
/* harmony import */ var jszip__WEBPACK_IMPORTED_MODULE_57___default = /*#__PURE__*/__webpack_require__.n(jszip__WEBPACK_IMPORTED_MODULE_57__);
|
|
100926
100906
|
|
|
100927
100907
|
|
|
100928
100908
|
|
|
@@ -100983,15 +100963,65 @@ const INSTRUCTION_ROW = [
|
|
|
100983
100963
|
"# Обязательно | The URL for the main image of your item. Images must be in a supported format (JPG/GIF/PNG) and at least 500 x 500 pixels.",
|
|
100984
100964
|
"# Обязательно | Фирменное название товара. Не более 100 символов."
|
|
100985
100965
|
];
|
|
100986
|
-
/**
|
|
100987
|
-
const
|
|
100988
|
-
|
|
100989
|
-
|
|
100966
|
+
/** Доп. query-параметры для ссылки каталога (RedTrack / utm / макросы Meta; не URL-encode — подстановка на стороне FB). */
|
|
100967
|
+
const DEFAULT_CATALOG_LINK_EXTRA_MACROS = 'sub1={{ad.id}}&sub2={{adset.id}}&sub3={{campaign.id}}&sub4={{ad.name}}&sub5={{adset.name}}&sub6={{campaign.name}}&sub7={{placement}}&sub8={{site_source_name}}&utm_source=facebook&utm_medium=paid';
|
|
100968
|
+
const DEFAULT_CATALOG_LINK_KEITARO_MACROS = 'utm_campaign={{campaign.name}}&utm_source={{site_source_name}}&utm_placement={{placement}}&campaign_id={{campaign.id}}&adset_id={{adset.id}}&ad_id={{ad.id}}&adset_name={{adset.name}}&ad_name={{ad.name}}';
|
|
100969
|
+
/** 8 случайных hex-символов для уникального суффикса имени файла на Drive. */
|
|
100970
|
+
function randomHex8() {
|
|
100971
|
+
const a = new Uint8Array(4);
|
|
100972
|
+
crypto.getRandomValues(a);
|
|
100973
|
+
return Array.from(a, b => b.toString(16).padStart(2, '0')).join('');
|
|
100974
|
+
}
|
|
100975
|
+
/** Имя файла при загрузке крео: N_xxxxxxxx.png — N = номер строки подхода в UI (1–10). */
|
|
100976
|
+
function creativeImageUploadFilename(creoApproachUiNumber) {
|
|
100977
|
+
return `${creoApproachUiNumber}_${randomHex8()}.png`;
|
|
100978
|
+
}
|
|
100979
|
+
/**
|
|
100980
|
+
* Из имени файла картинки на Drive — номер строки подхода к крео (1–10) для каталога/трекера.
|
|
100981
|
+
* Формат: N_xxxxxxxx; снимаются расширение, суффиксы « (N)» от дубликатов Google.
|
|
100982
|
+
* Старый формат (текст_hex8) — возвращается «лейбл» после снятия hex (не только цифры).
|
|
100983
|
+
*/
|
|
100984
|
+
function parseCreoApproachLabelFromImageFileName(fileName) {
|
|
100985
|
+
let s = fileName.replace(/\.[^/.]+$/i, '').trim();
|
|
100986
|
+
if (!s)
|
|
100987
|
+
return undefined;
|
|
100988
|
+
while (/\s+\(\d+\)$/.test(s)) {
|
|
100989
|
+
s = s.replace(/\s+\(\d+\)$/, '').trim();
|
|
100990
|
+
}
|
|
100991
|
+
const m = /^(\d+)_([0-9a-fA-F]{8})$/i.exec(s);
|
|
100992
|
+
if (m)
|
|
100993
|
+
return m[1];
|
|
100994
|
+
const legacy = s.replace(/_[0-9a-fA-F]{8}$/i, '').trim();
|
|
100995
|
+
return legacy || undefined;
|
|
100996
|
+
}
|
|
100997
|
+
const DEFAULT_CATALOG_TEXT_APPROACH_PARAM = 'sub19';
|
|
100998
|
+
const DEFAULT_CATALOG_CREO_APPROACH_PARAM = 'sub20';
|
|
100999
|
+
/** Имя query-параметра для трекера: латиница, цифры, _, - */
|
|
101000
|
+
function sanitizeCatalogUrlParamKey(raw, fallback) {
|
|
101001
|
+
const t = raw.trim();
|
|
101002
|
+
if (!t)
|
|
101003
|
+
return fallback;
|
|
101004
|
+
const cleaned = t.replace(/[^a-zA-Z0-9_-]/g, '').slice(0, 64);
|
|
101005
|
+
return cleaned || fallback;
|
|
101006
|
+
}
|
|
101007
|
+
/** Добавляет к URL лендинга creative_id, опционально кастомные параметры подходов (имена редактируются в UI) и строку доп. макросов. */
|
|
101008
|
+
function appendCreativeIdToCatalogLink(baseUrl, creativeId, catalogAnalytics, extraMacrosQueryString) {
|
|
100990
101009
|
const u = baseUrl.trim();
|
|
100991
101010
|
if (!u)
|
|
100992
101011
|
return u;
|
|
100993
101012
|
const sep = u.includes('?') ? '&' : '?';
|
|
100994
|
-
|
|
101013
|
+
const q = [`creative_id=${encodeURIComponent(creativeId)}`];
|
|
101014
|
+
const textKey = sanitizeCatalogUrlParamKey(catalogAnalytics?.textParamKey ?? '', DEFAULT_CATALOG_TEXT_APPROACH_PARAM);
|
|
101015
|
+
const creoKey = sanitizeCatalogUrlParamKey(catalogAnalytics?.creoParamKey ?? '', DEFAULT_CATALOG_CREO_APPROACH_PARAM);
|
|
101016
|
+
if (catalogAnalytics?.textApproach) {
|
|
101017
|
+
q.push(`${textKey}=${encodeURIComponent(catalogAnalytics.textApproach)}`);
|
|
101018
|
+
}
|
|
101019
|
+
if (catalogAnalytics?.creoApproach) {
|
|
101020
|
+
q.push(`${creoKey}=${encodeURIComponent(catalogAnalytics.creoApproach)}`);
|
|
101021
|
+
}
|
|
101022
|
+
const core = `${u}${sep}${q.join('&')}`;
|
|
101023
|
+
const tail = (extraMacrosQueryString ?? '').trim();
|
|
101024
|
+
return tail ? `${core}&${tail}` : core;
|
|
100995
101025
|
}
|
|
100996
101026
|
/** Текст ответа из OpenRouter/OpenAI chat completion (string или массив частей). */
|
|
100997
101027
|
function extractChatCompletionText(choice) {
|
|
@@ -101160,6 +101190,82 @@ function extractLeadingPriceNumber(value) {
|
|
|
101160
101190
|
return m[1].replace(',', '.');
|
|
101161
101191
|
return '99';
|
|
101162
101192
|
}
|
|
101193
|
+
/** Фон карточки крео: после 1-й переделки — светло-жёлтый, далее темнеет с каждой следующей. */
|
|
101194
|
+
function getRemakeHighlightBackground(remakeCount, dark) {
|
|
101195
|
+
if (remakeCount <= 0)
|
|
101196
|
+
return undefined;
|
|
101197
|
+
const step = Math.min(remakeCount - 1, 7);
|
|
101198
|
+
if (dark) {
|
|
101199
|
+
const opacities = [0.11, 0.16, 0.22, 0.28, 0.34, 0.42, 0.5, 0.58];
|
|
101200
|
+
return `rgba(255, 193, 7, ${opacities[step]})`;
|
|
101201
|
+
}
|
|
101202
|
+
const light = ['#fffde7', '#fff9c4', '#fff59d', '#ffee58', '#ffeb3b', '#fdd835', '#fbc02d', '#f9a825'];
|
|
101203
|
+
return light[step];
|
|
101204
|
+
}
|
|
101205
|
+
function sortedPairIndicesEqual(a, b) {
|
|
101206
|
+
const sa = [...a].sort((x, y) => x - y);
|
|
101207
|
+
const sb = [...b].sort((x, y) => x - y);
|
|
101208
|
+
if (sa.length !== sb.length)
|
|
101209
|
+
return false;
|
|
101210
|
+
return sa.every((v, i) => v === sb[i]);
|
|
101211
|
+
}
|
|
101212
|
+
function imageApproachCountsEqual(a, b) {
|
|
101213
|
+
if (a.length !== b.length)
|
|
101214
|
+
return false;
|
|
101215
|
+
return a.every((v, i) => v === b[i]);
|
|
101216
|
+
}
|
|
101217
|
+
function formatPairApproachesForDisplay(indices) {
|
|
101218
|
+
return [...indices]
|
|
101219
|
+
.sort((x, y) => x - y)
|
|
101220
|
+
.map(i => {
|
|
101221
|
+
const p = _prompts__WEBPACK_IMPORTED_MODULE_1__.PAIR_APPROACH_POOL[i];
|
|
101222
|
+
const label = p?.name ?? '?';
|
|
101223
|
+
return `${i + 1}. ${label}`;
|
|
101224
|
+
})
|
|
101225
|
+
.join('\n');
|
|
101226
|
+
}
|
|
101227
|
+
function formatImageCountsForDisplay(counts) {
|
|
101228
|
+
const lines = counts
|
|
101229
|
+
.map((c, i) => (c > 0 ? `${_prompts__WEBPACK_IMPORTED_MODULE_1__.CREO_APPROACHES[i]?.name ?? `№${i + 1}`}: ×${c}` : null))
|
|
101230
|
+
.filter((x) => x != null);
|
|
101231
|
+
return lines.length > 0 ? lines.join('\n') : 'ни один подход (все 0)';
|
|
101232
|
+
}
|
|
101233
|
+
/** Один раз прошли экран «Application Error» — больше не показывать (localStorage + Electron config). */
|
|
101234
|
+
const SECRET_UNLOCK_STORAGE_KEY = 'docs_combiner_secret_unlocked';
|
|
101235
|
+
async function fetchDriveFilePermissions(token, fileId) {
|
|
101236
|
+
const permissionsUrl = `https://www.googleapis.com/drive/v3/files/${fileId}?fields=permissions(id,type,role)&supportsAllDrives=true`;
|
|
101237
|
+
const permissionsResponse = await fetch(permissionsUrl, {
|
|
101238
|
+
headers: { Authorization: `Bearer ${token}` }
|
|
101239
|
+
});
|
|
101240
|
+
if (!permissionsResponse.ok) {
|
|
101241
|
+
return { ok: false, errorText: await permissionsResponse.text() };
|
|
101242
|
+
}
|
|
101243
|
+
const permissionsData = await permissionsResponse.json();
|
|
101244
|
+
return { ok: true, permissions: permissionsData.permissions || [] };
|
|
101245
|
+
}
|
|
101246
|
+
/** Доступ «любой по ссылке» / публичный читатель — нужен для скачивания референса по URL без OAuth. */
|
|
101247
|
+
function permissionsIncludeAnyoneLink(permissions) {
|
|
101248
|
+
return permissions.some(p => p.type === 'anyone');
|
|
101249
|
+
}
|
|
101250
|
+
async function verifyOfferFolderHasAnyoneLinkForImageGen(token, folderId) {
|
|
101251
|
+
const offerPermResult = await fetchDriveFilePermissions(token, folderId);
|
|
101252
|
+
if (!offerPermResult.ok) {
|
|
101253
|
+
return {
|
|
101254
|
+
ok: false,
|
|
101255
|
+
message: 'Не удалось проверить доступ к папке оффера в Google Диске.\n\n' +
|
|
101256
|
+
'Генерация изображений с референсом может не работать без доступа по ссылке.\n\n' +
|
|
101257
|
+
(offerPermResult.errorText.trim().slice(0, 280) || 'Ошибка API')
|
|
101258
|
+
};
|
|
101259
|
+
}
|
|
101260
|
+
if (!permissionsIncludeAnyoneLink(offerPermResult.permissions)) {
|
|
101261
|
+
return {
|
|
101262
|
+
ok: false,
|
|
101263
|
+
message: 'Папка оффера закрыта для доступа по ссылке: нет права «Все, у кого есть ссылка» (тип anyone).\n\n' +
|
|
101264
|
+
'Сервисы генерации скачивают product.png по публичному URL. Включите в Google Диске общий доступ с ролью «Читатель» для этой папки (или согласитесь, когда приложение предложит сделать это автоматически).'
|
|
101265
|
+
};
|
|
101266
|
+
}
|
|
101267
|
+
return { ok: true };
|
|
101268
|
+
}
|
|
101163
101269
|
function App() {
|
|
101164
101270
|
const [clientId, setClientId] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)('');
|
|
101165
101271
|
const [clientSecret, setClientSecret] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)('');
|
|
@@ -101174,8 +101280,12 @@ function App() {
|
|
|
101174
101280
|
// Переводы сгенерированных пар на русский: ключ = 0-based индекс пары
|
|
101175
101281
|
const [pairTranslations, setPairTranslations] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)({});
|
|
101176
101282
|
const [translatingPairs, setTranslatingPairs] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(false);
|
|
101283
|
+
/** Папка оффера: загрузка/сохранение контента и крео (как раньше) */
|
|
101177
101284
|
const [driveFolderUrl, setDriveFolderUrl] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)('');
|
|
101285
|
+
/** Корневая папка: только поле + проверка общего доступа и подпапки OFFERS (отдельно от папки оффера) */
|
|
101286
|
+
const [rootDriveFolderUrl, setRootDriveFolderUrl] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)('');
|
|
101178
101287
|
const [link, setLink] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)('');
|
|
101288
|
+
const linkInputRef = (0,react__WEBPACK_IMPORTED_MODULE_0__.useRef)(null);
|
|
101179
101289
|
const [openaiApiKey, setOpenaiApiKey] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)('');
|
|
101180
101290
|
const [openRouterBalance, setOpenRouterBalance] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(null);
|
|
101181
101291
|
const [openRouterAccountBalance, setOpenRouterAccountBalance] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(null);
|
|
@@ -101378,10 +101488,17 @@ function App() {
|
|
|
101378
101488
|
const [uploadingImages, setUploadingImages] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(false);
|
|
101379
101489
|
const [uploadingProduct, setUploadingProduct] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(false);
|
|
101380
101490
|
const [folderFilesInfo, setFolderFilesInfo] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(null);
|
|
101491
|
+
const [rootFolderInfo, setRootFolderInfo] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(null);
|
|
101381
101492
|
const productFileInputRef = react__WEBPACK_IMPORTED_MODULE_0___default().useRef(null);
|
|
101382
101493
|
const [checkingFolderFiles, setCheckingFolderFiles] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(false);
|
|
101494
|
+
const [checkingRootFolder, setCheckingRootFolder] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(false);
|
|
101495
|
+
const [drivePublicAccessWarning, setDrivePublicAccessWarning] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(false);
|
|
101496
|
+
/** Уже обработали запрос доступа по ссылке для корневой папки (OFFERS) */
|
|
101383
101497
|
const permissionCheckedFoldersRef = react__WEBPACK_IMPORTED_MODULE_0___default().useRef(new Set());
|
|
101498
|
+
/** Уже спрашивали про доступ по ссылке для папки оффера (нужен OpenRouter по uc?export=view) */
|
|
101499
|
+
const driveFolderPublicLinkPromptedRef = react__WEBPACK_IMPORTED_MODULE_0___default().useRef(new Set());
|
|
101384
101500
|
const folderCheckRunningRef = react__WEBPACK_IMPORTED_MODULE_0___default().useRef(false);
|
|
101501
|
+
const rootFolderCheckRunningRef = react__WEBPACK_IMPORTED_MODULE_0___default().useRef(false);
|
|
101385
101502
|
const [imagesProcessStartTime, setImagesProcessStartTime] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(null);
|
|
101386
101503
|
const [contentProcessStartTime, setContentProcessStartTime] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(null);
|
|
101387
101504
|
const [contentGenerationLogs, setContentGenerationLogs] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)([]);
|
|
@@ -101396,6 +101513,16 @@ function App() {
|
|
|
101396
101513
|
// const [availability, setAvailability] = useState('in stock');
|
|
101397
101514
|
// const [condition, setCondition] = useState('new');
|
|
101398
101515
|
const [linkError, setLinkError] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)('');
|
|
101516
|
+
/** В ссылку каталога: имя подхода к паре текстов (под трекер) */
|
|
101517
|
+
const [catalogUrlIncludeTextApproach, setCatalogUrlIncludeTextApproach] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(false);
|
|
101518
|
+
/** В ссылку каталога: подход крео — если крео загружены из приложения (есть file id на Drive) */
|
|
101519
|
+
const [catalogUrlIncludeCreoApproach, setCatalogUrlIncludeCreoApproach] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(false);
|
|
101520
|
+
/** Имя query-параметра для подхода к тексту (по умолчанию sub19) */
|
|
101521
|
+
const [catalogUrlTextApproachParam, setCatalogUrlTextApproachParam] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(DEFAULT_CATALOG_TEXT_APPROACH_PARAM);
|
|
101522
|
+
/** Имя query-параметра для подхода к крео (по умолчанию sub20) */
|
|
101523
|
+
const [catalogUrlCreoApproachParam, setCatalogUrlCreoApproachParam] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(DEFAULT_CATALOG_CREO_APPROACH_PARAM);
|
|
101524
|
+
/** Query-хвост после creative_id / sub19 / sub20 (редактируемый; пресет RedTrack). */
|
|
101525
|
+
const [catalogLinkExtraMacros, setCatalogLinkExtraMacros] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(DEFAULT_CATALOG_LINK_EXTRA_MACROS);
|
|
101399
101526
|
const [loading, setLoading] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(false);
|
|
101400
101527
|
const [authLoading, setAuthLoading] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(false);
|
|
101401
101528
|
const [generatedData, setGeneratedData] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)([]);
|
|
@@ -101412,9 +101539,36 @@ function App() {
|
|
|
101412
101539
|
const saved = localStorage.getItem('themeMode');
|
|
101413
101540
|
return saved === 'dark';
|
|
101414
101541
|
});
|
|
101415
|
-
// Secret unlock state
|
|
101416
|
-
const [unlocked, setUnlocked] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(
|
|
101542
|
+
// Secret unlock state — восстанавливаем из localStorage; при старте Electron подмешивает config.secretUnlockPassed
|
|
101543
|
+
const [unlocked, setUnlocked] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(() => {
|
|
101544
|
+
try {
|
|
101545
|
+
return localStorage.getItem(SECRET_UNLOCK_STORAGE_KEY) === '1';
|
|
101546
|
+
}
|
|
101547
|
+
catch {
|
|
101548
|
+
return false;
|
|
101549
|
+
}
|
|
101550
|
+
});
|
|
101417
101551
|
const [clickSequence, setClickSequence] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)([]);
|
|
101552
|
+
const persistSecretUnlockPassed = () => {
|
|
101553
|
+
try {
|
|
101554
|
+
localStorage.setItem(SECRET_UNLOCK_STORAGE_KEY, '1');
|
|
101555
|
+
}
|
|
101556
|
+
catch {
|
|
101557
|
+
// ignore
|
|
101558
|
+
}
|
|
101559
|
+
void (async () => {
|
|
101560
|
+
try {
|
|
101561
|
+
const api = getElectronAPI();
|
|
101562
|
+
if (api) {
|
|
101563
|
+
const current = await api.loadConfig();
|
|
101564
|
+
await api.saveConfig({ ...current, secretUnlockPassed: true });
|
|
101565
|
+
}
|
|
101566
|
+
}
|
|
101567
|
+
catch {
|
|
101568
|
+
// ignore
|
|
101569
|
+
}
|
|
101570
|
+
})();
|
|
101571
|
+
};
|
|
101418
101572
|
// Handle secret unlock clicks - simplified to left then right
|
|
101419
101573
|
const handleSecretClick = (e) => {
|
|
101420
101574
|
if (unlocked)
|
|
@@ -101439,6 +101593,7 @@ function App() {
|
|
|
101439
101593
|
// Second click: right side (after left)
|
|
101440
101594
|
setUnlocked(true);
|
|
101441
101595
|
setClickSequence([]);
|
|
101596
|
+
persistSecretUnlockPassed();
|
|
101442
101597
|
}
|
|
101443
101598
|
else {
|
|
101444
101599
|
// Wrong click or wrong sequence, reset
|
|
@@ -101453,7 +101608,7 @@ function App() {
|
|
|
101453
101608
|
}
|
|
101454
101609
|
};
|
|
101455
101610
|
// Create theme based on mode
|
|
101456
|
-
const theme = react__WEBPACK_IMPORTED_MODULE_0___default().useMemo(() => (0,
|
|
101611
|
+
const theme = react__WEBPACK_IMPORTED_MODULE_0___default().useMemo(() => (0,_mui_material__WEBPACK_IMPORTED_MODULE_36__["default"])({
|
|
101457
101612
|
palette: {
|
|
101458
101613
|
mode: darkMode ? 'dark' : 'light',
|
|
101459
101614
|
...(darkMode
|
|
@@ -101508,6 +101663,8 @@ function App() {
|
|
|
101508
101663
|
applyThemeStyles(darkMode);
|
|
101509
101664
|
}, [darkMode]);
|
|
101510
101665
|
const [promptManagerOpen, setPromptManagerOpen] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(false);
|
|
101666
|
+
/** После загрузки project-settings.json: спросить, подставить подходы из файла или оставить локальные. */
|
|
101667
|
+
const [approachLoadChoice, setApproachLoadChoice] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(null);
|
|
101511
101668
|
(0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => {
|
|
101512
101669
|
// Load config on mount
|
|
101513
101670
|
const loadKey = async () => {
|
|
@@ -101528,6 +101685,15 @@ function App() {
|
|
|
101528
101685
|
setOpenaiApiKey(config.openaiApiKey);
|
|
101529
101686
|
// Balance will be fetched automatically by useEffect when openaiApiKey changes
|
|
101530
101687
|
}
|
|
101688
|
+
if (config.secretUnlockPassed === true) {
|
|
101689
|
+
setUnlocked(true);
|
|
101690
|
+
try {
|
|
101691
|
+
localStorage.setItem(SECRET_UNLOCK_STORAGE_KEY, '1');
|
|
101692
|
+
}
|
|
101693
|
+
catch {
|
|
101694
|
+
// ignore
|
|
101695
|
+
}
|
|
101696
|
+
}
|
|
101531
101697
|
}
|
|
101532
101698
|
catch (err) {
|
|
101533
101699
|
// Silent fail
|
|
@@ -101536,8 +101702,11 @@ function App() {
|
|
|
101536
101702
|
// effect (which depends on [driveFolderUrl]) will have valid tokens available
|
|
101537
101703
|
try {
|
|
101538
101704
|
const cachedDriveFolderUrl = localStorage.getItem('cached_driveFolderUrl');
|
|
101705
|
+
const cachedRootDriveFolderUrl = localStorage.getItem('cached_rootDriveFolderUrl');
|
|
101539
101706
|
if (cachedDriveFolderUrl)
|
|
101540
101707
|
setDriveFolderUrl(cachedDriveFolderUrl);
|
|
101708
|
+
if (cachedRootDriveFolderUrl)
|
|
101709
|
+
setRootDriveFolderUrl(cachedRootDriveFolderUrl);
|
|
101541
101710
|
}
|
|
101542
101711
|
catch (err) {
|
|
101543
101712
|
// Silent fail
|
|
@@ -101545,7 +101714,7 @@ function App() {
|
|
|
101545
101714
|
};
|
|
101546
101715
|
loadKey();
|
|
101547
101716
|
// Load prompt overrides from Electron config
|
|
101548
|
-
(0,
|
|
101717
|
+
(0,_promptOverrides__WEBPACK_IMPORTED_MODULE_55__.loadOverridesFromElectron)();
|
|
101549
101718
|
}, []);
|
|
101550
101719
|
// Save form fields to localStorage whenever they change
|
|
101551
101720
|
(0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => {
|
|
@@ -101558,6 +101727,22 @@ function App() {
|
|
|
101558
101727
|
// Silent fail
|
|
101559
101728
|
}
|
|
101560
101729
|
}, [driveFolderUrl]);
|
|
101730
|
+
(0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => {
|
|
101731
|
+
try {
|
|
101732
|
+
if (rootDriveFolderUrl) {
|
|
101733
|
+
localStorage.setItem('cached_rootDriveFolderUrl', rootDriveFolderUrl);
|
|
101734
|
+
}
|
|
101735
|
+
else {
|
|
101736
|
+
localStorage.removeItem('cached_rootDriveFolderUrl');
|
|
101737
|
+
}
|
|
101738
|
+
}
|
|
101739
|
+
catch (err) {
|
|
101740
|
+
// Silent fail
|
|
101741
|
+
}
|
|
101742
|
+
}, [rootDriveFolderUrl]);
|
|
101743
|
+
(0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => {
|
|
101744
|
+
setDrivePublicAccessWarning(false);
|
|
101745
|
+
}, [rootDriveFolderUrl]);
|
|
101561
101746
|
// Auto-save AI Generation Settings, brand and link to Google Drive when they change
|
|
101562
101747
|
(0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => {
|
|
101563
101748
|
if (!driveFolderUrl)
|
|
@@ -101587,7 +101772,21 @@ function App() {
|
|
|
101587
101772
|
}
|
|
101588
101773
|
}, 1000);
|
|
101589
101774
|
return () => clearTimeout(timeoutId);
|
|
101590
|
-
}, [
|
|
101775
|
+
}, [
|
|
101776
|
+
generateProduct,
|
|
101777
|
+
generateGeo,
|
|
101778
|
+
generateAdditionalInfo,
|
|
101779
|
+
generatePriceWithCurrency,
|
|
101780
|
+
brand,
|
|
101781
|
+
link,
|
|
101782
|
+
catalogUrlIncludeTextApproach,
|
|
101783
|
+
catalogUrlIncludeCreoApproach,
|
|
101784
|
+
catalogUrlTextApproachParam,
|
|
101785
|
+
catalogUrlCreoApproachParam,
|
|
101786
|
+
catalogLinkExtraMacros,
|
|
101787
|
+
driveFolderUrl,
|
|
101788
|
+
loadingContentFromDrive
|
|
101789
|
+
]);
|
|
101591
101790
|
// Load generated content from Google Drive when driveFolderUrl changes
|
|
101592
101791
|
(0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => {
|
|
101593
101792
|
if (!driveFolderUrl) {
|
|
@@ -101602,7 +101801,9 @@ function App() {
|
|
|
101602
101801
|
setTexts(['']);
|
|
101603
101802
|
setLink('');
|
|
101604
101803
|
setUploadedLink('');
|
|
101804
|
+
setCatalogLinkExtraMacros(DEFAULT_CATALOG_LINK_EXTRA_MACROS);
|
|
101605
101805
|
setPairTranslations({});
|
|
101806
|
+
setApproachLoadChoice(null);
|
|
101606
101807
|
return;
|
|
101607
101808
|
}
|
|
101608
101809
|
const folderId = extractFolderId(driveFolderUrl);
|
|
@@ -101618,7 +101819,9 @@ function App() {
|
|
|
101618
101819
|
setTexts(['']);
|
|
101619
101820
|
setLink('');
|
|
101620
101821
|
setUploadedLink('');
|
|
101822
|
+
setCatalogLinkExtraMacros(DEFAULT_CATALOG_LINK_EXTRA_MACROS);
|
|
101621
101823
|
setPairTranslations({});
|
|
101824
|
+
setApproachLoadChoice(null);
|
|
101622
101825
|
return;
|
|
101623
101826
|
}
|
|
101624
101827
|
logToTerminal('log', '[Load] driveFolderUrl changed, clearing old data and loading from folderId:', folderId);
|
|
@@ -101630,7 +101833,9 @@ function App() {
|
|
|
101630
101833
|
setTexts(['']);
|
|
101631
101834
|
setLink('');
|
|
101632
101835
|
setUploadedLink('');
|
|
101836
|
+
setCatalogLinkExtraMacros(DEFAULT_CATALOG_LINK_EXTRA_MACROS);
|
|
101633
101837
|
setPairTranslations({});
|
|
101838
|
+
setApproachLoadChoice(null);
|
|
101634
101839
|
setLoadingContentFromDrive(true);
|
|
101635
101840
|
setDriveFilesFound({ content: false });
|
|
101636
101841
|
// Load content from Google Drive
|
|
@@ -101787,11 +101992,132 @@ function App() {
|
|
|
101787
101992
|
fetchValidationModels();
|
|
101788
101993
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
101789
101994
|
}, [openaiApiKey]);
|
|
101790
|
-
//
|
|
101995
|
+
// Корневая папка: общий доступ и подпапка OFFERS
|
|
101996
|
+
(0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => {
|
|
101997
|
+
let cancelled = false;
|
|
101998
|
+
const checkRootFolder = async () => {
|
|
101999
|
+
if (rootFolderCheckRunningRef.current)
|
|
102000
|
+
return;
|
|
102001
|
+
if (!rootDriveFolderUrl.trim()) {
|
|
102002
|
+
setRootFolderInfo(null);
|
|
102003
|
+
setDrivePublicAccessWarning(false);
|
|
102004
|
+
return;
|
|
102005
|
+
}
|
|
102006
|
+
const validToken = await getValidAccessToken();
|
|
102007
|
+
if (!validToken || cancelled) {
|
|
102008
|
+
if (!cancelled)
|
|
102009
|
+
setRootFolderInfo(null);
|
|
102010
|
+
return;
|
|
102011
|
+
}
|
|
102012
|
+
const rootFolderId = extractFolderId(rootDriveFolderUrl);
|
|
102013
|
+
if (!rootFolderId || cancelled) {
|
|
102014
|
+
if (!cancelled)
|
|
102015
|
+
setRootFolderInfo(null);
|
|
102016
|
+
return;
|
|
102017
|
+
}
|
|
102018
|
+
rootFolderCheckRunningRef.current = true;
|
|
102019
|
+
setCheckingRootFolder(true);
|
|
102020
|
+
try {
|
|
102021
|
+
if (!permissionCheckedFoldersRef.current.has(rootFolderId)) {
|
|
102022
|
+
const permissionsUrl = `https://www.googleapis.com/drive/v3/files/${rootFolderId}?fields=permissions(id,type,role)&supportsAllDrives=true`;
|
|
102023
|
+
const permissionsResponse = await fetch(permissionsUrl, {
|
|
102024
|
+
headers: {
|
|
102025
|
+
'Authorization': `Bearer ${validToken}`
|
|
102026
|
+
}
|
|
102027
|
+
});
|
|
102028
|
+
if (cancelled)
|
|
102029
|
+
return;
|
|
102030
|
+
permissionCheckedFoldersRef.current.add(rootFolderId);
|
|
102031
|
+
if (permissionsResponse.ok) {
|
|
102032
|
+
const permissionsData = await permissionsResponse.json();
|
|
102033
|
+
const anyonePerms = (permissionsData.permissions || []).filter((p) => p.type === 'anyone' && p.id);
|
|
102034
|
+
if (anyonePerms.length > 0) {
|
|
102035
|
+
if (cancelled)
|
|
102036
|
+
return;
|
|
102037
|
+
const revoke = window.confirm('У этой папки включён общий доступ по ссылке («Все, у кого есть ссылка» или публично в интернете).\n\n' +
|
|
102038
|
+
'Приложение использует ваш аккаунт Google — открывать папку всем не обязательно.\n\n' +
|
|
102039
|
+
'Убрать общий доступ для этой папки автоматически?');
|
|
102040
|
+
if (cancelled)
|
|
102041
|
+
return;
|
|
102042
|
+
if (revoke) {
|
|
102043
|
+
const tok = await getValidAccessToken();
|
|
102044
|
+
if (!tok || cancelled) {
|
|
102045
|
+
if (!cancelled)
|
|
102046
|
+
setRootFolderInfo(null);
|
|
102047
|
+
return;
|
|
102048
|
+
}
|
|
102049
|
+
for (const p of anyonePerms) {
|
|
102050
|
+
if (cancelled)
|
|
102051
|
+
break;
|
|
102052
|
+
const delUrl = `https://www.googleapis.com/drive/v3/files/${rootFolderId}/permissions/${p.id}?supportsAllDrives=true`;
|
|
102053
|
+
const delRes = await fetch(delUrl, {
|
|
102054
|
+
method: 'DELETE',
|
|
102055
|
+
headers: { 'Authorization': `Bearer ${tok}` }
|
|
102056
|
+
});
|
|
102057
|
+
if (!delRes.ok) {
|
|
102058
|
+
const errText = await delRes.text();
|
|
102059
|
+
logToTerminal('error', 'Failed to remove Drive permission:', errText);
|
|
102060
|
+
}
|
|
102061
|
+
}
|
|
102062
|
+
if (!cancelled)
|
|
102063
|
+
setDrivePublicAccessWarning(false);
|
|
102064
|
+
}
|
|
102065
|
+
else if (!cancelled) {
|
|
102066
|
+
setDrivePublicAccessWarning(true);
|
|
102067
|
+
}
|
|
102068
|
+
}
|
|
102069
|
+
else if (!cancelled) {
|
|
102070
|
+
setDrivePublicAccessWarning(false);
|
|
102071
|
+
}
|
|
102072
|
+
}
|
|
102073
|
+
}
|
|
102074
|
+
if (cancelled)
|
|
102075
|
+
return;
|
|
102076
|
+
const currentToken = await getValidAccessToken();
|
|
102077
|
+
if (!currentToken || cancelled) {
|
|
102078
|
+
if (!cancelled)
|
|
102079
|
+
setRootFolderInfo(null);
|
|
102080
|
+
return;
|
|
102081
|
+
}
|
|
102082
|
+
const fields = 'files(id, name)';
|
|
102083
|
+
const qOffers = `'${rootFolderId}' in parents and trashed = false and mimeType = 'application/vnd.google-apps.folder'`;
|
|
102084
|
+
const offersUrl = `https://www.googleapis.com/drive/v3/files?q=${encodeURIComponent(qOffers)}&fields=${encodeURIComponent(fields)}&supportsAllDrives=true`;
|
|
102085
|
+
const offersResponse = await fetch(offersUrl, {
|
|
102086
|
+
headers: { 'Authorization': `Bearer ${currentToken}` }
|
|
102087
|
+
});
|
|
102088
|
+
if (cancelled)
|
|
102089
|
+
return;
|
|
102090
|
+
let hasOffersFolder = false;
|
|
102091
|
+
if (offersResponse.ok) {
|
|
102092
|
+
const offersData = await offersResponse.json();
|
|
102093
|
+
hasOffersFolder = (offersData.files || []).some((f) => (f.name || '').toUpperCase() === 'OFFERS');
|
|
102094
|
+
}
|
|
102095
|
+
if (!cancelled) {
|
|
102096
|
+
setRootFolderInfo({ hasOffersFolder });
|
|
102097
|
+
}
|
|
102098
|
+
}
|
|
102099
|
+
catch (err) {
|
|
102100
|
+
if (!cancelled)
|
|
102101
|
+
setRootFolderInfo(null);
|
|
102102
|
+
}
|
|
102103
|
+
finally {
|
|
102104
|
+
rootFolderCheckRunningRef.current = false;
|
|
102105
|
+
if (!cancelled)
|
|
102106
|
+
setCheckingRootFolder(false);
|
|
102107
|
+
}
|
|
102108
|
+
};
|
|
102109
|
+
const timeoutId = setTimeout(() => {
|
|
102110
|
+
checkRootFolder();
|
|
102111
|
+
}, 500);
|
|
102112
|
+
return () => {
|
|
102113
|
+
cancelled = true;
|
|
102114
|
+
clearTimeout(timeoutId);
|
|
102115
|
+
};
|
|
102116
|
+
}, [rootDriveFolderUrl, accessToken, refreshToken]);
|
|
102117
|
+
// Рабочая папка Google Drive: product и крео-изображения
|
|
101791
102118
|
(0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => {
|
|
101792
102119
|
let cancelled = false;
|
|
101793
102120
|
const checkFolderFiles = async () => {
|
|
101794
|
-
// Prevent concurrent runs (e.g. if token refresh re-triggers the effect while a check is in progress)
|
|
101795
102121
|
if (folderCheckRunningRef.current)
|
|
101796
102122
|
return;
|
|
101797
102123
|
if (!driveFolderUrl.trim()) {
|
|
@@ -101813,47 +102139,38 @@ function App() {
|
|
|
101813
102139
|
folderCheckRunningRef.current = true;
|
|
101814
102140
|
setCheckingFolderFiles(true);
|
|
101815
102141
|
try {
|
|
101816
|
-
|
|
101817
|
-
|
|
101818
|
-
const permissionsUrl = `https://www.googleapis.com/drive/v3/files/${folderId}?fields=permissions(id,type,role)`;
|
|
101819
|
-
const permissionsResponse = await fetch(permissionsUrl, {
|
|
101820
|
-
headers: {
|
|
101821
|
-
'Authorization': `Bearer ${validToken}`
|
|
101822
|
-
}
|
|
101823
|
-
});
|
|
102142
|
+
if (!driveFolderPublicLinkPromptedRef.current.has(folderId)) {
|
|
102143
|
+
const permResult = await fetchDriveFilePermissions(validToken, folderId);
|
|
101824
102144
|
if (cancelled)
|
|
101825
102145
|
return;
|
|
101826
|
-
if (
|
|
101827
|
-
|
|
101828
|
-
|
|
102146
|
+
if (!permResult.ok) {
|
|
102147
|
+
logToTerminal('warn', 'Could not read offer folder permissions (will retry on next check):', permResult.errorText);
|
|
102148
|
+
}
|
|
102149
|
+
else {
|
|
102150
|
+
const hasPublicLinkAccess = permissionsIncludeAnyoneLink(permResult.permissions);
|
|
101829
102151
|
if (hasPublicLinkAccess) {
|
|
101830
|
-
|
|
101831
|
-
permissionCheckedFoldersRef.current.add(folderId);
|
|
102152
|
+
driveFolderPublicLinkPromptedRef.current.add(folderId);
|
|
101832
102153
|
}
|
|
101833
102154
|
else {
|
|
101834
|
-
// Mark as checked BEFORE showing confirm to prevent duplicate prompts
|
|
101835
|
-
permissionCheckedFoldersRef.current.add(folderId);
|
|
101836
102155
|
if (cancelled)
|
|
101837
102156
|
return;
|
|
101838
|
-
|
|
101839
|
-
|
|
101840
|
-
'
|
|
101841
|
-
'Разрешить автоматически включить доступ по ссылке для этой папки?');
|
|
102157
|
+
const userConsent = window.confirm('⚠️ Папка оффера на Google Диске не открыта для всех по ссылке.\n\n' +
|
|
102158
|
+
'Сервисы генерации изображений (OpenRouter) скачивают картинки по публичному URL — без доступа по ссылке запросы могут падать с ошибкой.\n\n' +
|
|
102159
|
+
'Включить доступ по ссылке для этой папки (читатель) автоматически?');
|
|
101842
102160
|
if (cancelled)
|
|
101843
102161
|
return;
|
|
101844
102162
|
if (userConsent) {
|
|
101845
|
-
|
|
101846
|
-
|
|
101847
|
-
if (!currentToken || cancelled) {
|
|
102163
|
+
const tok = await getValidAccessToken();
|
|
102164
|
+
if (!tok || cancelled) {
|
|
101848
102165
|
if (!cancelled)
|
|
101849
102166
|
setFolderFilesInfo(null);
|
|
101850
102167
|
return;
|
|
101851
102168
|
}
|
|
101852
|
-
const createPermissionUrl = `https://www.googleapis.com/drive/v3/files/${folderId}/permissions`;
|
|
102169
|
+
const createPermissionUrl = `https://www.googleapis.com/drive/v3/files/${folderId}/permissions?supportsAllDrives=true`;
|
|
101853
102170
|
const createPermissionResponse = await fetch(createPermissionUrl, {
|
|
101854
102171
|
method: 'POST',
|
|
101855
102172
|
headers: {
|
|
101856
|
-
'Authorization': `Bearer ${
|
|
102173
|
+
'Authorization': `Bearer ${tok}`,
|
|
101857
102174
|
'Content-Type': 'application/json'
|
|
101858
102175
|
},
|
|
101859
102176
|
body: JSON.stringify({
|
|
@@ -101865,22 +102182,34 @@ function App() {
|
|
|
101865
102182
|
return;
|
|
101866
102183
|
if (!createPermissionResponse.ok) {
|
|
101867
102184
|
const errorText = await createPermissionResponse.text();
|
|
101868
|
-
logToTerminal('error', 'Failed to enable public link access:', errorText);
|
|
101869
|
-
alert('⚠️ Не удалось автоматически включить доступ по
|
|
102185
|
+
logToTerminal('error', 'Failed to enable public link access for offer folder:', errorText);
|
|
102186
|
+
window.alert('⚠️ Не удалось автоматически включить доступ по ссылке.\n\n' +
|
|
102187
|
+
'Сделайте папку доступной по ссылке вручную в Google Диске (роль «Читатель»).');
|
|
102188
|
+
// Не помечаем folderId — при следующей проверке снова предложим / повторим
|
|
101870
102189
|
}
|
|
101871
102190
|
else {
|
|
101872
|
-
|
|
102191
|
+
const verify = await fetchDriveFilePermissions(tok, folderId);
|
|
102192
|
+
if (verify.ok && permissionsIncludeAnyoneLink(verify.permissions)) {
|
|
102193
|
+
driveFolderPublicLinkPromptedRef.current.add(folderId);
|
|
102194
|
+
logToTerminal('log', '✅ Public link access enabled for offer folder (verified)');
|
|
102195
|
+
}
|
|
102196
|
+
else {
|
|
102197
|
+
logToTerminal('warn', 'Permission API succeeded but anyone-link not visible on re-fetch; user should verify in Drive UI');
|
|
102198
|
+
window.alert('⚠️ Запрос на доступ отправлен, но повторная проверка не увидела права «для всех по ссылке».\n\n' +
|
|
102199
|
+
'Проверьте папку в Google Диске вручную: общий доступ → «Все, у кого есть ссылка» → Читатель.');
|
|
102200
|
+
}
|
|
101873
102201
|
}
|
|
101874
102202
|
}
|
|
101875
102203
|
else {
|
|
101876
|
-
|
|
102204
|
+
driveFolderPublicLinkPromptedRef.current.add(folderId);
|
|
102205
|
+
window.alert('⚠️ Без доступа по ссылке генерация с референсами из этой папки может не работать.\n\n' +
|
|
102206
|
+
'Включите вручную: Настройки доступа → «Все, у кого есть ссылка» → Читатель.');
|
|
101877
102207
|
}
|
|
101878
102208
|
}
|
|
101879
102209
|
}
|
|
101880
102210
|
}
|
|
101881
102211
|
if (cancelled)
|
|
101882
102212
|
return;
|
|
101883
|
-
// Then check folder files
|
|
101884
102213
|
const currentToken = await getValidAccessToken();
|
|
101885
102214
|
if (!currentToken || cancelled) {
|
|
101886
102215
|
if (!cancelled)
|
|
@@ -101889,7 +102218,7 @@ function App() {
|
|
|
101889
102218
|
}
|
|
101890
102219
|
const q = `'${folderId}' in parents and trashed = false and mimeType contains 'image/'`;
|
|
101891
102220
|
const fields = 'files(id, name)';
|
|
101892
|
-
const url = `https://www.googleapis.com/drive/v3/files?q=${encodeURIComponent(q)}&fields=${encodeURIComponent(fields)}`;
|
|
102221
|
+
const url = `https://www.googleapis.com/drive/v3/files?q=${encodeURIComponent(q)}&fields=${encodeURIComponent(fields)}&supportsAllDrives=true`;
|
|
101893
102222
|
const response = await fetch(url, {
|
|
101894
102223
|
headers: {
|
|
101895
102224
|
'Authorization': `Bearer ${currentToken}`
|
|
@@ -101897,30 +102226,28 @@ function App() {
|
|
|
101897
102226
|
});
|
|
101898
102227
|
if (cancelled)
|
|
101899
102228
|
return;
|
|
101900
|
-
if (response.ok) {
|
|
101901
|
-
const data = await response.json();
|
|
101902
|
-
const hasProduct = data.files.some((f) => {
|
|
101903
|
-
const name = f.name?.toLowerCase() || '';
|
|
101904
|
-
return name === 'product.png' || name === 'product.jpg' || name === 'product.webp';
|
|
101905
|
-
});
|
|
101906
|
-
const hasCreativeImages = data.files.some((f) => {
|
|
101907
|
-
const name = f.name?.toLowerCase() || '';
|
|
101908
|
-
return name !== 'product.png' && name !== 'product.jpg' && name !== 'product.webp';
|
|
101909
|
-
});
|
|
101910
|
-
if (!cancelled) {
|
|
101911
|
-
setFolderFilesInfo({ hasProduct, hasCreativeImages });
|
|
101912
|
-
// If product not found, poll every 10 seconds until found
|
|
101913
|
-
if (!hasProduct) {
|
|
101914
|
-
pollTimeoutId = setTimeout(() => {
|
|
101915
|
-
if (!cancelled)
|
|
101916
|
-
checkFolderFiles();
|
|
101917
|
-
}, 10_000);
|
|
101918
|
-
}
|
|
101919
|
-
}
|
|
101920
|
-
}
|
|
101921
|
-
else {
|
|
102229
|
+
if (!response.ok) {
|
|
101922
102230
|
if (!cancelled)
|
|
101923
102231
|
setFolderFilesInfo(null);
|
|
102232
|
+
return;
|
|
102233
|
+
}
|
|
102234
|
+
const data = await response.json();
|
|
102235
|
+
const hasProduct = data.files.some((f) => {
|
|
102236
|
+
const name = f.name?.toLowerCase() || '';
|
|
102237
|
+
return name === 'product.png' || name === 'product.jpg' || name === 'product.webp';
|
|
102238
|
+
});
|
|
102239
|
+
const hasCreativeImages = data.files.some((f) => {
|
|
102240
|
+
const name = f.name?.toLowerCase() || '';
|
|
102241
|
+
return name !== 'product.png' && name !== 'product.jpg' && name !== 'product.webp';
|
|
102242
|
+
});
|
|
102243
|
+
if (!cancelled) {
|
|
102244
|
+
setFolderFilesInfo({ hasProduct, hasCreativeImages });
|
|
102245
|
+
if (!hasProduct) {
|
|
102246
|
+
pollTimeoutId = setTimeout(() => {
|
|
102247
|
+
if (!cancelled)
|
|
102248
|
+
checkFolderFiles();
|
|
102249
|
+
}, 10_000);
|
|
102250
|
+
}
|
|
101924
102251
|
}
|
|
101925
102252
|
}
|
|
101926
102253
|
catch (err) {
|
|
@@ -101934,7 +102261,6 @@ function App() {
|
|
|
101934
102261
|
}
|
|
101935
102262
|
};
|
|
101936
102263
|
let pollTimeoutId = null;
|
|
101937
|
-
// Debounce check
|
|
101938
102264
|
const timeoutId = setTimeout(() => {
|
|
101939
102265
|
checkFolderFiles();
|
|
101940
102266
|
}, 500);
|
|
@@ -103041,7 +103367,7 @@ function App() {
|
|
|
103041
103367
|
setTexts(['']);
|
|
103042
103368
|
setPairTranslations({});
|
|
103043
103369
|
// Read pairs count from settings (3–10, default 3)
|
|
103044
|
-
const pairsCountInit = (0,
|
|
103370
|
+
const pairsCountInit = (0,_promptOverrides__WEBPACK_IMPORTED_MODULE_55__.getPairsCount)();
|
|
103045
103371
|
// Initialize placeholders
|
|
103046
103372
|
const initialTitles = Array.from({ length: pairsCountInit }, (_, index) => ({
|
|
103047
103373
|
index: index + 1,
|
|
@@ -103070,7 +103396,7 @@ function App() {
|
|
|
103070
103396
|
}
|
|
103071
103397
|
// Generate all pairs (title + text) in a single request
|
|
103072
103398
|
addLog(formatLogMessage('log', '📋 Generating title+text pairs in a single request...'));
|
|
103073
|
-
const selectedIndices = (0,
|
|
103399
|
+
const selectedIndices = (0,_promptOverrides__WEBPACK_IMPORTED_MODULE_55__.getSelectedPairApproaches)();
|
|
103074
103400
|
setLastUsedApproachIndices(selectedIndices);
|
|
103075
103401
|
const pairsCount = selectedIndices.length;
|
|
103076
103402
|
addLog(formatLogMessage('log', `⚙️ Generating ${pairsCount} pairs (approaches: ${selectedIndices.join(', ')})`));
|
|
@@ -104009,7 +104335,7 @@ function App() {
|
|
|
104009
104335
|
addLog(formatLogMessage(level, ...args));
|
|
104010
104336
|
};
|
|
104011
104337
|
logMsg('log', '📦 Creating ZIP archive with HTML and product image...');
|
|
104012
|
-
const zip = new (
|
|
104338
|
+
const zip = new (jszip__WEBPACK_IMPORTED_MODULE_57___default())();
|
|
104013
104339
|
// Replace product image path in HTML to match actual filename (png/jpg/webp)
|
|
104014
104340
|
const htmlWithProductPath = htmlContent.replace(/src=["']product\.(png|jpe?g|webp)["']/gi, `src="${productImageName}"`);
|
|
104015
104341
|
zip.file('index.html', htmlWithProductPath);
|
|
@@ -104331,6 +104657,15 @@ function App() {
|
|
|
104331
104657
|
throw new Error(errorMsg);
|
|
104332
104658
|
}
|
|
104333
104659
|
addLog(formatLogMessage('log', '✅ Folder ID extracted:', folderId));
|
|
104660
|
+
addLog(formatLogMessage('log', '🔒 Проверка доступа по ссылке к папке оффера (нужен для референса)...'));
|
|
104661
|
+
const pubGate = await verifyOfferFolderHasAnyoneLinkForImageGen(validToken, folderId);
|
|
104662
|
+
if (!pubGate.ok) {
|
|
104663
|
+
addLog(formatLogMessage('error', '❌ ' + pubGate.message));
|
|
104664
|
+
alert(pubGate.message);
|
|
104665
|
+
setGeneratingImages(false);
|
|
104666
|
+
return;
|
|
104667
|
+
}
|
|
104668
|
+
addLog(formatLogMessage('log', '✅ Доступ по ссылке к папке оффера подтверждён'));
|
|
104334
104669
|
// Check for product image (png/jpg/webp)
|
|
104335
104670
|
addLog(formatLogMessage('log', '🔍 Checking for product image...'));
|
|
104336
104671
|
const productImage = await fetchProductImage(folderId);
|
|
@@ -104341,8 +104676,8 @@ function App() {
|
|
|
104341
104676
|
}
|
|
104342
104677
|
addLog(formatLogMessage('log', '✅ Product image found'));
|
|
104343
104678
|
// Generate images with different approaches (количество по каждому подходу)
|
|
104344
|
-
const
|
|
104345
|
-
if (
|
|
104679
|
+
const expandedTasks = (0,_prompts__WEBPACK_IMPORTED_MODULE_1__.getCreoApproachExpandedTasks)();
|
|
104680
|
+
if (expandedTasks.length === 0) {
|
|
104346
104681
|
addLog(formatLogMessage('error', '❌ Укажите количество изображений (хотя бы 1) в настройках подходов'));
|
|
104347
104682
|
alert('Укажите количество изображений (1–4) хотя бы для одного подхода в настройках');
|
|
104348
104683
|
setGeneratingImages(false);
|
|
@@ -104351,11 +104686,15 @@ function App() {
|
|
|
104351
104686
|
// При "both" — на каждый подход генерируем и 1:1, и 2:3
|
|
104352
104687
|
const useBoth = imageAspectRatio === 'both';
|
|
104353
104688
|
const tasks = useBoth
|
|
104354
|
-
?
|
|
104355
|
-
{ approach:
|
|
104356
|
-
{ approach:
|
|
104689
|
+
? expandedTasks.flatMap(t => [
|
|
104690
|
+
{ approach: t.approach, poolIndex: t.poolIndex, ratio: '1:1' },
|
|
104691
|
+
{ approach: t.approach, poolIndex: t.poolIndex, ratio: '2:3' }
|
|
104357
104692
|
])
|
|
104358
|
-
:
|
|
104693
|
+
: expandedTasks.map(t => ({
|
|
104694
|
+
approach: t.approach,
|
|
104695
|
+
poolIndex: t.poolIndex,
|
|
104696
|
+
ratio: imageAspectRatio
|
|
104697
|
+
}));
|
|
104359
104698
|
const additionalInfoLine = generateAdditionalInfo.trim()
|
|
104360
104699
|
? `\n📋 ДОПОЛНИТЕЛЬНАЯ ИНФОРМАЦИЯ О ПРОДУКТЕ: ${generateAdditionalInfo.trim()}`
|
|
104361
104700
|
: '';
|
|
@@ -104374,6 +104713,7 @@ function App() {
|
|
|
104374
104713
|
index: index + 1,
|
|
104375
104714
|
imageUrl: undefined,
|
|
104376
104715
|
approach: t.approach.name + (useBoth ? ` (${t.ratio})` : ''),
|
|
104716
|
+
creoApproachUiNumber: t.poolIndex + 1,
|
|
104377
104717
|
aspectRatio: t.ratio,
|
|
104378
104718
|
uploaded: false,
|
|
104379
104719
|
checking: false,
|
|
@@ -104385,7 +104725,8 @@ function App() {
|
|
|
104385
104725
|
regenerating: false,
|
|
104386
104726
|
customRegeneratePrompt: '',
|
|
104387
104727
|
failed: false,
|
|
104388
|
-
generating: false // In sequential mode, images start queued (not generating)
|
|
104728
|
+
generating: false, // In sequential mode, images start queued (not generating)
|
|
104729
|
+
remakeCount: 0
|
|
104389
104730
|
}));
|
|
104390
104731
|
setGeneratedImagesData(initialPlaceholders);
|
|
104391
104732
|
addLog(formatLogMessage('log', `📝 Generated prompts for ${tasks.length} images${useBoth ? ' (1:1 + 2:3 на каждый подход)' : ''}`));
|
|
@@ -104542,7 +104883,7 @@ function App() {
|
|
|
104542
104883
|
imageUrl: null,
|
|
104543
104884
|
success: false,
|
|
104544
104885
|
error: new Error('Generation did not complete'),
|
|
104545
|
-
approach:
|
|
104886
|
+
approach: tasks[i]?.approach.name || 'Unknown',
|
|
104546
104887
|
originalPrompt: imagePrompts[i],
|
|
104547
104888
|
productImageUrl: productImage.url
|
|
104548
104889
|
});
|
|
@@ -104635,11 +104976,26 @@ function App() {
|
|
|
104635
104976
|
alert('Не удалось найти оригинальный промпт или изображение продукта для переделки');
|
|
104636
104977
|
return;
|
|
104637
104978
|
}
|
|
104979
|
+
const regenFolderId = extractFolderId(driveFolderUrl);
|
|
104980
|
+
if (!regenFolderId) {
|
|
104981
|
+
alert('Укажите корректный URL папки оффера на Google Drive');
|
|
104982
|
+
return;
|
|
104983
|
+
}
|
|
104638
104984
|
const addLog = (msg) => {
|
|
104639
104985
|
setImagesGenerationLogs(prev => [...prev, msg]);
|
|
104640
104986
|
logToTerminal('log', msg.replace(/\[.*?\]\s*/, ''));
|
|
104641
104987
|
};
|
|
104642
104988
|
try {
|
|
104989
|
+
const regenTok = await getValidAccessToken();
|
|
104990
|
+
if (!regenTok) {
|
|
104991
|
+
alert('Please log in with Google first');
|
|
104992
|
+
return;
|
|
104993
|
+
}
|
|
104994
|
+
const regenPub = await verifyOfferFolderHasAnyoneLinkForImageGen(regenTok, regenFolderId);
|
|
104995
|
+
if (!regenPub.ok) {
|
|
104996
|
+
alert(regenPub.message);
|
|
104997
|
+
return;
|
|
104998
|
+
}
|
|
104643
104999
|
// Get current customRegeneratePrompt from state
|
|
104644
105000
|
const currentImageData = generatedImagesData.find(img => img.index === imageData.index);
|
|
104645
105001
|
const customPrompt = currentImageData?.customRegeneratePrompt?.trim() || '';
|
|
@@ -104794,7 +105150,8 @@ ${imageData.originalPrompt}
|
|
|
104794
105150
|
checkErrors: undefined,
|
|
104795
105151
|
uploaded: false, // Reset uploaded status since it's a new image
|
|
104796
105152
|
customRegeneratePrompt: '', // Reset custom prompt after regeneration
|
|
104797
|
-
failed: false // Mark as successful
|
|
105153
|
+
failed: false, // Mark as successful
|
|
105154
|
+
remakeCount: (img.remakeCount ?? 0) + 1
|
|
104798
105155
|
}
|
|
104799
105156
|
: img));
|
|
104800
105157
|
// Run validation on the new image (skip if disabled)
|
|
@@ -104859,11 +105216,26 @@ ${imageData.originalPrompt}
|
|
|
104859
105216
|
alert('Не удалось найти оригинальный промпт или изображение продукта для переделки');
|
|
104860
105217
|
return;
|
|
104861
105218
|
}
|
|
105219
|
+
const freshFolderId = extractFolderId(driveFolderUrl);
|
|
105220
|
+
if (!freshFolderId) {
|
|
105221
|
+
alert('Укажите корректный URL папки оффера на Google Drive');
|
|
105222
|
+
return;
|
|
105223
|
+
}
|
|
104862
105224
|
const addLog = (msg) => {
|
|
104863
105225
|
setImagesGenerationLogs(prev => [...prev, msg]);
|
|
104864
105226
|
logToTerminal('log', msg.replace(/\[.*?\]\s*/, ''));
|
|
104865
105227
|
};
|
|
104866
105228
|
try {
|
|
105229
|
+
const freshTok = await getValidAccessToken();
|
|
105230
|
+
if (!freshTok) {
|
|
105231
|
+
alert('Please log in with Google first');
|
|
105232
|
+
return;
|
|
105233
|
+
}
|
|
105234
|
+
const freshPub = await verifyOfferFolderHasAnyoneLinkForImageGen(freshTok, freshFolderId);
|
|
105235
|
+
if (!freshPub.ok) {
|
|
105236
|
+
alert(freshPub.message);
|
|
105237
|
+
return;
|
|
105238
|
+
}
|
|
104867
105239
|
// Mark as regenerating (show overlay timer) - clear old image URL immediately to force re-render
|
|
104868
105240
|
setGeneratedImagesData(prev => prev.map(img => img.index === imageData.index
|
|
104869
105241
|
? {
|
|
@@ -104909,7 +105281,8 @@ ${imageData.originalPrompt}
|
|
|
104909
105281
|
checkErrors: undefined,
|
|
104910
105282
|
uploaded: false,
|
|
104911
105283
|
customRegeneratePrompt: '',
|
|
104912
|
-
failed: false
|
|
105284
|
+
failed: false,
|
|
105285
|
+
remakeCount: (img.remakeCount ?? 0) + 1
|
|
104913
105286
|
}
|
|
104914
105287
|
: img));
|
|
104915
105288
|
// Validate new image (skip if disabled)
|
|
@@ -105031,11 +105404,10 @@ ${imageData.originalPrompt}
|
|
|
105031
105404
|
logToTerminal('log', msg.replace(/\[.*?\]\s*/, ''));
|
|
105032
105405
|
};
|
|
105033
105406
|
try {
|
|
105034
|
-
const filename =
|
|
105407
|
+
const filename = creativeImageUploadFilename(imageData.creoApproachUiNumber);
|
|
105035
105408
|
addLog(formatLogMessage('log', `📤 Uploading image ${imageData.index} to Drive: ${filename}`));
|
|
105036
105409
|
const driveUrl = await uploadImageToDrive(imageData.imageUrl, filename, folderId, addLog);
|
|
105037
105410
|
addLog(formatLogMessage('log', `✅ Image ${imageData.index} uploaded: ${driveUrl}`));
|
|
105038
|
-
// Update uploaded status
|
|
105039
105411
|
setGeneratedImagesData(prev => prev.map(img => img.index === imageData.index ? { ...img, uploaded: true } : img));
|
|
105040
105412
|
// (Removed legacy Generated Images links list)
|
|
105041
105413
|
}
|
|
@@ -105075,9 +105447,8 @@ ${imageData.originalPrompt}
|
|
|
105075
105447
|
: img));
|
|
105076
105448
|
try {
|
|
105077
105449
|
addLog(formatLogMessage('log', `📤 Uploading ${notUploaded.length} image(s) to Drive (parallel)...`));
|
|
105078
|
-
const
|
|
105079
|
-
|
|
105080
|
-
const filename = `${generateProduct.replace(/\s+/g, '_')}_${imageData.index}_${baseTs}_${i}.png`;
|
|
105450
|
+
const results = await Promise.allSettled(notUploaded.map((imageData) => {
|
|
105451
|
+
const filename = creativeImageUploadFilename(imageData.creoApproachUiNumber);
|
|
105081
105452
|
addLog(formatLogMessage('log', `📤 Starting upload image ${imageData.index}: ${filename}`));
|
|
105082
105453
|
return uploadImageToDrive(imageData.imageUrl, filename, folderId, addLog).then(driveUrl => ({
|
|
105083
105454
|
index: imageData.index,
|
|
@@ -105157,6 +105528,22 @@ ${imageData.originalPrompt}
|
|
|
105157
105528
|
// invalid — leave as is
|
|
105158
105529
|
}
|
|
105159
105530
|
};
|
|
105531
|
+
const handleLinkPaste = (e) => {
|
|
105532
|
+
e.preventDefault();
|
|
105533
|
+
const pasted = e.clipboardData.getData('text/plain');
|
|
105534
|
+
const cleanedPaste = pasted.split('?')[0] ?? pasted;
|
|
105535
|
+
const input = e.currentTarget;
|
|
105536
|
+
const start = input.selectionStart ?? 0;
|
|
105537
|
+
const end = input.selectionEnd ?? 0;
|
|
105538
|
+
const newVal = link.slice(0, start) + cleanedPaste + link.slice(end);
|
|
105539
|
+
handleLinkChange(newVal);
|
|
105540
|
+
const pos = start + cleanedPaste.length;
|
|
105541
|
+
setTimeout(() => {
|
|
105542
|
+
const el = linkInputRef.current;
|
|
105543
|
+
if (el)
|
|
105544
|
+
el.setSelectionRange(pos, pos);
|
|
105545
|
+
}, 0);
|
|
105546
|
+
};
|
|
105160
105547
|
const extractFolderId = (url) => {
|
|
105161
105548
|
// Try to match format: /folders/([a-zA-Z0-9_-]+)
|
|
105162
105549
|
const foldersMatch = url.match(/folders\/([a-zA-Z0-9_-]+)/);
|
|
@@ -105203,7 +105590,13 @@ ${imageData.originalPrompt}
|
|
|
105203
105590
|
const name = f.name?.toLowerCase() || '';
|
|
105204
105591
|
return name !== 'product.png' && name !== 'product.jpg' && name !== 'product.webp';
|
|
105205
105592
|
});
|
|
105206
|
-
return filteredFiles
|
|
105593
|
+
return filteredFiles
|
|
105594
|
+
.filter((f) => f.id && f.name)
|
|
105595
|
+
.map((f) => ({
|
|
105596
|
+
fileId: f.id,
|
|
105597
|
+
name: f.name,
|
|
105598
|
+
viewUrl: `https://drive.google.com/file/d/${f.id}/view?usp=sharing`
|
|
105599
|
+
}));
|
|
105207
105600
|
};
|
|
105208
105601
|
const fetchProductImage = async (folderId) => {
|
|
105209
105602
|
const validToken = await getValidAccessToken();
|
|
@@ -105336,8 +105729,13 @@ ${imageData.originalPrompt}
|
|
|
105336
105729
|
},
|
|
105337
105730
|
brand: brandValue !== undefined ? brandValue : brand || '',
|
|
105338
105731
|
link: linkValue !== undefined ? linkValue : link || '',
|
|
105339
|
-
|
|
105340
|
-
|
|
105732
|
+
catalogUrlIncludeTextApproach,
|
|
105733
|
+
catalogUrlIncludeCreoApproach,
|
|
105734
|
+
catalogUrlTextApproachParam,
|
|
105735
|
+
catalogUrlCreoApproachParam,
|
|
105736
|
+
catalogLinkExtraMacros,
|
|
105737
|
+
selectedPairApproaches: (0,_promptOverrides__WEBPACK_IMPORTED_MODULE_55__.getSelectedPairApproaches)(),
|
|
105738
|
+
imageApproachCounts: (0,_promptOverrides__WEBPACK_IMPORTED_MODULE_55__.getImageApproachCounts)(),
|
|
105341
105739
|
savedAt: new Date().toISOString()
|
|
105342
105740
|
};
|
|
105343
105741
|
const jsonContent = JSON.stringify(dataToSave, null, 2);
|
|
@@ -105486,9 +105884,41 @@ ${imageData.originalPrompt}
|
|
|
105486
105884
|
setLink(loadedData.link || '');
|
|
105487
105885
|
logToTerminal('log', '[Load Content] Loaded link:', loadedData.link || '(empty)');
|
|
105488
105886
|
}
|
|
105489
|
-
|
|
105490
|
-
|
|
105491
|
-
|
|
105887
|
+
if (typeof loadedData.catalogUrlIncludeTextApproach === 'boolean') {
|
|
105888
|
+
setCatalogUrlIncludeTextApproach(loadedData.catalogUrlIncludeTextApproach);
|
|
105889
|
+
}
|
|
105890
|
+
if (typeof loadedData.catalogUrlIncludeCreoApproach === 'boolean') {
|
|
105891
|
+
setCatalogUrlIncludeCreoApproach(loadedData.catalogUrlIncludeCreoApproach);
|
|
105892
|
+
}
|
|
105893
|
+
if (typeof loadedData.catalogUrlTextApproachParam === 'string' && loadedData.catalogUrlTextApproachParam.trim()) {
|
|
105894
|
+
setCatalogUrlTextApproachParam(loadedData.catalogUrlTextApproachParam.trim());
|
|
105895
|
+
}
|
|
105896
|
+
if (typeof loadedData.catalogUrlCreoApproachParam === 'string' && loadedData.catalogUrlCreoApproachParam.trim()) {
|
|
105897
|
+
setCatalogUrlCreoApproachParam(loadedData.catalogUrlCreoApproachParam.trim());
|
|
105898
|
+
}
|
|
105899
|
+
if (typeof loadedData.catalogLinkExtraMacros === 'string') {
|
|
105900
|
+
setCatalogLinkExtraMacros(loadedData.catalogLinkExtraMacros);
|
|
105901
|
+
}
|
|
105902
|
+
else {
|
|
105903
|
+
setCatalogLinkExtraMacros(DEFAULT_CATALOG_LINK_EXTRA_MACROS);
|
|
105904
|
+
}
|
|
105905
|
+
const parsedApproaches = (0,_promptOverrides__WEBPACK_IMPORTED_MODULE_55__.parseApproachesFromDriveData)(loadedData);
|
|
105906
|
+
const currentPairs = (0,_promptOverrides__WEBPACK_IMPORTED_MODULE_55__.getSelectedPairApproaches)();
|
|
105907
|
+
const currentCounts = (0,_promptOverrides__WEBPACK_IMPORTED_MODULE_55__.getImageApproachCounts)();
|
|
105908
|
+
const hasDrivePairs = parsedApproaches.pairs !== null;
|
|
105909
|
+
const hasDriveCounts = parsedApproaches.counts !== null;
|
|
105910
|
+
if (hasDrivePairs || hasDriveCounts) {
|
|
105911
|
+
const pairsDiffer = hasDrivePairs && !sortedPairIndicesEqual(parsedApproaches.pairs, currentPairs);
|
|
105912
|
+
const countsDiffer = hasDriveCounts && !imageApproachCountsEqual(parsedApproaches.counts, currentCounts);
|
|
105913
|
+
if (pairsDiffer || countsDiffer) {
|
|
105914
|
+
setApproachLoadChoice({
|
|
105915
|
+
savedPairs: parsedApproaches.pairs,
|
|
105916
|
+
savedCounts: parsedApproaches.counts,
|
|
105917
|
+
currentPairs,
|
|
105918
|
+
currentCounts,
|
|
105919
|
+
});
|
|
105920
|
+
logToTerminal('log', '[Load Content] Offer file contains approach settings — asking user to apply or keep current');
|
|
105921
|
+
}
|
|
105492
105922
|
}
|
|
105493
105923
|
logToTerminal('log', '[Load Content] Successfully loaded content');
|
|
105494
105924
|
setDriveFilesFound(prev => ({ ...prev, content: false }));
|
|
@@ -105500,6 +105930,19 @@ ${imageData.originalPrompt}
|
|
|
105500
105930
|
return { found: false };
|
|
105501
105931
|
}
|
|
105502
105932
|
};
|
|
105933
|
+
const handleApproachLoadApplyFromFile = () => {
|
|
105934
|
+
if (!approachLoadChoice)
|
|
105935
|
+
return;
|
|
105936
|
+
const applied = (0,_promptOverrides__WEBPACK_IMPORTED_MODULE_55__.applyParsedApproachesFromDrive)(approachLoadChoice.savedPairs, approachLoadChoice.savedCounts);
|
|
105937
|
+
if (applied) {
|
|
105938
|
+
logToTerminal('log', '[Load Content] Applied approach settings from offer file (user choice)');
|
|
105939
|
+
}
|
|
105940
|
+
setApproachLoadChoice(null);
|
|
105941
|
+
};
|
|
105942
|
+
const handleApproachLoadKeepCurrent = () => {
|
|
105943
|
+
logToTerminal('log', '[Load Content] Kept local approach settings (user choice)');
|
|
105944
|
+
setApproachLoadChoice(null);
|
|
105945
|
+
};
|
|
105503
105946
|
syncDriveAfterPromptSaveRef.current = () => {
|
|
105504
105947
|
if (!driveFolderUrl || loadingContentFromDrive)
|
|
105505
105948
|
return;
|
|
@@ -105518,8 +105961,8 @@ ${imageData.originalPrompt}
|
|
|
105518
105961
|
};
|
|
105519
105962
|
(0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => {
|
|
105520
105963
|
const listener = () => syncDriveAfterPromptSaveRef.current();
|
|
105521
|
-
window.addEventListener(
|
|
105522
|
-
return () => window.removeEventListener(
|
|
105964
|
+
window.addEventListener(_promptOverrides__WEBPACK_IMPORTED_MODULE_55__.PROMPT_OVERRIDES_SAVED_EVENT, listener);
|
|
105965
|
+
return () => window.removeEventListener(_promptOverrides__WEBPACK_IMPORTED_MODULE_55__.PROMPT_OVERRIDES_SAVED_EVENT, listener);
|
|
105523
105966
|
}, []);
|
|
105524
105967
|
const handleGenerate = async () => {
|
|
105525
105968
|
if (!driveFolderUrl || !brand || !link) {
|
|
@@ -105574,9 +106017,17 @@ ${imageData.originalPrompt}
|
|
|
105574
106017
|
for (let i = 0; i < pairCount; i++) {
|
|
105575
106018
|
const title = titleList[i];
|
|
105576
106019
|
const text = textList[i];
|
|
106020
|
+
const pairApproachIdx = lastUsedApproachIndices[i] ?? i;
|
|
106021
|
+
const textApproachUiNumber = String(pairApproachIdx + 1);
|
|
105577
106022
|
for (const image of images) {
|
|
105578
106023
|
const id = `${brand}${idCounter++}`;
|
|
105579
|
-
const
|
|
106024
|
+
const creoFromFileName = parseCreoApproachLabelFromImageFileName(image.name);
|
|
106025
|
+
const rowLink = appendCreativeIdToCatalogLink(link, id, {
|
|
106026
|
+
textApproach: catalogUrlIncludeTextApproach ? textApproachUiNumber : undefined,
|
|
106027
|
+
creoApproach: catalogUrlIncludeCreoApproach && creoFromFileName ? creoFromFileName : undefined,
|
|
106028
|
+
textParamKey: catalogUrlTextApproachParam,
|
|
106029
|
+
creoParamKey: catalogUrlCreoApproachParam
|
|
106030
|
+
}, catalogLinkExtraMacros);
|
|
105580
106031
|
rows.push([
|
|
105581
106032
|
id,
|
|
105582
106033
|
title,
|
|
@@ -105585,15 +106036,15 @@ ${imageData.originalPrompt}
|
|
|
105585
106036
|
'new',
|
|
105586
106037
|
'10,00 USD',
|
|
105587
106038
|
rowLink,
|
|
105588
|
-
image,
|
|
106039
|
+
image.viewUrl,
|
|
105589
106040
|
brand
|
|
105590
106041
|
]);
|
|
105591
106042
|
}
|
|
105592
106043
|
}
|
|
105593
106044
|
setGeneratedData(rows);
|
|
105594
106045
|
// Create workbook
|
|
105595
|
-
const wb =
|
|
105596
|
-
const ws =
|
|
106046
|
+
const wb = xlsx__WEBPACK_IMPORTED_MODULE_56__.utils.book_new();
|
|
106047
|
+
const ws = xlsx__WEBPACK_IMPORTED_MODULE_56__.utils.aoa_to_sheet(rows);
|
|
105597
106048
|
// Set column widths (approximate pixel width / 7)
|
|
105598
106049
|
ws['!cols'] = [
|
|
105599
106050
|
{ wch: 20 }, // id
|
|
@@ -105606,9 +106057,9 @@ ${imageData.originalPrompt}
|
|
|
105606
106057
|
{ wch: 40 }, // image_link
|
|
105607
106058
|
{ wch: 20 } // brand
|
|
105608
106059
|
];
|
|
105609
|
-
|
|
106060
|
+
xlsx__WEBPACK_IMPORTED_MODULE_56__.utils.book_append_sheet(wb, ws, "Products");
|
|
105610
106061
|
// Generate buffer
|
|
105611
|
-
const wbout =
|
|
106062
|
+
const wbout = xlsx__WEBPACK_IMPORTED_MODULE_56__.write(wb, { bookType: 'xlsx', type: 'array' });
|
|
105612
106063
|
// Upload to Drive (имя файла по бренду)
|
|
105613
106064
|
const dateStr = new Date().toISOString().split('T')[0];
|
|
105614
106065
|
const fileName = `${brand}-${dateStr}.xlsx`;
|
|
@@ -105730,13 +106181,13 @@ ${imageData.originalPrompt}
|
|
|
105730
106181
|
setTestLoading(true);
|
|
105731
106182
|
try {
|
|
105732
106183
|
// Create simple test workbook with structure
|
|
105733
|
-
const wb =
|
|
106184
|
+
const wb = xlsx__WEBPACK_IMPORTED_MODULE_56__.utils.book_new();
|
|
105734
106185
|
const rows = [
|
|
105735
106186
|
INSTRUCTION_ROW,
|
|
105736
106187
|
['id', 'title', 'description', 'availability', 'condition', 'price', 'link', 'image_link', 'brand'],
|
|
105737
106188
|
['test1', 'Test Title', 'Test Description', 'in stock', 'new', '10.00 USD', 'http://test.com', 'http://test.com/img.jpg', 'TestBrand']
|
|
105738
106189
|
];
|
|
105739
|
-
const ws =
|
|
106190
|
+
const ws = xlsx__WEBPACK_IMPORTED_MODULE_56__.utils.aoa_to_sheet(rows);
|
|
105740
106191
|
// Set column widths
|
|
105741
106192
|
ws['!cols'] = [
|
|
105742
106193
|
{ wch: 20 }, // id
|
|
@@ -105749,8 +106200,8 @@ ${imageData.originalPrompt}
|
|
|
105749
106200
|
{ wch: 40 }, // image_link
|
|
105750
106201
|
{ wch: 20 } // brand
|
|
105751
106202
|
];
|
|
105752
|
-
|
|
105753
|
-
const wbout =
|
|
106203
|
+
xlsx__WEBPACK_IMPORTED_MODULE_56__.utils.book_append_sheet(wb, ws, "Test");
|
|
106204
|
+
const wbout = xlsx__WEBPACK_IMPORTED_MODULE_56__.write(wb, { bookType: 'xlsx', type: 'array' });
|
|
105754
106205
|
// Try to extract folder ID if available, otherwise upload to root
|
|
105755
106206
|
const folderId = driveFolderUrl ? extractFolderId(driveFolderUrl) : undefined;
|
|
105756
106207
|
const result = await uploadFileToDrive(wbout, 'test_table.xlsx', folderId || undefined);
|
|
@@ -105802,7 +106253,7 @@ ${imageData.originalPrompt}
|
|
|
105802
106253
|
};
|
|
105803
106254
|
// Show lock screen if not unlocked
|
|
105804
106255
|
if (!unlocked) {
|
|
105805
|
-
return (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
106256
|
+
return (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_37__["default"], { theme: theme },
|
|
105806
106257
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_4__["default"], null),
|
|
105807
106258
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { onClick: handleSecretClick, sx: {
|
|
105808
106259
|
width: '100vw',
|
|
@@ -105842,35 +106293,49 @@ ${imageData.originalPrompt}
|
|
|
105842
106293
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("br", null),
|
|
105843
106294
|
"Please contact system administrator"))));
|
|
105844
106295
|
}
|
|
105845
|
-
return (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
106296
|
+
return (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_37__["default"], { theme: theme },
|
|
105846
106297
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_4__["default"], null),
|
|
105847
106298
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_7__["default"], { maxWidth: "lg", sx: { py: 4 } },
|
|
105848
106299
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { sx: { display: 'flex', justifyContent: 'space-between', alignItems: 'center', mb: 2 } },
|
|
105849
106300
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "h4", component: "h1", sx: { fontWeight: 'bold', color: 'primary.main' } }, "Docs Combiner"),
|
|
105850
106301
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], null,
|
|
105851
106302
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_8__["default"], { onClick: () => setPromptManagerOpen(true), color: "inherit", "aria-label": "manage prompts", sx: { mr: 1 } },
|
|
105852
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
105853
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_8__["default"], { onClick: toggleTheme, color: "inherit", "aria-label": "toggle theme" }, darkMode ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
106303
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_52__["default"], null)),
|
|
106304
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_8__["default"], { onClick: toggleTheme, color: "inherit", "aria-label": "toggle theme" }, darkMode ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_42__["default"], null) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_41__["default"], null)))),
|
|
105854
106305
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_9__["default"], { variant: "outlined", sx: { mb: 4 } },
|
|
105855
106306
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_10__["default"], null,
|
|
105856
106307
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_11__["default"], { spacing: 3 },
|
|
105857
106308
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], null,
|
|
105858
106309
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "h6", gutterBottom: true }, "Google Drive Authentication"),
|
|
105859
|
-
|
|
105860
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
106310
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { sx: { mb: 2 } },
|
|
106311
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "subtitle2", color: "text.secondary", gutterBottom: true }, "\u041A\u043E\u0440\u043D\u0435\u0432\u0430\u044F \u043F\u0430\u043F\u043A\u0430 \u043F\u0440\u043E\u0435\u043A\u0442\u0430"),
|
|
106312
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "caption", color: "text.secondary", display: "block", sx: { mb: 1 } }, "\u0421\u0441\u044B\u043B\u043A\u0430 \u043D\u0430 \u043A\u043E\u0440\u043D\u0435\u0432\u0443\u044E \u043F\u0430\u043F\u043A\u0443 \u043D\u0430 Google \u0414\u0438\u0441\u043A\u0435 (\u0432\u043D\u0443\u0442\u0440\u0438 \u043D\u0435\u0451 \u0434\u043E\u043B\u0436\u043D\u0430 \u0431\u044B\u0442\u044C \u043F\u0430\u043F\u043A\u0430 OFFERS)."),
|
|
106313
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_12__["default"], { label: "URL \u043A\u043E\u0440\u043D\u0435\u0432\u043E\u0439 \u043F\u0430\u043F\u043A\u0438 Google Drive", variant: "outlined", fullWidth: true, value: rootDriveFolderUrl, onChange: (e) => setRootDriveFolderUrl(e.target.value), placeholder: "https://drive.google.com/drive/folders/...", sx: { mb: 1 } }),
|
|
106314
|
+
checkingRootFolder && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_13__["default"], null,
|
|
106315
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { component: "span", sx: { display: 'inline-flex', alignItems: 'center', gap: 1 } },
|
|
106316
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_14__["default"], { size: 14 }),
|
|
106317
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", null, "\u041F\u0440\u043E\u0432\u0435\u0440\u043A\u0430 \u043A\u043E\u0440\u043D\u0435\u0432\u043E\u0439 \u043F\u0430\u043F\u043A\u0438 (OFFERS, \u0434\u043E\u0441\u0442\u0443\u043F)...")))),
|
|
106318
|
+
drivePublicAccessWarning && extractFolderId(rootDriveFolderUrl) && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_15__["default"], { severity: "warning", sx: { mt: 1 } }, "\u041E\u0431\u0449\u0438\u0439 \u0434\u043E\u0441\u0442\u0443\u043F \u043F\u043E \u0441\u0441\u044B\u043B\u043A\u0435 \u0432\u0441\u0451 \u0435\u0449\u0451 \u0432\u043A\u043B\u044E\u0447\u0451\u043D. \u0417\u0430\u043A\u0440\u043E\u0439\u0442\u0435 \u0435\u0433\u043E \u0432\u0440\u0443\u0447\u043D\u0443\u044E \u0432 \u043D\u0430\u0441\u0442\u0440\u043E\u0439\u043A\u0430\u0445 \u0434\u043E\u0441\u0442\u0443\u043F\u0430 Google \u0414\u0438\u0441\u043A\u0430 \u0438\u043B\u0438 \u0441\u043C\u0435\u043D\u0438\u0442\u0435 \u043F\u0430\u043F\u043A\u0443 \u0438 \u0441\u043E\u0433\u043B\u0430\u0441\u0438\u0442\u0435\u0441\u044C \u0443\u0431\u0440\u0430\u0442\u044C \u0434\u043E\u0441\u0442\u0443\u043F \u0430\u0432\u0442\u043E\u043C\u0430\u0442\u0438\u0447\u0435\u0441\u043A\u0438.")),
|
|
106319
|
+
!checkingRootFolder && rootFolderInfo && !rootFolderInfo.hasOffersFolder && extractFolderId(rootDriveFolderUrl) && (accessToken || refreshToken) && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_15__["default"], { severity: "error", sx: { mt: 1 } }, "\u0412 \u043A\u043E\u0440\u043D\u0435\u0432\u043E\u0439 \u043F\u0430\u043F\u043A\u0435 \u043D\u0435\u0442 \u043F\u043E\u0434\u043F\u0430\u043F\u043A\u0438 OFFERS. \u0421\u043E\u0437\u0434\u0430\u0439\u0442\u0435 \u043F\u0430\u043F\u043A\u0443 \u0441 \u0438\u043C\u0435\u043D\u0435\u043C OFFERS (\u0440\u0435\u0433\u0438\u0441\u0442\u0440 \u043D\u0435 \u0432\u0430\u0436\u0435\u043D) \u0438 \u043F\u043E\u0432\u0442\u043E\u0440\u0438\u0442\u0435 \u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0443.")),
|
|
106320
|
+
!checkingRootFolder && !rootFolderInfo && rootDriveFolderUrl.trim() && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_13__["default"], null, (accessToken || refreshToken)
|
|
106321
|
+
? 'Введите корректную ссылку на корневую папку Google Drive'
|
|
106322
|
+
: 'Войдите в Google, чтобы проверить корневую папку и подпапку OFFERS'))),
|
|
106323
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_16__["default"], { sx: { my: 2 } }),
|
|
106324
|
+
accessToken ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_17__["default"], null,
|
|
106325
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_18__["default"], { expandIcon: react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_47__["default"], null) },
|
|
105861
106326
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { sx: { display: 'flex', alignItems: 'center', color: 'success.main' } },
|
|
105862
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
106327
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_43__["default"], { sx: { mr: 1 } }),
|
|
105863
106328
|
" Logged In (Credentials Hidden)")),
|
|
105864
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
106329
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_19__["default"], null,
|
|
105865
106330
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_11__["default"], { spacing: 2 },
|
|
105866
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
105867
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
106331
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_12__["default"], { label: "Client ID", variant: "outlined", fullWidth: true, value: clientId, onChange: (e) => handleClientIdChange(e.target.value), helperText: "From Google Cloud Console (OAuth 2.0 Client ID)" }),
|
|
106332
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_12__["default"], { label: "Client Secret", variant: "outlined", fullWidth: true, value: clientSecret, onChange: (e) => handleClientSecretChange(e.target.value) }),
|
|
105868
106333
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_16__["default"], null),
|
|
105869
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
105870
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
105871
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
106334
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_12__["default"], { label: "OpenRouter API Key", variant: "outlined", fullWidth: true, value: openaiApiKey, onChange: (e) => handleOpenaiApiKeyChange(e.target.value), helperText: "Required for AI generation (images and text). Your key is stored locally. Get your key at openrouter.ai" }))))) : (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_11__["default"], { spacing: 2 },
|
|
106335
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_12__["default"], { label: "Client ID", variant: "outlined", fullWidth: true, value: clientId, onChange: (e) => handleClientIdChange(e.target.value), helperText: "From Google Cloud Console (OAuth 2.0 Client ID)" }),
|
|
106336
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_12__["default"], { label: "Client Secret", variant: "outlined", fullWidth: true, value: clientSecret, onChange: (e) => handleClientSecretChange(e.target.value) }))),
|
|
105872
106337
|
openaiApiKey && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { sx: { display: 'flex', alignItems: 'center', gap: 2, mt: 2 } },
|
|
105873
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
106338
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_38__["default"], { color: openRouterAccountBalance !== null ? 'primary' : 'disabled' }),
|
|
105874
106339
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "body2", color: openRouterAccountBalance !== null ? 'text.primary' : 'text.secondary' },
|
|
105875
106340
|
"\u0411\u0430\u043B\u0430\u043D\u0441: ",
|
|
105876
106341
|
openRouterBalanceLoading ? 'Loading...' : (openRouterAccountBalance !== null ? `$${openRouterAccountBalance.toFixed(2)}` : 'N/A')),
|
|
@@ -105879,28 +106344,30 @@ ${imageData.originalPrompt}
|
|
|
105879
106344
|
"\u041B\u0438\u043C\u0438\u0442 \u043A\u043B\u044E\u0447\u0430: ",
|
|
105880
106345
|
openRouterBalanceLoading ? 'Loading...' : (openRouterBalance === -1 ? 'Без лимита' : (openRouterBalance !== null ? `${openRouterBalance.toFixed(4)}` : 'N/A'))))),
|
|
105881
106346
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_11__["default"], { direction: "row", spacing: 2, alignItems: "center", sx: { mt: 2 } },
|
|
105882
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
105883
|
-
accessToken && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
106347
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_20__["default"], { variant: "contained", color: accessToken ? "success" : "primary", onClick: handleLogin, disabled: authLoading || !clientId || !clientSecret, startIcon: authLoading ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_14__["default"], { size: 20, color: "inherit" }) : (accessToken ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_43__["default"], null) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_48__["default"], null)), sx: { flexGrow: 1 } }, authLoading ? 'Logging in...' : (accessToken ? 'Logged In' : 'Login with Google')),
|
|
106348
|
+
accessToken && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_20__["default"], { variant: "outlined", color: "error", onClick: handleLogout, startIcon: react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_49__["default"], null) }, "Logout")))),
|
|
105884
106349
|
!accessToken && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null,
|
|
105885
106350
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_16__["default"], null),
|
|
105886
106351
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], null,
|
|
105887
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
106352
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_12__["default"], { label: "OpenRouter API Key", variant: "outlined", fullWidth: true, value: openaiApiKey, onChange: (e) => handleOpenaiApiKeyChange(e.target.value), helperText: "Required for AI generation (images and text). Your key is stored locally. Get your key at openrouter.ai", sx: { mb: 2 } })))),
|
|
105888
106353
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_16__["default"], { sx: { my: 2 } }),
|
|
105889
106354
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], null,
|
|
105890
106355
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "h6", gutterBottom: true }, "Google Drive Folder"),
|
|
105891
106356
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_11__["default"], { direction: { xs: 'column', sm: 'row' }, spacing: 2 },
|
|
105892
106357
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { sx: { flexGrow: 1 } },
|
|
105893
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
105894
|
-
checkingFolderFiles && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
106358
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_12__["default"], { label: "Google Drive Folder URL", variant: "outlined", fullWidth: true, value: driveFolderUrl, onChange: (e) => setDriveFolderUrl(e.target.value), placeholder: "https://drive.google.com/drive/folders/..." }),
|
|
106359
|
+
checkingFolderFiles && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_13__["default"], null,
|
|
105895
106360
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { component: "span", sx: { display: 'inline-flex', alignItems: 'center', gap: 1 } },
|
|
105896
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
105897
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", null, "\u041F\u0440\u043E\u0432\u0435\u0440\u043A\u0430 \u0444\u0430\u0439\u043B\u043E\u0432...")))),
|
|
105898
|
-
!checkingFolderFiles && folderFilesInfo && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
106361
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_14__["default"], { size: 14 }),
|
|
106362
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", null, "\u041F\u0440\u043E\u0432\u0435\u0440\u043A\u0430 \u0444\u0430\u0439\u043B\u043E\u0432 \u0432 \u043F\u0430\u043F\u043A\u0435...")))),
|
|
106363
|
+
!checkingFolderFiles && folderFilesInfo && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_13__["default"], null,
|
|
105899
106364
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { component: "span", sx: { display: 'block' } }, folderFilesInfo.hasProduct ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { component: "span", sx: { color: 'success.main' } }, "\u2713 product.png/jpg/webp \u043D\u0430\u0439\u0434\u0435\u043D")) : (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { component: "span", sx: { color: 'info.main' } }, "\u2139 product.png/jpg/webp \u043D\u0435 \u043D\u0430\u0439\u0434\u0435\u043D \u2014 \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u0435 \u0447\u0435\u0440\u0435\u0437 \u043A\u043D\u043E\u043F\u043A\u0443 \u043D\u0438\u0436\u0435"))))),
|
|
105900
|
-
!checkingFolderFiles && !folderFilesInfo && driveFolderUrl.trim() && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
105901
|
-
|
|
106365
|
+
!checkingFolderFiles && !folderFilesInfo && driveFolderUrl.trim() && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_13__["default"], null, (accessToken || refreshToken)
|
|
106366
|
+
? 'Введите корректную ссылку на папку Google Drive'
|
|
106367
|
+
: 'Войдите в Google, чтобы проверить файлы в папке'))))),
|
|
106368
|
+
!driveFolderUrl.trim() ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_15__["default"], { severity: "info", sx: { mt: 2 } },
|
|
105902
106369
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "body1", sx: { fontWeight: 'bold', mb: 1 } }, "\u0423\u043A\u0430\u0436\u0438\u0442\u0435 \u043F\u0430\u043F\u043A\u0443 Google Drive \u0434\u043B\u044F \u043F\u0440\u043E\u0434\u043E\u043B\u0436\u0435\u043D\u0438\u044F"),
|
|
105903
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "body2" }, "\u0414\u043B\u044F \u0440\u0430\u0431\u043E\u0442\u044B \u0441 \u0433\u0435\u043D\u0435\u0440\u0430\u0446\u0438\u0435\u0439 \u043A\u043E\u043D\u0442\u0435\u043D\u0442\u0430 \u0438 \u0438\u0437\u043E\u0431\u0440\u0430\u0436\u0435\u043D\u0438\u0439 \u043D\u0435\u043E\u0431\u0445\u043E\u0434\u0438\u043C\u043E \u0443\u043A\u0430\u0437\u0430\u0442\u044C \u043F\u0430\u043F\u043A\u0443 Google Drive.
|
|
106370
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "body2" }, "\u0414\u043B\u044F \u0440\u0430\u0431\u043E\u0442\u044B \u0441 \u0433\u0435\u043D\u0435\u0440\u0430\u0446\u0438\u0435\u0439 \u043A\u043E\u043D\u0442\u0435\u043D\u0442\u0430 \u0438 \u0438\u0437\u043E\u0431\u0440\u0430\u0436\u0435\u043D\u0438\u0439 \u043D\u0435\u043E\u0431\u0445\u043E\u0434\u0438\u043C\u043E \u0443\u043A\u0430\u0437\u0430\u0442\u044C \u043F\u0430\u043F\u043A\u0443 Google Drive."))) : !extractFolderId(driveFolderUrl) ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_15__["default"], { severity: "warning", sx: { mt: 2 } },
|
|
105904
106371
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "body1", sx: { fontWeight: 'bold', mb: 1 } }, "\u0412\u0432\u0435\u0434\u0438\u0442\u0435 \u043A\u043E\u0440\u0440\u0435\u043A\u0442\u043D\u0443\u044E \u0441\u0441\u044B\u043B\u043A\u0443 \u043D\u0430 \u043F\u0430\u043F\u043A\u0443"),
|
|
105905
106372
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "body2" }, "\u0421\u0441\u044B\u043B\u043A\u0430 \u0434\u043E\u043B\u0436\u043D\u0430 \u0431\u044B\u0442\u044C \u0432 \u0444\u043E\u0440\u043C\u0430\u0442\u0435: https://drive.google.com/drive/folders/..."))) : loadingContentFromDrive ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { sx: {
|
|
105906
106373
|
display: 'flex',
|
|
@@ -105916,64 +106383,80 @@ ${imageData.originalPrompt}
|
|
|
105916
106383
|
? 'rgba(25, 118, 210, 0.1)'
|
|
105917
106384
|
: 'rgba(25, 118, 210, 0.05)'
|
|
105918
106385
|
} },
|
|
105919
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
106386
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_14__["default"], { size: 40, sx: { color: 'primary.main' } }),
|
|
105920
106387
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "body1", sx: { color: 'text.secondary', fontWeight: 'bold' } }, "\u0417\u0430\u0433\u0440\u0443\u0437\u043A\u0430 \u0434\u0430\u043D\u043D\u044B\u0445 \u0438\u0437 \u043F\u0430\u043F\u043A\u0438..."))) : (react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null,
|
|
105921
106388
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_11__["default"], { direction: { xs: 'column', sm: 'row' }, spacing: 2 },
|
|
105922
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
106389
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_12__["default"], { label: "Brand (Short ID)", variant: "outlined", sx: { flex: '0 0 320px', minWidth: 280 }, value: brand, InputProps: { readOnly: true }, placeholder: "\u0410\u0432\u0442\u043E: \u0442\u043E\u0432\u0430\u0440-\u0433\u0435\u043E-\u0446\u0435\u043D\u0430", helperText: "\u0410\u0432\u0442\u043E\u0433\u0435\u043D\u0435\u0440\u0430\u0446\u0438\u044F \u0438\u0437 \u0442\u043E\u0432\u0430\u0440\u0430, \u0433\u0435\u043E \u0438 \u0446\u0435\u043D\u044B" }),
|
|
105923
106390
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { sx: { flex: 1, minWidth: 0 } },
|
|
105924
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
106391
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_12__["default"], { label: "Link", variant: "outlined", fullWidth: true, value: link, onChange: (e) => handleLinkChange(e.target.value), onBlur: handleLinkBlur, error: !!linkError, helperText: linkError, placeholder: "https://example.com/product/", inputRef: linkInputRef, InputProps: { onPaste: handleLinkPaste } }))),
|
|
106392
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { sx: { display: 'flex', gap: 1, alignItems: 'flex-start', mt: 1.5 } },
|
|
106393
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_12__["default"], { label: "\u0414\u043E\u043F. \u043C\u0430\u043A\u0440\u043E\u0441\u044B (\u043A\u0430\u0442\u0430\u043B\u043E\u0433)", variant: "outlined", size: "small", fullWidth: true, multiline: true, minRows: 2, value: catalogLinkExtraMacros, onChange: (e) => setCatalogLinkExtraMacros(e.target.value), placeholder: DEFAULT_CATALOG_LINK_EXTRA_MACROS, helperText: "\u0414\u043E\u0431\u0430\u0432\u043B\u044F\u0435\u0442\u0441\u044F \u043F\u043E\u0441\u043B\u0435 creative_id \u0438 \u043F\u0430\u0440\u0430\u043C\u0435\u0442\u0440\u043E\u0432 \u043F\u043E\u0434\u0445\u043E\u0434\u043E\u0432. \u0421\u043E\u0445\u0440\u0430\u043D\u044F\u0435\u0442\u0441\u044F \u0432 JSON \u043D\u0430\u0441\u0442\u0440\u043E\u0435\u043A \u043F\u0430\u043F\u043A\u0438.", sx: { '& .MuiInputBase-input': { fontFamily: 'monospace', fontSize: 12 } } }),
|
|
106394
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_11__["default"], { spacing: 0.5, sx: { flexShrink: 0, mt: 0.5 } },
|
|
106395
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_20__["default"], { size: "small", variant: "outlined", onClick: () => setCatalogLinkExtraMacros(DEFAULT_CATALOG_LINK_EXTRA_MACROS), sx: { textTransform: 'none', whiteSpace: 'nowrap' } }, "redtrack"),
|
|
106396
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_20__["default"], { size: "small", variant: "outlined", onClick: () => setCatalogLinkExtraMacros(DEFAULT_CATALOG_LINK_KEITARO_MACROS), sx: { textTransform: 'none', whiteSpace: 'nowrap' } }, "keitaro"))),
|
|
106397
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_11__["default"], { spacing: 1.5, sx: { mt: 1 } },
|
|
106398
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_11__["default"], { direction: { xs: 'column', sm: 'row' }, spacing: 2, alignItems: { xs: 'stretch', sm: 'flex-start' } },
|
|
106399
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_21__["default"], { control: react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_22__["default"], { checked: catalogUrlIncludeTextApproach, onChange: e => setCatalogUrlIncludeTextApproach(e.target.checked), size: "small" }), label: react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], null,
|
|
106400
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "body2" }, "\u041F\u043E\u0434\u0445\u043E\u0434 \u043A \u0442\u0435\u043A\u0441\u0442\u0443 \u0432 URL \u043A\u0430\u0442\u0430\u043B\u043E\u0433\u0430"),
|
|
106401
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "caption", color: "text.secondary" }, "\u0417\u043D\u0430\u0447\u0435\u043D\u0438\u0435 \u2014 \u043D\u043E\u043C\u0435\u0440 \u0441\u0442\u0440\u043E\u043A\u0438 \u043F\u043E\u0434\u0445\u043E\u0434\u0430 \u0434\u043B\u044F \u043F\u0430\u0440 \u0432 \u0442\u0430\u0431\u043B\u0438\u0446\u0435 \u043D\u0430\u0441\u0442\u0440\u043E\u0435\u043A (1\u201310)")), sx: { alignItems: 'flex-start', mr: 0, flex: { sm: '1 1 200px' }, minWidth: 0 } }),
|
|
106402
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_12__["default"], { label: "\u041F\u0430\u0440\u0430\u043C\u0435\u0442\u0440 \u0434\u043B\u044F \u0442\u0435\u043A\u0441\u0442\u0430", size: "small", value: catalogUrlTextApproachParam, onChange: e => setCatalogUrlTextApproachParam(e.target.value), placeholder: DEFAULT_CATALOG_TEXT_APPROACH_PARAM, sx: { width: { xs: '100%', sm: 200 }, flexShrink: 0 }, helperText: `По умолчанию: ${DEFAULT_CATALOG_TEXT_APPROACH_PARAM}` })),
|
|
106403
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_11__["default"], { direction: { xs: 'column', sm: 'row' }, spacing: 2, alignItems: { xs: 'stretch', sm: 'flex-start' } },
|
|
106404
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_21__["default"], { control: react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_22__["default"], { checked: catalogUrlIncludeCreoApproach, onChange: e => setCatalogUrlIncludeCreoApproach(e.target.checked), size: "small" }), label: react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], null,
|
|
106405
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "body2" }, "\u041F\u043E\u0434\u0445\u043E\u0434 \u043A \u043A\u0440\u0435\u043E \u0432 URL \u043A\u0430\u0442\u0430\u043B\u043E\u0433\u0430"),
|
|
106406
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "caption", color: "text.secondary" }, "\u0417\u043D\u0430\u0447\u0435\u043D\u0438\u0435 \u2014 \u043D\u043E\u043C\u0435\u0440 N \u0438\u0437 \u0438\u043C\u0435\u043D\u0438 \u0444\u0430\u0439\u043B\u0430 N_xxxxxxxx.png \u043D\u0430 Drive (N = \u0441\u0442\u0440\u043E\u043A\u0430 \u043F\u043E\u0434\u0445\u043E\u0434\u0430 \u043A \u043A\u0440\u0435\u043E, 1\u201310); \u00AB (1)\u00BB \u043E\u0442 \u0434\u0443\u0431\u043B\u0438\u043A\u0430\u0442\u0430 Google \u0441\u043D\u0438\u043C\u0430\u0435\u0442\u0441\u044F")), sx: { alignItems: 'flex-start', mr: 0, flex: { sm: '1 1 200px' }, minWidth: 0 } }),
|
|
106407
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_12__["default"], { label: "\u041F\u0430\u0440\u0430\u043C\u0435\u0442\u0440 \u0434\u043B\u044F \u043A\u0440\u0435\u043E", size: "small", value: catalogUrlCreoApproachParam, onChange: e => setCatalogUrlCreoApproachParam(e.target.value), placeholder: DEFAULT_CATALOG_CREO_APPROACH_PARAM, sx: { width: { xs: '100%', sm: 200 }, flexShrink: 0 }, helperText: `По умолчанию: ${DEFAULT_CATALOG_CREO_APPROACH_PARAM}` }))),
|
|
105925
106408
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_16__["default"], { sx: { my: 2 } }),
|
|
105926
106409
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "h6", gutterBottom: true }, "AI Generation Settings"),
|
|
105927
106410
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], null,
|
|
105928
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
106411
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_12__["default"], { label: "\u0422\u043E\u0432\u0430\u0440", variant: "outlined", fullWidth: true, value: generateProduct, onChange: (e) => setGenerateProduct(e.target.value), placeholder: "\u043D\u0430\u043F\u0440\u0438\u043C\u0435\u0440: \u043A\u0430\u043F\u043B\u0438 \u043E\u0442 \u043F\u0430\u0440\u0430\u0437\u0438\u0442\u043E\u0432 Detoxil Water", sx: { mb: 2 } })),
|
|
105929
106412
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_11__["default"], { direction: "row", spacing: 2, sx: { mb: 2 } },
|
|
105930
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
105931
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
105932
|
-
endAdornment: (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
106413
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_12__["default"], { label: "\u0413\u0435\u043E", variant: "outlined", fullWidth: true, value: generateGeo, onChange: (e) => setGenerateGeo(e.target.value), placeholder: "\u043D\u0430\u043F\u0440\u0438\u043C\u0435\u0440: \u0420\u0443\u043C\u044B\u043D\u0438\u044F" }),
|
|
106414
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_12__["default"], { label: "\u0426\u0435\u043D\u0430 \u0438 \u0432\u0430\u043B\u044E\u0442\u0430", variant: "outlined", fullWidth: true, value: generatePriceWithCurrency, onChange: (e) => setGeneratePriceWithCurrency(e.target.value), placeholder: "\u043D\u0430\u043F\u0440\u0438\u043C\u0435\u0440: 29 euro, 11400 HUF, 149 RON \u0438\u043B\u0438 \u043B\u044E\u0431\u043E\u0439 \u0434\u0440\u0443\u0433\u043E\u0439 \u0444\u043E\u0440\u043C\u0430\u0442", helperText: "\u041B\u044E\u0431\u043E\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435 \u0434\u043B\u044F \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u043D\u0438\u044F \u0432 \u043F\u0440\u043E\u043C\u043F\u0442\u0435 \u0433\u0435\u043D\u0435\u0440\u0430\u0446\u0438\u0438 \u0438\u0437\u043E\u0431\u0440\u0430\u0436\u0435\u043D\u0438\u0439. \u041A\u043D\u043E\u043F\u043A\u0438 \u0441\u043F\u0440\u0430\u0432\u0430 \u043F\u043E\u0434\u0441\u0442\u0430\u0432\u043B\u044F\u044E\u0442 \u0441\u0438\u043C\u0432\u043E\u043B \u0432\u0430\u043B\u044E\u0442\u044B, \u0446\u0438\u0444\u0440\u0443 \u0431\u0435\u0440\u0443\u0442 \u0438\u0437 \u043F\u043E\u043B\u044F (\u0438\u043B\u0438 99).", InputProps: {
|
|
106415
|
+
endAdornment: (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_23__["default"], { position: "end" },
|
|
105933
106416
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { sx: { display: 'flex', alignItems: 'center', gap: 0.25, mr: -0.5 } },
|
|
105934
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
106417
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_24__["default"], { title: "\u041F\u043E\u0434\u0441\u0442\u0430\u0432\u0438\u0442\u044C $ (\u0446\u0438\u0444\u0440\u0430 \u0438\u0437 \u043F\u043E\u043B\u044F \u0438\u043B\u0438 99)" },
|
|
105935
106418
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_8__["default"], { size: "small", "aria-label": "\u0411\u044B\u0441\u0442\u0440\u043E \u0434\u043E\u043B\u043B\u0430\u0440", onClick: () => {
|
|
105936
106419
|
const n = extractLeadingPriceNumber(generatePriceWithCurrency);
|
|
105937
106420
|
setGeneratePriceWithCurrency(`$${n}`);
|
|
105938
106421
|
}, edge: "end" },
|
|
105939
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
105940
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
106422
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_39__["default"], { sx: { fontSize: 20 } }))),
|
|
106423
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_24__["default"], { title: "\u041F\u043E\u0434\u0441\u0442\u0430\u0432\u0438\u0442\u044C \u20AC (\u0446\u0438\u0444\u0440\u0430 \u0438\u0437 \u043F\u043E\u043B\u044F \u0438\u043B\u0438 99)" },
|
|
105941
106424
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_8__["default"], { size: "small", "aria-label": "\u0411\u044B\u0441\u0442\u0440\u043E \u0435\u0432\u0440\u043E", onClick: () => {
|
|
105942
106425
|
const n = extractLeadingPriceNumber(generatePriceWithCurrency);
|
|
105943
106426
|
setGeneratePriceWithCurrency(`€${n}`);
|
|
105944
106427
|
}, edge: "end", sx: { minWidth: 34, fontSize: '1rem', fontWeight: 700 } }, "\u20AC")),
|
|
105945
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
106428
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_24__["default"], { title: "\u041F\u043E\u0434\u0441\u0442\u0430\u0432\u0438\u0442\u044C z\u0142 (\u0446\u0438\u0444\u0440\u0430 \u0438\u0437 \u043F\u043E\u043B\u044F \u0438\u043B\u0438 99)" },
|
|
105946
106429
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_8__["default"], { size: "small", "aria-label": "\u0411\u044B\u0441\u0442\u0440\u043E \u0437\u043B\u043E\u0442\u044B\u0435", onClick: () => {
|
|
105947
106430
|
const n = extractLeadingPriceNumber(generatePriceWithCurrency);
|
|
105948
106431
|
setGeneratePriceWithCurrency(`${n} zł`);
|
|
105949
106432
|
}, edge: "end", sx: { minWidth: 36, fontSize: '0.8rem', fontWeight: 700, letterSpacing: -0.3 } }, "z\u0142"))))),
|
|
105950
106433
|
} })),
|
|
105951
106434
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], null,
|
|
105952
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
106435
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_12__["default"], { label: "\u0414\u043E\u043F\u043E\u043B\u043D\u0438\u0442\u0435\u043B\u044C\u043D\u0430\u044F \u0438\u043D\u0444\u043E\u0440\u043C\u0430\u0446\u0438\u044F (\u043D\u0435 \u043E\u0431\u044F\u0437\u0430\u0442\u0435\u043B\u044C\u043D\u043E)", variant: "outlined", fullWidth: true, multiline: true, minRows: 3, value: generateAdditionalInfo, onChange: (e) => setGenerateAdditionalInfo(e.target.value), placeholder: "\u0418\u043D\u0433\u0440\u0435\u0434\u0438\u0435\u043D\u0442\u044B, \u0443\u0442\u043E\u0447\u043D\u0435\u043D\u0438\u044F \u043A \u043F\u0440\u043E\u043C\u043F\u0442\u0443 \u0438 \u0442.\u0434.", sx: { mb: 2 } })),
|
|
105953
106436
|
openaiApiKey && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_11__["default"], { direction: "row", spacing: 2, sx: { mb: 2 } },
|
|
105954
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
105955
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
105956
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
106437
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_25__["default"], { fullWidth: true, variant: "outlined" },
|
|
106438
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_26__["default"], null, "\u041C\u043E\u0434\u0435\u043B\u044C \u0434\u043B\u044F \u0433\u0435\u043D\u0435\u0440\u0430\u0446\u0438\u0438 \u0438\u0437\u043E\u0431\u0440\u0430\u0436\u0435\u043D\u0438\u0439"),
|
|
106439
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_27__["default"], { value: selectedImageModel, onChange: (e) => handleImageModelChange(e.target.value), label: "\u041C\u043E\u0434\u0435\u043B\u044C \u0434\u043B\u044F \u0433\u0435\u043D\u0435\u0440\u0430\u0446\u0438\u0438 \u0438\u0437\u043E\u0431\u0440\u0430\u0436\u0435\u043D\u0438\u0439", disabled: loadingImageModels || imageModels.length === 0 }, loadingImageModels ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_28__["default"], { disabled: true },
|
|
105957
106440
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { sx: { display: 'flex', alignItems: 'center', gap: 1 } },
|
|
105958
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
105959
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", null, "\u0417\u0430\u0433\u0440\u0443\u0437\u043A\u0430 \u043C\u043E\u0434\u0435\u043B\u0435\u0439...")))) : imageModels.length === 0 ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
105960
|
-
!loadingImageModels && imageModels.length > 0 && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
106441
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_14__["default"], { size: 16 }),
|
|
106442
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", null, "\u0417\u0430\u0433\u0440\u0443\u0437\u043A\u0430 \u043C\u043E\u0434\u0435\u043B\u0435\u0439...")))) : imageModels.length === 0 ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_28__["default"], { disabled: true }, "\u041D\u0435\u0442 \u0434\u043E\u0441\u0442\u0443\u043F\u043D\u044B\u0445 \u043C\u043E\u0434\u0435\u043B\u0435\u0439")) : (imageModels.map((model) => (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_28__["default"], { key: model.id, value: model.id }, model.name))))),
|
|
106443
|
+
!loadingImageModels && imageModels.length > 0 && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_13__["default"], null, selectedImageModel === _models__WEBPACK_IMPORTED_MODULE_2__.MODELS.imageGeneration
|
|
105961
106444
|
? 'Используется модель по умолчанию'
|
|
105962
106445
|
: 'Выбрана модель: ' + (imageModels.find(m => m.id === selectedImageModel)?.name || selectedImageModel)))),
|
|
105963
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
105964
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
105965
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
106446
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_25__["default"], { fullWidth: true, variant: "outlined" },
|
|
106447
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_26__["default"], null, "\u041C\u043E\u0434\u0435\u043B\u044C \u0434\u043B\u044F \u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0438 \u043A\u0440\u0435\u0430\u0442\u0438\u0432\u043E\u0432"),
|
|
106448
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_27__["default"], { value: selectedValidationModel, onChange: (e) => handleValidationModelChange(e.target.value), label: "\u041C\u043E\u0434\u0435\u043B\u044C \u0434\u043B\u044F \u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0438 \u043A\u0440\u0435\u0430\u0442\u0438\u0432\u043E\u0432", disabled: loadingValidationModels || validationModels.length === 0 }, loadingValidationModels ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_28__["default"], { disabled: true },
|
|
105966
106449
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { sx: { display: 'flex', alignItems: 'center', gap: 1 } },
|
|
105967
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
105968
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", null, "\u0417\u0430\u0433\u0440\u0443\u0437\u043A\u0430 \u043C\u043E\u0434\u0435\u043B\u0435\u0439...")))) : validationModels.length === 0 ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
105969
|
-
!loadingValidationModels && validationModels.length > 0 && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
106450
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_14__["default"], { size: 16 }),
|
|
106451
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", null, "\u0417\u0430\u0433\u0440\u0443\u0437\u043A\u0430 \u043C\u043E\u0434\u0435\u043B\u0435\u0439...")))) : validationModels.length === 0 ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_28__["default"], { disabled: true }, "\u041D\u0435\u0442 \u0434\u043E\u0441\u0442\u0443\u043F\u043D\u044B\u0445 \u043C\u043E\u0434\u0435\u043B\u0435\u0439")) : (validationModels.map((model) => (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_28__["default"], { key: model.id, value: model.id }, model.name))))),
|
|
106452
|
+
!loadingValidationModels && validationModels.length > 0 && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_13__["default"], null, selectedValidationModel === _models__WEBPACK_IMPORTED_MODULE_2__.MODELS.creativeValidation
|
|
105970
106453
|
? 'Используется модель по умолчанию'
|
|
105971
106454
|
: 'Выбрана модель: ' + (validationModels.find(m => m.id === selectedValidationModel)?.name || selectedValidationModel))),
|
|
105972
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
106455
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_21__["default"], { control: react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_22__["default"], { checked: validationDisabled, onChange: (e) => handleValidationDisabledChange(e.target.checked), color: "primary" }), label: "\u041E\u0442\u043A\u043B\u044E\u0447\u0438\u0442\u044C \u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0443", sx: { mt: 1 } })))),
|
|
105973
106456
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_11__["default"], { direction: "row", spacing: 2, sx: { mb: 2 } },
|
|
105974
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
106457
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_20__["default"], { variant: "contained", color: "primary", startIcon: react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_40__["default"], null), onClick: handleGenerateContent, disabled: generating || loadingContentFromDrive || !openaiApiKey || !generateProduct.trim() || !generateGeo.trim(), sx: { flexGrow: 1 }, size: "large" }, generating ? 'Generating...' : 'Generate Titles & Descriptions'),
|
|
105975
106458
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_11__["default"], { direction: "row", spacing: 1, alignItems: "center", sx: { flexGrow: 1 } },
|
|
105976
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
106459
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_24__["default"], { title: imageAspectRatio === '1:1'
|
|
105977
106460
|
? '1:1 — квадрат (1024×1024 px)'
|
|
105978
106461
|
: imageAspectRatio === '2:3'
|
|
105979
106462
|
? '2:3 — портрет (1024×1536 px)'
|
|
@@ -105998,7 +106481,7 @@ ${imageData.originalPrompt}
|
|
|
105998
106481
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_30__["default"], { value: "1:1", sx: { px: 1.5, fontWeight: 600, fontSize: '0.8rem' } }, "1:1"),
|
|
105999
106482
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_30__["default"], { value: "2:3", sx: { px: 1.5, fontWeight: 600, fontSize: '0.8rem' } }, "2:3"),
|
|
106000
106483
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_30__["default"], { value: "both", sx: { px: 1.5, fontWeight: 600, fontSize: '0.8rem' } }, "\u041E\u0431\u0430")))),
|
|
106001
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
106484
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_20__["default"], { variant: "contained", color: "secondary", startIcon: react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_40__["default"], null), onClick: handleGenerateImages, disabled: generatingImages ||
|
|
106002
106485
|
!openaiApiKey ||
|
|
106003
106486
|
(!accessToken && !refreshToken) ||
|
|
106004
106487
|
!generateProduct.trim() ||
|
|
@@ -106016,9 +106499,9 @@ ${imageData.originalPrompt}
|
|
|
106016
106499
|
: !driveFolderUrl.trim()
|
|
106017
106500
|
? 'Заполните URL папки Google Drive'
|
|
106018
106501
|
: undefined }, generatingImages ? 'Generating Images...' : 'Generate Images')),
|
|
106019
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
106020
|
-
uploadedLink && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
106021
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
106502
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_20__["default"], { variant: "contained", color: "success", size: "large", onClick: handleGenerate, disabled: loading, startIcon: loading ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_14__["default"], { size: 20, color: "inherit" }) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_44__["default"], null), sx: { py: 1.5, fontSize: '1.1rem', flexGrow: 1 } }, loading ? 'Generating...' : 'Generate Catalog'),
|
|
106503
|
+
uploadedLink && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_15__["default"], { severity: "success", sx: { flexGrow: 1, minWidth: 0 }, action: react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_8__["default"], { "aria-label": "copy link", color: "inherit", size: "small", onClick: handleCopyLink, sx: { ml: 1 } },
|
|
106504
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_45__["default"], { fontSize: "small" })) },
|
|
106022
106505
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { sx: { display: 'flex', alignItems: 'center', gap: 1, flexWrap: 'wrap' } },
|
|
106023
106506
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", null,
|
|
106024
106507
|
"\u041A\u0430\u0442\u0430\u043B\u043E\u0433 \u0437\u0430\u0433\u0440\u0443\u0436\u0435\u043D!",
|
|
@@ -106028,17 +106511,17 @@ ${imageData.originalPrompt}
|
|
|
106028
106511
|
getElectronAPI().openExternal(uploadedLink);
|
|
106029
106512
|
}, style: { cursor: 'pointer', textDecoration: 'underline', color: 'inherit' } }, "\u041E\u0442\u043A\u0440\u044B\u0442\u044C \u0432 Google Drive")),
|
|
106030
106513
|
linkCopied && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "caption", sx: { color: 'success.dark', fontWeight: 'bold' } }, "\u0421\u043A\u043E\u043F\u0438\u0440\u043E\u0432\u0430\u043D\u043E!"))))),
|
|
106031
|
-
folderFilesInfo !== null && !folderFilesInfo.hasProduct && driveFolderUrl.trim() && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
106514
|
+
folderFilesInfo !== null && !folderFilesInfo.hasProduct && driveFolderUrl.trim() && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_15__["default"], { severity: "warning", sx: { mt: 1 } }, "\u0414\u043B\u044F \u0433\u0435\u043D\u0435\u0440\u0430\u0446\u0438\u0438 \u0438\u0437\u043E\u0431\u0440\u0430\u0436\u0435\u043D\u0438\u0439 \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044F product.png/jpg/webp. \u0421\u043D\u0430\u0447\u0430\u043B\u0430 \u0441\u0433\u0435\u043D\u0435\u0440\u0438\u0440\u0443\u0439\u0442\u0435 \u0435\u0433\u043E \u0441 \u043F\u043E\u043C\u043E\u0449\u044C\u044E \u043A\u043D\u043E\u043F\u043A\u0438 \"Generate Product from Banka\".")),
|
|
106032
106515
|
!generatingImages && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null,
|
|
106033
|
-
!openaiApiKey && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
106034
|
-
openaiApiKey && (!accessToken && !refreshToken) && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
106035
|
-
openaiApiKey && (accessToken || refreshToken) && !generateProduct.trim() && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
106036
|
-
openaiApiKey && (accessToken || refreshToken) && generateProduct.trim() && !generateGeo.trim() && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
106037
|
-
openaiApiKey && (accessToken || refreshToken) && generateProduct.trim() && generateGeo.trim() && !driveFolderUrl.trim() && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
106516
|
+
!openaiApiKey && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_15__["default"], { severity: "error", sx: { mt: 1 } }, "\u0417\u0430\u043F\u043E\u043B\u043D\u0438\u0442\u0435 OpenRouter API Key")),
|
|
106517
|
+
openaiApiKey && (!accessToken && !refreshToken) && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_15__["default"], { severity: "error", sx: { mt: 1 } }, "\u0412\u043E\u0439\u0434\u0438\u0442\u0435 \u0432 Google Drive")),
|
|
106518
|
+
openaiApiKey && (accessToken || refreshToken) && !generateProduct.trim() && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_15__["default"], { severity: "error", sx: { mt: 1 } }, "\u0417\u0430\u043F\u043E\u043B\u043D\u0438\u0442\u0435 \u043F\u043E\u043B\u0435 \u0422\u043E\u0432\u0430\u0440")),
|
|
106519
|
+
openaiApiKey && (accessToken || refreshToken) && generateProduct.trim() && !generateGeo.trim() && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_15__["default"], { severity: "error", sx: { mt: 1 } }, "\u0417\u0430\u043F\u043E\u043B\u043D\u0438\u0442\u0435 \u043F\u043E\u043B\u0435 \u0413\u0435\u043E")),
|
|
106520
|
+
openaiApiKey && (accessToken || refreshToken) && generateProduct.trim() && generateGeo.trim() && !driveFolderUrl.trim() && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_15__["default"], { severity: "error", sx: { mt: 1 } }, "\u0417\u0430\u043F\u043E\u043B\u043D\u0438\u0442\u0435 URL \u043F\u0430\u043F\u043A\u0438 Google Drive"))))),
|
|
106038
106521
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("input", { type: "file", ref: productFileInputRef, accept: "image/png,image/jpeg,image/jpg,image/webp", style: { display: 'none' }, onChange: handleProductFileSelected }),
|
|
106039
106522
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_11__["default"], { direction: "row", spacing: 2, sx: { mb: 2 } },
|
|
106040
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
106041
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
106523
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_20__["default"], { variant: "contained", color: "success", startIcon: uploadingProduct ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_14__["default"], { size: 20, color: "inherit" }) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_44__["default"], null), onClick: handleUploadProductFile, disabled: uploadingProduct || !accessToken || !driveFolderUrl.trim(), sx: { flexGrow: 1 }, size: "large" }, uploadingProduct ? 'Загрузка...' : 'Загрузить product.png/jpg/webp'),
|
|
106524
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_20__["default"], { variant: "contained", color: "info", startIcon: generatingLanding ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_14__["default"], { size: 20, color: "inherit" }) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_50__["default"], null), onClick: handleCreateLanding, disabled: generatingLanding ||
|
|
106042
106525
|
!openaiApiKey ||
|
|
106043
106526
|
!accessToken ||
|
|
106044
106527
|
!driveFolderUrl.trim() ||
|
|
@@ -106053,10 +106536,10 @@ ${imageData.originalPrompt}
|
|
|
106053
106536
|
generatedImagesData.length,
|
|
106054
106537
|
")"),
|
|
106055
106538
|
checkingImages && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { sx: { display: 'flex', alignItems: 'center', gap: 1, mb: 2 } },
|
|
106056
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
106539
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_14__["default"], { size: 16 }),
|
|
106057
106540
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "caption", sx: { color: 'text.secondary' } }, "\u041F\u0440\u043E\u0432\u0435\u0440\u043A\u0430 \u043A\u0430\u0447\u0435\u0441\u0442\u0432\u0430..."))),
|
|
106058
106541
|
generatedImagesData.length > 0 && generatedImagesData.some(img => !img.uploaded && img.imageUrl) && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { sx: { mb: 2 } },
|
|
106059
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
106542
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_20__["default"], { variant: "contained", color: "primary", onClick: handleUploadAllImages, disabled: uploadingImages || generatingImages || !driveFolderUrl.trim(), startIcon: uploadingImages ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_14__["default"], { size: 20 }) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_44__["default"], null), fullWidth: true }, uploadingImages ? 'Загрузка...' : `Загрузить все (${generatedImagesData.filter(img => !img.uploaded && img.imageUrl).length})`))),
|
|
106060
106543
|
generatedImagesData.length > 0 && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { sx: {
|
|
106061
106544
|
display: 'grid',
|
|
106062
106545
|
gridTemplateColumns: { xs: '1fr', sm: 'repeat(2, 1fr)', md: 'repeat(3, 1fr)' },
|
|
@@ -106065,8 +106548,20 @@ ${imageData.originalPrompt}
|
|
|
106065
106548
|
} }, generatedImagesData.map((imageData) => {
|
|
106066
106549
|
const imgRatio = imageData.aspectRatio ?? (imageAspectRatio === 'both' ? '1:1' : imageAspectRatio);
|
|
106067
106550
|
const aspectRatioCss = imgRatio === '2:3' ? '2 / 3' : '1 / 1';
|
|
106068
|
-
|
|
106069
|
-
|
|
106551
|
+
const remakeN = imageData.remakeCount ?? 0;
|
|
106552
|
+
const remakeBg = getRemakeHighlightBackground(remakeN, darkMode);
|
|
106553
|
+
return (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { key: imageData.index, sx: {
|
|
106554
|
+
position: 'relative',
|
|
106555
|
+
...(remakeBg
|
|
106556
|
+
? {
|
|
106557
|
+
p: 1,
|
|
106558
|
+
borderRadius: 1,
|
|
106559
|
+
bgcolor: remakeBg,
|
|
106560
|
+
boxSizing: 'border-box'
|
|
106561
|
+
}
|
|
106562
|
+
: {})
|
|
106563
|
+
} },
|
|
106564
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_24__["default"], { title: "\u0423\u0434\u0430\u043B\u0438\u0442\u044C \u043A\u0440\u0435\u0430\u0442\u0438\u0432" },
|
|
106070
106565
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", null,
|
|
106071
106566
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_8__["default"], { size: "small", "aria-label": "\u0423\u0434\u0430\u043B\u0438\u0442\u044C \u043A\u0440\u0435\u0430\u0442\u0438\u0432", sx: {
|
|
106072
106567
|
position: 'absolute',
|
|
@@ -106093,7 +106588,7 @@ ${imageData.originalPrompt}
|
|
|
106093
106588
|
imageData.generating ||
|
|
106094
106589
|
!!imageData.regenerating ||
|
|
106095
106590
|
!!imageData.uploading },
|
|
106096
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
106591
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_46__["default"], { fontSize: "small" })))),
|
|
106097
106592
|
imageData.generating ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { sx: {
|
|
106098
106593
|
width: '100%',
|
|
106099
106594
|
aspectRatio: aspectRatioCss,
|
|
@@ -106109,7 +106604,7 @@ ${imageData.originalPrompt}
|
|
|
106109
106604
|
gap: 2,
|
|
106110
106605
|
p: 3
|
|
106111
106606
|
} },
|
|
106112
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
106607
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_14__["default"], { size: 40, sx: { color: 'primary.main' } }),
|
|
106113
106608
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "body2", sx: { color: 'text.secondary', textAlign: 'center', fontWeight: 'bold' } }, "\u0413\u0435\u043D\u0435\u0440\u0430\u0446\u0438\u044F..."),
|
|
106114
106609
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "caption", sx: { color: 'text.secondary', textAlign: 'center' } }, imageData.approach),
|
|
106115
106610
|
generatingImages && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "caption", sx: { color: 'text.secondary', textAlign: 'center' } },
|
|
@@ -106129,7 +106624,7 @@ ${imageData.originalPrompt}
|
|
|
106129
106624
|
gap: 2,
|
|
106130
106625
|
p: 3
|
|
106131
106626
|
} },
|
|
106132
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
106627
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_14__["default"], { size: 40, sx: { color: 'primary.main' } }),
|
|
106133
106628
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "body2", sx: { color: 'text.secondary', textAlign: 'center', fontWeight: 'bold' } }, "\u041F\u0435\u0440\u0435\u0434\u0435\u043B\u043A\u0430..."),
|
|
106134
106629
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "caption", sx: { color: 'text.secondary', textAlign: 'center' } }, imageData.approach))) : imageData.imageUrl ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null,
|
|
106135
106630
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { component: "img", src: imageData.imageUrl, alt: `Generated Image ${imageData.index}`, sx: {
|
|
@@ -106164,7 +106659,7 @@ ${imageData.originalPrompt}
|
|
|
106164
106659
|
alignItems: 'center',
|
|
106165
106660
|
gap: 1
|
|
106166
106661
|
} },
|
|
106167
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
106662
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_14__["default"], { size: 40, sx: { color: 'primary.main' } }),
|
|
106168
106663
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "caption", sx: { color: 'white', fontWeight: 'bold', textShadow: '1px 1px 2px rgba(0,0,0,0.8)' } }, "\u041F\u0435\u0440\u0435\u0434\u0435\u043B\u043A\u0430..."))))) : imageData.failed ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { sx: {
|
|
106169
106664
|
width: '100%',
|
|
106170
106665
|
aspectRatio: aspectRatioCss,
|
|
@@ -106225,14 +106720,13 @@ ${imageData.originalPrompt}
|
|
|
106225
106720
|
imageData.checkErrors.length > 2 && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "caption", sx: { color: 'text.secondary', fontSize: '0.7rem' } },
|
|
106226
106721
|
"+",
|
|
106227
106722
|
imageData.checkErrors.length - 2,
|
|
106228
|
-
" \u0435\u0449\u0451")))),
|
|
106229
|
-
imageData.checkFailed && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_17__["default"], { size: "small", variant: "outlined", color: "warning", startIcon: react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_48__["default"], null), onClick: () => handleRetryCheck(imageData), disabled: imageData.checking, sx: { mt: 0.5, fontSize: '0.7rem', py: 0.25, px: 1 } }, "\u041F\u043E\u0432\u0442\u043E\u0440\u0438\u0442\u044C \u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0443")))),
|
|
106723
|
+
" \u0435\u0449\u0451")))))),
|
|
106230
106724
|
imageData.checkStatus === 'checking' && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "caption", sx: { color: 'warning.main', display: 'block' } }, "\uD83D\uDD0D \u041F\u0440\u043E\u0432\u0435\u0440\u044F\u0435\u0442\u0441\u044F...")),
|
|
106231
106725
|
imageData.checkStatus === 'pending' && !imageData.failed && !imageData.generating && imageData.imageUrl && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "caption", sx: { color: 'text.secondary', display: 'block' } }, "\u23F3 \u041E\u0436\u0438\u0434\u0430\u0435\u0442 \u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0438")),
|
|
106232
106726
|
imageData.failed && !imageData.generating && !imageData.imageUrl && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "caption", sx: { color: 'error.main', display: 'block', fontWeight: 'bold' } }, "\u274C \u0413\u0435\u043D\u0435\u0440\u0430\u0446\u0438\u044F \u043D\u0435 \u0443\u0434\u0430\u043B\u0430\u0441\u044C")),
|
|
106233
106727
|
imageData.uploaded && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "caption", sx: { color: 'success.main', display: 'block', mt: 0.5 } }, "\u2713 \u0417\u0430\u0433\u0440\u0443\u0436\u0435\u043D\u043E"))),
|
|
106234
106728
|
!imageData.generating && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { sx: { display: 'flex', gap: 1, flexDirection: 'column', mt: 1 } },
|
|
106235
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
106729
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_12__["default"], { size: "small", multiline: true, minRows: 2, maxRows: 4, fullWidth: true, placeholder: "\u0423\u0442\u043E\u0447\u043D\u0435\u043D\u0438\u044F \u0434\u043B\u044F \u043F\u0435\u0440\u0435\u0434\u0435\u043B\u043A\u0438 (\u0430\u0432\u0442\u043E\u043C\u0430\u0442\u0438\u0447\u0435\u0441\u043A\u0438 \u0437\u0430\u043F\u043E\u043B\u043D\u0435\u043D\u043E \u043F\u0440\u0438 \u043F\u0440\u043E\u0431\u043B\u0435\u043C\u0430\u0445)", value: imageData.customRegeneratePrompt || '', onChange: (e) => {
|
|
106236
106730
|
setGeneratedImagesData(prev => prev.map(img => img.index === imageData.index
|
|
106237
106731
|
? { ...img, customRegeneratePrompt: e.target.value }
|
|
106238
106732
|
: img));
|
|
@@ -106249,22 +106743,27 @@ ${imageData.originalPrompt}
|
|
|
106249
106743
|
: 'transparent'
|
|
106250
106744
|
}
|
|
106251
106745
|
} }),
|
|
106252
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
106253
|
-
|
|
106254
|
-
|
|
106255
|
-
|
|
106256
|
-
|
|
106257
|
-
|
|
106258
|
-
|
|
106259
|
-
|
|
106260
|
-
|
|
106261
|
-
|
|
106262
|
-
|
|
106746
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_11__["default"], { direction: "row", spacing: 1, sx: { width: '100%', alignItems: 'stretch' } },
|
|
106747
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_20__["default"], { size: "small", variant: "contained", color: imageData.failed ? 'error' : imageData.checkStatus === 'needs_rebuild' ? 'warning' : 'primary', startIcon: imageData.regenerating ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_14__["default"], { size: 16 }) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_40__["default"], null), onClick: () => handleRegenerateImage(imageData), disabled: imageData.regenerating ||
|
|
106748
|
+
imageData.uploading ||
|
|
106749
|
+
imageData.checkStatus === 'checking' ||
|
|
106750
|
+
!imageData.originalPrompt ||
|
|
106751
|
+
!imageData.productImageUrl ||
|
|
106752
|
+
(generatingImages && !imageData.imageUrl && !imageData.failed && !imageData.generating), sx: { flex: 1, minWidth: 0, py: 1, lineHeight: 1.2, whiteSpace: 'normal' } }, imageData.regenerating
|
|
106753
|
+
? (imageData.failed ? 'Генерация...' : 'Переделка...')
|
|
106754
|
+
: ((generatingImages && !imageData.imageUrl && !imageData.failed && !imageData.generating)
|
|
106755
|
+
? 'В очереди'
|
|
106756
|
+
: (!imageData.imageUrl ? 'Сгенерировать' : 'Переделать'))),
|
|
106757
|
+
imageData.imageUrl ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_20__["default"], { size: "small", variant: "outlined", color: "secondary", startIcon: react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_51__["default"], null), onClick: () => handleRegenerateImageFresh(imageData), disabled: imageData.regenerating ||
|
|
106758
|
+
imageData.uploading ||
|
|
106759
|
+
imageData.checkStatus === 'checking' ||
|
|
106760
|
+
!imageData.originalPrompt ||
|
|
106761
|
+
!imageData.productImageUrl, sx: { flex: 1, minWidth: 0, py: 1, lineHeight: 1.2, whiteSpace: 'normal' } }, "\u041F\u0435\u0440\u0435\u0434\u0435\u043B\u0430\u0442\u044C \u0437\u0430\u043D\u043E\u0432\u043E")) : null),
|
|
106762
|
+
imageData.imageUrl && !validationDisabled && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_20__["default"], { size: "small", variant: "outlined", color: "warning", startIcon: imageData.checkStatus === 'checking' ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_14__["default"], { size: 16, color: "inherit" })) : (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_51__["default"], null)), onClick: () => handleRetryCheck(imageData), disabled: imageData.regenerating ||
|
|
106263
106763
|
imageData.uploading ||
|
|
106264
|
-
imageData.
|
|
106265
|
-
|
|
106266
|
-
|
|
106267
|
-
!imageData.uploaded && imageData.imageUrl && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_17__["default"], { size: "small", variant: "outlined", startIcon: react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_40__["default"], null), onClick: () => {
|
|
106764
|
+
imageData.generating ||
|
|
106765
|
+
imageData.checkStatus === 'checking', fullWidth: true }, imageData.checkStatus === 'checking' ? 'Проверка…' : 'Перепроверить')),
|
|
106766
|
+
!imageData.uploaded && imageData.imageUrl && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_20__["default"], { size: "small", variant: "outlined", startIcon: react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_44__["default"], null), onClick: () => {
|
|
106268
106767
|
const folderId = extractFolderId(driveFolderUrl);
|
|
106269
106768
|
if (folderId) {
|
|
106270
106769
|
handleUploadImage(imageData, folderId);
|
|
@@ -106272,7 +106771,7 @@ ${imageData.originalPrompt}
|
|
|
106272
106771
|
}, disabled: imageData.uploading || imageData.regenerating || !driveFolderUrl.trim(), fullWidth: true }, imageData.uploading ? 'Загрузка...' : 'Загрузить'))))));
|
|
106273
106772
|
}))),
|
|
106274
106773
|
generatedImagesData.length > 0 && generatedImagesData.some(img => !img.uploaded && img.imageUrl) && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { sx: { mt: 2 } },
|
|
106275
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
106774
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_20__["default"], { variant: "contained", color: "primary", onClick: handleUploadAllImages, disabled: uploadingImages || generatingImages || !driveFolderUrl.trim(), startIcon: uploadingImages ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_14__["default"], { size: 20 }) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_44__["default"], null), fullWidth: true }, uploadingImages ? 'Загрузка...' : `Загрузить все (${generatedImagesData.filter(img => !img.uploaded && img.imageUrl).length})`))))),
|
|
106276
106775
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_16__["default"], { sx: { my: 2 } }),
|
|
106277
106776
|
(generatedTitlesData.length > 0 || generatedTextsData.length > 0 || loadingContentFromDrive) && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { sx: { mb: 2 } },
|
|
106278
106777
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { sx: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 1, mb: 1 } },
|
|
@@ -106282,14 +106781,14 @@ ${imageData.originalPrompt}
|
|
|
106282
106781
|
"/",
|
|
106283
106782
|
Math.max(generatedTitlesData.length, generatedTextsData.length),
|
|
106284
106783
|
")"),
|
|
106285
|
-
(generatedTitlesData.length > 0 || generatedTextsData.length > 0) && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
106784
|
+
(generatedTitlesData.length > 0 || generatedTextsData.length > 0) && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_24__["default"], { title: pairsJsonCopied ? 'Скопировано' : 'Скопировать все пары как JSON-массив' },
|
|
106286
106785
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_8__["default"], { size: "small", "aria-label": "\u0421\u043A\u043E\u043F\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u043F\u0430\u0440\u044B \u043A\u0430\u043A JSON", onClick: () => void copyGeneratedPairsAsJson(), disabled: generating, sx: {
|
|
106287
106786
|
opacity: 0.28,
|
|
106288
106787
|
p: 0.35,
|
|
106289
106788
|
color: 'text.secondary',
|
|
106290
106789
|
'&:hover': { opacity: 0.75, color: 'text.primary' },
|
|
106291
106790
|
} },
|
|
106292
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
106791
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_45__["default"], { sx: { fontSize: 16 } }))))),
|
|
106293
106792
|
loadingContentFromDrive && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { sx: {
|
|
106294
106793
|
display: 'flex',
|
|
106295
106794
|
flexDirection: 'column',
|
|
@@ -106304,7 +106803,7 @@ ${imageData.originalPrompt}
|
|
|
106304
106803
|
: 'rgba(25, 118, 210, 0.05)',
|
|
106305
106804
|
mb: 2
|
|
106306
106805
|
} },
|
|
106307
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
106806
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_14__["default"], { size: 40, sx: { color: 'primary.main' } }),
|
|
106308
106807
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "body1", sx: { color: 'text.secondary', fontWeight: 'bold' } }, "\u0417\u0430\u0433\u0440\u0443\u0437\u043A\u0430 \u043A\u043E\u043D\u0442\u0435\u043D\u0442\u0430 \u0438\u0437 Google Drive..."))),
|
|
106309
106808
|
(generatedTitlesData.length > 0 || generatedTextsData.length > 0) && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_11__["default"], { spacing: 2 }, Array.from({
|
|
106310
106809
|
length: Math.max(generatedTitlesData.length, generatedTextsData.length)
|
|
@@ -106345,82 +106844,96 @@ ${imageData.originalPrompt}
|
|
|
106345
106844
|
i + 1),
|
|
106346
106845
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "caption", color: "text.secondary" }, pairLabel),
|
|
106347
106846
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { sx: { flexGrow: 1, minWidth: 8 } }),
|
|
106348
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
106847
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_24__["default"], { title: "\u0423\u0434\u0430\u043B\u0438\u0442\u044C \u043F\u0430\u0440\u0443" },
|
|
106349
106848
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", null,
|
|
106350
106849
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_8__["default"], { size: "small", color: "error", "aria-label": "\u0423\u0434\u0430\u043B\u0438\u0442\u044C \u043F\u0430\u0440\u0443", onClick: () => handleDeleteGeneratedPair(i), disabled: pairGenerating || generating },
|
|
106351
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
106352
|
-
translatingPairs && !pairTranslations[i] ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
106353
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "caption", sx: { fontWeight: 700, display: 'block', mb: 0.5 } }, "\u0417\u0430\u0433\u043E\u043B\u043E\u0432\u043E\u043A:"),
|
|
106354
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "caption", sx: { display: 'block', mb: 1 } }, pairTranslations[i].titleRu),
|
|
106355
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "caption", sx: { fontWeight: 700, display: 'block', mb: 0.5 } }, "\u0422\u0435\u043A\u0441\u0442:"),
|
|
106356
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "caption", sx: { display: 'block' } }, pairTranslations[i].textRu)), placement: "right", arrow: true, componentsProps: {
|
|
106357
|
-
tooltip: { sx: { maxWidth: 360, fontSize: 12, lineHeight: 1.6, p: '10px 14px' } },
|
|
106358
|
-
} },
|
|
106359
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_8__["default"], { size: "small", sx: { p: 0.25, color: 'text.disabled', '&:hover': { color: 'primary.main' } } },
|
|
106360
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_44__["default"], { sx: { fontSize: 14 } })))) : null),
|
|
106850
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_46__["default"], { fontSize: "small" })))),
|
|
106851
|
+
translatingPairs && !pairTranslations[i] ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_14__["default"], { size: 13, sx: { color: 'text.disabled', ml: 0.5 } })) : null),
|
|
106361
106852
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_11__["default"], { spacing: 1.5 },
|
|
106362
|
-
titleData && (
|
|
106363
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
106364
|
-
|
|
106365
|
-
|
|
106366
|
-
|
|
106367
|
-
|
|
106368
|
-
|
|
106369
|
-
|
|
106370
|
-
|
|
106371
|
-
|
|
106372
|
-
|
|
106373
|
-
|
|
106374
|
-
|
|
106375
|
-
|
|
106376
|
-
|
|
106377
|
-
|
|
106378
|
-
|
|
106379
|
-
|
|
106380
|
-
|
|
106381
|
-
|
|
106382
|
-
|
|
106383
|
-
|
|
106384
|
-
|
|
106385
|
-
|
|
106386
|
-
|
|
106387
|
-
|
|
106388
|
-
|
|
106389
|
-
|
|
106390
|
-
|
|
106391
|
-
|
|
106392
|
-
|
|
106393
|
-
|
|
106394
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
106395
|
-
|
|
106396
|
-
|
|
106397
|
-
|
|
106398
|
-
|
|
106399
|
-
|
|
106400
|
-
|
|
106401
|
-
|
|
106402
|
-
|
|
106403
|
-
|
|
106404
|
-
|
|
106405
|
-
'
|
|
106406
|
-
|
|
106407
|
-
|
|
106408
|
-
|
|
106409
|
-
|
|
106410
|
-
|
|
106411
|
-
|
|
106412
|
-
|
|
106413
|
-
|
|
106414
|
-
|
|
106415
|
-
|
|
106416
|
-
|
|
106417
|
-
|
|
106418
|
-
|
|
106419
|
-
|
|
106420
|
-
|
|
106421
|
-
|
|
106422
|
-
|
|
106423
|
-
|
|
106853
|
+
titleData && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null,
|
|
106854
|
+
titleData.generating ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { sx: { display: 'flex', alignItems: 'center', gap: 1 } },
|
|
106855
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_14__["default"], { size: 16, sx: { color: 'primary.main' } }),
|
|
106856
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "body2", color: "text.secondary" }, "\u0413\u0435\u043D\u0435\u0440\u0430\u0446\u0438\u044F \u0437\u0430\u0433\u043E\u043B\u043E\u0432\u043A\u0430\u2026"))) : titleData.failed ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_12__["default"], { label: `Заголовок ${i + 1}`, variant: "outlined", fullWidth: true, size: "small", value: titleData.title, placeholder: "\u0412\u0432\u0435\u0434\u0438\u0442\u0435 \u0437\u0430\u0433\u043E\u043B\u043E\u0432\u043E\u043A \u0432\u0440\u0443\u0447\u043D\u0443\u044E", helperText: titleData.errorMessage ? `Не сгенерирован: ${titleData.errorMessage}` : 'Можно ввести или исправить заголовок вручную', error: !!titleData.errorMessage, onChange: (e) => {
|
|
106857
|
+
const newValue = e.target.value;
|
|
106858
|
+
setGeneratedTitlesData(prev => {
|
|
106859
|
+
const updated = prev.map(t => t.index === titleData.index
|
|
106860
|
+
? { ...t, title: newValue, failed: false, errorMessage: undefined }
|
|
106861
|
+
: t);
|
|
106862
|
+
setTitles(updated.map(t => t.title).filter(Boolean).join('\n'));
|
|
106863
|
+
return updated;
|
|
106864
|
+
});
|
|
106865
|
+
}, sx: {
|
|
106866
|
+
'& .MuiInputBase-root': {
|
|
106867
|
+
backgroundColor: (theme) => theme.palette.mode === 'dark'
|
|
106868
|
+
? 'rgba(244,67,54,0.08)'
|
|
106869
|
+
: 'rgba(244,67,54,0.04)'
|
|
106870
|
+
}
|
|
106871
|
+
} })) : (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_12__["default"], { label: `Заголовок ${i + 1}`, variant: "outlined", fullWidth: true, size: "small", value: titleData.title, onChange: (e) => {
|
|
106872
|
+
const newValue = e.target.value;
|
|
106873
|
+
setGeneratedTitlesData(prev => {
|
|
106874
|
+
const updated = prev.map(t => t.index === titleData.index ? { ...t, title: newValue } : t);
|
|
106875
|
+
setTitles(updated.map(t => t.title).filter(Boolean).join('\n'));
|
|
106876
|
+
return updated;
|
|
106877
|
+
});
|
|
106878
|
+
}, sx: {
|
|
106879
|
+
'& .MuiInputBase-root': {
|
|
106880
|
+
backgroundColor: (theme) => theme.palette.mode === 'dark'
|
|
106881
|
+
? 'rgba(76,175,80,0.08)'
|
|
106882
|
+
: 'rgba(76,175,80,0.04)'
|
|
106883
|
+
}
|
|
106884
|
+
} })),
|
|
106885
|
+
!titleData.generating && pairTranslations[i]?.titleRu?.trim() ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { component: "div", variant: "caption", sx: {
|
|
106886
|
+
mt: -0.5,
|
|
106887
|
+
pl: 1.5,
|
|
106888
|
+
pr: 1,
|
|
106889
|
+
fontSize: '0.7rem',
|
|
106890
|
+
lineHeight: 1.45,
|
|
106891
|
+
color: 'text.secondary',
|
|
106892
|
+
opacity: 0.92,
|
|
106893
|
+
} }, pairTranslations[i].titleRu)) : null)),
|
|
106894
|
+
textData && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null,
|
|
106895
|
+
textData.generating ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { sx: { display: 'flex', alignItems: 'center', gap: 1 } },
|
|
106896
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_14__["default"], { size: 16, sx: { color: 'primary.main' } }),
|
|
106897
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "body2", color: "text.secondary" }, "\u0413\u0435\u043D\u0435\u0440\u0430\u0446\u0438\u044F \u0442\u0435\u043A\u0441\u0442\u0430\u2026"))) : textData.failed ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_12__["default"], { label: `Текст ${i + 1}`, variant: "outlined", fullWidth: true, multiline: true, minRows: 3, value: textData.text, placeholder: "\u0412\u0432\u0435\u0434\u0438\u0442\u0435 \u0442\u0435\u043A\u0441\u0442 \u043E\u0431\u044A\u044F\u0432\u043B\u0435\u043D\u0438\u044F \u0432\u0440\u0443\u0447\u043D\u0443\u044E", helperText: textData.errorMessage ? `Не сгенерирован: ${textData.errorMessage}` : 'Можно ввести или исправить текст вручную', error: !!textData.errorMessage, onChange: (e) => {
|
|
106898
|
+
const newValue = e.target.value;
|
|
106899
|
+
setGeneratedTextsData(prev => {
|
|
106900
|
+
const updated = prev.map(t => t.index === textData.index
|
|
106901
|
+
? { ...t, text: newValue, failed: false, errorMessage: undefined }
|
|
106902
|
+
: t);
|
|
106903
|
+
setTexts(updated.map(t => t.text));
|
|
106904
|
+
return updated;
|
|
106905
|
+
});
|
|
106906
|
+
}, sx: {
|
|
106907
|
+
'& .MuiInputBase-root': {
|
|
106908
|
+
backgroundColor: (theme) => theme.palette.mode === 'dark'
|
|
106909
|
+
? 'rgba(244,67,54,0.08)'
|
|
106910
|
+
: 'rgba(244,67,54,0.04)'
|
|
106911
|
+
}
|
|
106912
|
+
} })) : (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_12__["default"], { label: `Текст ${i + 1}`, variant: "outlined", fullWidth: true, multiline: true, minRows: 3, value: textData.text, onChange: (e) => {
|
|
106913
|
+
const newValue = e.target.value;
|
|
106914
|
+
setGeneratedTextsData(prev => {
|
|
106915
|
+
const updated = prev.map(t => t.index === textData.index ? { ...t, text: newValue } : t);
|
|
106916
|
+
setTexts(updated.map(t => t.text).filter(Boolean));
|
|
106917
|
+
return updated;
|
|
106918
|
+
});
|
|
106919
|
+
}, sx: {
|
|
106920
|
+
'& .MuiInputBase-root': {
|
|
106921
|
+
backgroundColor: (theme) => theme.palette.mode === 'dark'
|
|
106922
|
+
? 'rgba(76,175,80,0.08)'
|
|
106923
|
+
: 'rgba(76,175,80,0.04)'
|
|
106924
|
+
}
|
|
106925
|
+
} })),
|
|
106926
|
+
!textData.generating && pairTranslations[i]?.textRu?.trim() ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { component: "div", variant: "caption", sx: {
|
|
106927
|
+
mt: -0.25,
|
|
106928
|
+
pl: 1.5,
|
|
106929
|
+
pr: 1,
|
|
106930
|
+
fontSize: '0.7rem',
|
|
106931
|
+
lineHeight: 1.45,
|
|
106932
|
+
color: 'text.secondary',
|
|
106933
|
+
opacity: 0.92,
|
|
106934
|
+
whiteSpace: 'pre-wrap',
|
|
106935
|
+
wordBreak: 'break-word',
|
|
106936
|
+
} }, pairTranslations[i].textRu)) : null)))));
|
|
106424
106937
|
}))))),
|
|
106425
106938
|
(landingGenerationLogs.length > 0 || generatingLanding) && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { sx: { mb: 2 } },
|
|
106426
106939
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "h6", gutterBottom: true, sx: { fontWeight: 'bold' } }, "\u041F\u0440\u043E\u0446\u0435\u0441\u0441 \u0441\u043E\u0437\u0434\u0430\u043D\u0438\u044F \u043B\u0435\u043D\u0434\u0438\u043D\u0433\u0430"),
|
|
@@ -106448,10 +106961,38 @@ ${imageData.originalPrompt}
|
|
|
106448
106961
|
'text.primary'
|
|
106449
106962
|
} }, log)))))),
|
|
106450
106963
|
generatingLanding && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { sx: { display: 'flex', alignItems: 'center', gap: 1, mb: 2 } },
|
|
106451
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
106964
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_14__["default"], { size: 20 }),
|
|
106452
106965
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "body2", sx: { color: 'text.secondary' } }, formatElapsedTime(elapsedTime.landing)))),
|
|
106453
|
-
!generatingLanding && generatedLandingHTML && generatedLandingImageBlob && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
106454
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
106966
|
+
!generatingLanding && generatedLandingHTML && generatedLandingImageBlob && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_20__["default"], { variant: "outlined", color: "primary", onClick: handlePreviewLanding, startIcon: react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_53__["default"], null), fullWidth: true }, "\u041F\u0440\u0435\u0434\u043F\u0440\u043E\u0441\u043C\u043E\u0442\u0440 \u043B\u0435\u043D\u0434\u0438\u043D\u0433\u0430"))))))))),
|
|
106967
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_32__["default"], { open: approachLoadChoice !== null, onClose: handleApproachLoadKeepCurrent, maxWidth: "md", fullWidth: true }, approachLoadChoice ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null,
|
|
106968
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_33__["default"], null, "\u041F\u043E\u0434\u0445\u043E\u0434\u044B \u0438\u0437 \u0444\u0430\u0439\u043B\u0430 \u043E\u0444\u0444\u0435\u0440\u0430"),
|
|
106969
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_34__["default"], null,
|
|
106970
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "body2", color: "text.secondary", sx: { mb: 2 } }, "\u0412 project-settings.json \u0435\u0441\u0442\u044C \u0441\u043E\u0445\u0440\u0430\u043D\u0451\u043D\u043D\u044B\u0435 \u043F\u043E\u0434\u0445\u043E\u0434\u044B \u0434\u043B\u044F \u0437\u0430\u0433\u043E\u043B\u043E\u0432\u043A\u043E\u0432/\u0442\u0435\u043A\u0441\u0442\u043E\u0432 \u0438 \u0434\u043B\u044F \u043A\u0440\u0435\u043E. \u041F\u0440\u0438\u043C\u0435\u043D\u0438\u0442\u044C \u0438\u0445 \u0432 \u043F\u0440\u0438\u043B\u043E\u0436\u0435\u043D\u0438\u0438 \u0438\u043B\u0438 \u043E\u0441\u0442\u0430\u0432\u0438\u0442\u044C \u0442\u0435, \u0447\u0442\u043E \u0443\u0436\u0435 \u0432\u044B\u0431\u0440\u0430\u043D\u044B \u043B\u043E\u043A\u0430\u043B\u044C\u043D\u043E?"),
|
|
106971
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_11__["default"], { spacing: 2 },
|
|
106972
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "subtitle2" }, "\u0417\u0430\u0433\u043E\u043B\u043E\u0432\u043A\u0438 \u0438 \u0442\u0435\u043A\u0441\u0442\u044B (\u043F\u0430\u0440\u044B \u043F\u043E\u0434\u0445\u043E\u0434\u043E\u0432)"),
|
|
106973
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_11__["default"], { direction: { xs: 'column', sm: 'row' }, spacing: 2 },
|
|
106974
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_31__["default"], { variant: "outlined", sx: { p: 1.5, flex: 1 } },
|
|
106975
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "caption", color: "text.secondary", display: "block", gutterBottom: true }, "\u0421\u0435\u0439\u0447\u0430\u0441 \u0432 \u043F\u0440\u0438\u043B\u043E\u0436\u0435\u043D\u0438\u0438"),
|
|
106976
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "body2", component: "div", sx: { whiteSpace: 'pre-wrap', fontFamily: 'inherit' } }, formatPairApproachesForDisplay(approachLoadChoice.currentPairs))),
|
|
106977
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_31__["default"], { variant: "outlined", sx: { p: 1.5, flex: 1 } },
|
|
106978
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "caption", color: "text.secondary", display: "block", gutterBottom: true }, "\u0412 \u0444\u0430\u0439\u043B\u0435 \u043E\u0444\u0444\u0435\u0440\u0430"),
|
|
106979
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "body2", component: "div", sx: { whiteSpace: 'pre-wrap', fontFamily: 'inherit' } }, approachLoadChoice.savedPairs
|
|
106980
|
+
? formatPairApproachesForDisplay(approachLoadChoice.savedPairs)
|
|
106981
|
+
: '— не указано (список для текстов не изменится)'))),
|
|
106982
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "subtitle2" }, "\u0418\u0437\u043E\u0431\u0440\u0430\u0436\u0435\u043D\u0438\u044F (\u043A\u043E\u043B\u0438\u0447\u0435\u0441\u0442\u0432\u043E \u043F\u043E \u043F\u043E\u0434\u0445\u043E\u0434\u0443)"),
|
|
106983
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_11__["default"], { direction: { xs: 'column', sm: 'row' }, spacing: 2 },
|
|
106984
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_31__["default"], { variant: "outlined", sx: { p: 1.5, flex: 1 } },
|
|
106985
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "caption", color: "text.secondary", display: "block", gutterBottom: true }, "\u0421\u0435\u0439\u0447\u0430\u0441 \u0432 \u043F\u0440\u0438\u043B\u043E\u0436\u0435\u043D\u0438\u0438"),
|
|
106986
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "body2", component: "div", sx: { whiteSpace: 'pre-wrap', fontFamily: 'inherit' } }, formatImageCountsForDisplay(approachLoadChoice.currentCounts))),
|
|
106987
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_31__["default"], { variant: "outlined", sx: { p: 1.5, flex: 1 } },
|
|
106988
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "caption", color: "text.secondary", display: "block", gutterBottom: true }, "\u0412 \u0444\u0430\u0439\u043B\u0435 \u043E\u0444\u0444\u0435\u0440\u0430"),
|
|
106989
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "body2", component: "div", sx: { whiteSpace: 'pre-wrap', fontFamily: 'inherit' } }, approachLoadChoice.savedCounts
|
|
106990
|
+
? formatImageCountsForDisplay(approachLoadChoice.savedCounts)
|
|
106991
|
+
: '— не указано (количества крео не изменятся)'))))),
|
|
106992
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_35__["default"], null,
|
|
106993
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_20__["default"], { onClick: handleApproachLoadKeepCurrent }, "\u041E\u0441\u0442\u0430\u0432\u0438\u0442\u044C \u043A\u0430\u043A \u0441\u0435\u0439\u0447\u0430\u0441"),
|
|
106994
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_20__["default"], { variant: "contained", onClick: handleApproachLoadApplyFromFile }, "\u041F\u0440\u0438\u043C\u0435\u043D\u0438\u0442\u044C \u0438\u0437 \u0444\u0430\u0439\u043B\u0430")))) : null),
|
|
106995
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_PromptManagerDialog__WEBPACK_IMPORTED_MODULE_54__["default"], { open: promptManagerOpen, onClose: () => setPromptManagerOpen(false) }))));
|
|
106455
106996
|
}
|
|
106456
106997
|
/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (App);
|
|
106457
106998
|
|
|
@@ -107259,7 +107800,14 @@ function PromptManagerDialog({ open, onClose }) {
|
|
|
107259
107800
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { type: "number", size: "small", value: count, onChange: (e) => {
|
|
107260
107801
|
const v = parseInt(e.target.value, 10);
|
|
107261
107802
|
handleImageApproachCountChange(i, isNaN(v) ? 0 : v);
|
|
107262
|
-
}, onBlur: handleImageCountBlur, inputProps: {
|
|
107803
|
+
}, onBlur: handleImageCountBlur, inputProps: {
|
|
107804
|
+
min: 0,
|
|
107805
|
+
max: 4,
|
|
107806
|
+
step: 1,
|
|
107807
|
+
onWheel: (e) => {
|
|
107808
|
+
e.preventDefault();
|
|
107809
|
+
},
|
|
107810
|
+
}, sx: { width: 56, '& .MuiInputBase-input': { textAlign: 'center', py: 0.5 } } })),
|
|
107263
107811
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("td", { style: { padding: '4px 8px', fontWeight: 500, whiteSpace: 'nowrap' } }, approach.name),
|
|
107264
107812
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("td", { style: { padding: '4px 8px', color: '#777' } }, approach.prompt.split('\n')[0])));
|
|
107265
107813
|
}))))),
|
|
@@ -107540,6 +108088,7 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
107540
108088
|
/* harmony export */ PRODUCT_TYPE_IMAGE_PRESETS: () => (/* binding */ PRODUCT_TYPE_IMAGE_PRESETS),
|
|
107541
108089
|
/* harmony export */ PRODUCT_TYPE_TEXT_PAIR_PRESETS: () => (/* binding */ PRODUCT_TYPE_TEXT_PAIR_PRESETS),
|
|
107542
108090
|
/* harmony export */ PROMPT_OVERRIDES_SAVED_EVENT: () => (/* binding */ PROMPT_OVERRIDES_SAVED_EVENT),
|
|
108091
|
+
/* harmony export */ applyParsedApproachesFromDrive: () => (/* binding */ applyParsedApproachesFromDrive),
|
|
107543
108092
|
/* harmony export */ getCreoApproachOverride: () => (/* binding */ getCreoApproachOverride),
|
|
107544
108093
|
/* harmony export */ getImageApproachCounts: () => (/* binding */ getImageApproachCounts),
|
|
107545
108094
|
/* harmony export */ getPairsCount: () => (/* binding */ getPairsCount),
|
|
@@ -107550,6 +108099,7 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
107550
108099
|
/* harmony export */ mergePromptApproachesFromDriveFile: () => (/* binding */ mergePromptApproachesFromDriveFile),
|
|
107551
108100
|
/* harmony export */ normalizeImageApproachCountsFromDrive: () => (/* binding */ normalizeImageApproachCountsFromDrive),
|
|
107552
108101
|
/* harmony export */ normalizeSelectedPairApproachesFromDrive: () => (/* binding */ normalizeSelectedPairApproachesFromDrive),
|
|
108102
|
+
/* harmony export */ parseApproachesFromDriveData: () => (/* binding */ parseApproachesFromDriveData),
|
|
107553
108103
|
/* harmony export */ productPresetNumbersToImageCounts: () => (/* binding */ productPresetNumbersToImageCounts),
|
|
107554
108104
|
/* harmony export */ productPresetNumbersToIndices: () => (/* binding */ productPresetNumbersToIndices),
|
|
107555
108105
|
/* harmony export */ resetAllOverrides: () => (/* binding */ resetAllOverrides),
|
|
@@ -107735,12 +108285,17 @@ function savePromptOverrides(overrides) {
|
|
|
107735
108285
|
}
|
|
107736
108286
|
/** Имя события после сохранения подходов в менеджере промптов — чтобы синхронизировать JSON на Drive. */
|
|
107737
108287
|
const PROMPT_OVERRIDES_SAVED_EVENT = 'docs-combiner-prompt-overrides-saved';
|
|
108288
|
+
/** Прочитать валидные подходы из объекта настроек с диска (без записи в localStorage). */
|
|
108289
|
+
function parseApproachesFromDriveData(loadedData) {
|
|
108290
|
+
return {
|
|
108291
|
+
pairs: normalizeSelectedPairApproachesFromDrive(loadedData.selectedPairApproaches),
|
|
108292
|
+
counts: normalizeImageApproachCountsFromDrive(loadedData.imageApproachCounts),
|
|
108293
|
+
};
|
|
108294
|
+
}
|
|
107738
108295
|
/**
|
|
107739
|
-
*
|
|
108296
|
+
* Применить к localStorage только те части, для которых переданы ненулевые массивы.
|
|
107740
108297
|
*/
|
|
107741
|
-
function
|
|
107742
|
-
const pairs = normalizeSelectedPairApproachesFromDrive(loadedData.selectedPairApproaches);
|
|
107743
|
-
const counts = normalizeImageApproachCountsFromDrive(loadedData.imageApproachCounts);
|
|
108298
|
+
function applyParsedApproachesFromDrive(pairs, counts) {
|
|
107744
108299
|
if (!pairs && !counts)
|
|
107745
108300
|
return false;
|
|
107746
108301
|
const overrides = loadPromptOverrides();
|
|
@@ -107759,6 +108314,13 @@ function mergePromptApproachesFromDriveFile(loadedData) {
|
|
|
107759
108314
|
}
|
|
107760
108315
|
return false;
|
|
107761
108316
|
}
|
|
108317
|
+
/**
|
|
108318
|
+
* Подмешать в localStorage выбранные подходы из project-settings.json на Drive (если поля валидны).
|
|
108319
|
+
*/
|
|
108320
|
+
function mergePromptApproachesFromDriveFile(loadedData) {
|
|
108321
|
+
const { pairs, counts } = parseApproachesFromDriveData(loadedData);
|
|
108322
|
+
return applyParsedApproachesFromDrive(pairs, counts);
|
|
108323
|
+
}
|
|
107762
108324
|
/**
|
|
107763
108325
|
* Получить оверрайд для простого промпта
|
|
107764
108326
|
*/
|
|
@@ -107873,6 +108435,7 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
107873
108435
|
/* harmony export */ PAIR_APPROACH_POOL: () => (/* binding */ PAIR_APPROACH_POOL),
|
|
107874
108436
|
/* harmony export */ TEXTS_APPROACH_POOL: () => (/* binding */ TEXTS_APPROACH_POOL),
|
|
107875
108437
|
/* harmony export */ TITLES_APPROACH_POOL: () => (/* binding */ TITLES_APPROACH_POOL),
|
|
108438
|
+
/* harmony export */ getCreoApproachExpandedTasks: () => (/* binding */ getCreoApproachExpandedTasks),
|
|
107876
108439
|
/* harmony export */ getCreoApproaches: () => (/* binding */ getCreoApproaches),
|
|
107877
108440
|
/* harmony export */ getImageCheckPrompt: () => (/* binding */ getImageCheckPrompt),
|
|
107878
108441
|
/* harmony export */ getImageGenerationBasePrompt: () => (/* binding */ getImageGenerationBasePrompt),
|
|
@@ -107953,57 +108516,57 @@ function _debugLog(...args) {
|
|
|
107953
108516
|
const PAIR_APPROACH_POOL = [
|
|
107954
108517
|
{
|
|
107955
108518
|
name: 'болевая точка',
|
|
107956
|
-
titleApproach: 'одна ясная боль (не две проблемы в одном заголовке). Усиливай через несправедливость / ощущение «так несправедливо» (устал бороться, снова срыв, тело не слушается) — не только сухое перечисление симптомов. ЗАГОЛОВОК = КОНСТАТАЦИЯ, не вопрос: ЗАПРЕЩЕНО заканчивать на «почему?»,
|
|
108519
|
+
titleApproach: 'одна ясная боль (не две проблемы в одном заголовке). Усиливай через несправедливость / ощущение «так несправедливо» (устал бороться, снова срыв, тело не слушается) — не только сухое перечисление симптомов. ЗАГОЛОВОК = КОНСТАТАЦИЯ, не вопрос: ЗАПРЕЩЕНО заканчивать на «почему?», «зачем?», «why?» и подобное — боль называешь фактом, не спрашиваешь',
|
|
107957
108520
|
textApproach: 'Одна центральная проблема за текст — не распыляйся на несколько болей. ЗАПРЕЩЕНО перечислять ингредиенты, состав, matcha/MCT/«формулу» — это территория «авторитет/экспертиза», не болевой точки. Опиши дискомфорт и как продукт снимает именно эту боль; без каталога компонентов.',
|
|
107958
108521
|
},
|
|
107959
108522
|
{
|
|
107960
108523
|
name: 'трансформация до/после',
|
|
107961
|
-
titleApproach: 'контраст СОСТОЯНИЙ и ощущений до/после (вздутие/усталость → лёгкость, тяжесть → контроль, «не узнаю себя в зеркале» → спокойствие) с якорем во времени во фразе, но БЕЗ цифр на весах. ЗАПРЕЩЕНО в заголовке: −X kg,
|
|
107962
|
-
textApproach: 'СТРОГО от первого лица (
|
|
108524
|
+
titleApproach: 'контраст СОСТОЯНИЙ и ощущений до/после (вздутие/усталость → лёгкость, тяжесть → контроль, «не узнаю себя в зеркале» → спокойствие) с якорем во времени во фразе, но БЕЗ цифр на весах. ЗАПРЕЩЕНО в заголовке: −X kg, «минус N кг», весы, любой явный минус килограммов (для похудения такой акцент — только у testimonial и только если продукт явно про вес)',
|
|
108525
|
+
textApproach: 'СТРОГО от первого лица (на языке GEO — естественное «я» для локали). Это не отзыв с именем — это МОЙ контраст «как было плохо / как стало лучше» по телу и эмоциям. ЗАПРЕЩЕНО копировать формат отзыва: не начинай как реклама «я попробовала продукт и минус X кг» подряд; сначала ощущения и жизнь до/после, продукт — связка, а не пересказ цифр с весов (цифры веса допустимы в тексте лишь второстепенно, если уместно; акцент — на смене состояния). ЗАПРЕЩЕНО соцдоказательство («многие отмечают», «тысячи уже выбрали» вместо личной истории).',
|
|
107963
108526
|
},
|
|
107964
108527
|
{
|
|
107965
108528
|
name: 'testimonial',
|
|
107966
108529
|
isTestimonial: true,
|
|
107967
|
-
titleApproach: 'короткая «живая» фраза с
|
|
108530
|
+
titleApproach: 'короткая «живая» фраза с **конкретным результатом по теме продукта** и сроком (7–14 дней). Цифры −кг, весы, «минус на весах» — **только** если продукт явно про похудение / контроль веса. Для паразитов/ЖКТ/суставов/простаты/сна и т.п. — результат = облегчение симптомов, комфорт, сон, подвижность, меньше дискомфорта (без выдуманных кг). Это отличает testimonial от «трансформации». НЕ используй «Имя, возраст:» в заголовке — только в тексте',
|
|
107968
108531
|
textApproach: `Это единственный подход-ОТЗЫВ: читатель должен поверить в реального человека.
|
|
107969
|
-
* Обязательно начало текста с «Имя, возраст:» (
|
|
108532
|
+
* Обязательно начало текста с «Имя, возраст:» (формат на языке GEO, например «Анна, 49 лет:», «Олег, 41 год:»)
|
|
107970
108533
|
* История только от первого лица после имени
|
|
107971
|
-
* Конкретный результат с таймингом (7–14 дней),
|
|
108534
|
+
* Конкретный результат с таймингом (7–14 дней), релевантный категории продукта; килограммы упоминай только если оффер действительно про вес/похудение
|
|
107972
108535
|
* Заканчивается приглашением попробовать + CTA`,
|
|
107973
108536
|
},
|
|
107974
108537
|
{
|
|
107975
108538
|
name: 'срочность/дефицит',
|
|
107976
108539
|
titleApproach: 'ТОЛЬКО дефицит оффера: время до конкретного дедлайна, остаток штук, «до полуночи», «осталось N упаковок» — ЗАПРЕЩЕНО в заголовке проблема, тело, продукт, «лишние кг», категория товара. Не баннер магазина — конкретная граница (день, час, число мест)',
|
|
107977
|
-
textApproach: 'Начни с конкретного сигнала ограниченности — времени или количества (
|
|
108540
|
+
textApproach: 'Начни с конкретного сигнала ограниченности — времени или количества («только сегодня», «последние упаковки», «Осталось 12 упаковок», «Акция до конца дня» — всё на языке GEO). Весь текст строится ИСКЛЮЧИТЕЛЬНО вокруг дефицита или дедлайна: осталось мало, время заканчивается, потом будет дороже или не будет вообще. ЗАПРЕЩЕНО упоминать состав, ингредиенты, свойства или пользу продукта — только ограниченность оффера. CTA максимально срочный.',
|
|
107978
108541
|
},
|
|
107979
108542
|
{
|
|
107980
108543
|
name: 'социальное доказательство',
|
|
107981
|
-
titleApproach: 'одна ЧИТАЕМАЯ фраза с крупной цифрой (
|
|
107982
|
-
textApproach: 'Начни с цифры или массового факта («Уже 50 000 клиентов», «9
|
|
108544
|
+
titleApproach: 'одна ЧИТАЕМАЯ фраза с крупной цифрой (уровень: «Уже 50 000 женщин выбрали … 🔥» на языке GEO) — грамматика и смысл на языке GEO должны сходиться; читатель понимает фразу с первого раза. ЗАПРЕЩЕНО несвязные склейки («9 из 10 выбирают контроль 🔥 голод» — бессмыслица) и обрывки, где цифра + существительные не составляют нормального высказывания',
|
|
108545
|
+
textApproach: 'Начни с цифры или массового факта («Уже 50 000 клиентов», «9 из 10 отмечают разницу» — на языке GEO). Акцент на том, что проблему уже решили тысячи — и ты тоже можешь.',
|
|
107983
108546
|
},
|
|
107984
108547
|
{
|
|
107985
108548
|
name: 'любопытство/интрига',
|
|
107986
|
-
titleApproach: 'провокационный вопрос или утверждение, которое ломает сразу ДВА привычных решения (диета
|
|
107987
|
-
textApproach: 'Начни с провокационного вопроса или неожиданного инсайта («Знаете, почему обычные средства не помогают?»,
|
|
108549
|
+
titleApproach: 'провокационный вопрос или утверждение, которое ломает сразу ДВА привычных решения (например диета и спорт одновременно) — но ОДНОЙ ЦЕЛЬНОЙ фразой: связный синтаксис, без рубки на обрывки через запятую и эмодзи посередине. Пример уровня на русском для тона: «Диета и зал, а живот всё равно? 🤔» — на GEO перепиши естественно; не три оторванных куска',
|
|
108550
|
+
textApproach: 'Начни с провокационного вопроса или неожиданного инсайта («Знаете, почему обычные средства не помогают?», «А вы знали, что…» — на языке GEO). Раскрой неочевидный факт о проблеме или механизме решения и выведи к продукту.',
|
|
107988
108551
|
},
|
|
107989
108552
|
{
|
|
107990
108553
|
name: 'авторитет/экспертиза',
|
|
107991
|
-
titleApproach: 'information gap: в заголовке ЗАПРЕЩЕНО называть ингредиенты и раскрывать метод/механизм напрямую — никаких matcha, MCT,
|
|
107992
|
-
textApproach: 'Начни с ФАКТА/утверждения об экспертизе (
|
|
108554
|
+
titleApproach: 'information gap: в заголовке ЗАПРЕЩЕНО называть ингредиенты и раскрывать метод/механизм напрямую — никаких matcha, MCT, «зелёный чай», «формула с…», «натуральный метод для…», «ускорить обмен веществ», «поддерживает обмен веществ» и т.п.; иначе ответ уже в заголовке и клик не нужен. Подай состав или подход как тайну / открытие / «что скрывают» / «почему это не то же самое, что обычные средства» — без конкретики, ответ только в основном тексте. ЗАПРЕЩЕНЫ эмодзи-подсказки по составу (например 🍵, если по смыслу выдаёт чай), если они заменяют то, что должен открыть текст. Не закрывай интригу сухими схемами вроде «Почему X и Y поддерживают…»',
|
|
108555
|
+
textApproach: 'Начни с ФАКТА/утверждения об экспертизе («Итальянская рецептура», «Произведено в Италии», «3 натуральных компонента», «Разработано фармацевтами» — перенеси смысл на язык GEO). Акцент на составе, происхождении или механизме действия. Почему это работает — объясни просто и убедительно.',
|
|
107993
108556
|
},
|
|
107994
108557
|
{
|
|
107995
108558
|
name: 'страх бездействия',
|
|
107996
|
-
titleApproach: 'узнаваемый паттерн промедления — ОДНА СВЯЗНАЯ фраза (допустимы многоточие, союз «но», тире), а не перечень обрывков через запятую. Пример уровня:
|
|
107997
|
-
textApproach: 'Начни с описания негативного сценария бездействия («С каждым днём становится хуже…», «Если не взять под контроль сейчас…»). Покажи, что проблема прогрессирует. Финальный CTA — ТОЛЬКО про заботу о себе / начать сейчас / не откладывать (на языке GEO). ЗАПРЕЩЕНЫ прямые призывы к заказу в финале:
|
|
108559
|
+
titleApproach: 'узнаваемый паттерн промедления — ОДНА СВЯЗНАЯ фраза (допустимы многоточие, союз «но», тире), а не перечень обрывков через запятую. Пример уровня: «Отложила на понедельник… а голод не ждёт 😣» — на GEO перепиши естественно; смысл течёт от начала к концу',
|
|
108560
|
+
textApproach: 'Начни с описания негативного сценария бездействия («С каждым днём становится хуже…», «Если не взять под контроль сейчас…»). Покажи, что проблема прогрессирует. Финальный CTA — ТОЛЬКО про заботу о себе / начать сейчас / не откладывать (на языке GEO). ЗАПРЕЩЕНЫ прямые призывы к заказу в финале: «закажи», «закажи сейчас», «купи», «купи сейчас», «оформи заказ» — вместо них: взять под контроль, сделать первый шаг, начать сегодня и т.п.',
|
|
107998
108561
|
},
|
|
107999
108562
|
{
|
|
108000
108563
|
name: 'прямой оффер/выгода',
|
|
108001
|
-
titleApproach: '
|
|
108002
|
-
textApproach: '
|
|
108564
|
+
titleApproach: 'выгода в заголовке = **-50%** как есть (знак процента), плюс по желанию 2–4 слова срочности на языке GEO («только сегодня», «сейчас»). ОБЯЗАТЕЛЬНО минимум один эмодзи (💸 🔥 ✨ 🎁 ⏳ 📦). **Не придумывай** другую механику: никаких «2-й пакет», «вторая упаковка», «полцены» вместо простого **-50%**, если в задании пользователя явно не сказано иначе. **-50% = просто -50%.**',
|
|
108565
|
+
textApproach: 'Коротко про сделку: **-50% не перефразируй** длинно («платишь половину», «акция на сегодня», «скидка на вторую упаковку»), если пользователь этого не писал — повтори **-50%** и добавь одну короткую фразу срочности + CTA. ЗАПРЕЩЕНО расписывать математику скидки и выдумывать условия акции. ЗАПРЕЩЕНО объяснять пользу продукта или боли — только **-50%**, срочность, CTA.',
|
|
108003
108566
|
},
|
|
108004
108567
|
{
|
|
108005
108568
|
name: 'ситуационный/узнаваемый момент',
|
|
108006
|
-
titleApproach: 'одна яркая узнаваемая сцена в 1–2 коротких связных сегментах (лучше одна картинка), без перечня симптомов через запятую. Пример уровня:
|
|
108569
|
+
titleApproach: 'одна яркая узнаваемая сцена в 1–2 коротких связных сегментах (лучше одна картинка), без перечня симптомов через запятую. Пример уровня: «После обеда джинсы жмут 😩» — на GEO перепиши естественно; сразу видно момент и боль; ЗАПРЕЩЕНО нагромождать «после обеда 😩 джинсы, живот, тесно» отдельными ярлыками',
|
|
108007
108570
|
textApproach: 'Начни с конкретной жизненной сцены, где проблема ощущается («[ключевой симптом категории продукта]…», «Вечером перед сном не можешь уснуть из-за дискомфорта…» — адаптируй под категорию). Создай узнаваемую ситуацию — читатель должен сказать «это про меня» — и предложи решение.',
|
|
108008
108571
|
},
|
|
108009
108572
|
];
|
|
@@ -108120,7 +108683,7 @@ ${distributionLines}
|
|
|
108120
108683
|
|
|
108121
108684
|
КРИТИЧНО — СРОК + ОФФЕР ДЛЯ КОНВЕРСИИ:
|
|
108122
108685
|
${deadlineNote}
|
|
108123
|
-
- Опционально (не обязательно): усили CTA упоминанием
|
|
108686
|
+
- Опционально (не обязательно): усили CTA упоминанием **-50%** как есть и ограниченности по времени («только сегодня/ограничено») — коротко, в конце; **не** заменяй -50% на «полцены», «вторая упаковка» и т.п., если это не в задании.${hasTestimonial ? '' : ''}
|
|
108124
108687
|
|
|
108125
108688
|
Требования к стилю и тону:
|
|
108126
108689
|
- Копия должна звучать как прямая реклама, а не как рассказ
|
|
@@ -108141,7 +108704,7 @@ ${deadlineNote}
|
|
|
108141
108704
|
- КРИТИЧНО: Каждый текст должен содержать хотя бы одно ясное ключевое слово проблемы, релевантное категории продукта (например, для суставов: боль/скованность/подвижность; для пищеварения: дискомфорт/тяжесть; для сна: бессонница/усталость — примеры только для формата, адаптируй под категорию). Если ключевое слово проблемы отсутствует — перепиши текст
|
|
108142
108705
|
- КРИТИЧНО: Каждый текст должен заканчиваться сильным и явным призывом к действию (кликни, попробуй сейчас, закажи сегодня, узнай больше и т.д.)
|
|
108143
108706
|
- Избегай слабых окончаний или информационного тона. Слабые или нейтральные окончания не допускаются
|
|
108144
|
-
- CTA должен быть “нажимным”: допускаются формулировки «не откладывай», «последний шанс», «только сегодня», «забери -50%» (всё строго на языке GEO)
|
|
108707
|
+
- CTA должен быть “нажимным”: допускаются формулировки «не откладывай», «последний шанс», «только сегодня», «забери -50%» (всё строго на языке GEO). Если пишешь скидку — **-50%** буквально, без выдуманной механики акции
|
|
108145
108708
|
- В каждом тексте строго следуй заданному формату старта согласно его подходу (см. распределение выше)
|
|
108146
108709
|
- Если ингредиенты предоставлены в дополнительной информации, упоминай их ТОЛЬКО если они естественно подходят выбранному рекламному подходу. Например: подходы авторитета/экспертизы выигрывают от деталей ингредиентов, в то время как подходы срочности/эмоционального триггера могут не нуждаться в них. Упоминай только релевантные ингредиенты, не обязательно все из них. Если ингредиенты не подходят подходу или не предоставлены — полностью пропусти их упоминание и не изобретай и не упоминай никакие ингредиенты
|
|
108147
108710
|
- Добавляй только существенные поддерживающие детали, которые усиливают убеждение или ясность, а не заполнители или общие утверждения. Будь кратким и прямым
|
|
@@ -108154,7 +108717,7 @@ ${deadlineNote}
|
|
|
108154
108717
|
- Разделяй разные тексты пустой строкой (двойной перевод строки)
|
|
108155
108718
|
- КРИТИЧНО: Каждый текст ДОЛЖЕН быть многострочным с естественными переносами строк. Используй переносы строк для разделения предложений, выделения ключевых моментов или создания визуальной структуры. НЕ пиши описания как одиночные непрерывные строки
|
|
108156
108719
|
- КРИТИЧНО: Все тексты ДОЛЖНЫ быть написаны на языке ${geo}. Используй точное название языка "${geo}" — не используй русский, английский или любой другой язык
|
|
108157
|
-
- ВСЕ слова в тексте должны быть на языке GEO. Английские фразы вроде «Made in Italy», «Made in Germany» ЗАПРЕЩЕНЫ — используй
|
|
108720
|
+
- ВСЕ слова в тексте должны быть на языке GEO. Английские фразы вроде «Made in Italy», «Made in Germany» ЗАПРЕЩЕНЫ — используй перевод на язык GEO (например «Произведено в Италии», «Сделано в Германии» и аналоги).
|
|
108158
108721
|
- После создания проверь их правильность И убедись в максимальном разнообразии между текстами
|
|
108159
108722
|
- Верни только финальные результаты. Не добавляй объяснений или комментариев`;
|
|
108160
108723
|
}
|
|
@@ -108232,6 +108795,7 @@ function getPairsSystemPrompt(geo, noOverride, count = 3, selectedIndices) {
|
|
|
108232
108795
|
- Служебные метки в начале строки пиши РОВНО как в примере: слово «ЗАГОЛОВОК» целиком кириллицей (не ZAG, не смесь латиницы и кириллицы), слово «ТЕКСТ» целиком кириллицей.
|
|
108233
108796
|
- Не вставляй строки «ЗАГОЛОВОК N:» внутрь текста объявления; каждый заголовок — отдельная строка перед своим «ТЕКСТ N:».
|
|
108234
108797
|
- Контент объявления (заголовок и текст) — на языке ${geo}; только метки ЗАГОЛОВОК/ТЕКСТ остаются кириллицей как шаблон.
|
|
108798
|
+
- Язык ${geo}: если это название страны — пиши на **официальном языке этой страны**; не путай близкие коды и локали (например Словения ≠ Словакия, хорватский ≠ словенский).
|
|
108235
108799
|
|
|
108236
108800
|
РАСПРЕДЕЛЕНИЕ ПОДХОДОВ ПО ПАРАМ:
|
|
108237
108801
|
${distributionLines}
|
|
@@ -108241,27 +108805,28 @@ ${distributionLines}
|
|
|
108241
108805
|
- Текст — раскрывает тот же угол глубже, добавляет детали, заканчивается CTA
|
|
108242
108806
|
- Текст НЕ повторяет заголовок дословно, но развивает его смысл
|
|
108243
108807
|
- Не подмешивай чужие углы: например в «трансформация до/после» не используй формулировки соцдоказательства («многие отмечают», «клиенты говорят»)
|
|
108244
|
-
${hasTransformAndTestimonial ? '\n- РАЗВЕДЕНИЕ «трансформация до/после» и «testimonial» в одном ответе: у трансформации заголовок = контраст ощущений/состояния (без −кг и без «минус X kg за N дней»); у testimonial
|
|
108808
|
+
${hasTransformAndTestimonial ? '\n- РАЗВЕДЕНИЕ «трансформация до/после» и «testimonial» в одном ответе: у трансформации заголовок = контраст ощущений/состояния (без −кг и без «минус X kg за N дней»); у testimonial −кг и весы в заголовке — **только если продукт в задании явно про похудение**; иначе testimonial = конкретный симптомный/комфортный результат + срок. Не делай два заголовка в одном формате «цифра + срок на весах».' : ''}
|
|
108245
108809
|
|
|
108246
108810
|
ТРЕБОВАНИЯ К ЗАГОЛОВКУ:
|
|
108247
108811
|
- До 55–60 символов, максимум 6–7 слов
|
|
108248
108812
|
- Цельность: заголовок читается как одно высказывание (или один связный вопрос целиком). ЗАПРЕЩЕНО склеивать несвязные ярлыки запятыми ради ключевых слов; эмодзи не должно разрывать грамматику так, что фраза перестаёт быть человеческой
|
|
108249
108813
|
- ЗАПРЕЩЕНО двоеточие (:) — используй тире (—) или переформулируй
|
|
108250
108814
|
- 1–2 эмодзи естественно (часто в конце фразы или после целого смыслового блока); избегай ⚠️ и 🚨${hasDirectOffer ? '\n- Для пары «прямой оффер/выгода» эмодзи в заголовке ОБЯЗАТЕЛЕН (минимум один) — визуально вровень с остальными парами набора' : ''}
|
|
108251
|
-
- Хотя бы одно ключевое слово проблемы, релевантное продукту${hasUrgencyScarcity ? '\n- ИСКЛЮЧЕНИЕ: для пары с подходом «срочность/дефицит» в заголовке ЗАПРЕЩЕНЫ симптомы, проблема, тело, продукт — только лимит оффера (время, количество, дедлайн)' : ''}${hasAuthorityExpertise ? '\n- Пара «авторитет/экспертиза»: заголовок держит information gap — без ингредиентов и без прямого названия механизма; состав и «как это работает» — только в тексте пары' : ''}
|
|
108252
|
-
- НЕ упоминай название продукта — заголовок = боль + триггер${hasUrgencyScarcity ? ' (кроме пары «срочность/дефицит»: там заголовок = только дефицит/дедлайн, без продукта и без боли)' : ''}${hasSocialProof ? '\n- Исключение: в паре «социальное доказательство» название продукта в заголовке допустимо, если оно входит в цельную фразу про массовый выбор (например
|
|
108815
|
+
- Хотя бы одно ключевое слово проблемы, релевантное продукту${hasUrgencyScarcity ? '\n- ИСКЛЮЧЕНИЕ: для пары с подходом «срочность/дефицит» в заголовке ЗАПРЕЩЕНЫ симптомы, проблема, тело, продукт — только лимит оффера (время, количество, дедлайн)' : ''}${hasDirectOffer ? '\n- ИСКЛЮЧЕНИЕ: для пары «прямой оффер/выгода» ключевое слово проблемы в заголовке **не обязательно**; ядро — **-50%** (+эмодзи + короткая срочность). **Не выдумывай** «2-й пакет / вторая упаковка / полцены» без данных в задании — **-50% это просто -50%.**' : ''}${hasAuthorityExpertise ? '\n- Пара «авторитет/экспертиза»: заголовок держит information gap — без ингредиентов и без прямого названия механизма; состав и «как это работает» — только в тексте пары' : ''}
|
|
108816
|
+
- НЕ упоминай название продукта — заголовок = боль + триггер${hasUrgencyScarcity ? ' (кроме пары «срочность/дефицит»: там заголовок = только дефицит/дедлайн, без продукта и без боли)' : ''}${hasSocialProof ? '\n- Исключение: в паре «социальное доказательство» название продукта в заголовке допустимо, если оно входит в цельную фразу про массовый выбор (например «Уже N тысяч человек выбрали [продукт]» на языке GEO)' : ''}
|
|
108253
108817
|
- Звучит как живая рекламная фраза, а не строка ключевых слов
|
|
108254
108818
|
|
|
108255
108819
|
ТРЕБОВАНИЯ К ТЕКСТУ:
|
|
108256
|
-
- 150–280 символов (testimonial — до 300)
|
|
108257
|
-
- Хотя бы одно ключевое слово проблемы (для «срочность/дефицит» в тексте допустимо слабее, если весь фокус — на лимите оффера)
|
|
108258
|
-
- Сильный явный CTA в конце («кликни», «попробуй сейчас», «закажи», «не жди»)${hasFearInaction ? '\n- ИСКЛЮЧЕНИЕ: для пары «страх бездействия» финальная фраза — не заказ, а забота о себе / начать сейчас; без
|
|
108259
|
-
- Короткие рубленые фразы, императивы, FOMO допустим${hasTestimonial ? '\n- Testimonial: строго от первого лица, начинается с «Имя, возраст:», конкретный результат с
|
|
108820
|
+
- 150–280 символов (testimonial — до 300)${hasDirectOffer ? '; для пары «прямой оффер/выгода» достаточно **120–200** символов, если текст = **-50%** + срочность + CTA без воды' : ''}
|
|
108821
|
+
- Хотя бы одно ключевое слово проблемы (для «срочность/дефицит» в тексте допустимо слабее, если весь фокус — на лимите оффера)${hasDirectOffer ? '; для «прямой оффер/выгода» ключевое слово проблемы **не обязательно** — фокус на **-50%** и CTA' : ''}
|
|
108822
|
+
- Сильный явный CTA в конце («кликни», «попробуй сейчас», «закажи», «не жди»)${hasFearInaction ? '\n- ИСКЛЮЧЕНИЕ: для пары «страх бездействия» финальная фраза — не заказ, а забота о себе / начать сейчас; без «закажи», «купи», «оформи заказ» в конце' : ''}
|
|
108823
|
+
- Короткие рубленые фразы, императивы, FOMO допустим${hasTestimonial ? '\n- Testimonial: строго от первого лица, начинается с «Имя, возраст:», конкретный результат с таймингом; тема результата = как в названии/описании продукта (антипаразитарное → ЖКТ/вздутие/дискомфорт и т.д.), не минус кг если продукт не про вес' : ''}
|
|
108260
108824
|
- Ингредиенты и состав из доп. информации — только в углах «авторитет/экспертиза» (и сходных); в «болевой точке» и чисто эмоциональных углах состав не перечислять
|
|
108261
108825
|
${deadlineNote}
|
|
108262
108826
|
|
|
108263
108827
|
ОБЩИЕ ТРЕБОВАНИЯ:
|
|
108264
108828
|
- Язык: ${geo} — все тексты строго на этом языке
|
|
108829
|
+
- Релевантность продукту из пользовательского сообщения: не подменяй категорию. Капли/средства от паразитов, детокс ЖКТ → симптомы и облегчение в этой зоне; **не делай главным мотивом −кг и весы**, если в задании нет явного похудения. Аналогично не смешивай суставы с простатой и т.д.
|
|
108265
108830
|
- Естественный человеческий тон, без академизма и AI-звучания
|
|
108266
108831
|
- Разные психологические триггеры в каждой паре, минимальное пересечение
|
|
108267
108832
|
- Верни ТОЛЬКО пары в указанном формате, без объяснений и комментариев`;
|
|
@@ -108384,10 +108949,10 @@ OTHER_TEXT: ["..."] (любой другой рекламный текст на
|
|
|
108384
108949
|
ШАГ 1 — HOOK/HEADLINE (критично):
|
|
108385
108950
|
- Должен быть ВЫШЕ всех элементов и читабелен (хорошо читается на телефоне)
|
|
108386
108951
|
- Допускается 1–4 строки (это НЕ ошибка). Ошибка только если текст нечитабелен или есть разрыв/перенос внутри слова.
|
|
108387
|
-
- Смысл: релевантно проблеме/выгоде продукта. Допускаются и боль/дискомфорт, и обещание/выгода (например
|
|
108952
|
+
- Смысл: релевантно проблеме/выгоде продукта. Допускаются и боль/дискомфорт, и обещание/выгода (например «станет легче день ото дня» — смысл на языке GEO). НЕ считай ошибкой формулировки обещаний результата или клеймы.
|
|
108388
108953
|
- ОБЯЗАТЕЛЬНО: ключевое слово проблемы явно в формулировке. Примеры по категориям: простата → простатит, простата; похудение → лишний вес, похудение; суставы → боль, колени, скованность; пищеварение → дискомфорт, вздутие; сон → бессонница, усталость. Отсутствие ключевого слова — ОШИБКА. Дополнительно для ориентира: ${keywords.join(', ')} (можно синонимы).
|
|
108389
|
-
- Проверь вторую часть заголовка. Если она состоит только из абстрактных слов (
|
|
108390
|
-
- Если заголовок слишком общий/абстрактный (
|
|
108954
|
+
- Проверь вторую часть заголовка. Если она состоит только из абстрактных слов («легче», «лучше», «решение», «помощь» без конкретики на языке GEO) без конкретного бенефита — отметь: РЕКОМЕНДАЦИЯ: заголовок можно усилить конкретикой
|
|
108955
|
+
- Если заголовок слишком общий/абстрактный («легче», «лучше» без конкретики) — отметь как РЕКОМЕНДАЦИЯ к улучшению (не ошибка, но слабо)
|
|
108391
108956
|
- РЕКОМЕНДАЦИЯ (CTR): верхний текст лучше делать как HOOK — ОЧЕНЬ крупный, жирный, ВСЕ БУКВЫ ПРОПИСНЫЕ, на яркой контрастной плашке. Если это не так — не ошибка, но отметь рекомендацией
|
|
108392
108957
|
|
|
108393
108958
|
${step2Bullets}
|
|
@@ -108458,6 +109023,8 @@ function getImageGenerationBasePrompt(generateGeo, generatePrice, generateCurren
|
|
|
108458
109023
|
Создай рекламный креатив для Facebook Ads ${ratio} (${ratioLabel}).
|
|
108459
109024
|
ВАЖНО: изображение должно быть ${ratioShape} — строго соблюдай пропорции холста.
|
|
108460
109025
|
Язык текста: ${generateGeo}.
|
|
109026
|
+
Если GEO — название страны (например «Чехия», «Румыния»), используй **основной официальный язык этой страны** на макете (Чехия → чешский; Румыния → румынский и т.д.). Валюта/символ цены из брифа и язык текста должны соответствовать одному рынку: при Kč — весь рекламный текст на чешском, не на румынском/польском/венгерском.
|
|
109027
|
+
ЗАПРЕЩЕНО копировать на макет примеры формулировок из этого промпта, если они на другом языке, чем требуется для ${generateGeo} — примеры только про структуру, слова придумывай на целевом языке.
|
|
108461
109028
|
|
|
108462
109029
|
🚫 СЛУЖЕБНЫЕ СЛОВА НЕ РИСОВАТЬ НА КАРТИНКЕ (КРИТИЧНО):
|
|
108463
109030
|
Слова HOOK, CTA, CAPS, BULLET, HEADLINE, PRICE, DISCOUNT, BULLETS, LAYER и любые похожие английские метки из этой инструкции (в т.ч. thumb‑stop) — только для тебя; на макете их НЕТ ни на кнопке, ни на плашках, ни мелким текстом. Кнопка: только реальный призыв на языке ${generateGeo} (1–2 слова), без префикса «CTA». Заголовок: только живой текст оффера, без слова HOOK. Заголовок делай прописными буквами на языке ${generateGeo}, но не пиши на изображении слово CAPS и не подписывай блоки ярлыками.
|
|
@@ -108493,20 +109060,20 @@ HOOK / HEADLINE (строгое правило):
|
|
|
108493
109060
|
- ОБЯЗАТЕЛЬНО содержит ключевое слово проблемы ЯВНО. Примеры по категориям: простата → простатит, простата; похудение → лишний вес, похудение; суставы → боль в суставах, колени, скованность; пищеварение → дискомфорт, вздутие, тяжесть; сон → бессонница, усталость. Без ключевого слова — ОШИБКА
|
|
108494
109061
|
- HOOK ВЫШЕ всех элементов (продукт, буллеты, CTA, цена). Самый крупный текстовый элемент на креативе
|
|
108495
109062
|
- HOOK должен быть ВИЗУАЛЬНО “тяжёлым”: ОЧЕНЬ крупный, ТОЛСТЫЙ/жирный шрифт, весь текст заголовка ПРОПИСНЫМИ буквами на языке ${generateGeo}, на яркой контрастной плашке/подложке. Это верхний главный элемент, цепляющий внимание в ленте
|
|
108496
|
-
- Можно (не обязательно) включить СРОК прямо в HOOK (например «7
|
|
108497
|
-
- Заголовок должен быть РЕЗКИМ и призывным: короткие рубленые фразы, вопросы и предупреждения допустимы. Можно использовать обращение на «ты» (
|
|
109063
|
+
- Можно (не обязательно) включить СРОК прямо в HOOK (например «7 дней», «14 дней» — перенеси число и слово «дней» на язык ${generateGeo}) как триггер
|
|
109064
|
+
- Заголовок должен быть РЕЗКИМ и призывным: короткие рубленые фразы, вопросы и предупреждения допустимы. Можно использовать обращение на «ты» (естественное для языка ${generateGeo}) и вопросительный знак
|
|
108498
109065
|
- заголовок НЕ должен быть абстрактным слоганом/лозунгом или метафорой без конкретной боли. Допускается «thumb‑stop» стиль (вызов/вопрос/предупреждение), если это конкретно и релевантно категории
|
|
108499
109066
|
- если не влезает: сначала измени композицию (расширь блок/переставь элементы), затем перепиши короче. НЕЛЬЗЯ уменьшать шрифт. HOOK всегда остаётся выше всех остальных элементов
|
|
108500
109067
|
- Не повторяй один и тот же заголовок в разных подходах: для текущего подхода придумай новый, уникальный заголовок. Варьируй: угол боли, формулировку, акцент (проблема vs облегчение)
|
|
108501
|
-
- Вторая часть заголовка = конкретное улучшение, не абстрактное слово.
|
|
109068
|
+
- Вторая часть заголовка = конкретное улучшение, не абстрактное слово. ПРАВИЛЬНО (структура; на макете — только язык ${generateGeo}): боль/вопрос + конкретное облегчение. НЕ ТАК: размытые «легче», «лучше», «решение» без конкретики
|
|
108502
109069
|
- Специфические медицинские термины или диагнозы разрешены в заголовке, но не обязательны. Варьируй между прямыми формулировками (если релевантно категории) и мягкими формулировками, фокусирующимися на симптомах и дискомфорте, для разных креативов. Не используй один и тот же термин во всех креативах
|
|
108503
|
-
ПРИМЕР (
|
|
108504
|
-
- НЕ ТАК:
|
|
108505
|
-
- ТАК (пищеварение):
|
|
108506
|
-
- ТАК (суставы):
|
|
108507
|
-
- ТАК (сон):
|
|
108508
|
-
- ТАК (простата):
|
|
108509
|
-
- ТАК (похудение):
|
|
109070
|
+
ПРИМЕР (русский — только формат и ритм; на макете пиши строго на языке ${generateGeo}, не копируй русский текст, если GEO не русскоязычный):
|
|
109071
|
+
- НЕ ТАК: «Борьба с токсинами» (лозунг, абстрактно)
|
|
109072
|
+
- ТАК (пищеварение): «Вздутие мучает? Легче к вечеру»
|
|
109073
|
+
- ТАК (суставы): «Боль в суставах? Двигайся свободнее»
|
|
109074
|
+
- ТАК (сон): «Бессонные ночи? Выспишься наконец»
|
|
109075
|
+
- ТАК (простата): «Простата беспокоит? Быстрое облегчение»
|
|
109076
|
+
- ТАК (похудение): «Лишний вес? Без жёстких диет»
|
|
108510
109077
|
❗ Если заголовок > 12 слов, похож на длинное предложение или звучит как лозунг без ключевого слова проблемы — ОШИБКА → пересоздай вариант.
|
|
108511
109078
|
|
|
108512
109079
|
BULLETS (жёсткое правило, ровно 3):
|
|
@@ -108516,14 +109083,14 @@ BULLETS (жёсткое правило, ровно 3):
|
|
|
108516
109083
|
- ВИЗУАЛ БУЛЛЕТОВ: крупные, с иконками/галочками (✓), на контрастных подложках. Буллеты ВНЕ упаковки/банки — не на продукте.
|
|
108517
109084
|
- Буллиты должны быть расположены ВЕРТИКАЛЬНО (столбиком), не горизонтально в одну строку. Минимальный размер шрифта буллитов — чтобы читались на экране телефона без зума
|
|
108518
109085
|
|
|
108519
|
-
❗ ВЫБОР БУЛЛЕТОВ (КРИТИЧНО):
|
|
109086
|
+
❗ ВЫБОР БУЛЛЕТОВ (КРИТИЧНО): Если выше по промпту задан блок «ОБЯЗАТЕЛЬНЫЕ БУЛЛЕТЫ» — используй ТОЛЬКО его (перевод на язык ${generateGeo}). Если такого блока нет — выбери 3 случайных смысла из пула ниже; пул на английском только для смысла, на макете **ноль английского** — короткие фразы строго на языке ${generateGeo}. Не копируй на макет язык примеров из этого промпта, кроме целевого ${generateGeo}.
|
|
108520
109087
|
|
|
108521
|
-
ПУЛ
|
|
108522
|
-
•
|
|
108523
|
-
•
|
|
108524
|
-
•
|
|
108525
|
-
•
|
|
108526
|
-
•
|
|
109088
|
+
ПУЛ СМЫСЛОВ (английский не печатать; переписать на ${generateGeo}, 2–4 слова каждый):
|
|
109089
|
+
• Action/benefit: less discomfort, less bloating, less pain, fast relief, daily comfort, easier movement, fewer symptoms, pain-free, calm stomach, calm nights, visible result
|
|
109090
|
+
• Time/speed: effect in 7–14 days, effect in 2 weeks, fast result, relief from day one, 3× faster, from first day, in the first days
|
|
109091
|
+
• Social proof: 9 of 10 recommend, 9 of 10 men recommend, 93% confirm, 8 of 10 satisfied, thousands happy customers
|
|
109092
|
+
• Formula: natural formula, natural ingredients, no harsh chemicals, selected composition, dermatologically tested
|
|
109093
|
+
• Quality of life: active comfort, worry-free days, more energy, restful sleep, easier life
|
|
108527
109094
|
|
|
108528
109095
|
❗ Если хоть один буллет > 4 слов или похож на предложение/обещание — ОШИБКА → пересоздай.
|
|
108529
109096
|
|
|
@@ -108531,9 +109098,9 @@ TEXT LIMIT:
|
|
|
108531
109098
|
- кроме: HOOK, 3 буллетов, цены, скидки, кнопки — ЛЮБОЙ другой текст запрещён (ярлыки/подписи/дисклеймеры/пояснения)
|
|
108532
109099
|
- ИСКЛЮЧЕНИЕ: если 🎯 ПОДХОД = ${noBulletsCond} → кроме HOOK, цены, скидки, CTA — НИКАКОГО другого текста. Буллиты запрещены. Other_text/urgency/trust‑печати запрещены
|
|
108533
109100
|
- ДОПУСКАЕТСЯ (не обязательно) ОДИН бейдж срочности: только ясные формулировки («только сегодня», «последние штуки», «акция до конца дня»). ЗАПРЕЩЕНО: «24h» — непонятно что означает.
|
|
108534
|
-
- ДОПУСКАЕТСЯ (не обязательно) 1–3 trust‑печати: печати цветные, яркие, в стиле FDA. Текст СТРОГО на языке ${generateGeo} — запрещены английские слова («NATURAL», «QUALITY» и т.д.).
|
|
109101
|
+
- ДОПУСКАЕТСЯ (не обязательно) 1–3 trust‑печати: печати цветные, яркие, в стиле FDA. Текст СТРОГО на языке ${generateGeo} — запрещены английские слова («NATURAL», «QUALITY» и т.д.). По смыслу: «натуральный», «натуральный состав» — оформи короткой фразой на языке ${generateGeo}, не латиницей. Размер как минимум как у буллитов. Мелкие печати — ОШИБКА.
|
|
108535
109102
|
- HOOK + буллеты <= 24 слова суммарно (HOOK до 12, буллеты до 12); если больше — ОШИБКА → пересоздай
|
|
108536
|
-
- Если хочешь добавить ощущение срочности — делай это через формулировки в HOOK/BULLETS, через реквизит/иконки, ИЛИ (не обязательно) через один короткий бейдж срочности. Только ясные формулировки (
|
|
109103
|
+
- Если хочешь добавить ощущение срочности — делай это через формулировки в HOOK/BULLETS, через реквизит/иконки, ИЛИ (не обязательно) через один короткий бейдж срочности. Только ясные формулировки на языке ${generateGeo} (уровень смысла: «последние штуки», «только сегодня», «акция до конца дня»). ЗАПРЕЩЕНО «24h» — непонятно что означает.
|
|
108537
109104
|
|
|
108538
109105
|
CTA > PRICE:
|
|
108539
109106
|
- кнопка CTA (1–2 слова на языке ${generateGeo}) — главный якорь нижнего блока (самый контрастный элемент внизу)
|
|
@@ -108549,7 +109116,7 @@ CTA > PRICE:
|
|
|
108549
109116
|
- Скидка: «-50%» ОБЯЗАТЕЛЬНО отдельным видимым бейджем (не только в цене!). Процент скидки должен быть явно читаем. Ярко, заметно, строго НЕ на банке/упаковке, визуально слабее CTA
|
|
108550
109117
|
- Кнопка CTA (1-2 слова)
|
|
108551
109118
|
- Опционально: 1 короткий бейдж срочности (ясные формулировки: «только сегодня», «последние штуки»; ЗАПРЕЩЕНО «24h»). Бейдж в углу кадра, контрастный, но меньше CTA. НЕ обязателен
|
|
108552
|
-
- Опционально: 1–3 trust‑печати (цветные, яркие, в стиле FDA; натуральность, премиальность, безопасность). Текст СТРОГО на языке ${generateGeo} — никакого английского.
|
|
109119
|
+
- Опционально: 1–3 trust‑печати (цветные, яркие, в стиле FDA; натуральность, премиальность, безопасность). Текст СТРОГО на языке ${generateGeo} — никакого английского. По смыслу: «натуральный», «натуральный состав», «качество» — коротко на ${generateGeo}; НЕ «NATURAL», «QUALITY». Размер как минимум как у буллитов. НЕ обязательны
|
|
108553
109120
|
- ИСКЛЮЧЕНИЕ: если 🎯 ПОДХОД = ${noBulletsCond} → показывай только: HOOK + PRICE + DISCOUNT + CTA. Буллиты/urgency/trust‑печати запрещены
|
|
108554
109121
|
|
|
108555
109122
|
ВИЗУАЛ:
|
|
@@ -108595,10 +109162,10 @@ AUTO-CHECK (перед финалом):
|
|
|
108595
109162
|
ВАЖНО: Твой ответ — это ИЗОБРАЖЕНИЕ, не текст. Не пиши план, не перечисляй элементы текстом, не рассуждай, не вызывай tools. Сразу генерируй визуальный креатив как картинку.`;
|
|
108596
109163
|
}
|
|
108597
109164
|
/**
|
|
108598
|
-
*
|
|
108599
|
-
*
|
|
109165
|
+
* Развёрнутый список задач крео: каждый подход повторяется N раз (0–4), N = imageApproachCounts[i].
|
|
109166
|
+
* poolIndex — индекс строки в CREO_APPROACHES (0-based); в UI таблице это номер строки poolIndex + 1 (1–10).
|
|
108600
109167
|
*/
|
|
108601
|
-
function
|
|
109168
|
+
function getCreoApproachExpandedTasks() {
|
|
108602
109169
|
const counts = (0,_promptOverrides__WEBPACK_IMPORTED_MODULE_0__.getImageApproachCounts)();
|
|
108603
109170
|
const result = [];
|
|
108604
109171
|
for (let i = 0; i < CREO_APPROACHES.length && i < counts.length; i++) {
|
|
@@ -108618,11 +109185,15 @@ function getCreoApproaches() {
|
|
|
108618
109185
|
_debugLog(`✅ Using CUSTOM approach: ${approach.name}`, `hasPrompt=${!!override.customPrompt}`, `hasHeadline=${!!override.customHeadlineAngle}`, `hasBullets=${!!override.customBulletsFocus}`);
|
|
108619
109186
|
}
|
|
108620
109187
|
for (let k = 0; k < counts[i]; k++) {
|
|
108621
|
-
result.push(resolved);
|
|
109188
|
+
result.push({ approach: resolved, poolIndex: i });
|
|
108622
109189
|
}
|
|
108623
109190
|
}
|
|
108624
109191
|
return result;
|
|
108625
109192
|
}
|
|
109193
|
+
/** Плоский список подходов (без индекса строки) — для обратной совместимости. */
|
|
109194
|
+
function getCreoApproaches() {
|
|
109195
|
+
return getCreoApproachExpandedTasks().map(t => t.approach);
|
|
109196
|
+
}
|
|
108626
109197
|
const CREO_APPROACHES = [
|
|
108627
109198
|
{
|
|
108628
109199
|
name: 'Эксперт / Авторитет',
|