docs-combiner 0.1.9 → 0.1.10
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 +568 -458
- package/dist/renderer.js.map +1 -1
- package/package.json +1 -1
package/dist/renderer.js
CHANGED
|
@@ -99616,37 +99616,39 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
99616
99616
|
/* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_22__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/InputLabel/InputLabel.js");
|
|
99617
99617
|
/* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_23__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/Select/Select.js");
|
|
99618
99618
|
/* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_24__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/MenuItem/MenuItem.js");
|
|
99619
|
-
/* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_25__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/
|
|
99620
|
-
/* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_26__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/
|
|
99621
|
-
/* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_27__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/
|
|
99622
|
-
/* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_28__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/
|
|
99623
|
-
/* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_29__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/
|
|
99624
|
-
/* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_30__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/
|
|
99625
|
-
/* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_31__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/
|
|
99626
|
-
/* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_32__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/
|
|
99627
|
-
/* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_33__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/
|
|
99628
|
-
/* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_34__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/
|
|
99629
|
-
/* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_35__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/
|
|
99630
|
-
/* harmony import */ var
|
|
99631
|
-
/* harmony import */ var
|
|
99632
|
-
/* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_38__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/
|
|
99633
|
-
/* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_39__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/
|
|
99634
|
-
/* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_40__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/
|
|
99635
|
-
/* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_41__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/
|
|
99636
|
-
/* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_42__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/
|
|
99637
|
-
/* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_43__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/
|
|
99638
|
-
/* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_44__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/
|
|
99639
|
-
/* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_45__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/
|
|
99640
|
-
/* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_46__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/
|
|
99641
|
-
/* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_47__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/
|
|
99642
|
-
/* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_48__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/
|
|
99643
|
-
/* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_49__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/
|
|
99644
|
-
/* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_50__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/
|
|
99645
|
-
/* harmony import */ var
|
|
99646
|
-
/* harmony import */ var
|
|
99647
|
-
/* harmony import */ var
|
|
99648
|
-
/* harmony import */ var
|
|
99649
|
-
/* harmony import */ var
|
|
99619
|
+
/* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_25__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/FormControlLabel/FormControlLabel.js");
|
|
99620
|
+
/* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_26__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/Checkbox/Checkbox.js");
|
|
99621
|
+
/* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_27__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/Tooltip/Tooltip.js");
|
|
99622
|
+
/* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_28__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/ToggleButtonGroup/ToggleButtonGroup.js");
|
|
99623
|
+
/* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_29__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/ToggleButton/ToggleButton.js");
|
|
99624
|
+
/* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_30__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/Paper/Paper.js");
|
|
99625
|
+
/* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_31__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/Dialog/Dialog.js");
|
|
99626
|
+
/* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_32__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/Backdrop/Backdrop.js");
|
|
99627
|
+
/* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_33__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/DialogTitle/DialogTitle.js");
|
|
99628
|
+
/* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_34__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/DialogContent/DialogContent.js");
|
|
99629
|
+
/* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_35__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/DialogActions/DialogActions.js");
|
|
99630
|
+
/* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_36__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/styles/createTheme.js");
|
|
99631
|
+
/* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_37__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/styles/ThemeProvider.js");
|
|
99632
|
+
/* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_38__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/AccountBalance.js");
|
|
99633
|
+
/* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_39__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/AutoAwesome.js");
|
|
99634
|
+
/* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_40__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/Brightness4.js");
|
|
99635
|
+
/* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_41__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/Brightness7.js");
|
|
99636
|
+
/* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_42__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/CheckCircle.js");
|
|
99637
|
+
/* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_43__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/CloudDownload.js");
|
|
99638
|
+
/* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_44__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/ContentCopy.js");
|
|
99639
|
+
/* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_45__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/ExpandMore.js");
|
|
99640
|
+
/* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_46__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/InfoOutlined.js");
|
|
99641
|
+
/* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_47__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/Login.js");
|
|
99642
|
+
/* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_48__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/Logout.js");
|
|
99643
|
+
/* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_49__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/NoteAdd.js");
|
|
99644
|
+
/* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_50__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/Replay.js");
|
|
99645
|
+
/* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_51__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/Settings.js");
|
|
99646
|
+
/* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_52__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/Visibility.js");
|
|
99647
|
+
/* harmony import */ var _PromptManagerDialog__WEBPACK_IMPORTED_MODULE_53__ = __webpack_require__(/*! ./PromptManagerDialog */ "./src/PromptManagerDialog.tsx");
|
|
99648
|
+
/* harmony import */ var _promptOverrides__WEBPACK_IMPORTED_MODULE_54__ = __webpack_require__(/*! ./promptOverrides */ "./src/promptOverrides.ts");
|
|
99649
|
+
/* harmony import */ var xlsx__WEBPACK_IMPORTED_MODULE_55__ = __webpack_require__(/*! xlsx */ "./node_modules/xlsx/xlsx.mjs");
|
|
99650
|
+
/* harmony import */ var jszip__WEBPACK_IMPORTED_MODULE_56__ = __webpack_require__(/*! jszip */ "./node_modules/jszip/dist/jszip.min.js");
|
|
99651
|
+
/* harmony import */ var jszip__WEBPACK_IMPORTED_MODULE_56___default = /*#__PURE__*/__webpack_require__.n(jszip__WEBPACK_IMPORTED_MODULE_56__);
|
|
99650
99652
|
|
|
99651
99653
|
|
|
99652
99654
|
|
|
@@ -99747,6 +99749,10 @@ function App() {
|
|
|
99747
99749
|
return saved || _models__WEBPACK_IMPORTED_MODULE_2__.MODELS.creativeValidation;
|
|
99748
99750
|
});
|
|
99749
99751
|
const [loadingValidationModels, setLoadingValidationModels] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(false);
|
|
99752
|
+
const [validationDisabled, setValidationDisabled] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(() => {
|
|
99753
|
+
const saved = localStorage.getItem('validationDisabled');
|
|
99754
|
+
return saved === 'true';
|
|
99755
|
+
});
|
|
99750
99756
|
const [imageAspectRatio, setImageAspectRatio] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(() => {
|
|
99751
99757
|
const saved = localStorage.getItem('imageAspectRatio');
|
|
99752
99758
|
// Migrate legacy values (4:5, 9:16) to 2:3
|
|
@@ -99958,7 +99964,7 @@ function App() {
|
|
|
99958
99964
|
}
|
|
99959
99965
|
};
|
|
99960
99966
|
// Create theme based on mode
|
|
99961
|
-
const theme = react__WEBPACK_IMPORTED_MODULE_0___default().useMemo(() => (0,
|
|
99967
|
+
const theme = react__WEBPACK_IMPORTED_MODULE_0___default().useMemo(() => (0,_mui_material__WEBPACK_IMPORTED_MODULE_36__["default"])({
|
|
99962
99968
|
palette: {
|
|
99963
99969
|
mode: darkMode ? 'dark' : 'light',
|
|
99964
99970
|
...(darkMode
|
|
@@ -100050,7 +100056,7 @@ function App() {
|
|
|
100050
100056
|
};
|
|
100051
100057
|
loadKey();
|
|
100052
100058
|
// Load prompt overrides from Electron config
|
|
100053
|
-
(0,
|
|
100059
|
+
(0,_promptOverrides__WEBPACK_IMPORTED_MODULE_54__.loadOverridesFromElectron)();
|
|
100054
100060
|
}, []);
|
|
100055
100061
|
// Save form fields to localStorage whenever they change
|
|
100056
100062
|
(0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => {
|
|
@@ -100146,15 +100152,8 @@ function App() {
|
|
|
100146
100152
|
logToTerminal('error', '[Load] Error loading content from Google Drive:', err);
|
|
100147
100153
|
setLoadingContentFromDrive(false);
|
|
100148
100154
|
});
|
|
100149
|
-
//
|
|
100150
|
-
|
|
100151
|
-
Promise.race([loadGeneratedImagesFromDrive(folderId), imagesLoadTimeout]).then((result) => {
|
|
100152
|
-
logToTerminal('log', '[Load] Images loading completed, found:', result.found);
|
|
100153
|
-
setLoadingImagesFromDrive(false);
|
|
100154
|
-
}).catch((err) => {
|
|
100155
|
-
logToTerminal('warn', '[Load] Images loading stopped:', err?.message || err);
|
|
100156
|
-
setLoadingImagesFromDrive(false);
|
|
100157
|
-
});
|
|
100155
|
+
// Креативы не кешируются — не загружаем изображения при открытии
|
|
100156
|
+
setLoadingImagesFromDrive(false);
|
|
100158
100157
|
}, [driveFolderUrl]);
|
|
100159
100158
|
// Sync generatedTitlesData with titles when titles changes (except when user is editing in UI)
|
|
100160
100159
|
(0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => {
|
|
@@ -100679,6 +100678,10 @@ function App() {
|
|
|
100679
100678
|
setSelectedValidationModel(modelId);
|
|
100680
100679
|
localStorage.setItem('selectedValidationModel', modelId);
|
|
100681
100680
|
};
|
|
100681
|
+
const handleValidationDisabledChange = (checked) => {
|
|
100682
|
+
setValidationDisabled(checked);
|
|
100683
|
+
localStorage.setItem('validationDisabled', String(checked));
|
|
100684
|
+
};
|
|
100682
100685
|
// Fetch OpenRouter account balance and key limit
|
|
100683
100686
|
const fetchOpenRouterBalance = async (apiKey) => {
|
|
100684
100687
|
const keyToUse = apiKey ?? openaiApiKey;
|
|
@@ -101537,7 +101540,7 @@ function App() {
|
|
|
101537
101540
|
setTexts(['']);
|
|
101538
101541
|
setPairTranslations({});
|
|
101539
101542
|
// Read pairs count from settings (3–10, default 3)
|
|
101540
|
-
const pairsCountInit = (0,
|
|
101543
|
+
const pairsCountInit = (0,_promptOverrides__WEBPACK_IMPORTED_MODULE_54__.getPairsCount)();
|
|
101541
101544
|
// Initialize placeholders
|
|
101542
101545
|
const initialTitles = Array.from({ length: pairsCountInit }, (_, index) => ({
|
|
101543
101546
|
index: index + 1,
|
|
@@ -101566,7 +101569,7 @@ function App() {
|
|
|
101566
101569
|
}
|
|
101567
101570
|
// Generate all pairs (title + text) in a single request
|
|
101568
101571
|
addLog(formatLogMessage('log', '📋 Generating title+text pairs in a single request...'));
|
|
101569
|
-
const selectedIndices = (0,
|
|
101572
|
+
const selectedIndices = (0,_promptOverrides__WEBPACK_IMPORTED_MODULE_54__.getSelectedPairApproaches)();
|
|
101570
101573
|
setLastUsedApproachIndices(selectedIndices);
|
|
101571
101574
|
const pairsCount = selectedIndices.length;
|
|
101572
101575
|
addLog(formatLogMessage('log', `⚙️ Generating ${pairsCount} pairs (approaches: ${selectedIndices.join(', ')})`));
|
|
@@ -101661,7 +101664,7 @@ function App() {
|
|
|
101661
101664
|
setGenerating(false);
|
|
101662
101665
|
}
|
|
101663
101666
|
};
|
|
101664
|
-
const generateImageWithDALLE = async (prompt, referenceImageUrl) => {
|
|
101667
|
+
const generateImageWithDALLE = async (prompt, referenceImageUrl, aspectRatioOverride) => {
|
|
101665
101668
|
if (!openaiApiKey) {
|
|
101666
101669
|
throw new Error('OpenRouter API key is not set');
|
|
101667
101670
|
}
|
|
@@ -101719,6 +101722,8 @@ function App() {
|
|
|
101719
101722
|
// For image generation models, content must be an array with text and image_url objects
|
|
101720
101723
|
const finalContent = referenceImageApiUrls.length > 0 ? content : prompt;
|
|
101721
101724
|
// Build image_config based on the model family.
|
|
101725
|
+
// When aspectRatioOverride is provided (e.g. in 'both' mode), use it. Otherwise use imageAspectRatio.
|
|
101726
|
+
const effectiveRatio = aspectRatioOverride ?? (imageAspectRatio === 'both' ? '1:1' : imageAspectRatio);
|
|
101722
101727
|
// openai/gpt-5-image* models use OpenAI's gpt-image-1 underneath, which only supports
|
|
101723
101728
|
// three discrete sizes: 1024x1024, 1024x1536, 1536x1024.
|
|
101724
101729
|
// The generic OpenRouter `aspect_ratio` param is ignored for these models.
|
|
@@ -101732,7 +101737,7 @@ function App() {
|
|
|
101732
101737
|
'1:1': '1024x1024',
|
|
101733
101738
|
'2:3': '1024x1536',
|
|
101734
101739
|
};
|
|
101735
|
-
const gptSize = gptSizeMap[
|
|
101740
|
+
const gptSize = gptSizeMap[effectiveRatio] || '1024x1024';
|
|
101736
101741
|
imageConfig = { size: gptSize };
|
|
101737
101742
|
imageAspectRatioParam = gptSize;
|
|
101738
101743
|
}
|
|
@@ -101742,7 +101747,7 @@ function App() {
|
|
|
101742
101747
|
'1:1': '1:1',
|
|
101743
101748
|
'2:3': '2:3',
|
|
101744
101749
|
};
|
|
101745
|
-
imageAspectRatioParam = aspectRatioMap[
|
|
101750
|
+
imageAspectRatioParam = aspectRatioMap[effectiveRatio] || '1:1';
|
|
101746
101751
|
imageConfig = { aspect_ratio: imageAspectRatioParam };
|
|
101747
101752
|
}
|
|
101748
101753
|
const requestBody = {
|
|
@@ -101921,7 +101926,7 @@ function App() {
|
|
|
101921
101926
|
if (imageUrl) {
|
|
101922
101927
|
const img = new Image();
|
|
101923
101928
|
img.onload = () => {
|
|
101924
|
-
logToTerminal('log', `📐 Actual image dimensions: ${img.naturalWidth}×${img.naturalHeight} (requested: ${
|
|
101929
|
+
logToTerminal('log', `📐 Actual image dimensions: ${img.naturalWidth}×${img.naturalHeight} (requested: ${effectiveRatio}, sent image_config: ${JSON.stringify(imageConfig)})`);
|
|
101925
101930
|
};
|
|
101926
101931
|
img.src = imageUrl;
|
|
101927
101932
|
}
|
|
@@ -102796,7 +102801,7 @@ function App() {
|
|
|
102796
102801
|
addLog(formatLogMessage(level, ...args));
|
|
102797
102802
|
};
|
|
102798
102803
|
logMsg('log', '📦 Creating ZIP archive with HTML and product image...');
|
|
102799
|
-
const zip = new (
|
|
102804
|
+
const zip = new (jszip__WEBPACK_IMPORTED_MODULE_56___default())();
|
|
102800
102805
|
zip.file('index.html', htmlContent);
|
|
102801
102806
|
zip.file('product.png', productImageBlob);
|
|
102802
102807
|
logMsg('log', '✅ Files added to archive: index.html, product.png');
|
|
@@ -103115,18 +103120,35 @@ function App() {
|
|
|
103115
103120
|
throw new Error(errorMsg);
|
|
103116
103121
|
}
|
|
103117
103122
|
addLog(formatLogMessage('log', '✅ product.png found'));
|
|
103118
|
-
//
|
|
103119
|
-
// NOTE: This generation prompt is intentionally STRICTER than the image validator (`validateCreativeImage`).
|
|
103120
|
-
// Keep the prompt strict even if validator allows some "acceptable" deviations (e.g. 2-line headline, benefit headline, CTA position, discount emphasis).
|
|
103121
|
-
// Use original currency symbol if available, otherwise use currency code
|
|
103122
|
-
const basePromptStructure = (0,_prompts__WEBPACK_IMPORTED_MODULE_1__.getImageGenerationBasePrompt)(generateGeo, generatePrice, currencyForPrompt, undefined, imageAspectRatio);
|
|
103123
|
-
// Generate images with different approaches (one per approach)
|
|
103123
|
+
// Generate images with different approaches (количество по каждому подходу)
|
|
103124
103124
|
const approaches = (0,_prompts__WEBPACK_IMPORTED_MODULE_1__.getCreoApproaches)();
|
|
103125
|
+
if (approaches.length === 0) {
|
|
103126
|
+
addLog(formatLogMessage('error', '❌ Укажите количество изображений (хотя бы 1) в настройках подходов'));
|
|
103127
|
+
alert('Укажите количество изображений (1–4) хотя бы для одного подхода в настройках');
|
|
103128
|
+
setGeneratingImages(false);
|
|
103129
|
+
return;
|
|
103130
|
+
}
|
|
103131
|
+
// При "both" — на каждый подход генерируем и 1:1, и 2:3
|
|
103132
|
+
const useBoth = imageAspectRatio === 'both';
|
|
103133
|
+
const tasks = useBoth
|
|
103134
|
+
? approaches.flatMap(a => [
|
|
103135
|
+
{ approach: a, ratio: '1:1' },
|
|
103136
|
+
{ approach: a, ratio: '2:3' }
|
|
103137
|
+
])
|
|
103138
|
+
: approaches.map(a => ({ approach: a, ratio: imageAspectRatio }));
|
|
103139
|
+
const additionalInfoLine = generateAdditionalInfo.trim()
|
|
103140
|
+
? `\n📋 ДОПОЛНИТЕЛЬНАЯ ИНФОРМАЦИЯ О ПРОДУКТЕ: ${generateAdditionalInfo.trim()}`
|
|
103141
|
+
: '';
|
|
103142
|
+
const imagePrompts = tasks.map(t => {
|
|
103143
|
+
const basePromptStructure = (0,_prompts__WEBPACK_IMPORTED_MODULE_1__.getImageGenerationBasePrompt)(generateGeo, generatePrice, currencyForPrompt, undefined, t.ratio);
|
|
103144
|
+
return `🏷️ ПРОДУКТ: ${generateProduct}${additionalInfoLine}\n\n${basePromptStructure}🏷️ ПРОДУКТ (повторение для ясности): ${generateProduct}${additionalInfoLine}\n🎯 ПОДХОД: ${t.approach.name}\n\n${t.approach.prompt}\n\n${t.approach.headlineAngle}\n\n${t.approach.bulletsFocus}\n\nТекст — строго следуй правилам этого подхода (HOOK обязателен; буллиты добавляй только если они разрешены для подхода).`;
|
|
103145
|
+
});
|
|
103125
103146
|
// Initialize placeholders for all images
|
|
103126
|
-
const initialPlaceholders =
|
|
103147
|
+
const initialPlaceholders = tasks.map((t, index) => ({
|
|
103127
103148
|
index: index + 1,
|
|
103128
103149
|
imageUrl: undefined,
|
|
103129
|
-
approach: approach.name,
|
|
103150
|
+
approach: t.approach.name + (useBoth ? ` (${t.ratio})` : ''),
|
|
103151
|
+
aspectRatio: t.ratio,
|
|
103130
103152
|
uploaded: false,
|
|
103131
103153
|
checking: false,
|
|
103132
103154
|
checkStatus: 'pending',
|
|
@@ -103140,13 +103162,9 @@ function App() {
|
|
|
103140
103162
|
generating: false // In sequential mode, images start queued (not generating)
|
|
103141
103163
|
}));
|
|
103142
103164
|
setGeneratedImagesData(initialPlaceholders);
|
|
103143
|
-
|
|
103144
|
-
|
|
103145
|
-
|
|
103146
|
-
const imagePrompts = approaches.map(approach => `🏷️ ПРОДУКТ: ${generateProduct}${additionalInfoLine}\n\n${basePromptStructure}🏷️ ПРОДУКТ (повторение для ясности): ${generateProduct}${additionalInfoLine}\n🎯 ПОДХОД: ${approach.name}\n\n${approach.prompt}\n\n${approach.headlineAngle}\n\n${approach.bulletsFocus}\n\nТекст — строго следуй правилам этого подхода (HOOK обязателен; буллиты добавляй только если они разрешены для подхода).`);
|
|
103147
|
-
addLog(formatLogMessage('log', `📝 Generated prompts for ${approaches.length} approaches`));
|
|
103148
|
-
const maxParallel = 3;
|
|
103149
|
-
addLog(formatLogMessage('log', `🚀 Generating ${approaches.length} images in parallel (up to ${maxParallel} at a time)...`));
|
|
103165
|
+
addLog(formatLogMessage('log', `📝 Generated prompts for ${tasks.length} images${useBoth ? ' (1:1 + 2:3 на каждый подход)' : ''}`));
|
|
103166
|
+
const maxParallel = 100; // like infinity
|
|
103167
|
+
addLog(formatLogMessage('log', `🚀 Generating ${tasks.length} images in parallel (up to ${maxParallel} at a time)...`));
|
|
103150
103168
|
const generationStartTime = Date.now();
|
|
103151
103169
|
const resultsMap = new Map();
|
|
103152
103170
|
// Ensure each slot has prompt+product reference from the start (needed for regeneration even on failures)
|
|
@@ -103157,9 +103175,11 @@ function App() {
|
|
|
103157
103175
|
})));
|
|
103158
103176
|
const runOne = async (i, isRetry) => {
|
|
103159
103177
|
const imageIndex = i + 1;
|
|
103160
|
-
const
|
|
103178
|
+
const task = tasks[i];
|
|
103179
|
+
const approachName = task?.approach.name || 'Unknown';
|
|
103161
103180
|
const prompt = imagePrompts[i];
|
|
103162
|
-
|
|
103181
|
+
const ratio = task?.ratio || '1:1';
|
|
103182
|
+
addLog(formatLogMessage('log', `${isRetry ? '🔄' : '🎨'} Генерация изображения ${imageIndex}/${tasks.length} (${approachName} ${ratio})...`));
|
|
103163
103183
|
// Reset slot state for this run
|
|
103164
103184
|
setGeneratedImagesData(prev => prev.map(img => img.index === imageIndex
|
|
103165
103185
|
? {
|
|
@@ -103177,7 +103197,7 @@ function App() {
|
|
|
103177
103197
|
}
|
|
103178
103198
|
: img));
|
|
103179
103199
|
try {
|
|
103180
|
-
const imageUrl = await generateImageWithDALLE(prompt, productImage.url);
|
|
103200
|
+
const imageUrl = await generateImageWithDALLE(prompt, productImage.url, ratio);
|
|
103181
103201
|
if (!imageUrl || typeof imageUrl !== 'string' || imageUrl.trim() === '') {
|
|
103182
103202
|
throw new Error('Generated image URL is empty or invalid');
|
|
103183
103203
|
}
|
|
@@ -103194,59 +103214,46 @@ function App() {
|
|
|
103194
103214
|
productImageUrl: productImage.url
|
|
103195
103215
|
}
|
|
103196
103216
|
: img));
|
|
103197
|
-
addLog(formatLogMessage('log', `✅ Изображение ${imageIndex}/${
|
|
103198
|
-
// Validate right after generation
|
|
103199
|
-
|
|
103200
|
-
|
|
103201
|
-
|
|
103202
|
-
|
|
103203
|
-
|
|
103204
|
-
|
|
103205
|
-
|
|
103206
|
-
|
|
103207
|
-
checking: false,
|
|
103208
|
-
checkStatus: validationResult.status,
|
|
103209
|
-
checkResult: validationResult.result,
|
|
103210
|
-
checkErrors: validationResult.errors,
|
|
103211
|
-
customRegeneratePrompt: validationResult.errors.length > 0
|
|
103212
|
-
? validationResult.errors.map(err => err.replace(/^ОШИБКА:\s*/i, '')).join('\n')
|
|
103213
|
-
: '',
|
|
103214
|
-
originalPrompt: img.originalPrompt || prompt,
|
|
103215
|
-
productImageUrl: img.productImageUrl || productImage.url
|
|
103216
|
-
}
|
|
103217
|
-
: img);
|
|
103218
|
-
// Save single image to Google Drive after validation
|
|
103219
|
-
if (driveFolderUrl) {
|
|
103220
|
-
const folderId = extractFolderId(driveFolderUrl);
|
|
103221
|
-
if (folderId) {
|
|
103222
|
-
const updatedImage = updated.find(img => img.index === imageIndex);
|
|
103223
|
-
if (updatedImage) {
|
|
103224
|
-
saveSingleImageToDrive(folderId, updatedImage).catch((err) => {
|
|
103225
|
-
console.log(`Failed to save image ${imageIndex} after validation:`, err);
|
|
103226
|
-
});
|
|
103227
|
-
}
|
|
103228
|
-
}
|
|
103217
|
+
addLog(formatLogMessage('log', `✅ Изображение ${imageIndex}/${tasks.length} сгенерировано`));
|
|
103218
|
+
// Validate right after generation (skip if validation disabled)
|
|
103219
|
+
const validationResult = validationDisabled
|
|
103220
|
+
? { status: 'ok', result: 'Проверка отключена', errors: [], checkFailed: false }
|
|
103221
|
+
: await (async () => {
|
|
103222
|
+
try {
|
|
103223
|
+
const res = await validateCreativeImage(imageUrl, generateProduct, generateGeo, addLog, approachName);
|
|
103224
|
+
if (!res)
|
|
103225
|
+
throw new Error('No validation result');
|
|
103226
|
+
return { ...res, checkFailed: false };
|
|
103229
103227
|
}
|
|
103230
|
-
|
|
103231
|
-
|
|
103232
|
-
|
|
103233
|
-
|
|
103234
|
-
|
|
103235
|
-
|
|
103236
|
-
|
|
103228
|
+
catch (validationErr) {
|
|
103229
|
+
const msg = validationErr?.message || String(validationErr);
|
|
103230
|
+
addLog(formatLogMessage('error', `❌ Ошибка проверки изображения ${imageIndex}: ${msg}`));
|
|
103231
|
+
return {
|
|
103232
|
+
status: 'needs_rebuild',
|
|
103233
|
+
result: `Ошибка проверки: ${msg}`,
|
|
103234
|
+
errors: [msg],
|
|
103235
|
+
checkFailed: true
|
|
103236
|
+
};
|
|
103237
|
+
}
|
|
103238
|
+
})();
|
|
103239
|
+
setGeneratedImagesData(prev => {
|
|
103240
|
+
const updated = prev.map(img => img.index === imageIndex
|
|
103237
103241
|
? {
|
|
103238
103242
|
...img,
|
|
103239
103243
|
checking: false,
|
|
103240
|
-
|
|
103241
|
-
|
|
103242
|
-
checkResult:
|
|
103243
|
-
checkErrors:
|
|
103244
|
-
customRegeneratePrompt:
|
|
103244
|
+
checkFailed: validationResult.checkFailed ?? false,
|
|
103245
|
+
checkStatus: validationResult.status,
|
|
103246
|
+
checkResult: validationResult.result,
|
|
103247
|
+
checkErrors: validationResult.errors,
|
|
103248
|
+
customRegeneratePrompt: validationResult.errors.length > 0
|
|
103249
|
+
? validationResult.errors.map(err => err.replace(/^ОШИБКА:\s*/i, '')).join('\n')
|
|
103250
|
+
: '',
|
|
103245
103251
|
originalPrompt: img.originalPrompt || prompt,
|
|
103246
103252
|
productImageUrl: img.productImageUrl || productImage.url
|
|
103247
103253
|
}
|
|
103248
|
-
: img)
|
|
103249
|
-
|
|
103254
|
+
: img);
|
|
103255
|
+
return updated;
|
|
103256
|
+
});
|
|
103250
103257
|
return {
|
|
103251
103258
|
index: imageIndex,
|
|
103252
103259
|
imageUrl,
|
|
@@ -103258,7 +103265,7 @@ function App() {
|
|
|
103258
103265
|
}
|
|
103259
103266
|
catch (err) {
|
|
103260
103267
|
const errorMessage = err?.message || String(err);
|
|
103261
|
-
addLog(formatLogMessage('error', `❌ Не удалось сгенерировать изображение ${imageIndex}/${
|
|
103268
|
+
addLog(formatLogMessage('error', `❌ Не удалось сгенерировать изображение ${imageIndex}/${tasks.length}: ${errorMessage}`));
|
|
103262
103269
|
setGeneratedImagesData(prev => prev.map(img => img.index === imageIndex
|
|
103263
103270
|
? {
|
|
103264
103271
|
...img,
|
|
@@ -103554,7 +103561,7 @@ ${imageData.originalPrompt}
|
|
|
103554
103561
|
});
|
|
103555
103562
|
}
|
|
103556
103563
|
addLog(formatLogMessage('log', `📤 Первые 300 символов промпта: ${improvedPrompt.substring(0, 300)}...`));
|
|
103557
|
-
const newImageUrl = await generateImageWithDALLE(improvedPrompt, referenceImages);
|
|
103564
|
+
const newImageUrl = await generateImageWithDALLE(improvedPrompt, referenceImages, imageData.aspectRatio ?? '1:1');
|
|
103558
103565
|
if (!newImageUrl)
|
|
103559
103566
|
throw new Error('No image URL returned');
|
|
103560
103567
|
addLog(formatLogMessage('log', `✅ Изображение ${imageData.index} переделано успешно`));
|
|
@@ -103582,9 +103589,15 @@ ${imageData.originalPrompt}
|
|
|
103582
103589
|
failed: false // Mark as successful
|
|
103583
103590
|
}
|
|
103584
103591
|
: img));
|
|
103585
|
-
// Run validation on the new image
|
|
103586
|
-
|
|
103587
|
-
|
|
103592
|
+
// Run validation on the new image (skip if disabled)
|
|
103593
|
+
let validationResult;
|
|
103594
|
+
if (validationDisabled) {
|
|
103595
|
+
validationResult = { status: 'ok', result: 'Проверка отключена', errors: [] };
|
|
103596
|
+
}
|
|
103597
|
+
else {
|
|
103598
|
+
addLog(formatLogMessage('log', `🔍 Проверка переделанного изображения ${imageData.index}...`));
|
|
103599
|
+
validationResult = await validateCreativeImage(newImageUrl, generateProduct, generateGeo, addLog, imageData.approach);
|
|
103600
|
+
}
|
|
103588
103601
|
// Update with validation result
|
|
103589
103602
|
setGeneratedImagesData(prev => {
|
|
103590
103603
|
const updated = prev.map(img => img.index === imageData.index
|
|
@@ -103602,18 +103615,6 @@ ${imageData.originalPrompt}
|
|
|
103602
103615
|
productImageUrl: img.productImageUrl || imageData.productImageUrl
|
|
103603
103616
|
}
|
|
103604
103617
|
: img);
|
|
103605
|
-
// Save single image to Google Drive after regeneration
|
|
103606
|
-
if (driveFolderUrl) {
|
|
103607
|
-
const folderId = extractFolderId(driveFolderUrl);
|
|
103608
|
-
if (folderId) {
|
|
103609
|
-
const updatedImage = updated.find(img => img.index === imageData.index);
|
|
103610
|
-
if (updatedImage) {
|
|
103611
|
-
saveSingleImageToDrive(folderId, updatedImage).catch((err) => {
|
|
103612
|
-
console.log(`Failed to save image ${imageData.index} after regeneration:`, err);
|
|
103613
|
-
});
|
|
103614
|
-
}
|
|
103615
|
-
}
|
|
103616
|
-
}
|
|
103617
103618
|
return updated;
|
|
103618
103619
|
});
|
|
103619
103620
|
const statusEmoji = validationResult.status === 'ok' ? '✅' : '❌';
|
|
@@ -103679,7 +103680,7 @@ ${imageData.originalPrompt}
|
|
|
103679
103680
|
${imageData.originalPrompt}
|
|
103680
103681
|
|
|
103681
103682
|
ВАЖНО: Твой ответ — это ИЗОБРАЖЕНИЕ, не текст. Не пиши план, не перечисляй элементы текстом, не рассуждай, не вызывай tools. Сразу генерируй визуальный креатив как картинку.`;
|
|
103682
|
-
const newImageUrl = await generateImageWithDALLE(freshPrompt, imageData.productImageUrl);
|
|
103683
|
+
const newImageUrl = await generateImageWithDALLE(freshPrompt, imageData.productImageUrl, imageData.aspectRatio ?? '1:1');
|
|
103683
103684
|
addLog(formatLogMessage('log', `✅ Изображение ${imageData.index} (с нуля) сгенерировано`));
|
|
103684
103685
|
// Update image data - always add timestamp for HTTP URLs to prevent browser caching
|
|
103685
103686
|
let updatedImageUrl = newImageUrl;
|
|
@@ -103704,9 +103705,15 @@ ${imageData.originalPrompt}
|
|
|
103704
103705
|
failed: false
|
|
103705
103706
|
}
|
|
103706
103707
|
: img));
|
|
103707
|
-
// Validate new image
|
|
103708
|
-
|
|
103709
|
-
|
|
103708
|
+
// Validate new image (skip if disabled)
|
|
103709
|
+
let validationResult;
|
|
103710
|
+
if (validationDisabled) {
|
|
103711
|
+
validationResult = { status: 'ok', result: 'Проверка отключена', errors: [] };
|
|
103712
|
+
}
|
|
103713
|
+
else {
|
|
103714
|
+
addLog(formatLogMessage('log', `🔍 Проверка изображения ${imageData.index} (с нуля)...`));
|
|
103715
|
+
validationResult = await validateCreativeImage(newImageUrl, generateProduct, generateGeo, addLog, imageData.approach);
|
|
103716
|
+
}
|
|
103710
103717
|
setGeneratedImagesData(prev => {
|
|
103711
103718
|
const updated = prev.map(img => img.index === imageData.index
|
|
103712
103719
|
? {
|
|
@@ -103722,18 +103729,6 @@ ${imageData.originalPrompt}
|
|
|
103722
103729
|
productImageUrl: img.productImageUrl || imageData.productImageUrl
|
|
103723
103730
|
}
|
|
103724
103731
|
: img);
|
|
103725
|
-
// Save single image to Google Drive after regeneration
|
|
103726
|
-
if (driveFolderUrl) {
|
|
103727
|
-
const folderId = extractFolderId(driveFolderUrl);
|
|
103728
|
-
if (folderId) {
|
|
103729
|
-
const updatedImage = updated.find(img => img.index === imageData.index);
|
|
103730
|
-
if (updatedImage) {
|
|
103731
|
-
saveSingleImageToDrive(folderId, updatedImage).catch((err) => {
|
|
103732
|
-
console.log(`Failed to save image ${imageData.index} after regeneration:`, err);
|
|
103733
|
-
});
|
|
103734
|
-
}
|
|
103735
|
-
}
|
|
103736
|
-
}
|
|
103737
103732
|
return updated;
|
|
103738
103733
|
});
|
|
103739
103734
|
}
|
|
@@ -103774,40 +103769,47 @@ ${imageData.originalPrompt}
|
|
|
103774
103769
|
checkErrors: undefined,
|
|
103775
103770
|
}
|
|
103776
103771
|
: img));
|
|
103777
|
-
|
|
103778
|
-
|
|
103779
|
-
|
|
103780
|
-
setGeneratedImagesData(prev => prev.map(img => img.index === imageData.index
|
|
103781
|
-
? {
|
|
103782
|
-
...img,
|
|
103783
|
-
checking: false,
|
|
103784
|
-
checkFailed: false,
|
|
103785
|
-
checkStatus: validationResult.status,
|
|
103786
|
-
checkResult: validationResult.result,
|
|
103787
|
-
checkErrors: validationResult.errors,
|
|
103788
|
-
customRegeneratePrompt: validationResult.errors.length > 0
|
|
103789
|
-
? validationResult.errors.map(err => err.replace(/^ОШИБКА:\s*/i, '')).join('\n')
|
|
103790
|
-
: '',
|
|
103791
|
-
}
|
|
103792
|
-
: img));
|
|
103793
|
-
const statusEmoji = validationResult.status === 'ok' ? '✅' : '❌';
|
|
103794
|
-
addLog(formatLogMessage('log', `${statusEmoji} Повторная проверка изображения ${imageData.index}: ${validationResult.status === 'ok' ? 'OK' : 'НУЖНА ПЕРЕСБОРКА'}`));
|
|
103772
|
+
let validationResult;
|
|
103773
|
+
if (validationDisabled) {
|
|
103774
|
+
validationResult = { status: 'ok', result: 'Проверка отключена', errors: [] };
|
|
103795
103775
|
}
|
|
103796
|
-
|
|
103797
|
-
|
|
103798
|
-
|
|
103799
|
-
|
|
103800
|
-
|
|
103801
|
-
|
|
103802
|
-
|
|
103803
|
-
|
|
103804
|
-
|
|
103805
|
-
|
|
103806
|
-
|
|
103807
|
-
|
|
103808
|
-
|
|
103809
|
-
|
|
103776
|
+
else {
|
|
103777
|
+
addLog(formatLogMessage('log', `🔍 Повторная проверка изображения ${imageData.index}...`));
|
|
103778
|
+
try {
|
|
103779
|
+
validationResult = await validateCreativeImage(imageData.imageUrl, generateProduct, generateGeo, addLog, imageData.approach);
|
|
103780
|
+
}
|
|
103781
|
+
catch (err) {
|
|
103782
|
+
const msg = err?.message || String(err);
|
|
103783
|
+
addLog(formatLogMessage('error', `❌ Ошибка повторной проверки изображения ${imageData.index}: ${msg}`));
|
|
103784
|
+
setGeneratedImagesData(prev => prev.map(img => img.index === imageData.index
|
|
103785
|
+
? {
|
|
103786
|
+
...img,
|
|
103787
|
+
checking: false,
|
|
103788
|
+
checkFailed: true,
|
|
103789
|
+
checkStatus: 'needs_rebuild',
|
|
103790
|
+
checkResult: `Ошибка проверки: ${msg}`,
|
|
103791
|
+
checkErrors: [msg],
|
|
103792
|
+
customRegeneratePrompt: '',
|
|
103793
|
+
}
|
|
103794
|
+
: img));
|
|
103795
|
+
return;
|
|
103796
|
+
}
|
|
103810
103797
|
}
|
|
103798
|
+
setGeneratedImagesData(prev => prev.map(img => img.index === imageData.index
|
|
103799
|
+
? {
|
|
103800
|
+
...img,
|
|
103801
|
+
checking: false,
|
|
103802
|
+
checkFailed: false,
|
|
103803
|
+
checkStatus: validationResult.status,
|
|
103804
|
+
checkResult: validationResult.result,
|
|
103805
|
+
checkErrors: validationResult.errors,
|
|
103806
|
+
customRegeneratePrompt: validationResult.errors.length > 0
|
|
103807
|
+
? validationResult.errors.map(err => err.replace(/^ОШИБКА:\s*/i, '')).join('\n')
|
|
103808
|
+
: '',
|
|
103809
|
+
}
|
|
103810
|
+
: img));
|
|
103811
|
+
const statusEmoji = validationResult.status === 'ok' ? '✅' : '❌';
|
|
103812
|
+
addLog(formatLogMessage('log', `${statusEmoji} Повторная проверка изображения ${imageData.index}: ${validationResult.status === 'ok' ? 'OK' : 'НУЖНА ПЕРЕСБОРКА'}`));
|
|
103811
103813
|
};
|
|
103812
103814
|
const handleUploadImage = async (imageData, folderId) => {
|
|
103813
103815
|
if (!imageData.imageUrl) {
|
|
@@ -103934,11 +103936,33 @@ ${imageData.originalPrompt}
|
|
|
103934
103936
|
const handleLinkChange = (val) => {
|
|
103935
103937
|
setLink(val);
|
|
103936
103938
|
try {
|
|
103937
|
-
|
|
103939
|
+
const toTest = /^https?:\/\//i.test(val.trim()) ? val : 'https://' + val.trim();
|
|
103940
|
+
new URL(toTest);
|
|
103941
|
+
setLinkError('');
|
|
103942
|
+
}
|
|
103943
|
+
catch {
|
|
103944
|
+
setLinkError(val.trim() ? 'Invalid URL format' : '');
|
|
103945
|
+
}
|
|
103946
|
+
};
|
|
103947
|
+
const handleLinkBlur = () => {
|
|
103948
|
+
const trimmed = link.trim();
|
|
103949
|
+
if (!trimmed)
|
|
103950
|
+
return;
|
|
103951
|
+
let toParse = trimmed;
|
|
103952
|
+
if (!/^https?:\/\//i.test(trimmed)) {
|
|
103953
|
+
toParse = 'https://' + trimmed;
|
|
103954
|
+
}
|
|
103955
|
+
try {
|
|
103956
|
+
const parsed = new URL(toParse);
|
|
103957
|
+
let path = parsed.pathname || '/';
|
|
103958
|
+
if (!path.endsWith('/'))
|
|
103959
|
+
path += '/';
|
|
103960
|
+
const result = `https://${parsed.host}${path}${parsed.search}${parsed.hash}`;
|
|
103961
|
+
setLink(result);
|
|
103938
103962
|
setLinkError('');
|
|
103939
103963
|
}
|
|
103940
103964
|
catch {
|
|
103941
|
-
|
|
103965
|
+
// invalid — leave as is
|
|
103942
103966
|
}
|
|
103943
103967
|
};
|
|
103944
103968
|
const extractFolderId = (url) => {
|
|
@@ -104715,8 +104739,8 @@ ${imageData.originalPrompt}
|
|
|
104715
104739
|
}
|
|
104716
104740
|
setGeneratedData(rows);
|
|
104717
104741
|
// Create workbook
|
|
104718
|
-
const wb =
|
|
104719
|
-
const ws =
|
|
104742
|
+
const wb = xlsx__WEBPACK_IMPORTED_MODULE_55__.utils.book_new();
|
|
104743
|
+
const ws = xlsx__WEBPACK_IMPORTED_MODULE_55__.utils.aoa_to_sheet(rows);
|
|
104720
104744
|
// Set column widths (approximate pixel width / 7)
|
|
104721
104745
|
ws['!cols'] = [
|
|
104722
104746
|
{ wch: 20 }, // id
|
|
@@ -104729,9 +104753,9 @@ ${imageData.originalPrompt}
|
|
|
104729
104753
|
{ wch: 40 }, // image_link
|
|
104730
104754
|
{ wch: 20 } // brand
|
|
104731
104755
|
];
|
|
104732
|
-
|
|
104756
|
+
xlsx__WEBPACK_IMPORTED_MODULE_55__.utils.book_append_sheet(wb, ws, "Products");
|
|
104733
104757
|
// Generate buffer
|
|
104734
|
-
const wbout =
|
|
104758
|
+
const wbout = xlsx__WEBPACK_IMPORTED_MODULE_55__.write(wb, { bookType: 'xlsx', type: 'array' });
|
|
104735
104759
|
// Upload to Drive
|
|
104736
104760
|
const dateStr = new Date().toISOString().split('T')[0];
|
|
104737
104761
|
const fileName = `${brand}-${dateStr}.xlsx`;
|
|
@@ -104853,13 +104877,13 @@ ${imageData.originalPrompt}
|
|
|
104853
104877
|
setTestLoading(true);
|
|
104854
104878
|
try {
|
|
104855
104879
|
// Create simple test workbook with structure
|
|
104856
|
-
const wb =
|
|
104880
|
+
const wb = xlsx__WEBPACK_IMPORTED_MODULE_55__.utils.book_new();
|
|
104857
104881
|
const rows = [
|
|
104858
104882
|
INSTRUCTION_ROW,
|
|
104859
104883
|
['id', 'title', 'description', 'availability', 'condition', 'price', 'link', 'image_link', 'brand'],
|
|
104860
104884
|
['test1', 'Test Title', 'Test Description', 'in stock', 'new', '10.00 USD', 'http://test.com', 'http://test.com/img.jpg', 'TestBrand']
|
|
104861
104885
|
];
|
|
104862
|
-
const ws =
|
|
104886
|
+
const ws = xlsx__WEBPACK_IMPORTED_MODULE_55__.utils.aoa_to_sheet(rows);
|
|
104863
104887
|
// Set column widths
|
|
104864
104888
|
ws['!cols'] = [
|
|
104865
104889
|
{ wch: 20 }, // id
|
|
@@ -104872,8 +104896,8 @@ ${imageData.originalPrompt}
|
|
|
104872
104896
|
{ wch: 40 }, // image_link
|
|
104873
104897
|
{ wch: 20 } // brand
|
|
104874
104898
|
];
|
|
104875
|
-
|
|
104876
|
-
const wbout =
|
|
104899
|
+
xlsx__WEBPACK_IMPORTED_MODULE_55__.utils.book_append_sheet(wb, ws, "Test");
|
|
104900
|
+
const wbout = xlsx__WEBPACK_IMPORTED_MODULE_55__.write(wb, { bookType: 'xlsx', type: 'array' });
|
|
104877
104901
|
// Try to extract folder ID if available, otherwise upload to root
|
|
104878
104902
|
const folderId = driveFolderUrl ? extractFolderId(driveFolderUrl) : undefined;
|
|
104879
104903
|
const result = await uploadFileToDrive(wbout, 'test_table.xlsx', folderId || undefined);
|
|
@@ -104907,7 +104931,7 @@ ${imageData.originalPrompt}
|
|
|
104907
104931
|
};
|
|
104908
104932
|
// Show lock screen if not unlocked
|
|
104909
104933
|
if (!unlocked) {
|
|
104910
|
-
return (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
104934
|
+
return (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_37__["default"], { theme: theme },
|
|
104911
104935
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_4__["default"], null),
|
|
104912
104936
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { onClick: handleSecretClick, sx: {
|
|
104913
104937
|
width: '100vw',
|
|
@@ -104947,24 +104971,24 @@ ${imageData.originalPrompt}
|
|
|
104947
104971
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("br", null),
|
|
104948
104972
|
"Please contact system administrator"))));
|
|
104949
104973
|
}
|
|
104950
|
-
return (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
104974
|
+
return (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_37__["default"], { theme: theme },
|
|
104951
104975
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_4__["default"], null),
|
|
104952
104976
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_7__["default"], { maxWidth: "lg", sx: { py: 4 } },
|
|
104953
104977
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { sx: { display: 'flex', justifyContent: 'space-between', alignItems: 'center', mb: 2 } },
|
|
104954
104978
|
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"),
|
|
104955
104979
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], null,
|
|
104956
104980
|
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 } },
|
|
104957
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
104958
|
-
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(
|
|
104981
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_51__["default"], null)),
|
|
104982
|
+
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_41__["default"], null) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_40__["default"], null)))),
|
|
104959
104983
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_9__["default"], { variant: "outlined", sx: { mb: 4 } },
|
|
104960
104984
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_10__["default"], null,
|
|
104961
104985
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_11__["default"], { spacing: 3 },
|
|
104962
104986
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], null,
|
|
104963
104987
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "h6", gutterBottom: true }, "Google Drive Authentication"),
|
|
104964
104988
|
accessToken ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_12__["default"], null,
|
|
104965
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_13__["default"], { expandIcon: react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
104989
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_13__["default"], { expandIcon: react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_45__["default"], null) },
|
|
104966
104990
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { sx: { display: 'flex', alignItems: 'center', color: 'success.main' } },
|
|
104967
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
104991
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_42__["default"], { sx: { mr: 1 } }),
|
|
104968
104992
|
" Logged In (Credentials Hidden)")),
|
|
104969
104993
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_14__["default"], null,
|
|
104970
104994
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_11__["default"], { spacing: 2 },
|
|
@@ -104975,7 +104999,7 @@ ${imageData.originalPrompt}
|
|
|
104975
104999
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_15__["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)" }),
|
|
104976
105000
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_15__["default"], { label: "Client Secret", variant: "outlined", fullWidth: true, value: clientSecret, onChange: (e) => handleClientSecretChange(e.target.value) }))),
|
|
104977
105001
|
openaiApiKey && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { sx: { display: 'flex', alignItems: 'center', gap: 2, mt: 2 } },
|
|
104978
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
105002
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_38__["default"], { color: openRouterAccountBalance !== null ? 'primary' : 'disabled' }),
|
|
104979
105003
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "body2", color: openRouterAccountBalance !== null ? 'text.primary' : 'text.secondary' },
|
|
104980
105004
|
"\u0411\u0430\u043B\u0430\u043D\u0441: ",
|
|
104981
105005
|
openRouterBalanceLoading ? 'Loading...' : (openRouterAccountBalance !== null ? `$${openRouterAccountBalance.toFixed(2)}` : 'N/A')),
|
|
@@ -104984,8 +105008,8 @@ ${imageData.originalPrompt}
|
|
|
104984
105008
|
"\u041B\u0438\u043C\u0438\u0442 \u043A\u043B\u044E\u0447\u0430: ",
|
|
104985
105009
|
openRouterBalanceLoading ? 'Loading...' : (openRouterBalance === -1 ? 'Без лимита' : (openRouterBalance !== null ? `${openRouterBalance.toFixed(4)}` : 'N/A'))))),
|
|
104986
105010
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_11__["default"], { direction: "row", spacing: 2, alignItems: "center", sx: { mt: 2 } },
|
|
104987
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_17__["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_18__["default"], { size: 20, color: "inherit" }) : (accessToken ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
104988
|
-
accessToken && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_17__["default"], { variant: "outlined", color: "error", onClick: handleLogout, startIcon: react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
105011
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_17__["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_18__["default"], { size: 20, color: "inherit" }) : (accessToken ? 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_47__["default"], null)), sx: { flexGrow: 1 } }, authLoading ? 'Logging in...' : (accessToken ? 'Logged In' : 'Login with Google')),
|
|
105012
|
+
accessToken && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_17__["default"], { variant: "outlined", color: "error", onClick: handleLogout, startIcon: react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_48__["default"], null) }, "Logout")))),
|
|
104989
105013
|
!accessToken && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null,
|
|
104990
105014
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_16__["default"], null),
|
|
104991
105015
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], null,
|
|
@@ -105010,9 +105034,9 @@ ${imageData.originalPrompt}
|
|
|
105010
105034
|
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"),
|
|
105011
105035
|
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. \u0412\u0441\u0435 \u0434\u0430\u043D\u043D\u044B\u0435 \u0431\u0443\u0434\u0443\u0442 \u0441\u043E\u0445\u0440\u0430\u043D\u044F\u0442\u044C\u0441\u044F \u0438 \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0442\u044C\u0441\u044F \u0438\u0437 \u044D\u0442\u043E\u0439 \u043F\u0430\u043F\u043A\u0438."))) : (react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null,
|
|
105012
105036
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_11__["default"], { direction: { xs: 'column', sm: 'row' }, spacing: 2 },
|
|
105013
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_15__["default"], { label: "Brand (Short ID)", variant: "outlined",
|
|
105014
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { sx: {
|
|
105015
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_15__["default"], { label: "Link", variant: "outlined", fullWidth: true, value: link, onChange: (e) => handleLinkChange(e.target.value), error: !!linkError, helperText: linkError, placeholder: "
|
|
105037
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_15__["default"], { label: "Brand (Short ID)", variant: "outlined", sx: { flex: '0 0 160px', minWidth: 140 }, value: brand, onChange: (e) => setBrand(e.target.value), placeholder: "e.g. NIKE" }),
|
|
105038
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { sx: { flex: 1, minWidth: 0 } },
|
|
105039
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_15__["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/" }))),
|
|
105016
105040
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_16__["default"], { sx: { my: 2 } }),
|
|
105017
105041
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "h6", gutterBottom: true }, "AI Generation Settings"),
|
|
105018
105042
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], null,
|
|
@@ -105040,18 +105064,22 @@ ${imageData.originalPrompt}
|
|
|
105040
105064
|
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_24__["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_24__["default"], { key: model.id, value: model.id }, model.name))))),
|
|
105041
105065
|
!loadingValidationModels && validationModels.length > 0 && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_19__["default"], null, selectedValidationModel === _models__WEBPACK_IMPORTED_MODULE_2__.MODELS.creativeValidation
|
|
105042
105066
|
? 'Используется модель по умолчанию'
|
|
105043
|
-
: 'Выбрана модель: ' + (validationModels.find(m => m.id === selectedValidationModel)?.name || selectedValidationModel)))
|
|
105067
|
+
: 'Выбрана модель: ' + (validationModels.find(m => m.id === selectedValidationModel)?.name || selectedValidationModel))),
|
|
105068
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_25__["default"], { control: react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_26__["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 } })))),
|
|
105044
105069
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_11__["default"], { direction: "row", spacing: 2, sx: { mb: 2 } },
|
|
105045
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_17__["default"], { variant: "contained", color: "primary", startIcon: react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
105070
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_17__["default"], { variant: "contained", color: "primary", startIcon: react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_39__["default"], null), onClick: handleGenerateContent, disabled: generating || loadingContentFromDrive || !openaiApiKey || !generateProduct.trim() || !generateGeo.trim(), sx: { flexGrow: 1 }, size: "large" }, generating ? 'Generating...' : 'Generate Titles & Descriptions'),
|
|
105046
105071
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_11__["default"], { direction: "row", spacing: 1, alignItems: "center", sx: { flexGrow: 1 } },
|
|
105047
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
105072
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_27__["default"], { title: imageAspectRatio === '1:1'
|
|
105048
105073
|
? '1:1 — квадрат (1024×1024 px)'
|
|
105049
|
-
: '2:3
|
|
105074
|
+
: imageAspectRatio === '2:3'
|
|
105075
|
+
? '2:3 — портрет (1024×1536 px)'
|
|
105076
|
+
: 'Оба — квадрат и портрет на каждый подход', placement: "top" },
|
|
105050
105077
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", null,
|
|
105051
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
105078
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_28__["default"], { value: imageAspectRatio, exclusive: true, onChange: (_e, val) => {
|
|
105052
105079
|
if (val && val !== imageAspectRatio) {
|
|
105053
105080
|
if (generatedImagesData.length > 0) {
|
|
105054
|
-
|
|
105081
|
+
const label = val === 'both' ? 'оба (1:1 + 2:3)' : val;
|
|
105082
|
+
if (window.confirm(`Сменить формат на ${label}? Сгенерированные изображения будут очищены.`)) {
|
|
105055
105083
|
setGeneratedImagesData([]);
|
|
105056
105084
|
setImageAspectRatio(val);
|
|
105057
105085
|
localStorage.setItem('imageAspectRatio', val);
|
|
@@ -105063,9 +105091,10 @@ ${imageData.originalPrompt}
|
|
|
105063
105091
|
}
|
|
105064
105092
|
}
|
|
105065
105093
|
}, size: "small", disabled: generatingImages, sx: { height: 42 } },
|
|
105066
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
105067
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
105068
|
-
|
|
105094
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_29__["default"], { value: "1:1", sx: { px: 1.5, fontWeight: 600, fontSize: '0.8rem' } }, "1:1"),
|
|
105095
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_29__["default"], { value: "2:3", sx: { px: 1.5, fontWeight: 600, fontSize: '0.8rem' } }, "2:3"),
|
|
105096
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_29__["default"], { value: "both", sx: { px: 1.5, fontWeight: 600, fontSize: '0.8rem' } }, "\u041E\u0431\u0430")))),
|
|
105097
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_17__["default"], { variant: "contained", color: "secondary", startIcon: react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_39__["default"], null), onClick: handleGenerateImages, disabled: generatingImages ||
|
|
105069
105098
|
loadingImagesFromDrive ||
|
|
105070
105099
|
!openaiApiKey ||
|
|
105071
105100
|
(!accessToken && !refreshToken) ||
|
|
@@ -105092,10 +105121,10 @@ ${imageData.originalPrompt}
|
|
|
105092
105121
|
openaiApiKey && (accessToken || refreshToken) && generateProduct.trim() && !generateGeo.trim() && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_20__["default"], { severity: "error", sx: { mt: 1 } }, "\u0417\u0430\u043F\u043E\u043B\u043D\u0438\u0442\u0435 \u043F\u043E\u043B\u0435 \u0413\u0435\u043E")),
|
|
105093
105122
|
openaiApiKey && (accessToken || refreshToken) && generateProduct.trim() && generateGeo.trim() && !driveFolderUrl.trim() && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_20__["default"], { severity: "error", sx: { mt: 1 } }, "\u0417\u0430\u043F\u043E\u043B\u043D\u0438\u0442\u0435 URL \u043F\u0430\u043F\u043A\u0438 Google Drive"))))),
|
|
105094
105123
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_11__["default"], { direction: "row", spacing: 2, sx: { mb: 2 } },
|
|
105095
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_17__["default"], { variant: "contained", color: "success", startIcon: react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
105124
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_17__["default"], { variant: "contained", color: "success", startIcon: react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_39__["default"], null), onClick: handleGenerateProduct, disabled: generatingProduct || !openaiApiKey || !accessToken || !driveFolderUrl.trim(), sx: { flexGrow: 1 }, size: "large" }, generatingProduct
|
|
105096
105125
|
? 'Generating Product...'
|
|
105097
105126
|
: (productGeneratedImage ? 'Перегенерировать Product' : 'Generate Product from Banka')),
|
|
105098
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_17__["default"], { variant: "contained", color: "info", startIcon: generatingLanding ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_18__["default"], { size: 20, color: "inherit" }) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
105127
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_17__["default"], { variant: "contained", color: "info", startIcon: generatingLanding ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_18__["default"], { size: 20, color: "inherit" }) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_49__["default"], null), onClick: handleCreateLanding, disabled: generatingLanding ||
|
|
105099
105128
|
!openaiApiKey ||
|
|
105100
105129
|
!accessToken ||
|
|
105101
105130
|
!driveFolderUrl.trim() ||
|
|
@@ -105133,168 +105162,172 @@ ${imageData.originalPrompt}
|
|
|
105133
105162
|
gridTemplateColumns: { xs: '1fr', sm: 'repeat(2, 1fr)', md: 'repeat(3, 1fr)' },
|
|
105134
105163
|
gap: 2,
|
|
105135
105164
|
mt: 1
|
|
105136
|
-
} }, generatedImagesData.map((imageData) =>
|
|
105137
|
-
imageData.
|
|
105138
|
-
|
|
105139
|
-
|
|
105140
|
-
|
|
105141
|
-
borderRadius: 1,
|
|
105142
|
-
backgroundColor: (theme) => theme.palette.mode === 'dark'
|
|
105143
|
-
? 'rgba(25, 118, 210, 0.1)'
|
|
105144
|
-
: 'rgba(25, 118, 210, 0.05)',
|
|
105145
|
-
display: 'flex',
|
|
105146
|
-
flexDirection: 'column',
|
|
105147
|
-
alignItems: 'center',
|
|
105148
|
-
justifyContent: 'center',
|
|
105149
|
-
gap: 2,
|
|
105150
|
-
p: 3
|
|
105151
|
-
} },
|
|
105152
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_18__["default"], { size: 40, sx: { color: 'primary.main' } }),
|
|
105153
|
-
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..."),
|
|
105154
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "caption", sx: { color: 'text.secondary', textAlign: 'center' } }, imageData.approach),
|
|
105155
|
-
generatingImages && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "caption", sx: { color: 'text.secondary', textAlign: 'center' } },
|
|
105156
|
-
"\u23F1\uFE0F \u041F\u0440\u043E\u0448\u043B\u043E: ",
|
|
105157
|
-
formatElapsedTime(elapsedTime.images))))) : imageData.imageUrl ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null,
|
|
105158
|
-
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: {
|
|
105165
|
+
} }, generatedImagesData.map((imageData) => {
|
|
105166
|
+
const imgRatio = imageData.aspectRatio ?? (imageAspectRatio === 'both' ? '1:1' : imageAspectRatio);
|
|
105167
|
+
const aspectRatioCss = imgRatio === '2:3' ? '2 / 3' : '1 / 1';
|
|
105168
|
+
return (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { key: imageData.index, sx: { position: 'relative' } },
|
|
105169
|
+
imageData.generating ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { sx: {
|
|
105159
105170
|
width: '100%',
|
|
105160
|
-
|
|
105161
|
-
|
|
105162
|
-
objectFit: 'contain',
|
|
105163
|
-
border: (theme) => {
|
|
105164
|
-
if (imageData.uploaded || imageData.checkStatus === 'ok') {
|
|
105165
|
-
return `2px solid ${theme.palette.success.main}`;
|
|
105166
|
-
}
|
|
105167
|
-
else if (imageData.checkStatus === 'needs_rebuild') {
|
|
105168
|
-
return `2px solid ${theme.palette.error.main}`;
|
|
105169
|
-
}
|
|
105170
|
-
else if (imageData.checkStatus === 'checking') {
|
|
105171
|
-
return `2px solid ${theme.palette.warning.main}`;
|
|
105172
|
-
}
|
|
105173
|
-
else {
|
|
105174
|
-
return `2px solid ${theme.palette.primary.main}`;
|
|
105175
|
-
}
|
|
105176
|
-
},
|
|
105171
|
+
aspectRatio: aspectRatioCss,
|
|
105172
|
+
border: (theme) => `2px dashed ${theme.palette.primary.main}`,
|
|
105177
105173
|
borderRadius: 1,
|
|
105178
|
-
backgroundColor: (theme) => theme.palette.mode === 'dark'
|
|
105179
|
-
|
|
105180
|
-
|
|
105181
|
-
position: 'absolute',
|
|
105182
|
-
top: '50%',
|
|
105183
|
-
left: '50%',
|
|
105184
|
-
transform: 'translate(-50%, -50%)',
|
|
105174
|
+
backgroundColor: (theme) => theme.palette.mode === 'dark'
|
|
105175
|
+
? 'rgba(25, 118, 210, 0.1)'
|
|
105176
|
+
: 'rgba(25, 118, 210, 0.05)',
|
|
105185
105177
|
display: 'flex',
|
|
105186
105178
|
flexDirection: 'column',
|
|
105187
105179
|
alignItems: 'center',
|
|
105188
|
-
|
|
105180
|
+
justifyContent: 'center',
|
|
105181
|
+
gap: 2,
|
|
105182
|
+
p: 3
|
|
105189
105183
|
} },
|
|
105190
105184
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_18__["default"], { size: 40, sx: { color: 'primary.main' } }),
|
|
105191
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "
|
|
105192
|
-
|
|
105193
|
-
|
|
105194
|
-
|
|
105195
|
-
|
|
105196
|
-
|
|
105197
|
-
|
|
105198
|
-
|
|
105199
|
-
|
|
105200
|
-
|
|
105201
|
-
|
|
105202
|
-
|
|
105203
|
-
|
|
105204
|
-
|
|
105205
|
-
|
|
105206
|
-
|
|
105207
|
-
|
|
105208
|
-
|
|
105209
|
-
|
|
105210
|
-
|
|
105211
|
-
|
|
105212
|
-
|
|
105213
|
-
|
|
105214
|
-
|
|
105215
|
-
|
|
105216
|
-
|
|
105217
|
-
|
|
105218
|
-
|
|
105219
|
-
|
|
105220
|
-
|
|
105221
|
-
|
|
105222
|
-
|
|
105223
|
-
|
|
105224
|
-
|
|
105225
|
-
|
|
105226
|
-
|
|
105227
|
-
|
|
105228
|
-
|
|
105229
|
-
|
|
105230
|
-
|
|
105231
|
-
|
|
105232
|
-
|
|
105233
|
-
|
|
105234
|
-
|
|
105235
|
-
|
|
105236
|
-
|
|
105237
|
-
|
|
105238
|
-
|
|
105239
|
-
|
|
105240
|
-
|
|
105241
|
-
|
|
105242
|
-
|
|
105243
|
-
|
|
105244
|
-
|
|
105245
|
-
|
|
105246
|
-
|
|
105247
|
-
|
|
105248
|
-
imageData.
|
|
105249
|
-
|
|
105250
|
-
|
|
105251
|
-
|
|
105252
|
-
|
|
105253
|
-
|
|
105254
|
-
|
|
105255
|
-
|
|
105256
|
-
|
|
105257
|
-
|
|
105258
|
-
|
|
105259
|
-
|
|
105260
|
-
|
|
105261
|
-
|
|
105262
|
-
},
|
|
105263
|
-
|
|
105264
|
-
|
|
105265
|
-
|
|
105266
|
-
|
|
105267
|
-
|
|
105268
|
-
|
|
105269
|
-
|
|
105270
|
-
|
|
105271
|
-
|
|
105272
|
-
|
|
105273
|
-
|
|
105274
|
-
} }),
|
|
105275
|
-
|
|
105276
|
-
imageData.
|
|
105277
|
-
imageData.
|
|
105278
|
-
|
|
105279
|
-
|
|
105280
|
-
|
|
105281
|
-
|
|
105282
|
-
|
|
105283
|
-
|
|
105284
|
-
|
|
105285
|
-
|
|
105286
|
-
|
|
105287
|
-
|
|
105288
|
-
|
|
105289
|
-
|
|
105290
|
-
|
|
105291
|
-
|
|
105292
|
-
|
|
105293
|
-
|
|
105294
|
-
|
|
105295
|
-
|
|
105185
|
+
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..."),
|
|
105186
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "caption", sx: { color: 'text.secondary', textAlign: 'center' } }, imageData.approach),
|
|
105187
|
+
generatingImages && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "caption", sx: { color: 'text.secondary', textAlign: 'center' } },
|
|
105188
|
+
"\u23F1\uFE0F \u041F\u0440\u043E\u0448\u043B\u043E: ",
|
|
105189
|
+
formatElapsedTime(elapsedTime.images))))) : imageData.imageUrl ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null,
|
|
105190
|
+
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: {
|
|
105191
|
+
width: '100%',
|
|
105192
|
+
height: 'auto',
|
|
105193
|
+
display: 'block',
|
|
105194
|
+
objectFit: 'contain',
|
|
105195
|
+
border: (theme) => {
|
|
105196
|
+
if (imageData.uploaded || imageData.checkStatus === 'ok') {
|
|
105197
|
+
return `2px solid ${theme.palette.success.main}`;
|
|
105198
|
+
}
|
|
105199
|
+
else if (imageData.checkStatus === 'needs_rebuild') {
|
|
105200
|
+
return `2px solid ${theme.palette.error.main}`;
|
|
105201
|
+
}
|
|
105202
|
+
else if (imageData.checkStatus === 'checking') {
|
|
105203
|
+
return `2px solid ${theme.palette.warning.main}`;
|
|
105204
|
+
}
|
|
105205
|
+
else {
|
|
105206
|
+
return `2px solid ${theme.palette.primary.main}`;
|
|
105207
|
+
}
|
|
105208
|
+
},
|
|
105209
|
+
borderRadius: 1,
|
|
105210
|
+
backgroundColor: (theme) => theme.palette.mode === 'dark' ? '#2a2a2a' : '#f5f5f5'
|
|
105211
|
+
} }),
|
|
105212
|
+
imageData.regenerating && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { sx: {
|
|
105213
|
+
position: 'absolute',
|
|
105214
|
+
top: '50%',
|
|
105215
|
+
left: '50%',
|
|
105216
|
+
transform: 'translate(-50%, -50%)',
|
|
105217
|
+
display: 'flex',
|
|
105218
|
+
flexDirection: 'column',
|
|
105219
|
+
alignItems: 'center',
|
|
105220
|
+
gap: 1
|
|
105221
|
+
} },
|
|
105222
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_18__["default"], { size: 40, sx: { color: 'primary.main' } }),
|
|
105223
|
+
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: {
|
|
105224
|
+
width: '100%',
|
|
105225
|
+
aspectRatio: aspectRatioCss,
|
|
105226
|
+
border: (theme) => `2px dashed ${theme.palette.error.main}`,
|
|
105227
|
+
borderRadius: 1,
|
|
105228
|
+
backgroundColor: (theme) => theme.palette.mode === 'dark'
|
|
105229
|
+
? 'rgba(244, 67, 54, 0.1)'
|
|
105230
|
+
: '#ffebee',
|
|
105231
|
+
display: 'flex',
|
|
105232
|
+
flexDirection: 'column',
|
|
105233
|
+
alignItems: 'center',
|
|
105234
|
+
justifyContent: 'center',
|
|
105235
|
+
gap: 2,
|
|
105236
|
+
p: 3
|
|
105237
|
+
} },
|
|
105238
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "h4", sx: { color: 'error.main' } }, "\u274C"),
|
|
105239
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "body2", sx: { color: 'error.main', textAlign: 'center', fontWeight: 'bold' } }, "\u041D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u0441\u0433\u0435\u043D\u0435\u0440\u0438\u0440\u043E\u0432\u0430\u0442\u044C"),
|
|
105240
|
+
imageData.errorMessage && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "caption", sx: { color: 'error.main', textAlign: 'center', fontSize: '0.7rem' } }, imageData.errorMessage.length > 100
|
|
105241
|
+
? imageData.errorMessage.substring(0, 100) + '...'
|
|
105242
|
+
: imageData.errorMessage)))) : (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { sx: {
|
|
105243
|
+
width: '100%',
|
|
105244
|
+
aspectRatio: aspectRatioCss,
|
|
105245
|
+
border: (theme) => `2px dashed ${theme.palette.divider}`,
|
|
105246
|
+
borderRadius: 1,
|
|
105247
|
+
backgroundColor: (theme) => theme.palette.mode === 'dark'
|
|
105248
|
+
? 'rgba(255,255,255,0.04)'
|
|
105249
|
+
: '#f5f5f5',
|
|
105250
|
+
display: 'flex',
|
|
105251
|
+
flexDirection: 'column',
|
|
105252
|
+
alignItems: 'center',
|
|
105253
|
+
justifyContent: 'center',
|
|
105254
|
+
gap: 2,
|
|
105255
|
+
p: 3
|
|
105256
|
+
} },
|
|
105257
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "h4", sx: { color: 'text.secondary' } }, "\u23F3"),
|
|
105258
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "body2", sx: { color: 'text.secondary', textAlign: 'center', fontWeight: 'bold' } }, "\u0412 \u043E\u0447\u0435\u0440\u0435\u0434\u0438"),
|
|
105259
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "caption", sx: { color: 'text.secondary', textAlign: 'center' } }, generatingImages ? 'Ожидает генерации...' : 'Готово к генерации'),
|
|
105260
|
+
generatingImages && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "caption", sx: { color: 'text.secondary', textAlign: 'center' } },
|
|
105261
|
+
"\u23F1\uFE0F \u041F\u0440\u043E\u0448\u043B\u043E: ",
|
|
105262
|
+
formatElapsedTime(elapsedTime.images))))),
|
|
105263
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { sx: { mt: 1, mb: 1 } },
|
|
105264
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "caption", sx: { display: 'block', fontWeight: 'bold' } },
|
|
105265
|
+
imageData.index,
|
|
105266
|
+
". ",
|
|
105267
|
+
imageData.approach),
|
|
105268
|
+
imageData.checkStatus === 'ok' && imageData.checkResult !== 'Проверка отключена' && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "caption", sx: { color: 'success.main', display: 'block', fontWeight: 'bold' } }, "\u2705 \u041F\u0440\u043E\u0432\u0435\u0440\u043A\u0430 \u043F\u0440\u043E\u0439\u0434\u0435\u043D\u0430")),
|
|
105269
|
+
imageData.checkStatus === 'needs_rebuild' && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], null,
|
|
105270
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "caption", sx: { color: 'error.main', display: 'block', fontWeight: 'bold' } }, imageData.checkFailed ? '⚠️ Ошибка проверки' : '❌ Требует пересборки'),
|
|
105271
|
+
imageData.checkErrors && imageData.checkErrors.length > 0 && !imageData.checkFailed && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { sx: { mt: 0.5 } },
|
|
105272
|
+
imageData.checkErrors.slice(0, 2).map((error, idx) => (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { key: idx, variant: "caption", sx: {
|
|
105273
|
+
color: 'error.main',
|
|
105274
|
+
display: 'block',
|
|
105275
|
+
fontSize: '0.7rem',
|
|
105276
|
+
lineHeight: 1.2
|
|
105277
|
+
} },
|
|
105278
|
+
"\u2022 ",
|
|
105279
|
+
error.length > 50 ? error.substring(0, 50) + '...' : error))),
|
|
105280
|
+
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' } },
|
|
105281
|
+
"+",
|
|
105282
|
+
imageData.checkErrors.length - 2,
|
|
105283
|
+
" \u0435\u0449\u0451")))),
|
|
105284
|
+
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_50__["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")))),
|
|
105285
|
+
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...")),
|
|
105286
|
+
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")),
|
|
105287
|
+
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")),
|
|
105288
|
+
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"))),
|
|
105289
|
+
!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 } },
|
|
105290
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_15__["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) => {
|
|
105291
|
+
setGeneratedImagesData(prev => prev.map(img => img.index === imageData.index
|
|
105292
|
+
? { ...img, customRegeneratePrompt: e.target.value }
|
|
105293
|
+
: img));
|
|
105294
|
+
}, disabled: imageData.regenerating ||
|
|
105295
|
+
imageData.uploading ||
|
|
105296
|
+
imageData.checkStatus === 'checking' ||
|
|
105297
|
+
(generatingImages && !imageData.imageUrl && !imageData.failed && !imageData.generating), sx: {
|
|
105298
|
+
'& .MuiInputBase-root': {
|
|
105299
|
+
fontSize: '0.875rem',
|
|
105300
|
+
backgroundColor: (theme) => imageData.checkStatus === 'needs_rebuild'
|
|
105301
|
+
? (theme.palette.mode === 'dark'
|
|
105302
|
+
? 'rgba(244, 67, 54, 0.15)'
|
|
105303
|
+
: 'rgba(244, 67, 54, 0.05)')
|
|
105304
|
+
: 'transparent'
|
|
105305
|
+
}
|
|
105306
|
+
} }),
|
|
105307
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_17__["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_18__["default"], { size: 16 }) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_39__["default"], null), onClick: () => handleRegenerateImage(imageData), disabled: imageData.regenerating ||
|
|
105308
|
+
imageData.uploading ||
|
|
105309
|
+
imageData.checkStatus === 'checking' ||
|
|
105310
|
+
!imageData.originalPrompt ||
|
|
105311
|
+
!imageData.productImageUrl ||
|
|
105312
|
+
(generatingImages && !imageData.imageUrl && !imageData.failed && !imageData.generating), fullWidth: true }, imageData.regenerating
|
|
105313
|
+
? (imageData.failed ? 'Генерация...' : 'Переделка...')
|
|
105314
|
+
: ((generatingImages && !imageData.imageUrl && !imageData.failed && !imageData.generating)
|
|
105315
|
+
? 'В очереди'
|
|
105316
|
+
: (!imageData.imageUrl ? 'Сгенерировать' : 'Переделать'))),
|
|
105317
|
+
imageData.imageUrl && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_17__["default"], { size: "small", variant: "outlined", color: "secondary", startIcon: react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_50__["default"], null), onClick: () => handleRegenerateImageFresh(imageData), disabled: imageData.regenerating ||
|
|
105318
|
+
imageData.uploading ||
|
|
105319
|
+
imageData.checkStatus === 'checking' ||
|
|
105320
|
+
!imageData.originalPrompt ||
|
|
105321
|
+
!imageData.productImageUrl, fullWidth: true }, "\u041F\u0435\u0440\u0435\u0434\u0435\u043B\u0430\u0442\u044C \u0437\u0430\u043D\u043E\u0432\u043E")),
|
|
105322
|
+
!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_43__["default"], null), onClick: () => {
|
|
105323
|
+
const folderId = extractFolderId(driveFolderUrl);
|
|
105324
|
+
if (folderId) {
|
|
105325
|
+
handleUploadImage(imageData, folderId);
|
|
105326
|
+
}
|
|
105327
|
+
}, disabled: imageData.uploading || imageData.regenerating || !driveFolderUrl.trim(), fullWidth: true }, imageData.uploading ? 'Загрузка...' : 'Загрузить'))))));
|
|
105328
|
+
}))),
|
|
105296
105329
|
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 } },
|
|
105297
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_17__["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_18__["default"], { size: 20 }) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
105330
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_17__["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_18__["default"], { size: 20 }) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_43__["default"], null), fullWidth: true }, uploadingImages ? 'Загрузка...' : `Загрузить все (${generatedImagesData.filter(img => !img.uploaded && img.imageUrl).length})`))))),
|
|
105298
105331
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_16__["default"], { sx: { my: 2 } }),
|
|
105299
105332
|
(generatedTitlesData.length > 0 || generatedTextsData.length > 0 || loadingContentFromDrive) && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { sx: { mb: 2 } },
|
|
105300
105333
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "h6", gutterBottom: true, sx: { fontWeight: 'bold' } },
|
|
@@ -105329,7 +105362,7 @@ ${imageData.originalPrompt}
|
|
|
105329
105362
|
const pairLabel = pairApproach ? pairApproach.name : `пара ${i + 1}`;
|
|
105330
105363
|
const pairGenerating = (titleData?.generating || textData?.generating);
|
|
105331
105364
|
const pairFailed = (!pairGenerating && titleData?.failed && textData?.failed);
|
|
105332
|
-
return (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
105365
|
+
return (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_30__["default"], { key: i, variant: "outlined", sx: {
|
|
105333
105366
|
p: 2,
|
|
105334
105367
|
borderColor: pairFailed
|
|
105335
105368
|
? 'error.main'
|
|
@@ -105357,7 +105390,7 @@ ${imageData.originalPrompt}
|
|
|
105357
105390
|
"\u041F\u0430\u0440\u0430 ",
|
|
105358
105391
|
i + 1),
|
|
105359
105392
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "caption", color: "text.secondary" }, pairLabel),
|
|
105360
|
-
translatingPairs && !pairTranslations[i] ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_18__["default"], { size: 13, sx: { color: 'text.disabled', ml: 0.5 } })) : pairTranslations[i] ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
105393
|
+
translatingPairs && !pairTranslations[i] ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_18__["default"], { size: 13, sx: { color: 'text.disabled', ml: 0.5 } })) : pairTranslations[i] ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_27__["default"], { title: react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], null,
|
|
105361
105394
|
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:"),
|
|
105362
105395
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "caption", sx: { display: 'block', mb: 1 } }, pairTranslations[i].titleRu),
|
|
105363
105396
|
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:"),
|
|
@@ -105365,7 +105398,7 @@ ${imageData.originalPrompt}
|
|
|
105365
105398
|
tooltip: { sx: { maxWidth: 360, fontSize: 12, lineHeight: 1.6, p: '10px 14px' } },
|
|
105366
105399
|
} },
|
|
105367
105400
|
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' } } },
|
|
105368
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
105401
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_46__["default"], { sx: { fontSize: 14 } })))) : null),
|
|
105369
105402
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_11__["default"], { spacing: 1.5 },
|
|
105370
105403
|
titleData && (titleData.generating ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { sx: { display: 'flex', alignItems: 'center', gap: 1 } },
|
|
105371
105404
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_18__["default"], { size: 16, sx: { color: 'primary.main' } }),
|
|
@@ -105406,7 +105439,7 @@ ${imageData.originalPrompt}
|
|
|
105406
105439
|
}))))),
|
|
105407
105440
|
(landingGenerationLogs.length > 0 || generatingLanding) && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { sx: { mb: 2 } },
|
|
105408
105441
|
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"),
|
|
105409
|
-
landingGenerationLogs.length > 0 && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
105442
|
+
landingGenerationLogs.length > 0 && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_30__["default"], { sx: {
|
|
105410
105443
|
p: 2,
|
|
105411
105444
|
backgroundColor: (theme) => theme.palette.mode === 'dark'
|
|
105412
105445
|
? 'rgba(25, 118, 210, 0.1)'
|
|
@@ -105432,11 +105465,11 @@ ${imageData.originalPrompt}
|
|
|
105432
105465
|
generatingLanding && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { sx: { display: 'flex', alignItems: 'center', gap: 1, mb: 2 } },
|
|
105433
105466
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_18__["default"], { size: 20 }),
|
|
105434
105467
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "body2", sx: { color: 'text.secondary' } }, formatElapsedTime(elapsedTime.landing)))),
|
|
105435
|
-
!generatingLanding && generatedLandingHTML && generatedLandingImageBlob && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_17__["default"], { variant: "outlined", color: "primary", onClick: handlePreviewLanding, startIcon: react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
105468
|
+
!generatingLanding && generatedLandingHTML && generatedLandingImageBlob && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_17__["default"], { variant: "outlined", color: "primary", onClick: handlePreviewLanding, startIcon: react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_52__["default"], null), fullWidth: true }, "\u041F\u0440\u0435\u0434\u043F\u0440\u043E\u0441\u043C\u043E\u0442\u0440 \u043B\u0435\u043D\u0434\u0438\u043D\u0433\u0430")))),
|
|
105436
105469
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_11__["default"], { direction: "row", spacing: 2 },
|
|
105437
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_17__["default"], { variant: "contained", size: "large", onClick: handleGenerate, disabled: loading || !accessToken, startIcon: loading ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_18__["default"], { size: 20, color: "inherit" }) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
105470
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_17__["default"], { variant: "contained", size: "large", onClick: handleGenerate, disabled: loading || !accessToken, startIcon: loading ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_18__["default"], { size: 20, color: "inherit" }) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_43__["default"], null), sx: { py: 1.5, fontSize: '1.1rem', flexGrow: 1 } }, loading ? 'Generating...' : 'Generate Table')),
|
|
105438
105471
|
uploadedLink && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_20__["default"], { severity: "success", sx: { mt: 2 }, 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 } },
|
|
105439
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
105472
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_44__["default"], { fontSize: "small" })) },
|
|
105440
105473
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { sx: { display: 'flex', alignItems: 'center', gap: 1 } },
|
|
105441
105474
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", null,
|
|
105442
105475
|
"File Uploaded!",
|
|
@@ -105446,8 +105479,8 @@ ${imageData.originalPrompt}
|
|
|
105446
105479
|
getElectronAPI().openExternal(uploadedLink);
|
|
105447
105480
|
}, style: { cursor: 'pointer', textDecoration: 'underline', color: 'inherit' } }, "Click here to open in Google Drive")),
|
|
105448
105481
|
linkCopied && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "caption", sx: { color: 'success.dark', fontWeight: 'bold' } }, "Copied!")))))))))),
|
|
105449
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
105450
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
105482
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_31__["default"], { open: productModalOpen, onClose: () => !generatingProduct && !uploadingProduct && setProductModalOpen(false), maxWidth: "lg", fullWidth: true },
|
|
105483
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_32__["default"], { open: generatingProduct || uploadingProduct, sx: {
|
|
105451
105484
|
position: 'absolute',
|
|
105452
105485
|
zIndex: (theme) => theme.zIndex.modal + 1,
|
|
105453
105486
|
backgroundColor: 'rgba(0, 0, 0, 0.7)',
|
|
@@ -105458,7 +105491,7 @@ ${imageData.originalPrompt}
|
|
|
105458
105491
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { sx: { display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 2 } },
|
|
105459
105492
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_18__["default"], { size: 60, sx: { color: 'white' } }),
|
|
105460
105493
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "h6", sx: { color: 'white', fontWeight: 'bold' } }, formatElapsedTime(elapsedTime.product))),
|
|
105461
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
105494
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_30__["default"], { sx: {
|
|
105462
105495
|
p: 3,
|
|
105463
105496
|
maxWidth: '80%',
|
|
105464
105497
|
maxHeight: '60%',
|
|
@@ -105482,9 +105515,9 @@ ${imageData.originalPrompt}
|
|
|
105482
105515
|
log.includes('⚠️') || log.toLowerCase().includes('warn') ? 'warning.main' :
|
|
105483
105516
|
'text.primary'
|
|
105484
105517
|
} }, log))))))),
|
|
105485
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
105518
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_33__["default"], null,
|
|
105486
105519
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "h6" }, "Product Image Generation")),
|
|
105487
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
105520
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_34__["default"], null,
|
|
105488
105521
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_11__["default"], { spacing: 3, sx: { mt: 1 } },
|
|
105489
105522
|
productSourceImages.length > 0 && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], null,
|
|
105490
105523
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "subtitle1", gutterBottom: true, sx: { fontWeight: 'bold' } },
|
|
@@ -105523,11 +105556,11 @@ ${imageData.originalPrompt}
|
|
|
105523
105556
|
mt: 1
|
|
105524
105557
|
} }))),
|
|
105525
105558
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_15__["default"], { label: "\u0414\u043E\u043F\u043E\u043B\u043D\u0438\u0442\u0435\u043B\u044C\u043D\u044B\u0435 \u0442\u0440\u0435\u0431\u043E\u0432\u0430\u043D\u0438\u044F \u043A \u0433\u0435\u043D\u0435\u0440\u0430\u0446\u0438\u0438", variant: "outlined", fullWidth: true, multiline: true, minRows: 2, value: productRegeneratePrompt, onChange: (e) => setProductRegeneratePrompt(e.target.value), placeholder: "\u041D\u0430\u043F\u0440\u0438\u043C\u0435\u0440: \u0441\u0434\u0435\u043B\u0430\u0439 \u0444\u043E\u043D \u0431\u0435\u043B\u044B\u043C, \u0443\u0432\u0435\u043B\u0438\u0447\u044C \u043B\u043E\u0433\u043E\u0442\u0438\u043F...", helperText: "\u042D\u0442\u0438 \u0442\u0440\u0435\u0431\u043E\u0432\u0430\u043D\u0438\u044F \u0431\u0443\u0434\u0443\u0442 \u0434\u043E\u0431\u0430\u0432\u043B\u0435\u043D\u044B \u043A \u0431\u0430\u0437\u043E\u0432\u043E\u043C\u0443 \u043F\u0440\u043E\u043C\u043F\u0442\u0443 (\u043D\u0435 \u0437\u0430\u043C\u0435\u043D\u044F\u044E\u0442 \u0435\u0433\u043E). \u041E\u0441\u0442\u0430\u0432\u044C\u0442\u0435 \u043F\u0443\u0441\u0442\u044B\u043C \u0434\u043B\u044F \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u043D\u0438\u044F \u0442\u043E\u043B\u044C\u043A\u043E \u0431\u0430\u0437\u043E\u0432\u043E\u0433\u043E \u043F\u0440\u043E\u043C\u043F\u0442\u0430.", disabled: generatingProduct || uploadingProduct }))),
|
|
105526
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
105559
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_35__["default"], { sx: { px: 3, pb: 2 } },
|
|
105527
105560
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_17__["default"], { onClick: () => setProductModalOpen(false), disabled: generatingProduct || uploadingProduct }, "\u0417\u0430\u043A\u0440\u044B\u0442\u044C"),
|
|
105528
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_17__["default"], { variant: "outlined", color: "secondary", onClick: handleRegenerateProduct, disabled: generatingProduct || uploadingProduct || !productSourceImages.length || !productGeneratedImage, startIcon: generatingProduct ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_18__["default"], { size: 20 }) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
105529
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_17__["default"], { variant: "contained", color: "primary", onClick: handleUploadProduct, disabled: generatingProduct || uploadingProduct || !productGeneratedImage || !driveFolderUrl.trim(), startIcon: uploadingProduct ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_18__["default"], { size: 20 }) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
105530
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
105561
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_17__["default"], { variant: "outlined", color: "secondary", onClick: handleRegenerateProduct, disabled: generatingProduct || uploadingProduct || !productSourceImages.length || !productGeneratedImage, startIcon: generatingProduct ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_18__["default"], { size: 20 }) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_39__["default"], null) }, generatingProduct ? 'Перегенерация...' : 'Перегенерировать'),
|
|
105562
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_17__["default"], { variant: "contained", color: "primary", onClick: handleUploadProduct, disabled: generatingProduct || uploadingProduct || !productGeneratedImage || !driveFolderUrl.trim(), startIcon: uploadingProduct ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_18__["default"], { size: 20 }) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_43__["default"], null) }, uploadingProduct ? 'Загрузка...' : 'Загрузить (product.png)'))),
|
|
105563
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_PromptManagerDialog__WEBPACK_IMPORTED_MODULE_53__["default"], { open: promptManagerOpen, onClose: () => setPromptManagerOpen(false) }))));
|
|
105531
105564
|
}
|
|
105532
105565
|
/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (App);
|
|
105533
105566
|
|
|
@@ -105962,12 +105995,15 @@ function PromptManagerDialog({ open, onClose }) {
|
|
|
105962
105995
|
const [viewModes, setViewModes] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)({});
|
|
105963
105996
|
// selectedApproaches: array of indices from PAIR_APPROACH_POOL, ordered
|
|
105964
105997
|
const [selectedApproaches, setSelectedApproaches] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)([0, 1, 2]);
|
|
105998
|
+
// imageApproachCounts: 8 элементов, каждый 0–4
|
|
105999
|
+
const [imageApproachCounts, setImageApproachCounts] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)([1, 1, 1, 1, 1, 1, 1, 1]);
|
|
105965
106000
|
// Загрузить оверрайды при открытии
|
|
105966
106001
|
(0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => {
|
|
105967
106002
|
if (open) {
|
|
105968
106003
|
const loaded = (0,_promptOverrides__WEBPACK_IMPORTED_MODULE_36__.loadPromptOverrides)();
|
|
105969
106004
|
setOverrides(loaded);
|
|
105970
106005
|
setSelectedApproaches((0,_promptOverrides__WEBPACK_IMPORTED_MODULE_36__.getSelectedPairApproaches)());
|
|
106006
|
+
setImageApproachCounts((0,_promptOverrides__WEBPACK_IMPORTED_MODULE_36__.getImageApproachCounts)());
|
|
105971
106007
|
setHasChanges(false);
|
|
105972
106008
|
}
|
|
105973
106009
|
}, [open]);
|
|
@@ -105992,6 +106028,17 @@ function PromptManagerDialog({ open, onClose }) {
|
|
|
105992
106028
|
return next;
|
|
105993
106029
|
});
|
|
105994
106030
|
};
|
|
106031
|
+
const handleImageApproachCountChange = (idx, count) => {
|
|
106032
|
+
const clamped = Math.max(0, Math.min(4, count));
|
|
106033
|
+
setImageApproachCounts(prev => {
|
|
106034
|
+
const next = [...prev];
|
|
106035
|
+
if (idx >= 0 && idx < next.length)
|
|
106036
|
+
next[idx] = clamped;
|
|
106037
|
+
setOverrides(o => ({ ...o, imageApproachCounts: next }));
|
|
106038
|
+
setHasChanges(true);
|
|
106039
|
+
return next;
|
|
106040
|
+
});
|
|
106041
|
+
};
|
|
105995
106042
|
const handleToggleOverride = (promptName, enabled) => {
|
|
105996
106043
|
setOverrides(prev => {
|
|
105997
106044
|
const prevOverride = prev[promptName];
|
|
@@ -106169,14 +106216,14 @@ function PromptManagerDialog({ open, onClose }) {
|
|
|
106169
106216
|
hasChanges && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_7__["default"], { label: "\u0415\u0441\u0442\u044C \u043D\u0435\u0441\u043E\u0445\u0440\u0430\u043D\u0435\u043D\u043D\u044B\u0435 \u0438\u0437\u043C\u0435\u043D\u0435\u043D\u0438\u044F", color: "warning", size: "small" })))),
|
|
106170
106217
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_15__["default"], null,
|
|
106171
106218
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_16__["default"], { value: tabValue, onChange: handleTabChange, sx: { borderBottom: 1, borderColor: 'divider' } },
|
|
106172
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_17__["default"], { label: "\
|
|
106219
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_17__["default"], { label: "\u041F\u043E\u0434\u0445\u043E\u0434\u044B" }),
|
|
106173
106220
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_17__["default"], { label: "\u0418\u0437\u043E\u0431\u0440\u0430\u0436\u0435\u043D\u0438\u044F" }),
|
|
106174
106221
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_17__["default"], { label: "\u0412\u0430\u043B\u0438\u0434\u0430\u0446\u0438\u044F" }),
|
|
106175
106222
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_17__["default"], { label: "\u041B\u0435\u043D\u0434\u0438\u043D\u0433" })),
|
|
106176
106223
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(TabPanel, { value: tabValue, index: 0 },
|
|
106177
106224
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_1__["default"], { sx: { mb: 3, p: 2, border: '1px solid', borderColor: 'divider', borderRadius: 1 } },
|
|
106178
106225
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { direction: "row", spacing: 2, alignItems: "center", sx: { mb: 1.5 } },
|
|
106179
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_3__["default"], { variant: "subtitle1", sx: { fontWeight: 600 } }, "\u041F\u043E\u0434\u0445\u043E\u0434\u044B \u0434\u043B\u044F \
|
|
106226
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_3__["default"], { variant: "subtitle1", sx: { fontWeight: 600 } }, "\u041F\u043E\u0434\u0445\u043E\u0434\u044B \u0434\u043B\u044F \u0442\u0435\u043A\u0441\u0442\u043E\u0432 (\u043F\u0430\u0440\u044B \u0437\u0430\u0433\u043E\u043B\u043E\u0432\u043E\u043A + \u0442\u0435\u043A\u0441\u0442)"),
|
|
106180
106227
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_7__["default"], { label: `Выбрано: ${selectedApproaches.length}`, color: "primary", size: "small" }),
|
|
106181
106228
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_3__["default"], { variant: "caption", color: "text.secondary" }, "(\u043C\u0438\u043D\u0438\u043C\u0443\u043C 2, \u043C\u0430\u043A\u0441\u0438\u043C\u0443\u043C 10)")),
|
|
106182
106229
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_1__["default"], { sx: { overflowX: 'auto' } },
|
|
@@ -106204,11 +106251,34 @@ function PromptManagerDialog({ open, onClose }) {
|
|
|
106204
106251
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("td", { style: { padding: '4px 8px', color: '#777' } }, p.titleApproach),
|
|
106205
106252
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("td", { style: { padding: '4px 8px', color: '#777' } }, p.textApproach.split('\n')[0])));
|
|
106206
106253
|
}))))),
|
|
106254
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_1__["default"], { sx: { mb: 3, p: 2, border: '1px solid', borderColor: 'divider', borderRadius: 1 } },
|
|
106255
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { direction: "row", spacing: 2, alignItems: "center", sx: { mb: 1.5 } },
|
|
106256
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_3__["default"], { variant: "subtitle1", sx: { fontWeight: 600 } }, "\u041F\u043E\u0434\u0445\u043E\u0434\u044B \u0434\u043B\u044F \u0438\u0437\u043E\u0431\u0440\u0430\u0436\u0435\u043D\u0438\u0439"),
|
|
106257
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_7__["default"], { label: `Всего: ${imageApproachCounts.reduce((a, b) => a + b, 0)}`, color: "primary", size: "small" }),
|
|
106258
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_3__["default"], { variant: "caption", color: "text.secondary" }, "(0\u20134 \u043D\u0430 \u043A\u0430\u0436\u0434\u044B\u0439 \u043F\u043E\u0434\u0445\u043E\u0434)")),
|
|
106259
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_1__["default"], { sx: { overflowX: 'auto' } },
|
|
106260
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("table", { style: { width: '100%', borderCollapse: 'collapse', fontSize: 12 } },
|
|
106261
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("thead", null,
|
|
106262
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("tr", null,
|
|
106263
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("th", { style: { textAlign: 'center', padding: '4px 8px', borderBottom: '1px solid #ccc', width: 70 } }, "\u041A\u043E\u043B-\u0432\u043E"),
|
|
106264
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("th", { style: { textAlign: 'left', padding: '4px 8px', borderBottom: '1px solid #ccc', whiteSpace: 'nowrap', width: 180 } }, "\u041F\u043E\u0434\u0445\u043E\u0434"),
|
|
106265
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("th", { style: { textAlign: 'left', padding: '4px 8px', borderBottom: '1px solid #ccc' } }, "\u041E\u043F\u0438\u0441\u0430\u043D\u0438\u0435"))),
|
|
106266
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("tbody", null, _prompts__WEBPACK_IMPORTED_MODULE_34__.CREO_APPROACHES.map((approach, i) => {
|
|
106267
|
+
const count = imageApproachCounts[i] ?? 0;
|
|
106268
|
+
return (react__WEBPACK_IMPORTED_MODULE_0___default().createElement("tr", { key: i, style: { opacity: count > 0 ? 1 : 0.6 } },
|
|
106269
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("td", { style: { textAlign: 'center', padding: '2px 8px', verticalAlign: 'middle' } },
|
|
106270
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { type: "number", size: "small", value: count, onChange: (e) => {
|
|
106271
|
+
const v = parseInt(e.target.value, 10);
|
|
106272
|
+
handleImageApproachCountChange(i, isNaN(v) ? 0 : v);
|
|
106273
|
+
}, inputProps: { min: 0, max: 4, step: 1 }, sx: { width: 56, '& .MuiInputBase-input': { textAlign: 'center', py: 0.5 } } })),
|
|
106274
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("td", { style: { padding: '4px 8px', fontWeight: 500, whiteSpace: 'nowrap' } }, approach.name),
|
|
106275
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("td", { style: { padding: '4px 8px', color: '#777' } }, approach.prompt.split('\n')[0])));
|
|
106276
|
+
}))))),
|
|
106207
106277
|
renderPromptEditor('getPairsSystemPrompt', 'Системный промпт (пары заголовок + текст)', 'Единый системный промпт, генерирующий все пары одним запросом. Переменные: ${geo}, ${count}, ${n}'),
|
|
106208
106278
|
renderPromptEditor('getPairsUserPrompt', 'Пользовательский промпт (пары)', 'Пользовательский промпт для генерации пар. Переменные: ${product}, ${geo}, ${additionalInfo}, ${count}, ${n}')),
|
|
106209
106279
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(TabPanel, { value: tabValue, index: 1 },
|
|
106210
106280
|
renderPromptEditor('getImageGenerationBasePrompt', 'Базовый промпт для изображений', 'Базовый промпт, используемый для всех подходов'),
|
|
106211
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_3__["default"], { variant: "h6", sx: { mt: 3, mb: 2 } }, "\
|
|
106281
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_3__["default"], { variant: "h6", sx: { mt: 3, mb: 2 } }, "\u0420\u0435\u0434\u0430\u043A\u0442\u0438\u0440\u043E\u0432\u0430\u043D\u0438\u0435 \u043F\u043E\u0434\u0445\u043E\u0434\u043E\u0432 \u0434\u043B\u044F \u0433\u0435\u043D\u0435\u0440\u0430\u0446\u0438\u0438 \u043A\u0440\u0435\u0430\u0442\u0438\u0432\u043E\u0432"),
|
|
106212
106282
|
_prompts__WEBPACK_IMPORTED_MODULE_34__.CREO_APPROACHES.map((approach) => {
|
|
106213
106283
|
const override = overrides.creoApproaches?.[approach.name];
|
|
106214
106284
|
const enabled = override?.enabled || false;
|
|
@@ -106478,6 +106548,7 @@ const MODELS = {
|
|
|
106478
106548
|
__webpack_require__.r(__webpack_exports__);
|
|
106479
106549
|
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
|
106480
106550
|
/* harmony export */ getCreoApproachOverride: () => (/* binding */ getCreoApproachOverride),
|
|
106551
|
+
/* harmony export */ getImageApproachCounts: () => (/* binding */ getImageApproachCounts),
|
|
106481
106552
|
/* harmony export */ getPairsCount: () => (/* binding */ getPairsCount),
|
|
106482
106553
|
/* harmony export */ getPromptOverride: () => (/* binding */ getPromptOverride),
|
|
106483
106554
|
/* harmony export */ getSelectedPairApproaches: () => (/* binding */ getSelectedPairApproaches),
|
|
@@ -106525,6 +106596,26 @@ function getSelectedPairApproaches() {
|
|
|
106525
106596
|
function getPairsCount() {
|
|
106526
106597
|
return getSelectedPairApproaches().length;
|
|
106527
106598
|
}
|
|
106599
|
+
/**
|
|
106600
|
+
* Получить количество изображений по каждому подходу (8 элементов, 0–4).
|
|
106601
|
+
* По умолчанию — по 1 на каждый подход.
|
|
106602
|
+
*/
|
|
106603
|
+
function getImageApproachCounts() {
|
|
106604
|
+
const overrides = loadPromptOverrides();
|
|
106605
|
+
if (overrides.imageApproachCounts && overrides.imageApproachCounts.length === 8) {
|
|
106606
|
+
return overrides.imageApproachCounts.map(c => Math.max(0, Math.min(4, c)));
|
|
106607
|
+
}
|
|
106608
|
+
// backward compat: selectedImageApproaches -> counts (1 for selected, 0 for not)
|
|
106609
|
+
if (overrides.selectedImageApproaches && overrides.selectedImageApproaches.length >= 1) {
|
|
106610
|
+
const counts = Array(8).fill(0);
|
|
106611
|
+
for (const i of overrides.selectedImageApproaches) {
|
|
106612
|
+
if (i >= 0 && i < 8)
|
|
106613
|
+
counts[i] = 1;
|
|
106614
|
+
}
|
|
106615
|
+
return counts;
|
|
106616
|
+
}
|
|
106617
|
+
return [1, 1, 1, 1, 1, 1, 1, 1];
|
|
106618
|
+
}
|
|
106528
106619
|
/**
|
|
106529
106620
|
* Загрузить оверрайды из localStorage
|
|
106530
106621
|
*/
|
|
@@ -107096,36 +107187,32 @@ function getValidationPrompt(product, geo, keywords, approachName, noOverride) {
|
|
|
107096
107187
|
: `ШАГ 2 — BULLETS (критично):
|
|
107097
107188
|
- РОВНО 3 буллета. Если буллетов не 3 — ОШИБКА.
|
|
107098
107189
|
- Каждый буллет должен быть читабельным (хорошо читается на телефоне, не микрошрифт)
|
|
107099
|
-
-
|
|
107190
|
+
- Буллеты: крупные, с иконками/галочками (✓), на контрастных подложках. Буллеты НЕ на упаковке/банке.
|
|
107100
107191
|
- Формат бенефита РАЗРЕШЁН: «Чувствуешь себя легче», «Больше энергии», «Без дискомфорта», «Лёгкость движений» — это бенефиты, НЕ предложения
|
|
107101
|
-
- ПРЕДЛОЖЕНИЕ (ошибка) = полная грамматическая конструкция с подлежащим + сказуемым + дополнением, например «Продукт быстро снижает дискомфорт». Короткие бенефиты
|
|
107192
|
+
- ПРЕДЛОЖЕНИЕ (ошибка) = полная грамматическая конструкция с подлежащим + сказуемым + дополнением, например «Продукт быстро снижает дискомфорт». Короткие бенефиты — не считать предложениями
|
|
107102
107193
|
- Буллиты с глаголом во 2-м лице («Чувствуешь...», «Получаешь...») или безличные («Больше энергии», «Без дискомфорта») — НЕ ошибка
|
|
107103
|
-
- Буллеты = свойства, характеристики ИЛИ
|
|
107104
|
-
-
|
|
107105
|
-
-
|
|
107106
|
-
// ШАГ 3 — TEXT LIMIT: PVP has no badges allowed, normal allows urgency/trust
|
|
107194
|
+
- Буллеты = свойства, характеристики ИЛИ бенефиты. Разрешено: «Reduce disconfortul», «Mai puține treziri», «Efect în 14 zile», цифры соц. доказательства.
|
|
107195
|
+
- Буллиты должны быть расположены вертикально (столбиком). Если буллиты идут горизонтально в одну строку — ОШИБКА: плохая читаемость на мобиле
|
|
107196
|
+
- Цена визуально ОТЛИЧНА от буллитов (цена — компактный блок без иконок; буллеты — с иконками/галочками). Если цена выглядит как буллет — ОШИБКА.`;
|
|
107197
|
+
// ШАГ 3 — TEXT LIMIT: PVP has no badges allowed, normal allows urgency/trust (без проверок по длине/количеству слов)
|
|
107107
107198
|
const step3TextLimit = isNoBullets
|
|
107108
|
-
? `ШАГ 3 —
|
|
107109
|
-
-
|
|
107110
|
-
-
|
|
107111
|
-
- Любой дополнительный текст (бейджи/подписи/пояснения/urgency/trust) — ОШИБКА: слишком много текста для punch‑креатива.
|
|
107199
|
+
? `ШАГ 3 — OTHER_TEXT (критично):
|
|
107200
|
+
- OTHER_TEXT должен быть ПУСТЫМ (0 элементов). Никаких дополнительных бейджей, подписей, ярлыков, trust‑печатей/urgency — НИЧЕГО.
|
|
107201
|
+
- Любой дополнительный текст (бейджи/подписи/пояснения/urgency/trust‑печати) — ОШИБКА: слишком много текста для punch‑креатива.
|
|
107112
107202
|
- На креативе допустимы ТОЛЬКО: HOOK, цена, скидка, кнопка CTA.`
|
|
107113
|
-
: `ШАГ 3 —
|
|
107114
|
-
- Общее число слов в HOOK/HEADLINE + BULLETS <= 16. Если больше — ошибка.
|
|
107203
|
+
: `ШАГ 3 — OTHER_TEXT (критично):
|
|
107115
107204
|
- По умолчанию любой другой рекламный текст (бейджи/подписи/пояснения) запрещён.
|
|
107116
|
-
- НО допускаются (не обязательно) дополнительные
|
|
107117
|
-
A) URGENCY (0–1 шт):
|
|
107118
|
-
B) TRUST (0–3
|
|
107205
|
+
- НО допускаются (не обязательно) дополнительные бейджи ВНЕ упаковки — это НЕ ошибка, если ВСЕ элементы OTHER_TEXT подпадают под разрешённые типы:
|
|
107206
|
+
A) URGENCY (0–1 шт): бейдж срочности/дефицита — только ясные формулировки («только сегодня», «последние штуки», «акция до конца дня»). ЗАПРЕЩЕНО: «24h» и подобные — непонятно что означает.
|
|
107207
|
+
B) TRUST (0–3 шт, для «Минимализм / Clean Big Text» — макс 1): печати цветные, яркие, очень похожие на печать FDA. Подчёркивают: натуральность состава, премиальность, безопасность. Допустимо: качество, натуральные ингредиенты, экологичность, контроль качества. Печати — размер как минимум как у буллитов, крупные. Даже одна печать — крупная.
|
|
107119
107208
|
Правила для каждого элемента OTHER_TEXT:
|
|
107120
|
-
* короткий: 1–3 слова ИЛИ число+слово (например «24h»)
|
|
107121
107209
|
* строго на языке ${geo} (без английских слов)
|
|
107122
107210
|
* без цены/скидки/процентов (кроме обязательного поля DISCOUNT), без доменов/ссылок
|
|
107123
|
-
*
|
|
107124
|
-
* TRUST‑бейджи должны быть про доверие/сервис (качество/доставка/поддержка/проверено/рекомендуют), не про «лечит/результаты». Запрещено: «рекомендовано врачами», «клинически доказано», «одобрено Минздравом» и любые фразы, которые требуют доказательств/авторитетов
|
|
107211
|
+
* TRUST‑печати — про натуральность/премиальность/безопасность (не про доставку/поддержку)
|
|
107125
107212
|
Примеры стиля (адаптируй к языку GEO, не требуются):
|
|
107126
|
-
- URGENCY: «Ostatnie sztuki», «Tylko dziś», «Koniec dzi
|
|
107127
|
-
- TRUST: «Wysoka jakość», «
|
|
107128
|
-
- Если OTHER_TEXT содержит что-то вне этих типов, или URGENCY > 1, или TRUST > 3 — ОШИБКА.`;
|
|
107213
|
+
- URGENCY: «Ostatnie sztuki», «Tylko dziś», «Koniec dziś» (НЕ «24h» — непонятно)
|
|
107214
|
+
- TRUST: «Naturalna formuła», «Wysoka jakość», «Bezpieczne», «Eko», «Kontrola jakości»
|
|
107215
|
+
- Если OTHER_TEXT содержит что-то вне этих типов, или URGENCY > 1, или TRUST > 3 (для Минимализма — TRUST > 1) — ОШИБКА.`;
|
|
107129
107216
|
return `Ты — СТРОГИЙ валидатор рекламных креативов (1:1). Не улучшай и не предлагай идеи — только проверка и вердикт.
|
|
107130
107217
|
Продукт: ${product}. GEO/язык: ${geo}.${approachLine}
|
|
107131
107218
|
|
|
@@ -107142,15 +107229,13 @@ DISCOUNT: "..." (если нет — "нет")
|
|
|
107142
107229
|
CTA: "..." (если нет — "нет")
|
|
107143
107230
|
OTHER_TEXT: ["..."] (любой другой рекламный текст на макете ВНЕ упаковки и ВНЕ элементов выше; название/бренд на упаковке НЕ включай)
|
|
107144
107231
|
(если можешь, для ясности — не обязательно):
|
|
107145
|
-
URGENCY_BADGE: "..." (
|
|
107146
|
-
TRUST_BADGES: ["..."] (
|
|
107232
|
+
URGENCY_BADGE: "..." (бейдж срочности, если есть; «24h» — ОШИБКА, непонятно что означает)
|
|
107233
|
+
TRUST_BADGES: ["..."] (печати цветные, яркие, в стиле FDA; про натуральность/премиальность/безопасность; размер как у буллитов — крупные, если есть)
|
|
107147
107234
|
|
|
107148
107235
|
ШАГ 1 — HOOK/HEADLINE (критично):
|
|
107149
107236
|
- Должен быть в верхнем блоке и читабелен (хорошо читается на телефоне)
|
|
107150
|
-
- РОВНО 3–5 слов
|
|
107151
107237
|
- Допускается 1–2 строки (это НЕ ошибка). Ошибка только если текст нечитабелен или есть разрыв/перенос внутри слова.
|
|
107152
|
-
- Смысл: релевантно проблеме/выгоде продукта. Допускаются и боль/дискомфорт, и обещание/выгода (например «Könnyebb napok»). НЕ считай
|
|
107153
|
-
- Мягкие обещания результата («Nopți liniștite», «Stomac fără griji») — не ошибка. Ошибка только если есть медицинская гарантия или диагноз.
|
|
107238
|
+
- Смысл: релевантно проблеме/выгоде продукта. Допускаются и боль/дискомфорт, и обещание/выгода (например «Könnyebb napok»). НЕ считай ошибкой формулировки обещаний результата или клеймы.
|
|
107154
107239
|
- Желательно: ключевое слово боли/проблемы в формулировке (как часть смысла), но отсутствие ключевого слова само по себе НЕ является ошибкой. Примеры для ориентира: ${keywords.join(', ')} (можно синонимы).
|
|
107155
107240
|
- Проверь вторую часть заголовка. Если она состоит только из абстрактных слов («Mai ușor», «Mai bine», «Soluția», «Ajutor») без конкретного бенефита — отметь: РЕКОМЕНДАЦИЯ: заголовок можно усилить конкретикой
|
|
107156
107241
|
- Если заголовок слишком общий/абстрактный («Mai ușor», «Mai bine» без конкретики) — отметь как РЕКОМЕНДАЦИЯ к улучшению (не ошибка, но слабо)
|
|
@@ -107158,19 +107243,15 @@ TRUST_BADGES: ["..."] (бейджи доверия/сервиса, если ес
|
|
|
107158
107243
|
|
|
107159
107244
|
${step2Bullets}
|
|
107160
107245
|
|
|
107161
|
-
ШАГ 2.5 — CLAIMS CHECK
|
|
107162
|
-
-
|
|
107163
|
-
- ЗАПРЕЩЕНЫ только: «лечит», «вылечивает», «гарантируем», «100%», «навсегда», «полностью избавляет», диагностика заболеваний
|
|
107164
|
-
- «Выводит/устраняет токсины» для детокс-продуктов — это мягкий клейм, НЕ медицинская гарантия
|
|
107165
|
-
- Если найден запрещённый клейм — ошибка. Мягкие клеймы — не ошибка.
|
|
107166
|
-
- Специфические медицинские термины или диагнозы — разрешены, но не должны повторяться чрезмерно. Если в HOOK/HEADLINE + BULLETS один и тот же специфический термин встречается более 1 раза — РЕКОМЕНДАЦИЯ: разнообразить формулировки, использовать синонимы или фокус на симптомах вместо повторения термина
|
|
107246
|
+
ШАГ 2.5 — CLAIMS CHECK:
|
|
107247
|
+
- Клеймы по результату (жёсткие/абсолютные или мягкие) — НЕ проверяются и НЕ запрещаются. Не блокируй за формулировки обещаний результата.
|
|
107167
107248
|
|
|
107168
107249
|
${step3TextLimit}
|
|
107169
107250
|
|
|
107170
107251
|
ШАГ 4 — CTA > PRICE (критично):
|
|
107171
|
-
- CTA:
|
|
107172
|
-
-
|
|
107173
|
-
- Скидка
|
|
107252
|
+
- CTA: на языке ${geo}, хорошо заметная кнопка (позиция НЕ важна: можно вправо/влево/по центру). Главное — CTA читабельна и выглядит как кнопка.
|
|
107253
|
+
- Цена: ОБЯЗАТЕЛЬНО ДВЕ — старая (до скидки) + новая. Если только одна цена — ОШИБКА. Старая зачёркнута ТОЛСТОЙ линией (не тонкой!), новая выразительно. Тонкое/незаметное зачёркивание — ОШИБКА.
|
|
107254
|
+
- Скидка ОБЯЗАТЕЛЬНА: «-50%» (возможны варианты символа минуса: -, – или −). Ярко, заметно. Строго НЕ на упаковке/банке.
|
|
107174
107255
|
- Не считать ошибкой, если скидка/цена конкурируют с CTA по акценту — это допустимо, пока CTA остаётся хорошо заметной и читабельной.
|
|
107175
107256
|
- Если скидка указана и она не равна -50% — ошибка.
|
|
107176
107257
|
|
|
@@ -107181,13 +107262,18 @@ ${step3TextLimit}
|
|
|
107181
107262
|
ШАГ 6 — КОМПОЗИЦИЯ:
|
|
107182
107263
|
- Если креатив без человека (lifestyle/clean), проверь наличие контекста использования (кухня, стол, тумбочка, и т.д.). Продукт на полностью пустом/белом фоне без контекста — РЕКОМЕНДАЦИЯ к улучшению (не критичная ошибка, но слабый визуал)
|
|
107183
107264
|
- КОНТРАСТ ПЛАШЕК: если хотя бы одна текстовая плашка (HOOK, буллеты, CTA или цена) визуально сливается с фоном и текст плохо читается — это ОШИБКА.
|
|
107265
|
+
- ЦЕНА: ОБЯЗАТЕЛЬНО ДВЕ — старая зачёркнута ТОЛСТОЙ линией (не тонкой!), новая выразительно. Одна цена или тонкое зачёркивание — ОШИБКА. Цена не должна выглядеть как буллет.
|
|
107266
|
+
- TRUST‑печати: если печати мелкие или текст нечитабелен на телефоне — ОШИБКА (размер как минимум как у буллитов).
|
|
107267
|
+
- СКИДКА «-50%»: ярко, заметно, на контрастной подложке. Строго НЕ на упаковке/банке. Если скидка на продукте или бледная/незаметна — ОШИБКА.
|
|
107268
|
+
- ЦЕНА: ОБЯЗАТЕЛЬНО ДВЕ — старая зачёркнута ТОЛСТОЙ линией (не тонкой!), новая выразительно. Одна цена или тонкое зачёркивание — ОШИБКА.
|
|
107269
|
+
- Бейджи срочности: «24h» и подобные неясные формулировки — ОШИБКА (непонятно что означает). Ясные («только сегодня», «последние штуки») — ок.
|
|
107184
107270
|
|
|
107185
107271
|
ФИНАЛ:
|
|
107186
107272
|
Выведи строго:
|
|
107187
107273
|
СТАТУС: OK / НУЖНА ПЕРЕСБОРКА
|
|
107188
107274
|
Затем список ошибок, каждая строка начинается с "ОШИБКА:" (кратко, по делу). Если ошибок нет — напиши "ОШИБКА: нет".
|
|
107189
107275
|
Затем список рекомендаций (если есть), каждая строка начинается с "РЕКОМЕНДАЦИЯ:" (кратко, по делу). Если рекомендаций нет — напиши "РЕКОМЕНДАЦИЯ: нет".
|
|
107190
|
-
Не блокируй за
|
|
107276
|
+
Не блокируй за клеймы по результату или формулировки обещаний.`;
|
|
107191
107277
|
}
|
|
107192
107278
|
/**
|
|
107193
107279
|
* Базовый промпт для генерации изображений креативов
|
|
@@ -107205,10 +107291,12 @@ function getImageGenerationBasePrompt(generateGeo, generatePrice, generateCurren
|
|
|
107205
107291
|
}
|
|
107206
107292
|
_debugLog('⚠️ Using DEFAULT getImageGenerationBasePrompt');
|
|
107207
107293
|
}
|
|
107208
|
-
// Подходы без буллитов —
|
|
107209
|
-
const
|
|
107294
|
+
// Подходы без буллитов — из подходов с count > 0
|
|
107295
|
+
const counts = (0,_promptOverrides__WEBPACK_IMPORTED_MODULE_0__.getImageApproachCounts)();
|
|
107296
|
+
const selectedApproaches = CREO_APPROACHES.filter((_, i) => counts[i] > 0);
|
|
107297
|
+
const noBulletsNames = selectedApproaches.filter(a => a.noBullets).map(a => a.name);
|
|
107210
107298
|
const noBulletsCond = noBulletsNames.map(n => `"${n}"`).join(' или ');
|
|
107211
|
-
const totalApproaches =
|
|
107299
|
+
const totalApproaches = counts.reduce((a, b) => a + b, 0);
|
|
107212
107300
|
const ratio = aspectRatio || '1:1';
|
|
107213
107301
|
const ratioLabel = ratio === '1:1' ? '1:1 (квадрат, 1024×1024 px)' : '2:3 (портрет, 1024×1536 px)';
|
|
107214
107302
|
const ratioShape = ratio === '1:1' ? 'квадратным' : 'вертикальным 2:3 (портрет)';
|
|
@@ -107236,8 +107324,13 @@ CRITICAL RULES (это ВАЛИДАЦИЯ, не рекомендации; есл
|
|
|
107236
107324
|
- Цена/скидка = триггер "сейчас"
|
|
107237
107325
|
- CTA = финальный шаг к действию
|
|
107238
107326
|
|
|
107327
|
+
❗ ЦЕНА (КРИТИЧНО — НЕ ПРОПУСКАЙ):
|
|
107328
|
+
- ОБЯЗАТЕЛЬНО ДВЕ цены: старая (до скидки) + новая (${generatePrice} ${generateCurrency}). Одна цена = ОШИБКА.
|
|
107329
|
+
- Старая = 2× новой (при -50%). Новая — выразительно, крупно. Старая — зачёркнута.
|
|
107330
|
+
- Зачёркивание: ТОЛСТАЯ линия (не тонкая!), контрастная, хорошо видимая. Тонкая/незаметная линия = ОШИБКА.
|
|
107331
|
+
|
|
107239
107332
|
ЯЗЫК + ТОН:
|
|
107240
|
-
- ВСЕ слова строго на языке ${generateGeo} (HOOK/буллеты/CTA/скидка/опциональный бейдж срочности/опциональные trust
|
|
107333
|
+
- ВСЕ слова строго на языке ${generateGeo} (HOOK/буллеты/CTA/скидка/опциональный бейдж срочности/опциональные trust‑печати). Английские слова запрещены. Исключений нет.
|
|
107241
107334
|
- Тон: убедительный, но честный. Лёгкая эмоция и срочность — ок. Запрещено: ложные обещания, диагностика заболеваний, слова «лечит/вылечивает/гарантируем».
|
|
107242
107335
|
|
|
107243
107336
|
HOOK / HEADLINE (строгое правило):
|
|
@@ -107260,12 +107353,13 @@ HOOK / HEADLINE (строгое правило):
|
|
|
107260
107353
|
- ТАК (сон): «Álmatlan éjszakák? Pihenj végre»
|
|
107261
107354
|
❗ Если заголовок > 5 слов, похож на предложение, распадается на 2 смысловых блока или звучит как лозунг — ОШИБКА → пересоздай вариант.
|
|
107262
107355
|
|
|
107263
|
-
BULLETS (жёсткое
|
|
107356
|
+
BULLETS (жёсткое правило, ровно 3):
|
|
107264
107357
|
- По умолчанию: ровно 3 буллета
|
|
107265
107358
|
- ИСКЛЮЧЕНИЕ: если 🎯 ПОДХОД = ${noBulletsCond} → буллиты ЗАПРЕЩЕНЫ (0 буллитов). Не добавляй буллет‑блок вообще
|
|
107266
107359
|
- каждый 2–3 слова (макс 4); без запятых; буллет НЕ должен выглядеть как предложение
|
|
107267
107360
|
- буллеты = свойства ИЛИ ощущаемые преимущества (комфорт, лёгкость, спокойствие). Запрещено: диагнозы, жёсткие медицинские гарантии («лечит», «вылечивает», «избавляет навсегда»). Разрешено: мягкие результаты («Reduce disconfortul», «Mai puține simptome») — примеры формата, адаптируй под категорию, сроки без гарантий («Efect în 7-14 zile», «Rezultat vizibil rapid»), цифры как соц. доказательство («9 din 10 bărbați recomandă»).
|
|
107268
107361
|
- Делай буллеты более активными и конкретными: глаголы действия + сроки + цифры. Примеры формата: «Reduce X», «Ulga od 1. dnia», «Efekt w 7 dni», «93% potwierdza», «3× szybciej» (адаптируй под язык GEO и категорию)
|
|
107362
|
+
- ВИЗУАЛ БУЛЛЕТОВ: крупные, с иконками/галочками (✓), на контрастных подложках. Буллеты ВНЕ упаковки/банки — не на продукте.
|
|
107269
107363
|
- Буллиты должны быть расположены ВЕРТИКАЛЬНО (столбиком), не горизонтально в одну строку. Минимальный размер шрифта буллитов — чтобы читались на экране телефона без зума
|
|
107270
107364
|
- Не повторяй один и тот же набор буллитов во всех подходах: для текущего подхода используй свой набор и акценты. Варианты: свойства (Formulă naturală), бенефиты (Reduce disconfortul), сроки (Efect în 7-14 zile), соц. доказательство (9 din 10 recomandă)
|
|
107271
107365
|
ПРАВИЛЬНО (пример формата — адаптируй под категорию продукта): «Confort zilnic», «Fără dureri», «Reduce disconfortul», «Mișcare ușoară», «Efect în 2 săptămâni».
|
|
@@ -107274,30 +107368,34 @@ BULLETS (жёсткое правило):
|
|
|
107274
107368
|
|
|
107275
107369
|
TEXT LIMIT:
|
|
107276
107370
|
- кроме: HOOK, 3 буллетов, цены, скидки, кнопки — ЛЮБОЙ другой текст запрещён (ярлыки/подписи/дисклеймеры/пояснения)
|
|
107277
|
-
- ИСКЛЮЧЕНИЕ: если 🎯 ПОДХОД = ${noBulletsCond} → кроме HOOK, цены, скидки, CTA — НИКАКОГО другого текста. Буллиты запрещены. Other_text/urgency/trust
|
|
107278
|
-
- ДОПУСКАЕТСЯ (не обязательно) ОДИН
|
|
107279
|
-
- ДОПУСКАЕТСЯ (не обязательно) 1–3
|
|
107371
|
+
- ИСКЛЮЧЕНИЕ: если 🎯 ПОДХОД = ${noBulletsCond} → кроме HOOK, цены, скидки, CTA — НИКАКОГО другого текста. Буллиты запрещены. Other_text/urgency/trust‑печати запрещены
|
|
107372
|
+
- ДОПУСКАЕТСЯ (не обязательно) ОДИН бейдж срочности: только ясные формулировки («только сегодня», «последние штуки», «акция до конца дня»). ЗАПРЕЩЕНО: «24h» — непонятно что означает.
|
|
107373
|
+
- ДОПУСКАЕТСЯ (не обязательно) 1–3 trust‑печати: печати цветные, яркие, очень похожие на печать FDA. Подчёркивают: натуральность состава, премиальность, безопасность продукта. Допустимо также: качество, натуральные ингредиенты, экологичность, контроль качества. Короткий текст (1–3 слова) на языке ${generateGeo}, компактно по низу. КРИТИЧНО: печати должны быть КРУПНЫМИ — размер как минимум как у буллитов, лучше крупнее. Текст читабелен на телефоне без зума. Даже одна печать — крупная. Мелкие печати — ОШИБКА. Запрещено: «рекомендовано врачами», «клинически доказано», «одобрено Минздравом» и любые фразы, требующие доказательств
|
|
107280
107374
|
- HOOK + буллеты <= 16 слов суммарно; если больше — ОШИБКА → пересоздай
|
|
107281
|
-
- Если хочешь добавить ощущение срочности — делай это через формулировки в HOOK/BULLETS, через реквизит/иконки, ИЛИ (не обязательно) через один короткий
|
|
107375
|
+
- Если хочешь добавить ощущение срочности — делай это через формулировки в HOOK/BULLETS, через реквизит/иконки, ИЛИ (не обязательно) через один короткий бейдж срочности. Только ясные формулировки («Ostatnie sztuki», «Tylko dziś», «Koniec dziś»). ЗАПРЕЩЕНО «24h» — непонятно что означает.
|
|
107282
107376
|
|
|
107283
107377
|
CTA > PRICE:
|
|
107284
107378
|
- кнопка CTA (1–2 слова на языке ${generateGeo}) — главный якорь нижнего блока (самый контрастный элемент внизу)
|
|
107285
107379
|
- цена и скидка видны, но слабее CTA; скидка «-50%» ОБЯЗАТЕЛЬНА и не должна конкурировать с кнопкой
|
|
107380
|
+
- ЦЕНА: ОБЯЗАТЕЛЬНО ДВЕ — старая зачёркнута ТОЛСТОЙ линией (не тонкой!), новая выразительно. Одна цена или тонкое зачёркивание — ОШИБКА. Цена не должна выглядеть как буллет.
|
|
107286
107381
|
❗ Если цена/скидка/бейдж по контрасту или размеру равны или сильнее кнопки — ОШИБКА → ослабь цену/скидку или усили CTA и пересоздай.
|
|
107287
107382
|
❗ ИСКЛЮЧЕНИЕ: если 🎯 ПОДХОД = ${noBulletsCond} → цена и «-50%» могут быть более крупными и заметными, но CTA всё равно должен оставаться очень заметным и выглядеть как кнопка (не теряется на фоне)
|
|
107288
107383
|
|
|
107289
107384
|
ПОКАЗЫВАЙ ТОЛЬКО ЭТИ ТЕКСТОВЫЕ ЭЛЕМЕНТЫ:
|
|
107290
107385
|
- HOOK (1 строка; CAPS; жирный; на яркой контрастной подложке)
|
|
107291
|
-
- 3 буллета
|
|
107292
|
-
- Цена: ${generatePrice} ${generateCurrency}
|
|
107293
|
-
- Скидка:
|
|
107386
|
+
- 3 буллета (крупные, с иконками/галочками ✓, на контрастных подложках, НЕ на банке/упаковке)
|
|
107387
|
+
- Цена: ОБЯЗАТЕЛЬНО ДВЕ — старая (2×${generatePrice} ${generateCurrency}) зачёркнута ТОЛСТОЙ контрастной линией + новая ${generatePrice} ${generateCurrency} выразительно. Одна цена = ОШИБКА. Тонкая линия зачёркивания = ОШИБКА. Без слов. Не на упаковке.
|
|
107388
|
+
- Скидка: «-50%» (обязательно, отдельным бейджем; ярко, заметно; строго НЕ на банке/упаковке; визуально слабее CTA)
|
|
107294
107389
|
- Кнопка CTA (1-2 слова)
|
|
107295
|
-
- Опционально: 1 короткий бейдж срочности (
|
|
107296
|
-
- Опционально: 1–3
|
|
107297
|
-
- ИСКЛЮЧЕНИЕ: если 🎯 ПОДХОД = ${noBulletsCond} → показывай только: HOOK + PRICE + DISCOUNT + CTA. Буллиты/urgency/trust запрещены
|
|
107390
|
+
- Опционально: 1 короткий бейдж срочности (ясные формулировки: «только сегодня», «последние штуки»; ЗАПРЕЩЕНО «24h»). Бейдж в углу кадра, контрастный, но меньше CTA. НЕ обязателен
|
|
107391
|
+
- Опционально: 1–3 trust‑печати (цветные, яркие, очень похожие на печать FDA; подчёркивают натуральность, премиальность, безопасность; допустимо: качество, натуральные ингредиенты, экологичность, контроль качества). Короткий текст на языке ${generateGeo}. Размер как минимум как у буллитов, лучше крупнее — читабельны на телефоне без зума. Даже одна печать — крупная. Для подхода «Минимализм» — макс 1 печать. НЕ обязательны
|
|
107392
|
+
- ИСКЛЮЧЕНИЕ: если 🎯 ПОДХОД = ${noBulletsCond} → показывай только: HOOK + PRICE + DISCOUNT + CTA. Буллиты/urgency/trust‑печати запрещены
|
|
107298
107393
|
|
|
107299
107394
|
ВИЗУАЛ:
|
|
107300
107395
|
- Иерархия: HOOK > продукт > CTA > цена > буллеты
|
|
107396
|
+
- Буллеты: крупные, с иконками/галочками (✓), на контрастных подложках. Строго ВНЕ упаковки/банки.
|
|
107397
|
+
- Цена: ОБЯЗАТЕЛЬНО ДВЕ — старая зачёркнута ТОЛСТОЙ линией (не тонкой!), новая выразительно. Одна цена или тонкое зачёркивание = ОШИБКА. Визуально ОТЛИЧНА от буллитов.
|
|
107398
|
+
- Скидка «-50%»: ярко, заметно, на контрастной подложке. Строго ВНЕ упаковки/банки.
|
|
107301
107399
|
- Текст на контрастных плашках, читабельно на телефоне. Допускается мультяшная/комиксовая стилистика текста (не обязательно)
|
|
107302
107400
|
- КОНТРАСТ ПЛАШЕК: каждая текстовая плашка (HOOK, буллеты, CTA, цена) должна иметь высокий контраст с фоном — светлый текст на тёмной подложке ИЛИ тёмный текст на светлой. Плашка, сливающаяся с фоном = ОШИБКА → добавь подложку или измени цвет фона/плашки.
|
|
107303
107401
|
- АНГЛИЙСКИЙ НА УПАКОВКЕ: если на этикетке продукта есть английский текст (например название/описание на упаковке) — не приближай её настолько, чтобы эти надписи были читабельны как отдельный контент. Упаковка = визуальный объект; мелкий этикеточный текст должен быть нечитабелен или едва различим.
|
|
@@ -107311,20 +107409,21 @@ ANTI-TEMPLATE DIVERSITY (КРИТИЧНО):
|
|
|
107311
107409
|
- Ты сейчас создаёшь ОДИН креатив для текущего подхода. В проекте будет серия из ${totalApproaches} креативов, поэтому у каждого подхода должна быть своя узнаваемая композиция.
|
|
107312
107410
|
- Для ЭТОГО креатива НЕ используй универсальный шаблон. Обязательно вариируй: (1) крупность/кроп (close-up vs medium vs flat-lay), (2) угол камеры (прямо vs сверху vs диагональ), (3) расположение блоков HOOK/BULLETS/CTA/PRICE/DISCOUNT, (4) свет/фон (но без лишнего текста).
|
|
107313
107411
|
- Ориентируйся на строку «🎯 ПОДХОД: ...» и примени соответствующую раскладку ниже (только одну, соответствующую текущему подходу):
|
|
107314
|
-
* 🎯 ПОДХОД: Эксперт / Авторитет → БЕЗ человека. Профессиональный контекст с реквизитом экспертизы вокруг продукта. Продукт в центре. HOOK сверху справа, BULLETS справа ниже, CTA снизу справа, PRICE/DISCOUNT рядом с CTA (слабее CTA). Trust
|
|
107315
|
-
* 🎯 ПОДХОД: Lifestyle / Момент приёма → FLAT-LAY/СВЕРХУ или 3/4 сверху на столе/тумбочке. Продукт в центре, реквизит "момент приёма" вокруг. HOOK сверху по центру, BULLETS сбоку (вертикально, шрифт достаточно крупный для чтения на телефоне без зума), CTA снизу по центру, PRICE/DISCOUNT рядом (слабее CTA). Urgency‑бейдж (если есть) — в
|
|
107316
|
-
* 🎯 ПОДХОД: Эмоция / Портрет → ЭТО ЕДИНСТВЕННЫЙ ПОДХОД С ЧЕЛОВЕКОМ В СЕРИИ. ОЧЕНЬ крупный портрет лица (thumb‑stop), взгляд в камеру — лицо занимает верхние 2/3 кадра и доминирует. Продукт в руке или у подбородка. HOOK сверху по центру. BULLETS, CTA, PRICE/DISCOUNT — строго в нижней трети, НЕ перекрывают лицо и не конкурируют с ним по размеру.
|
|
107317
|
-
* 🎯 ПОДХОД: Визуализация проблемы → Инфографика/схема: слева проблема (иконка/схема зоны тела, релевантной продукту), справа решение + продукт. HOOK сверху по центру, BULLETS справа или снизу (вертикально), CTA снизу справа, PRICE/DISCOUNT возле CTA. Красный акцент только на проблеме.
|
|
107318
|
-
* 🎯 ПОДХОД: Power / Сила решения → БЕЗ человека. ДИНАМИЧНЫЙ комикс‑кадр, диагональная композиция. Продукт как “герой” + power‑иконки (щит/молния/бёрст). HOOK сверху слева на яркой плашке, BULLETS слева ниже, CTA снизу справа, PRICE/DISCOUNT возле CTA.
|
|
107319
|
-
* 🎯 ПОДХОД: Минимализм / Clean Big Text → Белый/градиентный фон, минимум элементов. ОГРОМНЫЙ HOOK занимает верх/центр, продукт крупно (центр/право), CTA снизу по центру, PRICE/DISCOUNT рядом (слабее CTA). Trust
|
|
107412
|
+
* 🎯 ПОДХОД: Эксперт / Авторитет → БЕЗ человека. Профессиональный контекст с реквизитом экспертизы вокруг продукта. Продукт в центре. HOOK сверху справа, BULLETS справа ниже, CTA снизу справа, PRICE/DISCOUNT рядом с CTA (слабее CTA). Trust‑печати (если есть) — компактно по низу, размер как минимум как у буллитов (крупные, читабельны на телефоне).
|
|
107413
|
+
* 🎯 ПОДХОД: Lifestyle / Момент приёма → FLAT-LAY/СВЕРХУ или 3/4 сверху на столе/тумбочке. Продукт в центре, реквизит "момент приёма" вокруг. HOOK сверху по центру, BULLETS сбоку (вертикально, шрифт достаточно крупный для чтения на телефоне без зума), CTA снизу по центру, PRICE/DISCOUNT рядом (слабее CTA). Urgency‑бейдж (если есть) — в углу, только ясные формулировки, НЕ «24h». Trust‑печати (если есть) — компактно по низу, размер как минимум как у буллитов (крупные, читабельны на телефоне).
|
|
107414
|
+
* 🎯 ПОДХОД: Эмоция / Портрет → ЭТО ЕДИНСТВЕННЫЙ ПОДХОД С ЧЕЛОВЕКОМ В СЕРИИ. ОЧЕНЬ крупный портрет лица (thumb‑stop), взгляд в камеру — лицо занимает верхние 2/3 кадра и доминирует. Продукт в руке или у подбородка. HOOK сверху по центру. BULLETS, CTA, PRICE/DISCOUNT, trust‑печати — строго в нижней трети, НЕ перекрывают лицо и не конкурируют с ним по размеру.
|
|
107415
|
+
* 🎯 ПОДХОД: Визуализация проблемы → Инфографика/схема: слева проблема (иконка/схема зоны тела, релевантной продукту), справа решение + продукт. HOOK сверху по центру, BULLETS справа или снизу (вертикально), CTA снизу справа, PRICE/DISCOUNT возле CTA. Trust‑печати (если есть) — компактно по низу, размер как минимум как у буллитов (крупные, читабельны на телефоне). Красный акцент только на проблеме.
|
|
107416
|
+
* 🎯 ПОДХОД: Power / Сила решения → БЕЗ человека. ДИНАМИЧНЫЙ комикс‑кадр, диагональная композиция. Продукт как “герой” + power‑иконки (щит/молния/бёрст). HOOK сверху слева на яркой плашке, BULLETS слева ниже, CTA снизу справа, PRICE/DISCOUNT возле CTA. Trust‑печати (если есть) — компактно по низу, размер как минимум как у буллитов (крупные, читабельны на телефоне).
|
|
107417
|
+
* 🎯 ПОДХОД: Минимализм / Clean Big Text → Белый/градиентный фон, минимум элементов. ОГРОМНЫЙ HOOK занимает верх/центр, продукт крупно (центр/право), CTA снизу по центру, PRICE/DISCOUNT рядом (слабее CTA). Trust‑печати (если есть) — размер как минимум как у буллитов, крупные и читабельные.
|
|
107320
107418
|
* 🎯 ПОДХОД: Problem Visual Punch → БЕЗ человека. Яркий сплошной фон (красный/оранжевый) или агрессивный градиент. В центре КРУПНАЯ иконка/схема зоны тела, релевантной продукту (для суставов — колено; для пищеварения — желудок), с красным свечением. Продукт крупно рядом. HOOK 3–4 слова МАКС, огромный CAPS. БЕЗ буллитов. PRICE + «-50%» крупно и заметно. CTA контрастной кнопкой
|
|
107321
107419
|
* 🎯 ПОДХОД: Любительский Примитивизм → БЕЗ человека. Чёрный или кислотный сплошной фон. Продукт по центру или справа без декора. HOOK сверху — крупный, грубый bold/рукописный, CAPS, 3–4 слова. Крупные надписи цены/скидки вокруг продукта. CTA — плоская кнопка без градиентов. БЕЗ буллитов, бейджей, теней, иконок.
|
|
107322
107420
|
|
|
107323
107421
|
AUTO-CHECK (перед финалом):
|
|
107324
107422
|
- HOOK: 3–5 слов, 1 строка, CAPS, жирный на контрастной плашке, боль + направление облегчения (не лозунг), язык ${generateGeo} без английских слов
|
|
107325
107423
|
- Буллеты: по умолчанию ровно 3, каждый <= 4 слов, без запятых, не предложения. ИСКЛЮЧЕНИЕ: если 🎯 ПОДХОД = ${noBulletsCond} → буллетов 0 (запрещены)
|
|
107326
|
-
- Нет лишнего текста кроме: HOOK, буллетов, цены, скидки, кнопки (+ опционально 1
|
|
107424
|
+
- Нет лишнего текста кроме: HOOK, буллетов, цены, скидки, кнопки (+ опционально 1 бейдж срочности + опционально 1–3 trust‑печати)
|
|
107327
107425
|
- Есть скидка «-50%» (вне упаковки) и она слабее CTA
|
|
107426
|
+
- Цена: ОБЯЗАТЕЛЬНО ДВЕ (старая + новая). Старая зачёркнута ТОЛСТОЙ контрастной линией. Одна цена = ОШИБКА. Тонкая/незаметная линия зачёркивания = ОШИБКА
|
|
107328
107427
|
- CTA визуально сильнее цены/скидки
|
|
107329
107428
|
- Контраст: каждая текстовая плашка читабельна на телефоне — ни одна не сливается с фоном
|
|
107330
107429
|
Если хоть один пункт нарушен — пересоздай креатив.
|
|
@@ -107332,57 +107431,68 @@ AUTO-CHECK (перед финалом):
|
|
|
107332
107431
|
ВАЖНО: Твой ответ — это ИЗОБРАЖЕНИЕ, не текст. Не пиши план, не перечисляй элементы текстом, не рассуждай, не вызывай tools. Сразу генерируй визуальный креатив как картинку.`;
|
|
107333
107432
|
}
|
|
107334
107433
|
/**
|
|
107335
|
-
* Получить подходы с учетом
|
|
107434
|
+
* Получить подходы с учетом количества и оверрайдов.
|
|
107435
|
+
* Каждый подход повторяется N раз (0–4), где N = imageApproachCounts[i].
|
|
107336
107436
|
*/
|
|
107337
107437
|
function getCreoApproaches() {
|
|
107338
|
-
|
|
107438
|
+
const counts = (0,_promptOverrides__WEBPACK_IMPORTED_MODULE_0__.getImageApproachCounts)();
|
|
107439
|
+
const result = [];
|
|
107440
|
+
for (let i = 0; i < CREO_APPROACHES.length && i < counts.length; i++) {
|
|
107441
|
+
const approach = CREO_APPROACHES[i];
|
|
107442
|
+
if (!approach)
|
|
107443
|
+
continue;
|
|
107339
107444
|
const override = (0,_promptOverrides__WEBPACK_IMPORTED_MODULE_0__.getCreoApproachOverride)(approach.name);
|
|
107340
|
-
|
|
107341
|
-
|
|
107342
|
-
return {
|
|
107445
|
+
const resolved = override?.enabled
|
|
107446
|
+
? {
|
|
107343
107447
|
...approach,
|
|
107344
107448
|
prompt: override.customPrompt || approach.prompt,
|
|
107345
107449
|
headlineAngle: override.customHeadlineAngle || approach.headlineAngle,
|
|
107346
107450
|
bulletsFocus: override.customBulletsFocus || approach.bulletsFocus
|
|
107347
|
-
}
|
|
107451
|
+
}
|
|
107452
|
+
: approach;
|
|
107453
|
+
if (override?.enabled) {
|
|
107454
|
+
_debugLog(`✅ Using CUSTOM approach: ${approach.name}`, `hasPrompt=${!!override.customPrompt}`, `hasHeadline=${!!override.customHeadlineAngle}`, `hasBullets=${!!override.customBulletsFocus}`);
|
|
107348
107455
|
}
|
|
107349
|
-
|
|
107350
|
-
|
|
107456
|
+
for (let k = 0; k < counts[i]; k++) {
|
|
107457
|
+
result.push(resolved);
|
|
107458
|
+
}
|
|
107459
|
+
}
|
|
107460
|
+
return result;
|
|
107351
107461
|
}
|
|
107352
107462
|
const CREO_APPROACHES = [
|
|
107353
107463
|
{
|
|
107354
107464
|
name: 'Эксперт / Авторитет',
|
|
107355
|
-
prompt: `ЭКСПЕРТ / АВТОРИТЕТ (без человека): стиль “рекомендация эксперта”, но БЕЗ человека. Профессиональный контекст — аптечные полки на фоне / медицинский планшет / стетоскоп / рецептурный блокнот как реквизит рядом с продуктом. Продукт в центре как “рекомендованное решение”. Чистый профессиональный фон, высокий контраст. Trust
|
|
107465
|
+
prompt: `ЭКСПЕРТ / АВТОРИТЕТ (без человека): стиль “рекомендация эксперта”, но БЕЗ человека. Профессиональный контекст — аптечные полки на фоне / медицинский планшет / стетоскоп / рецептурный блокнот как реквизит рядом с продуктом. Продукт в центре как “рекомендованное решение”. Чистый профессиональный фон, высокий контраст. Trust‑печати (1–3 шт): цветные, яркие, очень похожие на печать FDA; подчёркивают натуральность состава, премиальность, безопасность. Размер как минимум как у буллитов — крупные, читабельны на телефоне. Даже одна печать — крупная.`,
|
|
107356
107466
|
headlineAngle: `HOOK: угол «предупреждение / интрига / специалисты знают». Формат: вопрос‑предупреждение ИЛИ “специалисты знают/используют” (адаптируй под GEO). 3–5 слов, 1 строка, CAPS.`,
|
|
107357
107467
|
bulletsFocus: `БУЛЛИТЫ: “доверие + действие + конкретика”. Минимум 1 буллет с действием на главную боль (глагол), минимум 1 со сроком/скоростью, плюс 1 с цифрой/соц.доказательством (если уместно). Всё строго на языке GEO и релевантно категории. ЗАПРЕЩЕНО: абстрактные буллиты без действия/результата/срока/цифры (например «Naturalna formuła» сама по себе).`
|
|
107358
107468
|
},
|
|
107359
107469
|
{
|
|
107360
107470
|
name: 'Lifestyle / Момент приёма',
|
|
107361
|
-
prompt: `LIFESTYLE / МОМЕНТ ПРИЁМА: продукт в контексте использования (кухня/стол/спальня/тумбочка). Без человека, но с "историей" (стакан воды, чай, тарелка, будильник/часы/календарь). Срочность: реквизит (часы/таймер‑иконка) и/или опциональный urgency‑бейдж (1–3 слова) в углу
|
|
107471
|
+
prompt: `LIFESTYLE / МОМЕНТ ПРИЁМА: продукт в контексте использования (кухня/стол/спальня/тумбочка). Без человека, но с "историей" (стакан воды, чай, тарелка, будильник/часы/календарь). Срочность: реквизит (часы/таймер‑иконка) и/или опциональный urgency‑бейдж (1–3 слова) в углу кадра — только ясные формулировки («только сегодня», «последние штуки»), ЗАПРЕЩЕНО «24h». Высокий контраст, яркий акцент на продукте. Опционально: 1–3 trust‑печати по низу (цветные, яркие, очень похожие на печать FDA; натуральность/премиальность/безопасность). Размер как минимум как у буллитов — крупные, читабельны на телефоне. Даже одна печать — крупная. ВАЖНО: буллиты располагаются вертикально и всегда читабельны на экране телефона без зума — даже если уходят вбок, минимальный размер шрифта буллитов не уменьшается. Если буллиты не вмещаются сбоку с нужным шрифтом — переставь их вниз.`,
|
|
107362
107472
|
headlineAngle: `HOOK: угол «цифры + срочность». Формат: число/процент + ограничение времени/“сейчас/сегодня” (адаптируй под GEO), 3–5 слов, 1 строка, CAPS.`,
|
|
107363
107473
|
bulletsFocus: `БУЛЛИТЫ: активные глаголы + сроки + цифры. Минимум 1 буллет со сроком/скоростью, минимум 1 с цифрой/соц.доказательством. Всё 2–4 слова, без запятых, строго на языке GEO и релевантно категории. ЗАПРЕЩЕНО: абстрактные буллиты без действия/результата/срока/цифры.`
|
|
107364
107474
|
},
|
|
107365
107475
|
{
|
|
107366
107476
|
name: 'Эмоция / Портрет',
|
|
107367
|
-
prompt: `ЭМОЦИЯ / ПОРТРЕТ: ЭТО ЕДИНСТВЕННЫЙ ПОДХОД С ЧЕЛОВЕКОМ В СЕРИИ. Используй максимально: ОЧЕНЬ крупный план лица (thumb‑stop), прямой взгляд в камеру, сильная эмоция облегчения/надежды (без широкой стоковой улыбки). Возраст человека подбери под категорию и ЦА продукта: по умолчанию 50–60, но для категорий с более молодой аудиторией (например похудение/фитнес) допускается 35–55. Продукт в руке на уровне лица или рядом, хорошо виден. Свет "тень → свет" на лице допустим. Минимум отвлекающих деталей, высокий контраст. Опционально: 1–3 trust
|
|
107477
|
+
prompt: `ЭМОЦИЯ / ПОРТРЕТ: ЭТО ЕДИНСТВЕННЫЙ ПОДХОД С ЧЕЛОВЕКОМ В СЕРИИ. Используй максимально: ОЧЕНЬ крупный план лица (thumb‑stop), прямой взгляд в камеру, сильная эмоция облегчения/надежды (без широкой стоковой улыбки). Возраст человека подбери под категорию и ЦА продукта: по умолчанию 50–60, но для категорий с более молодой аудиторией (например похудение/фитнес) допускается 35–55. Продукт в руке на уровне лица или рядом, хорошо виден. Свет "тень → свет" на лице допустим. Минимум отвлекающих деталей, высокий контраст. Опционально: 1–3 trust‑печати по низу (цветные, яркие, очень похожие на печать FDA; натуральность/премиальность/безопасность). Размер как минимум как у буллитов — крупные, читабельны на телефоне. Даже одна печать — крупная. ИЕРАРХИЯ: лицо — главный и доминирующий визуальный элемент (верхние 2/3 кадра). Все текстовые блоки (HOOK исключение — сверху) уходят в нижнюю треть. Буллиты, цена, CTA НЕ перекрывают лицо и НЕ конкурируют с ним по визуальному весу — они заметно меньше и ниже.`,
|
|
107368
107478
|
headlineAngle: `HOOK: угол «персонально на “ты” + результат/облегчение». 3–5 слов, 1 строка, CAPS. Тон максимально личный и прямой.`,
|
|
107369
107479
|
bulletsFocus: `БУЛЛИТЫ: про ощущение и качество жизни, но в формате действий/результата + срок/скорость + (если уместно) цифра. Всё строго на GEO. ЗАПРЕЩЕНО: абстрактные буллиты без действия/результата/срока/цифры.`
|
|
107370
107480
|
},
|
|
107371
107481
|
{
|
|
107372
107482
|
name: 'Визуализация проблемы',
|
|
107373
|
-
prompt: `ВИЗУАЛИЗАЦИЯ ПРОБЛЕМЫ (без человека): схема/иконка проблемной зоны тела, строго соответствующей категории продукта (для суставов — колено/сустав/позвоночник; для пищеварения — желудок; для простаты — силуэт мужчины) + мягкий красный акцент на этой зоне (не шок‑контент, без графики). Рядом продукт как решение. Можно добавить простую стрелку/переход “проблема → облегчение” как графику (без лишнего текста). Чистый фон, высокая читабельность. Опционально: 1–3 trust
|
|
107483
|
+
prompt: `ВИЗУАЛИЗАЦИЯ ПРОБЛЕМЫ (без человека): схема/иконка проблемной зоны тела, строго соответствующей категории продукта (для суставов — колено/сустав/позвоночник; для пищеварения — желудок; для простаты — силуэт мужчины) + мягкий красный акцент на этой зоне (не шок‑контент, без графики). Рядом продукт как решение. Можно добавить простую стрелку/переход “проблема → облегчение” как графику (без лишнего текста). Чистый фон, высокая читабельность. Опционально: 1–3 trust‑печати по низу (цветные, яркие, очень похожие на печать FDA; натуральность/премиальность/безопасность). Размер как минимум как у буллитов — крупные, читабельны на телефоне. Даже одна печать — крупная. БЕЗ человека.`,
|
|
107374
107484
|
headlineAngle: `HOOK: прямой вопрос о боли/дискомфорте (релевантно категории). 3–5 слов, 1 строка, CAPS, вопросительный знак допустим.`,
|
|
107375
107485
|
bulletsFocus: `БУЛЛИТЫ: механика/результат в активной форме + срок/скорость + конкретика. Без диагнозов и гарантий. Всё строго на GEO. ЗАПРЕЩЕНО: абстрактные буллиты без действия/результата/срока/цифры.`
|
|
107376
107486
|
},
|
|
107377
107487
|
{
|
|
107378
107488
|
name: 'Power / Сила решения',
|
|
107379
|
-
prompt: `POWER / СИЛА РЕШЕНИЯ (без человека): метафоры силы и победы над проблемой: щит, молния, энергия, взрыв‑бёрст, мощные стикеры/иконки. Продукт как “герой” в центре, высокая энергия, контрастные агрессивные цвета. Можно комикс/anti‑design подачу, но всё должно быть читабельно. Без лишнего текста. Опционально: 1–3 trust
|
|
107489
|
+
prompt: `POWER / СИЛА РЕШЕНИЯ (без человека): метафоры силы и победы над проблемой: щит, молния, энергия, взрыв‑бёрст, мощные стикеры/иконки. Продукт как “герой” в центре, высокая энергия, контрастные агрессивные цвета. Можно комикс/anti‑design подачу, но всё должно быть читабельно. Без лишнего текста. Опционально: 1–3 trust‑печати по низу (цветные, яркие, очень похожие на печать FDA; натуральность/премиальность/безопасность). Размер как минимум как у буллитов — крупные, читабельны на телефоне. Даже одна печать — крупная. БЕЗ человека. Только продукт + power‑иконки.`,
|
|
107380
107490
|
headlineAngle: `HOOK: угол «было → стало / победа над проблемой». Можно использовать стрелку “→” как часть перехода. 3–5 слов, 1 строка, CAPS.`,
|
|
107381
107491
|
bulletsFocus: `БУЛЛИТЫ: активные глаголы + скорость/срок + конкретика + (если уместно) цифра. Без гарантий. Всё строго на GEO. ЗАПРЕЩЕНО: абстрактные буллиты без действия/результата/срока/цифры.`
|
|
107382
107492
|
},
|
|
107383
107493
|
{
|
|
107384
107494
|
name: 'Минимализм / Clean Big Text',
|
|
107385
|
-
prompt: `МИНИМАЛИЗМ / CLEAN BIG TEXT (без человека): белый или мягкий градиентный фон, премиальное ощущение. ОГРОМНЫЙ HOOK как главный элемент (CAPS, жирный, на контрастной плашке). Продукт крупно, минимум реквизита, минимум шума. Тени/премиальные материалы допустимы, но без лишнего текста. БЕЗ человека. Urgency и trust
|
|
107495
|
+
prompt: `МИНИМАЛИЗМ / CLEAN BIG TEXT (без человека): белый или мягкий градиентный фон, премиальное ощущение. ОГРОМНЫЙ HOOK как главный элемент (CAPS, жирный, на контрастной плашке). Продукт крупно, минимум реквизита, минимум шума. Тени/премиальные материалы допустимы, но без лишнего текста. БЕЗ человека. Urgency и trust‑печати в этом подходе НЕ рекомендуются — они нарушают чистоту и ощущение премиальности. Добавляй печати только если это критически необходимо, не более 1, но крупную — размер как у буллитов.`,
|
|
107386
107496
|
headlineAngle: `HOOK: одна максимально простая сильная фраза (коротко и ясно), 3–5 слов, 1 строка, CAPS.`,
|
|
107387
107497
|
bulletsFocus: `БУЛЛИТЫ: максимально коротко, но конкретно: действие + срок/скорость + цифра/доказательство (если уместно). Никаких абстрактных буллитов без конкретики. Всё строго на GEO.`
|
|
107388
107498
|
},
|
|
@@ -107399,7 +107509,7 @@ const CREO_APPROACHES = [
|
|
|
107399
107509
|
- CTA: контрастная яркая кнопка
|
|
107400
107510
|
|
|
107401
107511
|
Цель: считывание за 1 секунду. Минимум текста, максимум визуального удара.
|
|
107402
|
-
БЕЗ человека. Никаких trust
|
|
107512
|
+
БЕЗ человека. Никаких trust‑печатей/urgency бейджей — только HOOK + PRICE + -50% + CTA.`,
|
|
107403
107513
|
headlineAngle: `HOOK: «ПРОЩАЙ/КОНЕЦ/СТОП + [проблема]!». Эмоция победы/избавления. 3–4 слова, CAPS.`,
|
|
107404
107514
|
bulletsFocus: `БУЛЛИТЫ: ЗАПРЕЩЕНЫ. Вся информация — в HOOK и крупных надписях.`
|
|
107405
107515
|
},
|
|
@@ -107414,7 +107524,7 @@ const CREO_APPROACHES = [
|
|
|
107414
107524
|
- Элементы выглядят «вырезанными и приклеенными»: неровные края, отсутствие выравнивания по сетке
|
|
107415
107525
|
- Крупные текстовые надписи рядом с продуктом: цена, скидка; допустимо одно короткое слово-восклицание («РАБОТАЕТ!», «ПРОВЕРЕНО!») на языке GEO
|
|
107416
107526
|
- Кнопка CTA: плоская, без градиентов, контрастный сплошной цвет
|
|
107417
|
-
- НИКАКИХ буллитов,
|
|
107527
|
+
- НИКАКИХ буллитов, trust‑печатей, urgency‑бейджей, иконок — только продукт и текст`,
|
|
107418
107528
|
headlineAngle: `HOOK: максимально прямолинейный — короткий, грубый, без украшений. 3–4 слова, CAPS, как объявление на столбе. Никакого маркетингового лоска, никаких абстрактных слоганов.`,
|
|
107419
107529
|
bulletsFocus: `БУЛЛИТЫ: ЗАПРЕЩЕНЫ. Всё — в HOOK и крупных надписях вокруг продукта (цена, скидка, одно слово-восклицание).`
|
|
107420
107530
|
}
|