docs-combiner 0.1.18 → 0.1.19
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/main.js +181 -6
- package/dist/preload.js +2 -0
- package/dist/renderer.js +699 -176
- package/dist/renderer.js.map +1 -1
- package/package.json +1 -1
package/dist/renderer.js
CHANGED
|
@@ -101114,8 +101114,8 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
101114
101114
|
/* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_19__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/CircularProgress/CircularProgress.js");
|
|
101115
101115
|
/* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_20__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/Alert/Alert.js");
|
|
101116
101116
|
/* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_21__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/Divider/Divider.js");
|
|
101117
|
-
/* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_22__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/
|
|
101118
|
-
/* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_23__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/
|
|
101117
|
+
/* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_22__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/InputAdornment/InputAdornment.js");
|
|
101118
|
+
/* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_23__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/Button/Button.js");
|
|
101119
101119
|
/* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_24__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/FormControlLabel/FormControlLabel.js");
|
|
101120
101120
|
/* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_25__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/Checkbox/Checkbox.js");
|
|
101121
101121
|
/* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_26__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/FormControl/FormControl.js");
|
|
@@ -101157,9 +101157,11 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
101157
101157
|
/* harmony import */ var _PromptManagerDialog__WEBPACK_IMPORTED_MODULE_62__ = __webpack_require__(/*! ./PromptManagerDialog */ "./src/PromptManagerDialog.tsx");
|
|
101158
101158
|
/* harmony import */ var _promptOverrides__WEBPACK_IMPORTED_MODULE_63__ = __webpack_require__(/*! ./promptOverrides */ "./src/promptOverrides.ts");
|
|
101159
101159
|
/* harmony import */ var _appSettingsBundle__WEBPACK_IMPORTED_MODULE_64__ = __webpack_require__(/*! ./appSettingsBundle */ "./src/appSettingsBundle.ts");
|
|
101160
|
-
/* harmony import */ var
|
|
101161
|
-
/* harmony import */ var
|
|
101162
|
-
/* harmony import */ var
|
|
101160
|
+
/* harmony import */ var _flexcardBalance__WEBPACK_IMPORTED_MODULE_65__ = __webpack_require__(/*! ./flexcardBalance */ "./src/flexcardBalance.ts");
|
|
101161
|
+
/* harmony import */ var xlsx__WEBPACK_IMPORTED_MODULE_66__ = __webpack_require__(/*! xlsx */ "./node_modules/xlsx/xlsx.mjs");
|
|
101162
|
+
/* harmony import */ var jszip__WEBPACK_IMPORTED_MODULE_67__ = __webpack_require__(/*! jszip */ "./node_modules/jszip/dist/jszip.min.js");
|
|
101163
|
+
/* harmony import */ var jszip__WEBPACK_IMPORTED_MODULE_67___default = /*#__PURE__*/__webpack_require__.n(jszip__WEBPACK_IMPORTED_MODULE_67__);
|
|
101164
|
+
|
|
101163
101165
|
|
|
101164
101166
|
|
|
101165
101167
|
|
|
@@ -101313,19 +101315,51 @@ function extractChatCompletionText(choice) {
|
|
|
101313
101315
|
if (!msg)
|
|
101314
101316
|
return '';
|
|
101315
101317
|
const c = msg.content;
|
|
101316
|
-
|
|
101317
|
-
|
|
101318
|
-
|
|
101319
|
-
|
|
101318
|
+
let fromContent = '';
|
|
101319
|
+
if (typeof c === 'string') {
|
|
101320
|
+
fromContent = c;
|
|
101321
|
+
}
|
|
101322
|
+
else if (Array.isArray(c)) {
|
|
101323
|
+
fromContent = c
|
|
101320
101324
|
.map((part) => (typeof part === 'string' ? part : part?.text ?? part?.content ?? ''))
|
|
101321
101325
|
.filter(Boolean)
|
|
101322
101326
|
.join('');
|
|
101323
101327
|
}
|
|
101324
|
-
if (c != null && typeof c === 'object' && typeof c.text === 'string') {
|
|
101325
|
-
|
|
101328
|
+
else if (c != null && typeof c === 'object' && typeof c.text === 'string') {
|
|
101329
|
+
fromContent = c.text;
|
|
101330
|
+
}
|
|
101331
|
+
if (fromContent.trim())
|
|
101332
|
+
return fromContent;
|
|
101333
|
+
// Часть моделей (reasoning) кладёт текст в reasoning/refusal — иначе «Полный ответ» пустой.
|
|
101334
|
+
const reasoning = msg.reasoning;
|
|
101335
|
+
if (typeof reasoning === 'string' && reasoning.trim())
|
|
101336
|
+
return reasoning;
|
|
101337
|
+
if (Array.isArray(reasoning)) {
|
|
101338
|
+
const r = reasoning
|
|
101339
|
+
.map((p) => (typeof p === 'string' ? p : p?.text ?? ''))
|
|
101340
|
+
.filter(Boolean)
|
|
101341
|
+
.join('\n');
|
|
101342
|
+
if (r.trim())
|
|
101343
|
+
return r;
|
|
101326
101344
|
}
|
|
101345
|
+
const refusal = msg.refusal;
|
|
101346
|
+
if (typeof refusal === 'string' && refusal.trim())
|
|
101347
|
+
return refusal;
|
|
101327
101348
|
return '';
|
|
101328
101349
|
}
|
|
101350
|
+
/** Сырой JSON, если в message не извлекли ни одной буквы — иначе «Полный ответ» = пусто и UI показывает лишь подсказку из checkErrors. */
|
|
101351
|
+
const VALIDATOR_RESULT_RAW_JSON_MAX = 48_000;
|
|
101352
|
+
function buildValidatorStoredResultText(content, data) {
|
|
101353
|
+
if (content.trim().length > 0) {
|
|
101354
|
+
return content;
|
|
101355
|
+
}
|
|
101356
|
+
const raw = JSON.stringify(data ?? {}, null, 2);
|
|
101357
|
+
const pre = 'Текст ответа модели не извлечён из message.content (проверьте reasoning/формат в JSON ниже). Ответ API:\n\n';
|
|
101358
|
+
if (raw.length <= VALIDATOR_RESULT_RAW_JSON_MAX) {
|
|
101359
|
+
return pre + raw;
|
|
101360
|
+
}
|
|
101361
|
+
return `${pre}${raw.slice(0, VALIDATOR_RESULT_RAW_JSON_MAX)}…\n[обрезано по ${VALIDATOR_RESULT_RAW_JSON_MAX} симв.]`;
|
|
101362
|
+
}
|
|
101329
101363
|
/** Обрыв ответа по лимиту токенов (OpenRouter / OpenAI-совместимый completion). */
|
|
101330
101364
|
function isCompletionTruncatedByTokenLimit(choice) {
|
|
101331
101365
|
if (!choice)
|
|
@@ -101426,7 +101460,8 @@ function isValidationNegationLine(s) {
|
|
|
101426
101460
|
const t = normalizeValidationErrorText(s).toLowerCase();
|
|
101427
101461
|
if (!t)
|
|
101428
101462
|
return true;
|
|
101429
|
-
|
|
101463
|
+
const tBare = t.replace(/\.+$/g, '').trim();
|
|
101464
|
+
if (tBare === 'нет')
|
|
101430
101465
|
return true;
|
|
101431
101466
|
if (t.includes('нет ошибок') || t.includes('ошибок нет'))
|
|
101432
101467
|
return true;
|
|
@@ -101513,6 +101548,17 @@ function extractLeadingPriceNumber(value) {
|
|
|
101513
101548
|
return m[1].replace(',', '.');
|
|
101514
101549
|
return '99';
|
|
101515
101550
|
}
|
|
101551
|
+
/** Крео подходит под «Загрузить правильные» — как зелёная подпись «Проверка пройдена»: статус ok и реальная проверка (не «отключена»). Список checkErrors при ok не используем: парсер иногда оставляет ложные строки вроде «нет.». */
|
|
101552
|
+
function isCreoPassedValidatorForDriveUpload(img) {
|
|
101553
|
+
return img.checkStatus === 'ok' && img.checkResult !== 'Проверка отключена';
|
|
101554
|
+
}
|
|
101555
|
+
/** Автозагрузка на Drive только после реального OK валидатора (не при отключённой проверке). */
|
|
101556
|
+
function shouldUploadCreoAfterValidatorOk(uploadAfterValidatorOk, validationDisabled, validationResult) {
|
|
101557
|
+
return (uploadAfterValidatorOk &&
|
|
101558
|
+
!validationDisabled &&
|
|
101559
|
+
validationResult.status === 'ok' &&
|
|
101560
|
+
validationResult.result !== 'Проверка отключена');
|
|
101561
|
+
}
|
|
101516
101562
|
/** Фон карточки крео: после 1-й переделки — светло-жёлтый, далее темнеет с каждой следующей. */
|
|
101517
101563
|
function getRemakeHighlightBackground(remakeCount, dark) {
|
|
101518
101564
|
if (remakeCount <= 0)
|
|
@@ -101616,6 +101662,13 @@ function App() {
|
|
|
101616
101662
|
const [openRouterAccountBalance, setOpenRouterAccountBalance] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(null);
|
|
101617
101663
|
const [openRouterBalanceLoading, setOpenRouterBalanceLoading] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(false);
|
|
101618
101664
|
const fetchBalanceRef = react__WEBPACK_IMPORTED_MODULE_0___default().useRef(null);
|
|
101665
|
+
const [flexcardApiKey, setFlexcardApiKey] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)('');
|
|
101666
|
+
/** Сумма USD по всем строкам `GET /api/v1/finance/accounts/`; null — ошибка / нет данных */
|
|
101667
|
+
const [flexCardUsdTotal, setFlexCardUsdTotal] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(null);
|
|
101668
|
+
const [flexCardBalanceLoading, setFlexCardBalanceLoading] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(false);
|
|
101669
|
+
const [telegramBotToken, setTelegramBotToken] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)('');
|
|
101670
|
+
const [telegramChatId, setTelegramChatId] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)('');
|
|
101671
|
+
const [telegramTestSending, setTelegramTestSending] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(false);
|
|
101619
101672
|
const [generateProduct, setGenerateProduct] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)('');
|
|
101620
101673
|
const [generateGeo, setGenerateGeo] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)('');
|
|
101621
101674
|
const [generateAdditionalInfo, setGenerateAdditionalInfo] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)('');
|
|
@@ -101678,6 +101731,14 @@ function App() {
|
|
|
101678
101731
|
return false;
|
|
101679
101732
|
}
|
|
101680
101733
|
});
|
|
101734
|
+
const [uploadAfterValidatorOk, setUploadAfterValidatorOk] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(() => {
|
|
101735
|
+
try {
|
|
101736
|
+
return localStorage.getItem('uploadAfterValidatorOk') === 'true';
|
|
101737
|
+
}
|
|
101738
|
+
catch {
|
|
101739
|
+
return false;
|
|
101740
|
+
}
|
|
101741
|
+
});
|
|
101681
101742
|
const [imageAspectRatio, setImageAspectRatio] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(() => {
|
|
101682
101743
|
const saved = localStorage.getItem('imageAspectRatio');
|
|
101683
101744
|
// Migrate legacy values (4:5, 9:16) to 2:3
|
|
@@ -101737,6 +101798,7 @@ function App() {
|
|
|
101737
101798
|
'rub': 'RUB',
|
|
101738
101799
|
'forint': 'HUF',
|
|
101739
101800
|
'forints': 'HUF',
|
|
101801
|
+
'ft': 'HUF', // Hungarian forint (e.g. "11 400 Ft")
|
|
101740
101802
|
'huf': 'HUF',
|
|
101741
101803
|
'zloty': 'PLN',
|
|
101742
101804
|
'zlotys': 'PLN',
|
|
@@ -101751,6 +101813,7 @@ function App() {
|
|
|
101751
101813
|
'krone': 'DKK',
|
|
101752
101814
|
'kroner': 'DKK',
|
|
101753
101815
|
'dkk': 'DKK',
|
|
101816
|
+
'kč': 'CZK',
|
|
101754
101817
|
'koruna': 'CZK',
|
|
101755
101818
|
'koruny': 'CZK',
|
|
101756
101819
|
'czk': 'CZK',
|
|
@@ -101876,6 +101939,14 @@ function App() {
|
|
|
101876
101939
|
const [generatingImages, setGeneratingImages] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(false);
|
|
101877
101940
|
const [imagesGenerationLogs, setImagesGenerationLogs] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)([]);
|
|
101878
101941
|
const [generatedImagesData, setGeneratedImagesData] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)([]);
|
|
101942
|
+
const { pendingDriveUploadCreos, pendingValidatorOkDriveUploadCreos } = react__WEBPACK_IMPORTED_MODULE_0___default().useMemo(() => {
|
|
101943
|
+
const pending = generatedImagesData.filter(img => !img.uploaded && img.imageUrl);
|
|
101944
|
+
return {
|
|
101945
|
+
pendingDriveUploadCreos: pending,
|
|
101946
|
+
pendingValidatorOkDriveUploadCreos: pending.filter(isCreoPassedValidatorForDriveUpload)
|
|
101947
|
+
};
|
|
101948
|
+
}, [generatedImagesData]);
|
|
101949
|
+
const creoAutoUploadAfterValidatorOkRef = react__WEBPACK_IMPORTED_MODULE_0___default().useRef(async () => { });
|
|
101879
101950
|
const [checkingImages, setCheckingImages] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(false);
|
|
101880
101951
|
const [uploadingImages, setUploadingImages] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(false);
|
|
101881
101952
|
/** Индекс крео, для которого идёт удаление файла с Drive (кнопка «Удалить с Диска»). */
|
|
@@ -102098,6 +102169,13 @@ function App() {
|
|
|
102098
102169
|
setOpenaiApiKey(config.openaiApiKey);
|
|
102099
102170
|
// Balance will be fetched automatically by useEffect when openaiApiKey changes
|
|
102100
102171
|
}
|
|
102172
|
+
if (config.flexcardApiKey) {
|
|
102173
|
+
setFlexcardApiKey(String(config.flexcardApiKey));
|
|
102174
|
+
}
|
|
102175
|
+
if (config.telegramBotToken)
|
|
102176
|
+
setTelegramBotToken(String(config.telegramBotToken));
|
|
102177
|
+
if (config.telegramChatId)
|
|
102178
|
+
setTelegramChatId(String(config.telegramChatId));
|
|
102101
102179
|
if (config.secretUnlockPassed === true) {
|
|
102102
102180
|
setUnlocked(true);
|
|
102103
102181
|
try {
|
|
@@ -102413,6 +102491,25 @@ function App() {
|
|
|
102413
102491
|
return () => clearInterval(intervalId);
|
|
102414
102492
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
102415
102493
|
}, [openaiApiKey]);
|
|
102494
|
+
// FlexCard: баланс при ключе, каждые 10 минут и при открытии диалога резервной копии
|
|
102495
|
+
(0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => {
|
|
102496
|
+
if (!flexcardApiKey.trim()) {
|
|
102497
|
+
setFlexCardUsdTotal(null);
|
|
102498
|
+
return;
|
|
102499
|
+
}
|
|
102500
|
+
void fetchFlexCardBalance();
|
|
102501
|
+
const intervalId = setInterval(() => {
|
|
102502
|
+
void fetchFlexCardBalance();
|
|
102503
|
+
}, 600000);
|
|
102504
|
+
return () => clearInterval(intervalId);
|
|
102505
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
102506
|
+
}, [flexcardApiKey]);
|
|
102507
|
+
(0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => {
|
|
102508
|
+
if (!settingsBackupDialogOpen || !flexcardApiKey.trim())
|
|
102509
|
+
return;
|
|
102510
|
+
void fetchFlexCardBalance();
|
|
102511
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
102512
|
+
}, [settingsBackupDialogOpen]);
|
|
102416
102513
|
// Fetch image models when API key changes
|
|
102417
102514
|
(0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => {
|
|
102418
102515
|
if (!openaiApiKey) {
|
|
@@ -102702,7 +102799,7 @@ function App() {
|
|
|
102702
102799
|
clearTimeout(pollTimeoutId);
|
|
102703
102800
|
};
|
|
102704
102801
|
}, [driveFolderUrl, accessToken, refreshToken]);
|
|
102705
|
-
const saveConfig = async (newClientId, newClientSecret, newAccessToken, newRefreshToken, newOpenaiApiKey) => {
|
|
102802
|
+
const saveConfig = async (newClientId, newClientSecret, newAccessToken, newRefreshToken, newOpenaiApiKey, newFlexcardApiKey, newTelegramBotToken, newTelegramChatId) => {
|
|
102706
102803
|
try {
|
|
102707
102804
|
const api = getElectronAPI();
|
|
102708
102805
|
if (api) {
|
|
@@ -102713,7 +102810,10 @@ function App() {
|
|
|
102713
102810
|
clientSecret: newClientSecret ?? clientSecret,
|
|
102714
102811
|
accessToken: newAccessToken ?? accessToken,
|
|
102715
102812
|
refreshToken: newRefreshToken ?? refreshToken,
|
|
102716
|
-
openaiApiKey: newOpenaiApiKey ?? openaiApiKey
|
|
102813
|
+
openaiApiKey: newOpenaiApiKey ?? openaiApiKey,
|
|
102814
|
+
flexcardApiKey: newFlexcardApiKey ?? flexcardApiKey,
|
|
102815
|
+
telegramBotToken: newTelegramBotToken ?? telegramBotToken,
|
|
102816
|
+
telegramChatId: newTelegramChatId ?? telegramChatId,
|
|
102717
102817
|
});
|
|
102718
102818
|
}
|
|
102719
102819
|
}
|
|
@@ -102946,6 +103046,15 @@ function App() {
|
|
|
102946
103046
|
/* ignore */
|
|
102947
103047
|
}
|
|
102948
103048
|
};
|
|
103049
|
+
const handleUploadAfterValidatorOkChange = (checked) => {
|
|
103050
|
+
setUploadAfterValidatorOk(checked);
|
|
103051
|
+
try {
|
|
103052
|
+
localStorage.setItem('uploadAfterValidatorOk', String(checked));
|
|
103053
|
+
}
|
|
103054
|
+
catch {
|
|
103055
|
+
/* ignore */
|
|
103056
|
+
}
|
|
103057
|
+
};
|
|
102949
103058
|
// Fetch OpenRouter account balance and key limit
|
|
102950
103059
|
const fetchOpenRouterBalance = async (apiKey) => {
|
|
102951
103060
|
const keyToUse = apiKey ?? openaiApiKey;
|
|
@@ -103131,6 +103240,73 @@ function App() {
|
|
|
103131
103240
|
fetchBalanceRef.current = fetchPromise;
|
|
103132
103241
|
await fetchPromise;
|
|
103133
103242
|
};
|
|
103243
|
+
const fetchFlexCardBalance = async (apiKey) => {
|
|
103244
|
+
const keyToUse = (apiKey ?? flexcardApiKey).trim();
|
|
103245
|
+
if (!keyToUse) {
|
|
103246
|
+
setFlexCardUsdTotal(null);
|
|
103247
|
+
return;
|
|
103248
|
+
}
|
|
103249
|
+
setFlexCardBalanceLoading(true);
|
|
103250
|
+
try {
|
|
103251
|
+
const total = await (0,_flexcardBalance__WEBPACK_IMPORTED_MODULE_65__.fetchFlexCardFinanceAccountsUsdTotal)(keyToUse);
|
|
103252
|
+
setFlexCardUsdTotal(total);
|
|
103253
|
+
if (total === null) {
|
|
103254
|
+
logToTerminal('warn', '⚠️ FlexCard: не удалось загрузить finance/accounts (ключ или права API).');
|
|
103255
|
+
}
|
|
103256
|
+
}
|
|
103257
|
+
catch (e) {
|
|
103258
|
+
setFlexCardUsdTotal(null);
|
|
103259
|
+
logToTerminal('error', '❌ FlexCard:', e instanceof Error ? e.message : String(e));
|
|
103260
|
+
}
|
|
103261
|
+
finally {
|
|
103262
|
+
setFlexCardBalanceLoading(false);
|
|
103263
|
+
}
|
|
103264
|
+
};
|
|
103265
|
+
const handleFlexcardApiKeyChange = (val) => {
|
|
103266
|
+
setFlexcardApiKey(val);
|
|
103267
|
+
saveConfig(undefined, undefined, undefined, undefined, undefined, val);
|
|
103268
|
+
if (val.trim()) {
|
|
103269
|
+
void fetchFlexCardBalance(val);
|
|
103270
|
+
}
|
|
103271
|
+
else {
|
|
103272
|
+
setFlexCardUsdTotal(null);
|
|
103273
|
+
}
|
|
103274
|
+
};
|
|
103275
|
+
const handleTelegramBotTokenChange = (val) => {
|
|
103276
|
+
setTelegramBotToken(val);
|
|
103277
|
+
saveConfig(undefined, undefined, undefined, undefined, undefined, undefined, val, undefined);
|
|
103278
|
+
};
|
|
103279
|
+
const handleTelegramChatIdChange = (val) => {
|
|
103280
|
+
setTelegramChatId(val);
|
|
103281
|
+
saveConfig(undefined, undefined, undefined, undefined, undefined, undefined, undefined, val);
|
|
103282
|
+
};
|
|
103283
|
+
const handleTelegramTestSend = async () => {
|
|
103284
|
+
const api = getElectronAPI();
|
|
103285
|
+
if (!api?.telegramSendTest) {
|
|
103286
|
+
alert('Отправка теста доступна в приложении Electron.');
|
|
103287
|
+
return;
|
|
103288
|
+
}
|
|
103289
|
+
const token = telegramBotToken.trim();
|
|
103290
|
+
const chat = telegramChatId.trim();
|
|
103291
|
+
if (!token || !chat) {
|
|
103292
|
+
alert('Укажите токен бота и ID чата.');
|
|
103293
|
+
return;
|
|
103294
|
+
}
|
|
103295
|
+
setTelegramTestSending(true);
|
|
103296
|
+
try {
|
|
103297
|
+
const r = await api.telegramSendTest(token, chat);
|
|
103298
|
+
if (r.ok)
|
|
103299
|
+
alert('Сообщение отправлено.');
|
|
103300
|
+
else
|
|
103301
|
+
alert(r.error || 'Ошибка отправки.');
|
|
103302
|
+
}
|
|
103303
|
+
catch (e) {
|
|
103304
|
+
alert(e instanceof Error ? e.message : String(e));
|
|
103305
|
+
}
|
|
103306
|
+
finally {
|
|
103307
|
+
setTelegramTestSending(false);
|
|
103308
|
+
}
|
|
103309
|
+
};
|
|
103134
103310
|
// Fetch available image generation models from OpenRouter
|
|
103135
103311
|
const fetchImageModels = async (apiKey) => {
|
|
103136
103312
|
const keyToUse = apiKey ?? openaiApiKey;
|
|
@@ -103189,14 +103365,6 @@ function App() {
|
|
|
103189
103365
|
name: model.name || model.id
|
|
103190
103366
|
}))
|
|
103191
103367
|
.sort((a, b) => a.name.localeCompare(b.name));
|
|
103192
|
-
// Debug: log raw structure of a few representative models
|
|
103193
|
-
const debugModels = (data.data || []).filter((m) => m.id?.includes('flux') || m.id?.includes('riverflow') || m.id?.includes('gemini')).slice(0, 6);
|
|
103194
|
-
if (debugModels.length > 0) {
|
|
103195
|
-
logToTerminal('log', '🔬 Image model raw structures (flux/riverflow/gemini sample):');
|
|
103196
|
-
debugModels.forEach((m) => {
|
|
103197
|
-
logToTerminal('log', ` ${m.id} → architecture=${JSON.stringify(m.architecture)}, modalities=${JSON.stringify(m.modalities)}`);
|
|
103198
|
-
});
|
|
103199
|
-
}
|
|
103200
103368
|
logToTerminal('log', `✅ Found ${imageGenModels.length} image generation models`);
|
|
103201
103369
|
setImageModels(imageGenModels);
|
|
103202
103370
|
// Если выбранной модели нет в списке API — сброс на дефолт (отдельно для 1:1 и 2:3)
|
|
@@ -103766,6 +103934,20 @@ function App() {
|
|
|
103766
103934
|
});
|
|
103767
103935
|
return result;
|
|
103768
103936
|
};
|
|
103937
|
+
/** Уведомление в Telegram, если в настройках заданы токен и chat id (только Electron). */
|
|
103938
|
+
const sendTelegramNotification = async (text) => {
|
|
103939
|
+
const api = getElectronAPI();
|
|
103940
|
+
const token = telegramBotToken.trim();
|
|
103941
|
+
const chat = telegramChatId.trim();
|
|
103942
|
+
if (!api?.telegramSendMessage || !token || !chat)
|
|
103943
|
+
return;
|
|
103944
|
+
try {
|
|
103945
|
+
await api.telegramSendMessage(token, chat, text);
|
|
103946
|
+
}
|
|
103947
|
+
catch {
|
|
103948
|
+
/* ignore */
|
|
103949
|
+
}
|
|
103950
|
+
};
|
|
103769
103951
|
/**
|
|
103770
103952
|
* Переводит массив сгенерированных пар на русский одним запросом.
|
|
103771
103953
|
* При ошибке выставляется pairTranslationFailed (кнопка «Запросить перевод»).
|
|
@@ -103830,6 +104012,7 @@ function App() {
|
|
|
103830
104012
|
setPairTranslations(translations);
|
|
103831
104013
|
setPairTranslationFailed(false);
|
|
103832
104014
|
logToTerminal('log', '[Translate RU] OK, пар переведено:', parsed.length);
|
|
104015
|
+
void sendTelegramNotification('Docs Combiner: тексты сгенерированы, перевод на русский выполнен.');
|
|
103833
104016
|
}
|
|
103834
104017
|
catch {
|
|
103835
104018
|
logToTerminal('warn', '[Translate RU] Ошибка запроса или разбора — см. консоль / лог');
|
|
@@ -104397,7 +104580,7 @@ function App() {
|
|
|
104397
104580
|
const oldStr = Number.isFinite(oldNum)
|
|
104398
104581
|
? (Number.isInteger(oldNum) ? String(oldNum) : (Math.round(oldNum * 100) / 100).toString().replace(/\.?0+$/, ''))
|
|
104399
104582
|
: '';
|
|
104400
|
-
priceBriefForValidation = `Новая цена по брифу (после скидки -50%): ${briefPrice} ${briefCurrency}${currencySymbol ? `, символ валюты: ${currencySymbol}` : ''}. ${Number.isFinite(oldNum) ? `Ожидаемая старая цена до скидки: ${oldStr} ${briefCurrency} (2× новой).` : 'Старая цена на макете должна быть в 2 раза больше новой.'} Любые другие суммы — ошибка «не совпадает с
|
|
104583
|
+
priceBriefForValidation = `Новая цена по брифу (после скидки -50%): ${briefPrice} ${briefCurrency}${currencySymbol ? `, символ валюты: ${currencySymbol}` : ''}. ${Number.isFinite(oldNum) ? `Ожидаемая старая цена до скидки: ${oldStr} ${briefCurrency} (2× новой).` : 'Старая цена на макете должна быть в 2 раза больше новой.'} Любые другие суммы — ошибка «не совпадает с брифом». На макете в зоне цен должна быть **именно эта валюта** (${briefCurrency}${currencySymbol ? ` или эквивалентный символ ${currencySymbol}` : ''}); иная валюта или её сокращения (например лв/BGN при EUR) — ошибка валидатора, нужна пересборка.`;
|
|
104401
104584
|
logMsg('log', `💶 Эталон цен для валидации: новая ${briefPrice} ${briefCurrency}${oldStr ? `, старая ${oldStr}` : ''}`);
|
|
104402
104585
|
}
|
|
104403
104586
|
else {
|
|
@@ -104601,7 +104784,7 @@ function App() {
|
|
|
104601
104784
|
: status === 'needs_rebuild'
|
|
104602
104785
|
? (snippet
|
|
104603
104786
|
? [`Валидатор не выписал строки «ОШИБКА:». Фрагмент ответа: ${snippet}`]
|
|
104604
|
-
: ['Валидатор
|
|
104787
|
+
: ['Валидатор требует пересборки, а строки «ОШИБКА:» не разобрали. Сырой ответ/JSON — в «Полном ответе валидатора» под карточкой; при пустом контенте модели смотрите и лог.'])
|
|
104605
104788
|
: [];
|
|
104606
104789
|
if (truncatedByLimit) {
|
|
104607
104790
|
const truncationMsg = 'ОШИБКА: ответ валидатора обрезан по лимиту токенов (OpenRouter/провайдер вернули неполный текст — обычно finish_reason=length). Повторите проверку или выберите модель без тяжёлого reasoning.';
|
|
@@ -104618,7 +104801,7 @@ function App() {
|
|
|
104618
104801
|
}
|
|
104619
104802
|
return {
|
|
104620
104803
|
status,
|
|
104621
|
-
result: content,
|
|
104804
|
+
result: buildValidatorStoredResultText(content, data),
|
|
104622
104805
|
errors: finalErrors
|
|
104623
104806
|
};
|
|
104624
104807
|
};
|
|
@@ -104913,7 +105096,7 @@ function App() {
|
|
|
104913
105096
|
addLog(formatLogMessage(level, ...args));
|
|
104914
105097
|
};
|
|
104915
105098
|
logMsg('log', '📦 Creating ZIP archive with HTML and product image...');
|
|
104916
|
-
const zip = new (
|
|
105099
|
+
const zip = new (jszip__WEBPACK_IMPORTED_MODULE_67___default())();
|
|
104917
105100
|
// Replace product image path in HTML to match actual filename (png/jpg/webp)
|
|
104918
105101
|
const htmlWithProductPath = htmlContent.replace(/src=["']product\.(png|jpe?g|webp)["']/gi, `src="${productImageName}"`);
|
|
104919
105102
|
zip.file('index.html', htmlWithProductPath);
|
|
@@ -105309,16 +105492,104 @@ function App() {
|
|
|
105309
105492
|
}));
|
|
105310
105493
|
setGeneratedImagesData(initialPlaceholders);
|
|
105311
105494
|
addLog(formatLogMessage('log', `📝 Generated prompts for ${tasks.length} images${useBoth ? ' (1:1 + 2:3 на каждый подход)' : ''}`));
|
|
105312
|
-
const maxParallel =
|
|
105495
|
+
const maxParallel = 12;
|
|
105313
105496
|
addLog(formatLogMessage('log', `🚀 Generating ${tasks.length} images in parallel (up to ${maxParallel} at a time)...`));
|
|
105314
105497
|
const generationStartTime = Date.now();
|
|
105315
105498
|
const resultsMap = new Map();
|
|
105499
|
+
const validationTasks = [];
|
|
105316
105500
|
// Ensure each slot has prompt+product reference from the start (needed for regeneration even on failures)
|
|
105317
105501
|
setGeneratedImagesData(prev => prev.map((img, i) => ({
|
|
105318
105502
|
...img,
|
|
105319
105503
|
originalPrompt: img.originalPrompt || imagePrompts[i],
|
|
105320
105504
|
productImageUrl: img.productImageUrl || productImage.url
|
|
105321
105505
|
})));
|
|
105506
|
+
const runValidationForGeneratedImage = async (imageIndex, imageUrl, prompt, approachName, approachLabel, ratio) => {
|
|
105507
|
+
const validationResult = validationDisabled
|
|
105508
|
+
? { status: 'ok', result: 'Проверка отключена', errors: [], checkFailed: false }
|
|
105509
|
+
: await (async () => {
|
|
105510
|
+
try {
|
|
105511
|
+
const res = await validateCreativeImage(imageUrl, generateProduct, generateGeo, addLog, approachName, productImage.url);
|
|
105512
|
+
if (!res)
|
|
105513
|
+
throw new Error('No validation result');
|
|
105514
|
+
return { ...res, checkFailed: false };
|
|
105515
|
+
}
|
|
105516
|
+
catch (validationErr) {
|
|
105517
|
+
const msg = validationErr?.message || String(validationErr);
|
|
105518
|
+
addLog(formatLogMessage('error', `❌ Ошибка проверки изображения ${imageIndex}: ${msg}`));
|
|
105519
|
+
return {
|
|
105520
|
+
status: 'needs_rebuild',
|
|
105521
|
+
result: `Ошибка проверки: ${msg}`,
|
|
105522
|
+
errors: [msg],
|
|
105523
|
+
checkFailed: true
|
|
105524
|
+
};
|
|
105525
|
+
}
|
|
105526
|
+
})();
|
|
105527
|
+
let scheduleValidatorAutoRemake = false;
|
|
105528
|
+
const formattedValidationErrors = formatValidationErrorsForRegeneratePrompt(validationResult.errors);
|
|
105529
|
+
const validatorTransportRemake = validationResult.checkFailed === true;
|
|
105530
|
+
(0,react_dom__WEBPACK_IMPORTED_MODULE_1__.flushSync)(() => {
|
|
105531
|
+
setGeneratedImagesData(prev => {
|
|
105532
|
+
const cur = prev.find(i => i.index === imageIndex);
|
|
105533
|
+
const useAuto = shouldAutoRemakeAfterValidation(autoRemakeOnValidatorError, validationDisabled, validationResult, imageUrl, cur?.validatorTransportAutoRemakeDone);
|
|
105534
|
+
scheduleValidatorAutoRemake = useAuto;
|
|
105535
|
+
return prev.map(img => img.index === imageIndex
|
|
105536
|
+
? {
|
|
105537
|
+
...img,
|
|
105538
|
+
checking: false,
|
|
105539
|
+
checkFailed: validationResult.checkFailed ?? false,
|
|
105540
|
+
checkStatus: validationResult.status,
|
|
105541
|
+
checkResult: validationResult.result,
|
|
105542
|
+
checkErrors: validationResult.errors,
|
|
105543
|
+
customRegeneratePrompt: useAuto && validatorTransportRemake
|
|
105544
|
+
? ''
|
|
105545
|
+
: formattedValidationErrors,
|
|
105546
|
+
originalPrompt: img.originalPrompt || prompt,
|
|
105547
|
+
productImageUrl: img.productImageUrl || productImage.url,
|
|
105548
|
+
validatorTransportAutoRemakeDone: useAuto
|
|
105549
|
+
? true
|
|
105550
|
+
: (img.validatorTransportAutoRemakeDone ?? false)
|
|
105551
|
+
}
|
|
105552
|
+
: img);
|
|
105553
|
+
});
|
|
105554
|
+
});
|
|
105555
|
+
let verified;
|
|
105556
|
+
if (scheduleValidatorAutoRemake) {
|
|
105557
|
+
addLog(formatLogMessage('log', `🔄 Автопеределка с нуля изображения ${imageIndex} после ошибки валидатора (один раз)...`));
|
|
105558
|
+
const fr = await handleRegenerateImageFresh({
|
|
105559
|
+
index: imageIndex,
|
|
105560
|
+
approach: approachLabel,
|
|
105561
|
+
aspectRatio: ratio,
|
|
105562
|
+
originalPrompt: prompt,
|
|
105563
|
+
productImageUrl: productImage.url,
|
|
105564
|
+
creoApproachUiNumber: tasks[imageIndex - 1].poolIndex + 1,
|
|
105565
|
+
}, { fromAutoValidatorRemake: true });
|
|
105566
|
+
verified = fr?.verified === true;
|
|
105567
|
+
}
|
|
105568
|
+
else {
|
|
105569
|
+
verified = validationDisabled || validationResult.status === 'ok';
|
|
105570
|
+
if (shouldUploadCreoAfterValidatorOk(uploadAfterValidatorOk, validationDisabled, validationResult)) {
|
|
105571
|
+
const taskMeta = tasks[imageIndex - 1];
|
|
105572
|
+
if (taskMeta && folderId) {
|
|
105573
|
+
await creoAutoUploadAfterValidatorOkRef.current({
|
|
105574
|
+
imageData: {
|
|
105575
|
+
index: imageIndex,
|
|
105576
|
+
imageUrl,
|
|
105577
|
+
approach: approachLabel,
|
|
105578
|
+
creoApproachUiNumber: taskMeta.poolIndex + 1,
|
|
105579
|
+
aspectRatio: ratio,
|
|
105580
|
+
},
|
|
105581
|
+
folderId,
|
|
105582
|
+
validationResult,
|
|
105583
|
+
});
|
|
105584
|
+
}
|
|
105585
|
+
}
|
|
105586
|
+
}
|
|
105587
|
+
const existingResult = resultsMap.get(imageIndex);
|
|
105588
|
+
if (existingResult) {
|
|
105589
|
+
resultsMap.set(imageIndex, { ...existingResult, verified });
|
|
105590
|
+
}
|
|
105591
|
+
return { index: imageIndex, verified };
|
|
105592
|
+
};
|
|
105322
105593
|
const runOne = async (i, isRetry) => {
|
|
105323
105594
|
const imageIndex = i + 1;
|
|
105324
105595
|
const task = tasks[i];
|
|
@@ -105362,70 +105633,14 @@ function App() {
|
|
|
105362
105633
|
}
|
|
105363
105634
|
: img));
|
|
105364
105635
|
addLog(formatLogMessage('log', `✅ Изображение ${imageIndex}/${tasks.length} сгенерировано`));
|
|
105365
|
-
// Validate right after generation (skip if validation disabled)
|
|
105366
|
-
const validationResult = validationDisabled
|
|
105367
|
-
? { status: 'ok', result: 'Проверка отключена', errors: [], checkFailed: false }
|
|
105368
|
-
: await (async () => {
|
|
105369
|
-
try {
|
|
105370
|
-
const res = await validateCreativeImage(imageUrl, generateProduct, generateGeo, addLog, approachName, productImage.url);
|
|
105371
|
-
if (!res)
|
|
105372
|
-
throw new Error('No validation result');
|
|
105373
|
-
return { ...res, checkFailed: false };
|
|
105374
|
-
}
|
|
105375
|
-
catch (validationErr) {
|
|
105376
|
-
const msg = validationErr?.message || String(validationErr);
|
|
105377
|
-
addLog(formatLogMessage('error', `❌ Ошибка проверки изображения ${imageIndex}: ${msg}`));
|
|
105378
|
-
return {
|
|
105379
|
-
status: 'needs_rebuild',
|
|
105380
|
-
result: `Ошибка проверки: ${msg}`,
|
|
105381
|
-
errors: [msg],
|
|
105382
|
-
checkFailed: true
|
|
105383
|
-
};
|
|
105384
|
-
}
|
|
105385
|
-
})();
|
|
105386
105636
|
const approachLabel = approachName + (useBoth ? ` (${ratio})` : '');
|
|
105387
|
-
|
|
105388
|
-
|
|
105389
|
-
const validatorTransportRemake = validationResult.checkFailed === true;
|
|
105390
|
-
(0,react_dom__WEBPACK_IMPORTED_MODULE_1__.flushSync)(() => {
|
|
105391
|
-
setGeneratedImagesData(prev => {
|
|
105392
|
-
const cur = prev.find(i => i.index === imageIndex);
|
|
105393
|
-
const useAuto = shouldAutoRemakeAfterValidation(autoRemakeOnValidatorError, validationDisabled, validationResult, imageUrl, cur?.validatorTransportAutoRemakeDone);
|
|
105394
|
-
scheduleValidatorAutoRemake = useAuto;
|
|
105395
|
-
return prev.map(img => img.index === imageIndex
|
|
105396
|
-
? {
|
|
105397
|
-
...img,
|
|
105398
|
-
checking: false,
|
|
105399
|
-
checkFailed: validationResult.checkFailed ?? false,
|
|
105400
|
-
checkStatus: validationResult.status,
|
|
105401
|
-
checkResult: validationResult.result,
|
|
105402
|
-
checkErrors: validationResult.errors,
|
|
105403
|
-
customRegeneratePrompt: useAuto && validatorTransportRemake
|
|
105404
|
-
? ''
|
|
105405
|
-
: formattedValidationErrors,
|
|
105406
|
-
originalPrompt: img.originalPrompt || prompt,
|
|
105407
|
-
productImageUrl: img.productImageUrl || productImage.url,
|
|
105408
|
-
validatorTransportAutoRemakeDone: useAuto
|
|
105409
|
-
? true
|
|
105410
|
-
: (img.validatorTransportAutoRemakeDone ?? false)
|
|
105411
|
-
}
|
|
105412
|
-
: img);
|
|
105413
|
-
});
|
|
105414
|
-
});
|
|
105415
|
-
if (scheduleValidatorAutoRemake) {
|
|
105416
|
-
addLog(formatLogMessage('log', `🔄 Автопеределка с нуля изображения ${imageIndex} после ошибки валидатора (один раз)...`));
|
|
105417
|
-
await handleRegenerateImageFresh({
|
|
105418
|
-
index: imageIndex,
|
|
105419
|
-
approach: approachLabel,
|
|
105420
|
-
aspectRatio: ratio,
|
|
105421
|
-
originalPrompt: prompt,
|
|
105422
|
-
productImageUrl: productImage.url,
|
|
105423
|
-
}, { fromAutoValidatorRemake: true });
|
|
105424
|
-
}
|
|
105637
|
+
setCheckingImages(!validationDisabled);
|
|
105638
|
+
validationTasks.push(runValidationForGeneratedImage(imageIndex, imageUrl, prompt, approachName, approachLabel, ratio));
|
|
105425
105639
|
return {
|
|
105426
105640
|
index: imageIndex,
|
|
105427
105641
|
imageUrl,
|
|
105428
105642
|
success: true,
|
|
105643
|
+
verified: validationDisabled,
|
|
105429
105644
|
approach: approachName,
|
|
105430
105645
|
originalPrompt: prompt,
|
|
105431
105646
|
productImageUrl: productImage.url
|
|
@@ -105449,6 +105664,7 @@ function App() {
|
|
|
105449
105664
|
index: imageIndex,
|
|
105450
105665
|
imageUrl: null,
|
|
105451
105666
|
success: false,
|
|
105667
|
+
verified: false,
|
|
105452
105668
|
error: err,
|
|
105453
105669
|
approach: approachName,
|
|
105454
105670
|
originalPrompt: prompt,
|
|
@@ -105483,6 +105699,7 @@ function App() {
|
|
|
105483
105699
|
index: idx,
|
|
105484
105700
|
imageUrl: null,
|
|
105485
105701
|
success: false,
|
|
105702
|
+
verified: false,
|
|
105486
105703
|
error: new Error('Generation did not complete'),
|
|
105487
105704
|
approach: tasks[i]?.approach.name || 'Unknown',
|
|
105488
105705
|
originalPrompt: imagePrompts[i],
|
|
@@ -105538,6 +105755,24 @@ function App() {
|
|
|
105538
105755
|
await Promise.all(retryWorkers);
|
|
105539
105756
|
generationResults = Array.from(resultsMap.values()).sort((a, b) => a.index - b.index);
|
|
105540
105757
|
}
|
|
105758
|
+
if (validationTasks.length > 0) {
|
|
105759
|
+
addLog(formatLogMessage('log', `🔍 Ожидание проверок: ${validationTasks.length} задач(и)...`));
|
|
105760
|
+
const validationResults = await Promise.all(validationTasks.map(task => task.catch((err) => {
|
|
105761
|
+
const msg = err?.message || String(err);
|
|
105762
|
+
addLog(formatLogMessage('error', `❌ Ошибка задачи проверки: ${msg}`));
|
|
105763
|
+
return { index: -1, verified: false };
|
|
105764
|
+
})));
|
|
105765
|
+
validationResults.forEach(result => {
|
|
105766
|
+
if (result.index < 0)
|
|
105767
|
+
return;
|
|
105768
|
+
const existingResult = resultsMap.get(result.index);
|
|
105769
|
+
if (existingResult) {
|
|
105770
|
+
resultsMap.set(result.index, { ...existingResult, verified: result.verified });
|
|
105771
|
+
}
|
|
105772
|
+
});
|
|
105773
|
+
generationResults = Array.from(resultsMap.values()).sort((a, b) => a.index - b.index);
|
|
105774
|
+
setCheckingImages(false);
|
|
105775
|
+
}
|
|
105541
105776
|
const generationDuration = Date.now() - generationStartTime;
|
|
105542
105777
|
const successfulImages = generationResults.filter(r => r.success);
|
|
105543
105778
|
const finalFailedImages = generationResults.filter(r => !r.success);
|
|
@@ -105552,6 +105787,10 @@ function App() {
|
|
|
105552
105787
|
addLog(formatLogMessage('log', `🎉 === Image generation process completed ===`));
|
|
105553
105788
|
addLog(formatLogMessage('log', `⏱️ Total time: ${overallDuration}ms (${(overallDuration / 1000).toFixed(2)}s)`));
|
|
105554
105789
|
addLog(formatLogMessage('log', `✅ Successfully generated ${successfulImages.length}/${imagePrompts.length} images`));
|
|
105790
|
+
if (imagePrompts.length > 0 &&
|
|
105791
|
+
generationResults.every(r => r.success && r.verified)) {
|
|
105792
|
+
void sendTelegramNotification('Docs Combiner: все изображения сгенерированы и проверены.');
|
|
105793
|
+
}
|
|
105555
105794
|
// Stop generating state to hide backdrop and show images
|
|
105556
105795
|
setGeneratingImages(false);
|
|
105557
105796
|
setCheckingImages(false);
|
|
@@ -105565,10 +105804,12 @@ function App() {
|
|
|
105565
105804
|
}
|
|
105566
105805
|
finally {
|
|
105567
105806
|
setGeneratingImages(false);
|
|
105807
|
+
setCheckingImages(false);
|
|
105568
105808
|
}
|
|
105569
105809
|
}
|
|
105570
105810
|
catch (err) {
|
|
105571
105811
|
setGeneratingImages(false);
|
|
105812
|
+
setCheckingImages(false);
|
|
105572
105813
|
logToTerminal('error', '❌ Error:', err?.message || err);
|
|
105573
105814
|
}
|
|
105574
105815
|
};
|
|
@@ -105763,16 +106004,30 @@ ${imageData.originalPrompt}
|
|
|
105763
106004
|
// Run validation on the new image (skip if disabled)
|
|
105764
106005
|
let validationResult;
|
|
105765
106006
|
if (validationDisabled) {
|
|
105766
|
-
validationResult = { status: 'ok', result: 'Проверка отключена', errors: [] };
|
|
106007
|
+
validationResult = { status: 'ok', result: 'Проверка отключена', errors: [], checkFailed: false };
|
|
105767
106008
|
}
|
|
105768
106009
|
else {
|
|
105769
106010
|
addLog(formatLogMessage('log', `🔍 Проверка переделанного изображения ${imageData.index}...`));
|
|
105770
|
-
|
|
106011
|
+
try {
|
|
106012
|
+
const res = await validateCreativeImage(newImageUrl, generateProduct, generateGeo, addLog, imageData.approach, imageData.productImageUrl);
|
|
106013
|
+
validationResult = { ...res, checkFailed: false };
|
|
106014
|
+
}
|
|
106015
|
+
catch (validationErr) {
|
|
106016
|
+
const msg = validationErr?.message || String(validationErr);
|
|
106017
|
+
addLog(formatLogMessage('error', `❌ Ошибка проверки переделанного изображения ${imageData.index}: ${msg}`));
|
|
106018
|
+
validationResult = {
|
|
106019
|
+
status: 'needs_rebuild',
|
|
106020
|
+
result: `Ошибка проверки: ${msg}`,
|
|
106021
|
+
errors: [msg],
|
|
106022
|
+
checkFailed: true,
|
|
106023
|
+
};
|
|
106024
|
+
}
|
|
105771
106025
|
}
|
|
105772
106026
|
// Update with validation result (+ одна автопеределка при needs_rebuild с замечаниями, если включено)
|
|
105773
106027
|
const outcomeForAuto = {
|
|
105774
106028
|
status: validationResult.status,
|
|
105775
106029
|
errors: validationResult.errors,
|
|
106030
|
+
checkFailed: validationResult.checkFailed,
|
|
105776
106031
|
};
|
|
105777
106032
|
const formattedRegenErrors = formatValidationErrorsForRegeneratePrompt(validationResult.errors);
|
|
105778
106033
|
const regenTransportRemake = outcomeForAuto.checkFailed === true;
|
|
@@ -105786,6 +106041,7 @@ ${imageData.originalPrompt}
|
|
|
105786
106041
|
? {
|
|
105787
106042
|
...img,
|
|
105788
106043
|
checking: false,
|
|
106044
|
+
checkFailed: validationResult.checkFailed ?? false,
|
|
105789
106045
|
checkStatus: validationResult.status,
|
|
105790
106046
|
checkResult: validationResult.result,
|
|
105791
106047
|
checkErrors: validationResult.errors,
|
|
@@ -105807,8 +106063,26 @@ ${imageData.originalPrompt}
|
|
|
105807
106063
|
aspectRatio: imageData.aspectRatio,
|
|
105808
106064
|
originalPrompt: imageData.originalPrompt,
|
|
105809
106065
|
productImageUrl: imageData.productImageUrl,
|
|
106066
|
+
creoApproachUiNumber: currentImageData?.creoApproachUiNumber,
|
|
105810
106067
|
}, { fromAutoValidatorRemake: true });
|
|
105811
106068
|
}
|
|
106069
|
+
if (!scheduleAfterRegenValidation &&
|
|
106070
|
+
shouldUploadCreoAfterValidatorOk(uploadAfterValidatorOk, validationDisabled, validationResult)) {
|
|
106071
|
+
const creoNum = currentImageData?.creoApproachUiNumber ??
|
|
106072
|
+
generatedImagesData.find(img => img.index === imageData.index)?.creoApproachUiNumber ??
|
|
106073
|
+
1;
|
|
106074
|
+
await creoAutoUploadAfterValidatorOkRef.current({
|
|
106075
|
+
imageData: {
|
|
106076
|
+
index: imageData.index,
|
|
106077
|
+
imageUrl: updatedImageUrl,
|
|
106078
|
+
approach: imageData.approach,
|
|
106079
|
+
creoApproachUiNumber: creoNum,
|
|
106080
|
+
aspectRatio: imageData.aspectRatio,
|
|
106081
|
+
},
|
|
106082
|
+
folderId: regenFolderId,
|
|
106083
|
+
validationResult,
|
|
106084
|
+
});
|
|
106085
|
+
}
|
|
105812
106086
|
const statusEmoji = validationResult.status === 'ok' ? '✅' : '❌';
|
|
105813
106087
|
addLog(formatLogMessage('log', `${statusEmoji} Переделанное изображение ${imageData.index}: ${validationResult.status === 'ok' ? 'OK' : 'НУЖНА ПЕРЕСБОРКА'}`));
|
|
105814
106088
|
if (validationResult.errors.length > 0) {
|
|
@@ -105841,12 +106115,12 @@ ${imageData.originalPrompt}
|
|
|
105841
106115
|
const handleRegenerateImageFresh = async (imageData, opts) => {
|
|
105842
106116
|
if (!imageData.originalPrompt || !imageData.productImageUrl) {
|
|
105843
106117
|
alert('Не удалось найти оригинальный промпт или изображение продукта для переделки');
|
|
105844
|
-
return;
|
|
106118
|
+
return { verified: false };
|
|
105845
106119
|
}
|
|
105846
106120
|
const freshFolderId = extractFolderId(driveFolderUrl);
|
|
105847
106121
|
if (!freshFolderId) {
|
|
105848
106122
|
alert('Укажите корректный URL папки оффера на Google Drive');
|
|
105849
|
-
return;
|
|
106123
|
+
return { verified: false };
|
|
105850
106124
|
}
|
|
105851
106125
|
const addLog = (msg) => {
|
|
105852
106126
|
setImagesGenerationLogs(prev => [...prev, msg]);
|
|
@@ -105856,12 +106130,12 @@ ${imageData.originalPrompt}
|
|
|
105856
106130
|
const freshTok = await getValidAccessToken();
|
|
105857
106131
|
if (!freshTok) {
|
|
105858
106132
|
alert('Please log in with Google first');
|
|
105859
|
-
return;
|
|
106133
|
+
return { verified: false };
|
|
105860
106134
|
}
|
|
105861
106135
|
const freshPub = await verifyOfferFolderHasAnyoneLinkForImageGen(freshTok, freshFolderId);
|
|
105862
106136
|
if (!freshPub.ok) {
|
|
105863
106137
|
alert(freshPub.message);
|
|
105864
|
-
return;
|
|
106138
|
+
return { verified: false };
|
|
105865
106139
|
}
|
|
105866
106140
|
// Mark as regenerating (show overlay timer) - clear old image URL immediately to force re-render
|
|
105867
106141
|
setGeneratedImagesData(prev => prev.map(img => img.index === imageData.index
|
|
@@ -105919,15 +106193,29 @@ ${imageData.originalPrompt}
|
|
|
105919
106193
|
// Validate new image (skip if disabled)
|
|
105920
106194
|
let validationResult;
|
|
105921
106195
|
if (validationDisabled) {
|
|
105922
|
-
validationResult = { status: 'ok', result: 'Проверка отключена', errors: [] };
|
|
106196
|
+
validationResult = { status: 'ok', result: 'Проверка отключена', errors: [], checkFailed: false };
|
|
105923
106197
|
}
|
|
105924
106198
|
else {
|
|
105925
106199
|
addLog(formatLogMessage('log', `🔍 Проверка изображения ${imageData.index} (с нуля)...`));
|
|
105926
|
-
|
|
106200
|
+
try {
|
|
106201
|
+
const res = await validateCreativeImage(newImageUrl, generateProduct, generateGeo, addLog, imageData.approach, imageData.productImageUrl);
|
|
106202
|
+
validationResult = { ...res, checkFailed: false };
|
|
106203
|
+
}
|
|
106204
|
+
catch (validationErr) {
|
|
106205
|
+
const msg = validationErr?.message || String(validationErr);
|
|
106206
|
+
addLog(formatLogMessage('error', `❌ Ошибка проверки изображения ${imageData.index} (с нуля): ${msg}`));
|
|
106207
|
+
validationResult = {
|
|
106208
|
+
status: 'needs_rebuild',
|
|
106209
|
+
result: `Ошибка проверки: ${msg}`,
|
|
106210
|
+
errors: [msg],
|
|
106211
|
+
checkFailed: true,
|
|
106212
|
+
};
|
|
106213
|
+
}
|
|
105927
106214
|
}
|
|
105928
106215
|
const outcomeFresh = {
|
|
105929
106216
|
status: validationResult.status,
|
|
105930
106217
|
errors: validationResult.errors,
|
|
106218
|
+
checkFailed: validationResult.checkFailed,
|
|
105931
106219
|
};
|
|
105932
106220
|
const formattedFreshErrors = formatValidationErrorsForRegeneratePrompt(validationResult.errors);
|
|
105933
106221
|
const freshTransportRemake = outcomeFresh.checkFailed === true;
|
|
@@ -105941,6 +106229,7 @@ ${imageData.originalPrompt}
|
|
|
105941
106229
|
? {
|
|
105942
106230
|
...img,
|
|
105943
106231
|
checking: false,
|
|
106232
|
+
checkFailed: validationResult.checkFailed ?? false,
|
|
105944
106233
|
checkStatus: validationResult.status,
|
|
105945
106234
|
checkResult: validationResult.result,
|
|
105946
106235
|
checkErrors: validationResult.errors,
|
|
@@ -105956,14 +106245,34 @@ ${imageData.originalPrompt}
|
|
|
105956
106245
|
});
|
|
105957
106246
|
if (scheduleAfterFreshValidation && imageData.originalPrompt && imageData.productImageUrl) {
|
|
105958
106247
|
addLog(formatLogMessage('log', `🔄 Автопеределка с нуля изображения ${imageData.index} после ошибки валидатора (один раз)...`));
|
|
105959
|
-
await handleRegenerateImageFresh({
|
|
106248
|
+
return await handleRegenerateImageFresh({
|
|
105960
106249
|
index: imageData.index,
|
|
105961
106250
|
approach: imageData.approach,
|
|
105962
106251
|
aspectRatio: imageData.aspectRatio,
|
|
105963
106252
|
originalPrompt: imageData.originalPrompt,
|
|
105964
106253
|
productImageUrl: imageData.productImageUrl,
|
|
106254
|
+
creoApproachUiNumber: imageData.creoApproachUiNumber,
|
|
105965
106255
|
}, { fromAutoValidatorRemake: true });
|
|
105966
106256
|
}
|
|
106257
|
+
const creoApproachUiNumberFresh = imageData.creoApproachUiNumber ??
|
|
106258
|
+
generatedImagesData.find(img => img.index === imageData.index)?.creoApproachUiNumber ??
|
|
106259
|
+
1;
|
|
106260
|
+
if (shouldUploadCreoAfterValidatorOk(uploadAfterValidatorOk, validationDisabled, validationResult)) {
|
|
106261
|
+
await creoAutoUploadAfterValidatorOkRef.current({
|
|
106262
|
+
imageData: {
|
|
106263
|
+
index: imageData.index,
|
|
106264
|
+
imageUrl: updatedImageUrl,
|
|
106265
|
+
approach: imageData.approach,
|
|
106266
|
+
creoApproachUiNumber: creoApproachUiNumberFresh,
|
|
106267
|
+
aspectRatio: imageData.aspectRatio,
|
|
106268
|
+
},
|
|
106269
|
+
folderId: freshFolderId,
|
|
106270
|
+
validationResult,
|
|
106271
|
+
});
|
|
106272
|
+
}
|
|
106273
|
+
return {
|
|
106274
|
+
verified: validationDisabled || validationResult.status === 'ok',
|
|
106275
|
+
};
|
|
105967
106276
|
}
|
|
105968
106277
|
catch (err) {
|
|
105969
106278
|
addLog(formatLogMessage('error', `❌ Ошибка при переделке заново изображения ${imageData.index}: ${err.message}`));
|
|
@@ -105980,6 +106289,7 @@ ${imageData.originalPrompt}
|
|
|
105980
106289
|
}
|
|
105981
106290
|
: img));
|
|
105982
106291
|
alert('Ошибка при переделке заново: ' + err.message);
|
|
106292
|
+
return { verified: false };
|
|
105983
106293
|
}
|
|
105984
106294
|
};
|
|
105985
106295
|
const handleRetryCheck = async (imageData) => {
|
|
@@ -106049,6 +106359,8 @@ ${imageData.originalPrompt}
|
|
|
106049
106359
|
aspectRatio: imageData.aspectRatio,
|
|
106050
106360
|
originalPrompt: imageData.originalPrompt,
|
|
106051
106361
|
productImageUrl: imageData.productImageUrl,
|
|
106362
|
+
creoApproachUiNumber: imageData.creoApproachUiNumber ??
|
|
106363
|
+
generatedImagesData.find(img => img.index === imageData.index)?.creoApproachUiNumber,
|
|
106052
106364
|
}, { fromAutoValidatorRemake: true });
|
|
106053
106365
|
}
|
|
106054
106366
|
return;
|
|
@@ -106089,8 +106401,30 @@ ${imageData.originalPrompt}
|
|
|
106089
106401
|
aspectRatio: imageData.aspectRatio,
|
|
106090
106402
|
originalPrompt: imageData.originalPrompt,
|
|
106091
106403
|
productImageUrl: imageData.productImageUrl,
|
|
106404
|
+
creoApproachUiNumber: imageData.creoApproachUiNumber ??
|
|
106405
|
+
generatedImagesData.find(img => img.index === imageData.index)?.creoApproachUiNumber,
|
|
106092
106406
|
}, { fromAutoValidatorRemake: true });
|
|
106093
106407
|
}
|
|
106408
|
+
if (!scheduleValidatorAutoRemakeRetry &&
|
|
106409
|
+
shouldUploadCreoAfterValidatorOk(uploadAfterValidatorOk, validationDisabled, validationResult)) {
|
|
106410
|
+
const retryFid = extractFolderId(driveFolderUrl);
|
|
106411
|
+
if (retryFid && imageData.imageUrl) {
|
|
106412
|
+
const creoNum = imageData.creoApproachUiNumber ??
|
|
106413
|
+
generatedImagesData.find(img => img.index === imageData.index)?.creoApproachUiNumber ??
|
|
106414
|
+
1;
|
|
106415
|
+
await creoAutoUploadAfterValidatorOkRef.current({
|
|
106416
|
+
imageData: {
|
|
106417
|
+
index: imageData.index,
|
|
106418
|
+
imageUrl: imageData.imageUrl,
|
|
106419
|
+
approach: imageData.approach,
|
|
106420
|
+
creoApproachUiNumber: creoNum,
|
|
106421
|
+
aspectRatio: imageData.aspectRatio,
|
|
106422
|
+
},
|
|
106423
|
+
folderId: retryFid,
|
|
106424
|
+
validationResult,
|
|
106425
|
+
});
|
|
106426
|
+
}
|
|
106427
|
+
}
|
|
106094
106428
|
const statusEmoji = validationResult.status === 'ok' ? '✅' : '❌';
|
|
106095
106429
|
addLog(formatLogMessage('log', `${statusEmoji} Повторная проверка изображения ${imageData.index}: ${validationResult.status === 'ok' ? 'OK' : 'НУЖНА ПЕРЕСБОРКА'}`));
|
|
106096
106430
|
};
|
|
@@ -106133,7 +106467,15 @@ ${imageData.originalPrompt}
|
|
|
106133
106467
|
: img));
|
|
106134
106468
|
}
|
|
106135
106469
|
};
|
|
106136
|
-
|
|
106470
|
+
creoAutoUploadAfterValidatorOkRef.current = async (args) => {
|
|
106471
|
+
if (!shouldUploadCreoAfterValidatorOk(uploadAfterValidatorOk, validationDisabled, args.validationResult)) {
|
|
106472
|
+
return;
|
|
106473
|
+
}
|
|
106474
|
+
if (!args.folderId?.trim() || !args.imageData.imageUrl?.trim())
|
|
106475
|
+
return;
|
|
106476
|
+
await handleUploadImage(args.imageData, args.folderId);
|
|
106477
|
+
};
|
|
106478
|
+
const handleUploadAllImages = async (opts) => {
|
|
106137
106479
|
if (!driveFolderUrl.trim()) {
|
|
106138
106480
|
alert('Please fill in Google Drive Folder URL');
|
|
106139
106481
|
return;
|
|
@@ -106143,9 +106485,11 @@ ${imageData.originalPrompt}
|
|
|
106143
106485
|
alert('Invalid Google Drive Folder URL');
|
|
106144
106486
|
return;
|
|
106145
106487
|
}
|
|
106146
|
-
const notUploaded =
|
|
106488
|
+
const notUploaded = opts?.correctOnly ? pendingValidatorOkDriveUploadCreos : pendingDriveUploadCreos;
|
|
106147
106489
|
if (notUploaded.length === 0) {
|
|
106148
|
-
alert(
|
|
106490
|
+
alert(opts?.correctOnly
|
|
106491
|
+
? 'Нет незагруженных крео с успешной проверкой валидатором (зелёная рамка, «Проверка пройдена»).'
|
|
106492
|
+
: 'All images are already uploaded');
|
|
106149
106493
|
return;
|
|
106150
106494
|
}
|
|
106151
106495
|
setUploadingImages(true);
|
|
@@ -106158,7 +106502,9 @@ ${imageData.originalPrompt}
|
|
|
106158
106502
|
? { ...img, uploading: true, uploadStartTime: Date.now() }
|
|
106159
106503
|
: img));
|
|
106160
106504
|
try {
|
|
106161
|
-
addLog(formatLogMessage('log',
|
|
106505
|
+
addLog(formatLogMessage('log', opts?.correctOnly
|
|
106506
|
+
? `📤 Uploading ${notUploaded.length} image(s) with validator OK to Drive (parallel)...`
|
|
106507
|
+
: `📤 Uploading ${notUploaded.length} image(s) to Drive (parallel)...`));
|
|
106162
106508
|
const results = await Promise.allSettled(notUploaded.map((imageData) => {
|
|
106163
106509
|
const uploadAspect = imageData.aspectRatio ?? (imageAspectRatio === '2:3' ? '2:3' : '1:1');
|
|
106164
106510
|
const filename = creativeImageUploadFilename(imageData.creoApproachUiNumber, uploadAspect);
|
|
@@ -106326,6 +106672,19 @@ ${imageData.originalPrompt}
|
|
|
106326
106672
|
alert('Не удалось прочитать буфер обмена. Разрешите доступ к буферу в браузере или вставьте ссылку вручную (Ctrl+V / Cmd+V).');
|
|
106327
106673
|
}
|
|
106328
106674
|
};
|
|
106675
|
+
const handlePasteFlexcardApiKey = async () => {
|
|
106676
|
+
try {
|
|
106677
|
+
const text = (await navigator.clipboard.readText()).trim();
|
|
106678
|
+
if (!text) {
|
|
106679
|
+
alert('Буфер обмена пуст.');
|
|
106680
|
+
return;
|
|
106681
|
+
}
|
|
106682
|
+
handleFlexcardApiKeyChange(text);
|
|
106683
|
+
}
|
|
106684
|
+
catch {
|
|
106685
|
+
alert('Не удалось прочитать буфер обмена. Разрешите доступ к буферу в браузере или вставьте ключ вручную (Ctrl+V / Cmd+V).');
|
|
106686
|
+
}
|
|
106687
|
+
};
|
|
106329
106688
|
const handleLinkPaste = (e) => {
|
|
106330
106689
|
e.preventDefault();
|
|
106331
106690
|
const pasted = e.clipboardData.getData('text/plain');
|
|
@@ -106927,8 +107286,8 @@ ${imageData.originalPrompt}
|
|
|
106927
107286
|
}
|
|
106928
107287
|
setGeneratedData(rows);
|
|
106929
107288
|
// Create workbook
|
|
106930
|
-
const wb =
|
|
106931
|
-
const ws =
|
|
107289
|
+
const wb = xlsx__WEBPACK_IMPORTED_MODULE_66__.utils.book_new();
|
|
107290
|
+
const ws = xlsx__WEBPACK_IMPORTED_MODULE_66__.utils.aoa_to_sheet(rows);
|
|
106932
107291
|
// Set column widths (approximate pixel width / 7)
|
|
106933
107292
|
ws['!cols'] = [
|
|
106934
107293
|
{ wch: 20 }, // id
|
|
@@ -106941,9 +107300,9 @@ ${imageData.originalPrompt}
|
|
|
106941
107300
|
{ wch: 40 }, // image_link
|
|
106942
107301
|
{ wch: 20 } // brand
|
|
106943
107302
|
];
|
|
106944
|
-
|
|
107303
|
+
xlsx__WEBPACK_IMPORTED_MODULE_66__.utils.book_append_sheet(wb, ws, "Products");
|
|
106945
107304
|
// Generate buffer
|
|
106946
|
-
const wbout =
|
|
107305
|
+
const wbout = xlsx__WEBPACK_IMPORTED_MODULE_66__.write(wb, { bookType: 'xlsx', type: 'array' });
|
|
106947
107306
|
// Upload to Drive (имя файла по бренду)
|
|
106948
107307
|
const dateStr = new Date().toISOString().split('T')[0];
|
|
106949
107308
|
const fileName = `${brand}-${dateStr}.xlsx`;
|
|
@@ -107073,13 +107432,13 @@ ${imageData.originalPrompt}
|
|
|
107073
107432
|
setTestLoading(true);
|
|
107074
107433
|
try {
|
|
107075
107434
|
// Create simple test workbook with structure
|
|
107076
|
-
const wb =
|
|
107435
|
+
const wb = xlsx__WEBPACK_IMPORTED_MODULE_66__.utils.book_new();
|
|
107077
107436
|
const rows = [
|
|
107078
107437
|
INSTRUCTION_ROW,
|
|
107079
107438
|
['id', 'title', 'description', 'availability', 'condition', 'price', 'link', 'image_link', 'brand'],
|
|
107080
107439
|
['test1', 'Test Title', 'Test Description', 'in stock', 'new', testPrice, 'http://test.com', 'http://test.com/img.jpg', 'TestBrand']
|
|
107081
107440
|
];
|
|
107082
|
-
const ws =
|
|
107441
|
+
const ws = xlsx__WEBPACK_IMPORTED_MODULE_66__.utils.aoa_to_sheet(rows);
|
|
107083
107442
|
// Set column widths
|
|
107084
107443
|
ws['!cols'] = [
|
|
107085
107444
|
{ wch: 20 }, // id
|
|
@@ -107092,8 +107451,8 @@ ${imageData.originalPrompt}
|
|
|
107092
107451
|
{ wch: 40 }, // image_link
|
|
107093
107452
|
{ wch: 20 } // brand
|
|
107094
107453
|
];
|
|
107095
|
-
|
|
107096
|
-
const wbout =
|
|
107454
|
+
xlsx__WEBPACK_IMPORTED_MODULE_66__.utils.book_append_sheet(wb, ws, "Test");
|
|
107455
|
+
const wbout = xlsx__WEBPACK_IMPORTED_MODULE_66__.write(wb, { bookType: 'xlsx', type: 'array' });
|
|
107097
107456
|
// Try to extract folder ID if available, otherwise upload to root
|
|
107098
107457
|
const folderId = driveFolderUrl ? extractFolderId(driveFolderUrl) : undefined;
|
|
107099
107458
|
const result = await uploadFileToDrive(wbout, 'test_table.xlsx', folderId || undefined);
|
|
@@ -107166,6 +107525,9 @@ ${imageData.originalPrompt}
|
|
|
107166
107525
|
if (g('autoRemakeOnValidatorError') !== undefined) {
|
|
107167
107526
|
setAutoRemakeOnValidatorError(g('autoRemakeOnValidatorError') === 'true');
|
|
107168
107527
|
}
|
|
107528
|
+
if (g('uploadAfterValidatorOk') !== undefined) {
|
|
107529
|
+
setUploadAfterValidatorOk(g('uploadAfterValidatorOk') === 'true');
|
|
107530
|
+
}
|
|
107169
107531
|
const ar = g('imageAspectRatio');
|
|
107170
107532
|
if (ar === '1:1' || ar === '2:3' || ar === 'both')
|
|
107171
107533
|
setImageAspectRatio(ar);
|
|
@@ -107276,6 +107638,12 @@ ${imageData.originalPrompt}
|
|
|
107276
107638
|
setClientSecret(String(ec.clientSecret));
|
|
107277
107639
|
if (ec.openaiApiKey !== undefined)
|
|
107278
107640
|
setOpenaiApiKey(String(ec.openaiApiKey));
|
|
107641
|
+
if (ec.flexcardApiKey !== undefined)
|
|
107642
|
+
setFlexcardApiKey(String(ec.flexcardApiKey));
|
|
107643
|
+
if (ec.telegramBotToken !== undefined)
|
|
107644
|
+
setTelegramBotToken(String(ec.telegramBotToken));
|
|
107645
|
+
if (ec.telegramChatId !== undefined)
|
|
107646
|
+
setTelegramChatId(String(ec.telegramChatId));
|
|
107279
107647
|
if (ec.accessToken !== undefined)
|
|
107280
107648
|
setAccessToken(String(ec.accessToken));
|
|
107281
107649
|
if (ec.refreshToken !== undefined)
|
|
@@ -107386,29 +107754,52 @@ ${imageData.originalPrompt}
|
|
|
107386
107754
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_17__["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)" }),
|
|
107387
107755
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_17__["default"], { label: "Client Secret", variant: "outlined", fullWidth: true, value: clientSecret, onChange: (e) => handleClientSecretChange(e.target.value) }),
|
|
107388
107756
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_21__["default"], null),
|
|
107389
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_17__["default"], { label: "OpenRouter API Key", variant: "outlined", fullWidth: true, value: openaiApiKey, onChange: (e) => handleOpenaiApiKeyChange(e.target.value), helperText: "Required for AI generation (images and text). Your key is stored locally. Get your key at openrouter.ai" })
|
|
107390
|
-
|
|
107391
|
-
|
|
107392
|
-
|
|
107393
|
-
|
|
107394
|
-
|
|
107395
|
-
|
|
107396
|
-
|
|
107397
|
-
|
|
107398
|
-
|
|
107757
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_17__["default"], { label: "OpenRouter API Key", variant: "outlined", fullWidth: true, value: openaiApiKey, onChange: (e) => handleOpenaiApiKeyChange(e.target.value), helperText: "Required for AI generation (images and text). Your key is stored locally. Get your key at openrouter.ai" }),
|
|
107758
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_17__["default"], { label: "FlexCard API Key", variant: "outlined", fullWidth: true, value: flexcardApiKey, onChange: (e) => handleFlexcardApiKeyChange(e.target.value), helperText: "\u041E\u043F\u0446\u0438\u043E\u043D\u0430\u043B\u044C\u043D\u043E: \u0431\u0430\u043B\u0430\u043D\u0441 \u043A\u043E\u0448\u0435\u043B\u044C\u043A\u043E\u0432 \u043D\u0430 flexcard.cards (\u0440\u0430\u0437\u0434\u0435\u043B Team \u2192 API). \u041A\u043B\u044E\u0447 \u0445\u0440\u0430\u043D\u0438\u0442\u0441\u044F \u043B\u043E\u043A\u0430\u043B\u044C\u043D\u043E \u0432 config.", InputProps: {
|
|
107759
|
+
endAdornment: (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_22__["default"], { position: "end" },
|
|
107760
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_9__["default"], { title: "\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u044C \u0438\u0437 \u0431\u0443\u0444\u0435\u0440\u0430 \u043E\u0431\u043C\u0435\u043D\u0430" },
|
|
107761
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_10__["default"], { edge: "end", "aria-label": "\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u044C \u043A\u043B\u044E\u0447 FlexCard \u0438\u0437 \u0431\u0443\u0444\u0435\u0440\u0430", onClick: () => void handlePasteFlexcardApiKey() },
|
|
107762
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_51__["default"], null))))),
|
|
107763
|
+
} }),
|
|
107764
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_13__["default"], { direction: "row", spacing: 1, alignItems: "center", sx: { flexWrap: 'nowrap', gap: 1 } },
|
|
107765
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_17__["default"], { label: "Telegram bot token", size: "small", fullWidth: true, sx: { flex: 2, minWidth: 0 }, value: telegramBotToken, onChange: (e) => handleTelegramBotTokenChange(e.target.value), placeholder: "123456789:ABC...", autoComplete: "off" }),
|
|
107766
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_17__["default"], { label: "Chat ID", size: "small", sx: { flex: 1, minWidth: 72, maxWidth: 200 }, value: telegramChatId, onChange: (e) => handleTelegramChatIdChange(e.target.value), placeholder: "-100\u2026", autoComplete: "off" }),
|
|
107767
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_23__["default"], { variant: "outlined", size: "small", disabled: telegramTestSending || !telegramBotToken.trim() || !telegramChatId.trim(), onClick: () => void handleTelegramTestSend(), sx: { flexShrink: 0, whiteSpace: 'nowrap', minWidth: 'auto' } }, telegramTestSending ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_19__["default"], { size: 18, color: "inherit" })) : ('Тест'))),
|
|
107768
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_18__["default"], { sx: { mt: 0 } }, "Telegram \u2014 \u0434\u043B\u044F \u0431\u0443\u0434\u0443\u0449\u0438\u0445 \u043E\u043F\u043E\u0432\u0435\u0449\u0435\u043D\u0438\u0439; \u0442\u0435\u0441\u0442 \u0448\u043B\u0451\u0442 \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u0435 \u0438\u0437 Electron (\u043E\u0431\u0445\u043E\u0434 CORS).")))),
|
|
107769
|
+
(openaiApiKey || flexcardApiKey.trim()) && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { sx: { display: 'flex', alignItems: 'center', gap: 2, mt: 2, flexWrap: 'wrap' } },
|
|
107770
|
+
openaiApiKey && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null,
|
|
107771
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_41__["default"], { color: openRouterAccountBalance !== null ? 'primary' : 'disabled' }),
|
|
107772
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_7__["default"], { variant: "body2", color: openRouterAccountBalance !== null ? 'text.primary' : 'text.secondary' },
|
|
107773
|
+
"OpenRouter \u2014 \u0431\u0430\u043B\u0430\u043D\u0441: ",
|
|
107774
|
+
openRouterBalanceLoading ? '…' : (openRouterAccountBalance !== null ? `$${openRouterAccountBalance.toFixed(2)}` : 'N/A')),
|
|
107775
|
+
(openRouterBalanceLoading || openRouterBalance !== -1) && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null,
|
|
107776
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_7__["default"], { variant: "body2", color: "text.secondary" }, "\u2022"),
|
|
107777
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_7__["default"], { variant: "body2", color: openRouterBalance !== null ? 'text.primary' : 'text.secondary' },
|
|
107778
|
+
"\u043B\u0438\u043C\u0438\u0442 \u043A\u043B\u044E\u0447\u0430:",
|
|
107779
|
+
' ',
|
|
107780
|
+
openRouterBalanceLoading ? '…' : openRouterBalance === null ? 'N/A' : `${openRouterBalance.toFixed(4)}`))))),
|
|
107781
|
+
openaiApiKey && flexcardApiKey.trim() && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_7__["default"], { variant: "body2", color: "text.secondary" }, "\u2022")),
|
|
107782
|
+
flexcardApiKey.trim() && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_7__["default"], { component: "span", variant: "body2", color: flexCardUsdTotal !== null ? 'text.primary' : 'text.secondary' },
|
|
107783
|
+
"flexcard",
|
|
107784
|
+
' ',
|
|
107785
|
+
flexCardBalanceLoading
|
|
107786
|
+
? '…'
|
|
107787
|
+
: flexCardUsdTotal === null
|
|
107788
|
+
? 'N/A'
|
|
107789
|
+
: `$${flexCardUsdTotal.toFixed(2)}`)))),
|
|
107399
107790
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_13__["default"], { direction: "row", spacing: 2, alignItems: "center", sx: { mt: 2 }, flexWrap: "wrap", useFlexGap: true },
|
|
107400
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
107791
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_23__["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_19__["default"], { size: 20, color: "inherit" }) : (accessToken ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_47__["default"], null) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_55__["default"], null)), sx: { flexGrow: 1, minWidth: 200 } }, authLoading ? 'Logging in...' : (accessToken ? 'Logged In' : 'Login with Google')),
|
|
107401
107792
|
authLoading && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null,
|
|
107402
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
107403
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
107404
|
-
accessToken && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
107793
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_23__["default"], { variant: "outlined", color: "primary", onClick: () => void handleReopenAuthBrowser(), startIcon: react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_58__["default"], null) }, "\u041E\u0442\u043A\u0440\u044B\u0442\u044C \u0441\u0442\u0440\u0430\u043D\u0438\u0446\u0443 \u0432\u0445\u043E\u0434\u0430 \u0441\u043D\u043E\u0432\u0430"),
|
|
107794
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_23__["default"], { variant: "outlined", color: "inherit", onClick: () => void handleCancelPendingAuth(), startIcon: react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_48__["default"], null) }, "\u041E\u0442\u043C\u0435\u043D\u0438\u0442\u044C \u0432\u0445\u043E\u0434"))),
|
|
107795
|
+
accessToken && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_23__["default"], { variant: "outlined", color: "error", onClick: handleLogout, startIcon: react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_56__["default"], null) }, "Logout")))),
|
|
107405
107796
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_21__["default"], { sx: { my: 2 } }),
|
|
107406
107797
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], null,
|
|
107407
107798
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_7__["default"], { variant: "h6", gutterBottom: true }, "Google Drive Folder"),
|
|
107408
107799
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_13__["default"], { direction: { xs: 'column', sm: 'row' }, spacing: 2 },
|
|
107409
107800
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { sx: { flexGrow: 1 } },
|
|
107410
107801
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_17__["default"], { label: "Google Drive Folder URL", variant: "outlined", fullWidth: true, value: driveFolderUrl, onChange: (e) => setDriveFolderUrl(e.target.value), placeholder: "https://drive.google.com/drive/folders/...", InputProps: {
|
|
107411
|
-
endAdornment: (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
107802
|
+
endAdornment: (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_22__["default"], { position: "end" },
|
|
107412
107803
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_9__["default"], { title: "\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u044C \u0438\u0437 \u0431\u0443\u0444\u0435\u0440\u0430 \u043E\u0431\u043C\u0435\u043D\u0430" },
|
|
107413
107804
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_10__["default"], { edge: "end", "aria-label": "\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u044C \u0441\u0441\u044B\u043B\u043A\u0443 \u043D\u0430 \u043F\u0430\u043F\u043A\u0443 \u0438\u0437 \u0431\u0443\u0444\u0435\u0440\u0430", onClick: () => void handlePasteDriveFolderUrl() },
|
|
107414
107805
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_51__["default"], null)))))
|
|
@@ -107447,7 +107838,7 @@ ${imageData.originalPrompt}
|
|
|
107447
107838
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { sx: { flex: 1, minWidth: 0 } },
|
|
107448
107839
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_17__["default"], { label: "Link", variant: "outlined", fullWidth: true, value: link, onChange: (e) => handleLinkChange(e.target.value), onBlur: handleLinkBlur, error: !!linkError, helperText: linkError, placeholder: "https://example.com/product/", inputRef: linkInputRef, InputProps: {
|
|
107449
107840
|
onPaste: handleLinkPaste,
|
|
107450
|
-
endAdornment: (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
107841
|
+
endAdornment: (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_22__["default"], { position: "end" },
|
|
107451
107842
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_9__["default"], { title: "\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u044C \u0438\u0437 \u0431\u0443\u0444\u0435\u0440\u0430 \u043E\u0431\u043C\u0435\u043D\u0430" },
|
|
107452
107843
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_10__["default"], { edge: "end", "aria-label": "\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u044C \u0441\u0441\u044B\u043B\u043A\u0443 \u043D\u0430 \u0442\u043E\u0432\u0430\u0440 \u0438\u0437 \u0431\u0443\u0444\u0435\u0440\u0430", onClick: () => void handlePasteProductLink() },
|
|
107453
107844
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_51__["default"], null)))))
|
|
@@ -107455,8 +107846,8 @@ ${imageData.originalPrompt}
|
|
|
107455
107846
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { sx: { display: 'flex', gap: 1, alignItems: 'flex-start', mt: 1.5 } },
|
|
107456
107847
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_17__["default"], { label: "\u0414\u043E\u043F. \u043C\u0430\u043A\u0440\u043E\u0441\u044B (\u043A\u0430\u0442\u0430\u043B\u043E\u0433)", variant: "outlined", size: "small", fullWidth: true, multiline: true, minRows: 2, value: catalogLinkExtraMacros, onChange: (e) => setCatalogLinkExtraMacros(e.target.value), placeholder: DEFAULT_CATALOG_LINK_EXTRA_MACROS, helperText: "\u0414\u043E\u0431\u0430\u0432\u043B\u044F\u0435\u0442\u0441\u044F \u043F\u043E\u0441\u043B\u0435 creative_id \u0438 \u043F\u0430\u0440\u0430\u043C\u0435\u0442\u0440\u043E\u0432 \u043F\u043E\u0434\u0445\u043E\u0434\u043E\u0432 (sub18, sub19, sub20 \u043F\u0440\u0438 \u0432\u043A\u043B\u044E\u0447\u0435\u043D\u0438\u0438). \u0421\u043E\u0445\u0440\u0430\u043D\u044F\u0435\u0442\u0441\u044F \u0432 JSON \u043D\u0430\u0441\u0442\u0440\u043E\u0435\u043A \u043F\u0430\u043F\u043A\u0438.", sx: { '& .MuiInputBase-input': { fontFamily: 'monospace', fontSize: 12 } } }),
|
|
107457
107848
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_13__["default"], { spacing: 0.5, sx: { flexShrink: 0, mt: 0.5 } },
|
|
107458
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
107459
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
107849
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_23__["default"], { size: "small", variant: "outlined", onClick: () => setCatalogLinkExtraMacros(DEFAULT_CATALOG_LINK_EXTRA_MACROS), sx: { textTransform: 'none', whiteSpace: 'nowrap' } }, "redtrack"),
|
|
107850
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_23__["default"], { size: "small", variant: "outlined", onClick: () => setCatalogLinkExtraMacros(DEFAULT_CATALOG_LINK_KEITARO_MACROS), sx: { textTransform: 'none', whiteSpace: 'nowrap' } }, "keitaro"))),
|
|
107460
107851
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_13__["default"], { spacing: 1.5, sx: { mt: 1 } },
|
|
107461
107852
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_13__["default"], { direction: { xs: 'column', sm: 'row' }, spacing: 2, alignItems: { xs: 'stretch', sm: 'flex-start' } },
|
|
107462
107853
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_24__["default"], { control: react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_25__["default"], { checked: catalogUrlIncludeTextApproach, onChange: e => setCatalogUrlIncludeTextApproach(e.target.checked), size: "small" }), label: react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], null,
|
|
@@ -107480,7 +107871,7 @@ ${imageData.originalPrompt}
|
|
|
107480
107871
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_13__["default"], { direction: "row", spacing: 2, sx: { mb: 2 } },
|
|
107481
107872
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_17__["default"], { label: "\u0413\u0435\u043E", variant: "outlined", fullWidth: true, value: generateGeo, onChange: (e) => setGenerateGeo(e.target.value), placeholder: "\u043D\u0430\u043F\u0440\u0438\u043C\u0435\u0440: \u0420\u0443\u043C\u044B\u043D\u0438\u044F" }),
|
|
107482
107873
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_17__["default"], { label: "\u0426\u0435\u043D\u0430 \u0438 \u0432\u0430\u043B\u044E\u0442\u0430", variant: "outlined", fullWidth: true, value: generatePriceWithCurrency, onChange: (e) => setGeneratePriceWithCurrency(e.target.value), placeholder: "\u043D\u0430\u043F\u0440\u0438\u043C\u0435\u0440: 29 euro, 11400 HUF, 149 RON \u0438\u043B\u0438 \u043B\u044E\u0431\u043E\u0439 \u0434\u0440\u0443\u0433\u043E\u0439 \u0444\u043E\u0440\u043C\u0430\u0442", helperText: "\u041B\u044E\u0431\u043E\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435 \u0434\u043B\u044F \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u043D\u0438\u044F \u0432 \u043F\u0440\u043E\u043C\u043F\u0442\u0435 \u0433\u0435\u043D\u0435\u0440\u0430\u0446\u0438\u0438 \u0438\u0437\u043E\u0431\u0440\u0430\u0436\u0435\u043D\u0438\u0439. \u041A\u043D\u043E\u043F\u043A\u0438 \u0441\u043F\u0440\u0430\u0432\u0430 \u043F\u043E\u0434\u0441\u0442\u0430\u0432\u043B\u044F\u044E\u0442 \u0441\u0438\u043C\u0432\u043E\u043B \u0432\u0430\u043B\u044E\u0442\u044B, \u0446\u0438\u0444\u0440\u0443 \u0431\u0435\u0440\u0443\u0442 \u0438\u0437 \u043F\u043E\u043B\u044F (\u0438\u043B\u0438 99).", InputProps: {
|
|
107483
|
-
endAdornment: (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
107874
|
+
endAdornment: (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_22__["default"], { position: "end" },
|
|
107484
107875
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { sx: { display: 'flex', alignItems: 'center', gap: 0.25, mr: -0.5 } },
|
|
107485
107876
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_9__["default"], { title: "\u041F\u043E\u0434\u0441\u0442\u0430\u0432\u0438\u0442\u044C $ (\u0446\u0438\u0444\u0440\u0430 \u0438\u0437 \u043F\u043E\u043B\u044F \u0438\u043B\u0438 99)" },
|
|
107486
107877
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_10__["default"], { size: "small", "aria-label": "\u0411\u044B\u0441\u0442\u0440\u043E \u0434\u043E\u043B\u043B\u0430\u0440", onClick: () => {
|
|
@@ -107505,10 +107896,10 @@ ${imageData.originalPrompt}
|
|
|
107505
107896
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_13__["default"], { direction: { xs: 'column', md: 'row' }, spacing: 2, sx: { mb: 2, alignItems: 'stretch' } },
|
|
107506
107897
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_26__["default"], { fullWidth: true, variant: "outlined", sx: { flex: { md: '1 1 0' }, minWidth: { md: 0 } } },
|
|
107507
107898
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_27__["default"], null, "\u041C\u043E\u0434\u0435\u043B\u044C \u0434\u043B\u044F \u043A\u0432\u0430\u0434\u0440\u0430\u0442\u043E\u0432 (1:1)"),
|
|
107508
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_28__["default"], { value: selectedImageModelSquare, onChange: (e) => handleImageModelSquareChange(e.target.value), label: "\u041C\u043E\u0434\u0435\u043B\u044C \u0434\u043B\u044F \u043A\u0432\u0430\u0434\u0440\u0430\u0442\u043E\u0432 (1:1)", disabled: loadingImageModels || imageModels.length === 0 }, loadingImageModels ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_29__["default"], { disabled: true },
|
|
107899
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_28__["default"], { value: imageModels.some(m => m.id === selectedImageModelSquare) ? selectedImageModelSquare : '', onChange: (e) => handleImageModelSquareChange(e.target.value), label: "\u041C\u043E\u0434\u0435\u043B\u044C \u0434\u043B\u044F \u043A\u0432\u0430\u0434\u0440\u0430\u0442\u043E\u0432 (1:1)", disabled: loadingImageModels || imageModels.length === 0 }, loadingImageModels ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_29__["default"], { value: "", disabled: true },
|
|
107509
107900
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { sx: { display: 'flex', alignItems: 'center', gap: 1 } },
|
|
107510
107901
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_19__["default"], { size: 16 }),
|
|
107511
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", null, "\u0417\u0430\u0433\u0440\u0443\u0437\u043A\u0430 \u043C\u043E\u0434\u0435\u043B\u0435\u0439...")))) : imageModels.length === 0 ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_29__["default"], { disabled: true }, "\u041D\u0435\u0442 \u0434\u043E\u0441\u0442\u0443\u043F\u043D\u044B\u0445 \u043C\u043E\u0434\u0435\u043B\u0435\u0439")) : (imageModels.map((model) => (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_29__["default"], { key: model.id, value: model.id }, model.name))))),
|
|
107902
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", null, "\u0417\u0430\u0433\u0440\u0443\u0437\u043A\u0430 \u043C\u043E\u0434\u0435\u043B\u0435\u0439...")))) : imageModels.length === 0 ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_29__["default"], { value: "", disabled: true }, "\u041D\u0435\u0442 \u0434\u043E\u0441\u0442\u0443\u043F\u043D\u044B\u0445 \u043C\u043E\u0434\u0435\u043B\u0435\u0439")) : (imageModels.map((model) => (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_29__["default"], { key: model.id, value: model.id }, model.name))))),
|
|
107512
107903
|
!loadingImageModels && imageModels.length > 0 && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_18__["default"], null, selectedImageModelSquare === _models__WEBPACK_IMPORTED_MODULE_3__.MODELS.imageGeneration
|
|
107513
107904
|
? 'По умолчанию для квадрата'
|
|
107514
107905
|
: '1:1: ' +
|
|
@@ -107516,10 +107907,10 @@ ${imageData.originalPrompt}
|
|
|
107516
107907
|
selectedImageModelSquare)))),
|
|
107517
107908
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_26__["default"], { fullWidth: true, variant: "outlined", sx: { flex: { md: '1 1 0' }, minWidth: { md: 0 } } },
|
|
107518
107909
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_27__["default"], null, "\u041C\u043E\u0434\u0435\u043B\u044C \u0434\u043B\u044F \u043F\u0440\u044F\u043C\u043E\u0443\u0433\u043E\u043B\u044C\u043D\u0438\u043A\u043E\u0432 (2:3)"),
|
|
107519
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_28__["default"], { value: selectedImageModelRect, onChange: (e) => handleImageModelRectChange(e.target.value), label: "\u041C\u043E\u0434\u0435\u043B\u044C \u0434\u043B\u044F \u043F\u0440\u044F\u043C\u043E\u0443\u0433\u043E\u043B\u044C\u043D\u0438\u043A\u043E\u0432 (2:3)", disabled: loadingImageModels || imageModels.length === 0 }, loadingImageModels ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_29__["default"], { disabled: true },
|
|
107910
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_28__["default"], { value: imageModels.some(m => m.id === selectedImageModelRect) ? selectedImageModelRect : '', onChange: (e) => handleImageModelRectChange(e.target.value), label: "\u041C\u043E\u0434\u0435\u043B\u044C \u0434\u043B\u044F \u043F\u0440\u044F\u043C\u043E\u0443\u0433\u043E\u043B\u044C\u043D\u0438\u043A\u043E\u0432 (2:3)", disabled: loadingImageModels || imageModels.length === 0 }, loadingImageModels ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_29__["default"], { value: "", disabled: true },
|
|
107520
107911
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { sx: { display: 'flex', alignItems: 'center', gap: 1 } },
|
|
107521
107912
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_19__["default"], { size: 16 }),
|
|
107522
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", null, "\u0417\u0430\u0433\u0440\u0443\u0437\u043A\u0430 \u043C\u043E\u0434\u0435\u043B\u0435\u0439...")))) : imageModels.length === 0 ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_29__["default"], { disabled: true }, "\u041D\u0435\u0442 \u0434\u043E\u0441\u0442\u0443\u043F\u043D\u044B\u0445 \u043C\u043E\u0434\u0435\u043B\u0435\u0439")) : (imageModels.map((model) => (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_29__["default"], { key: model.id, value: model.id }, model.name))))),
|
|
107913
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", null, "\u0417\u0430\u0433\u0440\u0443\u0437\u043A\u0430 \u043C\u043E\u0434\u0435\u043B\u0435\u0439...")))) : imageModels.length === 0 ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_29__["default"], { value: "", disabled: true }, "\u041D\u0435\u0442 \u0434\u043E\u0441\u0442\u0443\u043F\u043D\u044B\u0445 \u043C\u043E\u0434\u0435\u043B\u0435\u0439")) : (imageModels.map((model) => (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_29__["default"], { key: model.id, value: model.id }, model.name))))),
|
|
107523
107914
|
!loadingImageModels && imageModels.length > 0 && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_18__["default"], null, selectedImageModelRect === _models__WEBPACK_IMPORTED_MODULE_3__.MODELS.imageGeneration
|
|
107524
107915
|
? 'По умолчанию для 2:3'
|
|
107525
107916
|
: '2:3: ' +
|
|
@@ -107527,25 +107918,29 @@ ${imageData.originalPrompt}
|
|
|
107527
107918
|
selectedImageModelRect)))),
|
|
107528
107919
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_26__["default"], { fullWidth: true, variant: "outlined", sx: { flex: { md: '1 1 0' }, minWidth: { md: 0 } } },
|
|
107529
107920
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_27__["default"], null, "\u041C\u043E\u0434\u0435\u043B\u044C \u0434\u043B\u044F \u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0438 \u043A\u0440\u0435\u0430\u0442\u0438\u0432\u043E\u0432"),
|
|
107530
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_28__["default"], { value: selectedValidationModel, onChange: (e) => handleValidationModelChange(e.target.value), label: "\u041C\u043E\u0434\u0435\u043B\u044C \u0434\u043B\u044F \u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0438 \u043A\u0440\u0435\u0430\u0442\u0438\u0432\u043E\u0432", disabled: loadingValidationModels || validationModels.length === 0 }, loadingValidationModels ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_29__["default"], { disabled: true },
|
|
107921
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_28__["default"], { value: validationModels.some(m => m.id === selectedValidationModel) ? selectedValidationModel : '', onChange: (e) => handleValidationModelChange(e.target.value), label: "\u041C\u043E\u0434\u0435\u043B\u044C \u0434\u043B\u044F \u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0438 \u043A\u0440\u0435\u0430\u0442\u0438\u0432\u043E\u0432", disabled: loadingValidationModels || validationModels.length === 0 }, loadingValidationModels ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_29__["default"], { value: "", disabled: true },
|
|
107531
107922
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { sx: { display: 'flex', alignItems: 'center', gap: 1 } },
|
|
107532
107923
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_19__["default"], { size: 16 }),
|
|
107533
|
-
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_29__["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_29__["default"], { key: model.id, value: model.id }, model.name))))),
|
|
107924
|
+
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_29__["default"], { value: "", 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_29__["default"], { key: model.id, value: model.id }, model.name))))),
|
|
107534
107925
|
!loadingValidationModels && validationModels.length > 0 && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_18__["default"], null, selectedValidationModel === _models__WEBPACK_IMPORTED_MODULE_3__.MODELS.creativeValidation
|
|
107535
107926
|
? 'Используется модель по умолчанию'
|
|
107536
107927
|
: 'Выбрана модель: ' + (validationModels.find(m => m.id === selectedValidationModel)?.name || selectedValidationModel))),
|
|
107537
107928
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_24__["default"], { control: react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_25__["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 } }),
|
|
107538
107929
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_24__["default"], { control: react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_25__["default"], { checked: autoRemakeOnValidatorError, onChange: (e) => handleAutoRemakeOnValidatorErrorChange(e.target.checked), color: "primary", disabled: validationDisabled }), label: "\u0430\u0432\u0442\u043E\u043F\u0435\u0440\u0435\u0434\u0435\u043B\u043A\u0430", sx: { mt: 0.5, display: 'block' } }),
|
|
107930
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_24__["default"], { control: react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_25__["default"], { checked: uploadAfterValidatorOk, onChange: (e) => handleUploadAfterValidatorOkChange(e.target.checked), color: "primary", disabled: validationDisabled }), label: "\u0417\u0430\u0433\u0440\u0443\u0436\u0430\u0442\u044C \u043F\u043E\u0441\u043B\u0435 \u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0438", sx: { mt: 0.5, display: 'block' } }),
|
|
107539
107931
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_18__["default"], { sx: { mt: 0, mx: 0 } }, validationDisabled
|
|
107540
107932
|
? 'Недоступно, пока проверка отключена.'
|
|
107541
|
-
: 'Один раз на слот креатива: при сбое проверки (сеть, таймаут, ошибка API) или когда валидатор вернул «нужна пересборка» с замечаниями — автоматически одна полная переделка с нуля (исходный промпт + product, без правок по списку ошибок).')
|
|
107933
|
+
: 'Один раз на слот креатива: при сбое проверки (сеть, таймаут, ошибка API) или когда валидатор вернул «нужна пересборка» с замечаниями — автоматически одна полная переделка с нуля (исходный промпт + product, без правок по списку ошибок).'),
|
|
107934
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_18__["default"], { sx: { mt: 0.5, mx: 0 } }, validationDisabled
|
|
107935
|
+
? ''
|
|
107936
|
+
: '«Загружать после проверки»: при ответе валидатора OK файл сразу загружается в папку оффера на Google Drive (нужны URL папки и вход в Google).'))),
|
|
107542
107937
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_13__["default"], { direction: { xs: 'column', md: 'row' }, spacing: 2, sx: { mb: 2, alignItems: 'stretch' } },
|
|
107543
107938
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_26__["default"], { fullWidth: true, variant: "outlined", sx: { flex: { md: '1 1 0' }, minWidth: { md: 0 } } },
|
|
107544
107939
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_27__["default"], null, "\u041C\u043E\u0434\u0435\u043B\u044C \u0434\u043B\u044F \u0437\u0430\u0433\u043E\u043B\u043E\u0432\u043A\u043E\u0432 \u0438 \u0442\u0435\u043A\u0441\u0442\u043E\u0432"),
|
|
107545
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_28__["default"], { value: selectedContentModel, onChange: (e) => handleContentModelChange(e.target.value), label: "\u041C\u043E\u0434\u0435\u043B\u044C \u0434\u043B\u044F \u0437\u0430\u0433\u043E\u043B\u043E\u0432\u043A\u043E\u0432 \u0438 \u0442\u0435\u043A\u0441\u0442\u043E\u0432", disabled: loadingValidationModels || chatModels.length === 0 }, loadingValidationModels ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_29__["default"], { disabled: true },
|
|
107940
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_28__["default"], { value: chatModels.some(m => m.id === selectedContentModel) ? selectedContentModel : '', onChange: (e) => handleContentModelChange(e.target.value), label: "\u041C\u043E\u0434\u0435\u043B\u044C \u0434\u043B\u044F \u0437\u0430\u0433\u043E\u043B\u043E\u0432\u043A\u043E\u0432 \u0438 \u0442\u0435\u043A\u0441\u0442\u043E\u0432", disabled: loadingValidationModels || chatModels.length === 0 }, loadingValidationModels ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_29__["default"], { value: "", disabled: true },
|
|
107546
107941
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { sx: { display: 'flex', alignItems: 'center', gap: 1 } },
|
|
107547
107942
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_19__["default"], { size: 16 }),
|
|
107548
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", null, "\u0417\u0430\u0433\u0440\u0443\u0437\u043A\u0430 \u043C\u043E\u0434\u0435\u043B\u0435\u0439...")))) : chatModels.length === 0 ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_29__["default"], { disabled: true }, "\u041D\u0435\u0442 \u0434\u043E\u0441\u0442\u0443\u043F\u043D\u044B\u0445 \u043C\u043E\u0434\u0435\u043B\u0435\u0439")) : (chatModels.map((model) => (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_29__["default"], { key: model.id, value: model.id }, model.name))))),
|
|
107943
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", null, "\u0417\u0430\u0433\u0440\u0443\u0437\u043A\u0430 \u043C\u043E\u0434\u0435\u043B\u0435\u0439...")))) : chatModels.length === 0 ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_29__["default"], { value: "", disabled: true }, "\u041D\u0435\u0442 \u0434\u043E\u0441\u0442\u0443\u043F\u043D\u044B\u0445 \u043C\u043E\u0434\u0435\u043B\u0435\u0439")) : (chatModels.map((model) => (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_29__["default"], { key: model.id, value: model.id }, model.name))))),
|
|
107549
107944
|
!loadingValidationModels && chatModels.length > 0 && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_18__["default"], null, selectedContentModel === _models__WEBPACK_IMPORTED_MODULE_3__.MODELS.contentGeneration
|
|
107550
107945
|
? 'Заголовки, описания, пары и перевод — модель по умолчанию из кода'
|
|
107551
107946
|
: 'Заголовки и тексты: ' +
|
|
@@ -107553,17 +107948,17 @@ ${imageData.originalPrompt}
|
|
|
107553
107948
|
selectedContentModel)))),
|
|
107554
107949
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_26__["default"], { fullWidth: true, variant: "outlined", sx: { flex: { md: '1 1 0' }, minWidth: { md: 0 } } },
|
|
107555
107950
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_27__["default"], null, "\u041C\u043E\u0434\u0435\u043B\u044C \u0434\u043B\u044F \u0433\u0435\u043D\u0435\u0440\u0430\u0446\u0438\u0438 \u043B\u0435\u043D\u0434\u0438\u043D\u0433\u0430"),
|
|
107556
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_28__["default"], { value: selectedLandingModel, onChange: (e) => handleLandingModelChange(e.target.value), label: "\u041C\u043E\u0434\u0435\u043B\u044C \u0434\u043B\u044F \u0433\u0435\u043D\u0435\u0440\u0430\u0446\u0438\u0438 \u043B\u0435\u043D\u0434\u0438\u043D\u0433\u0430", disabled: loadingValidationModels || chatModels.length === 0 }, loadingValidationModels ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_29__["default"], { disabled: true },
|
|
107951
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_28__["default"], { value: chatModels.some(m => m.id === selectedLandingModel) ? selectedLandingModel : '', onChange: (e) => handleLandingModelChange(e.target.value), label: "\u041C\u043E\u0434\u0435\u043B\u044C \u0434\u043B\u044F \u0433\u0435\u043D\u0435\u0440\u0430\u0446\u0438\u0438 \u043B\u0435\u043D\u0434\u0438\u043D\u0433\u0430", disabled: loadingValidationModels || chatModels.length === 0 }, loadingValidationModels ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_29__["default"], { value: "", disabled: true },
|
|
107557
107952
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { sx: { display: 'flex', alignItems: 'center', gap: 1 } },
|
|
107558
107953
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_19__["default"], { size: 16 }),
|
|
107559
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", null, "\u0417\u0430\u0433\u0440\u0443\u0437\u043A\u0430 \u043C\u043E\u0434\u0435\u043B\u0435\u0439...")))) : chatModels.length === 0 ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_29__["default"], { disabled: true }, "\u041D\u0435\u0442 \u0434\u043E\u0441\u0442\u0443\u043F\u043D\u044B\u0445 \u043C\u043E\u0434\u0435\u043B\u0435\u0439")) : (chatModels.map((model) => (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_29__["default"], { key: model.id, value: model.id }, model.name))))),
|
|
107954
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", null, "\u0417\u0430\u0433\u0440\u0443\u0437\u043A\u0430 \u043C\u043E\u0434\u0435\u043B\u0435\u0439...")))) : chatModels.length === 0 ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_29__["default"], { value: "", disabled: true }, "\u041D\u0435\u0442 \u0434\u043E\u0441\u0442\u0443\u043F\u043D\u044B\u0445 \u043C\u043E\u0434\u0435\u043B\u0435\u0439")) : (chatModels.map((model) => (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_29__["default"], { key: model.id, value: model.id }, model.name))))),
|
|
107560
107955
|
!loadingValidationModels && chatModels.length > 0 && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_18__["default"], null, selectedLandingModel === _models__WEBPACK_IMPORTED_MODULE_3__.MODELS.landingGeneration
|
|
107561
107956
|
? 'HTML лендинга — модель по умолчанию из кода'
|
|
107562
107957
|
: 'Лендинг: ' +
|
|
107563
107958
|
(chatModels.find(m => m.id === selectedLandingModel)?.name ||
|
|
107564
107959
|
selectedLandingModel))))))),
|
|
107565
107960
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_13__["default"], { direction: "row", spacing: 2, sx: { mb: 2 } },
|
|
107566
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
107961
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_23__["default"], { variant: "contained", color: "primary", startIcon: react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_43__["default"], null), onClick: handleGenerateContent, disabled: generating || loadingContentFromDrive || !openaiApiKey || !generateProduct.trim() || !generateGeo.trim(), sx: { flexGrow: 1 }, size: "large" }, generating ? 'Generating...' : 'Generate Titles & Descriptions'),
|
|
107567
107962
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_13__["default"], { direction: "row", spacing: 1, alignItems: "center", sx: { flexGrow: 1 } },
|
|
107568
107963
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_9__["default"], { title: imageAspectRatio === '1:1'
|
|
107569
107964
|
? '1:1 — квадрат (1024×1024 px)'
|
|
@@ -107590,7 +107985,7 @@ ${imageData.originalPrompt}
|
|
|
107590
107985
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_31__["default"], { value: "1:1", sx: { px: 1.5, fontWeight: 600, fontSize: '0.8rem' } }, "1:1"),
|
|
107591
107986
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_31__["default"], { value: "2:3", sx: { px: 1.5, fontWeight: 600, fontSize: '0.8rem' } }, "2:3"),
|
|
107592
107987
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_31__["default"], { value: "both", sx: { px: 1.5, fontWeight: 600, fontSize: '0.8rem' } }, "\u041E\u0431\u0430")))),
|
|
107593
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
107988
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_23__["default"], { variant: "contained", color: "secondary", startIcon: react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_43__["default"], null), onClick: handleGenerateImages, disabled: generatingImages ||
|
|
107594
107989
|
!openaiApiKey ||
|
|
107595
107990
|
(!accessToken && !refreshToken) ||
|
|
107596
107991
|
!generateProduct.trim() ||
|
|
@@ -107608,7 +108003,7 @@ ${imageData.originalPrompt}
|
|
|
107608
108003
|
: !driveFolderUrl.trim()
|
|
107609
108004
|
? 'Заполните URL папки Google Drive'
|
|
107610
108005
|
: undefined }, generatingImages ? 'Generating Images...' : 'Generate Images')),
|
|
107611
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
108006
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_23__["default"], { variant: "contained", color: "success", size: "large", onClick: handleGenerate, disabled: loading, startIcon: loading ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_19__["default"], { size: 20, color: "inherit" }) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_49__["default"], null), sx: { py: 1.5, fontSize: '1.1rem', flexGrow: 1 } }, loading ? 'Generating...' : 'Generate Catalog'),
|
|
107612
108007
|
uploadedLink && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_20__["default"], { severity: "success", sx: { flexGrow: 1, minWidth: 0 }, action: react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_10__["default"], { "aria-label": "copy link", color: "inherit", size: "small", onClick: handleCopyLink, sx: { ml: 1 } },
|
|
107613
108008
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_50__["default"], { fontSize: "small" })) },
|
|
107614
108009
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { sx: { display: 'flex', alignItems: 'center', gap: 1, flexWrap: 'wrap' } },
|
|
@@ -107629,8 +108024,8 @@ ${imageData.originalPrompt}
|
|
|
107629
108024
|
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"))))),
|
|
107630
108025
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("input", { type: "file", ref: productFileInputRef, accept: "image/png,image/jpeg,image/jpg,image/webp", style: { display: 'none' }, onChange: handleProductFileSelected }),
|
|
107631
108026
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_13__["default"], { direction: "row", spacing: 2, sx: { mb: 2 } },
|
|
107632
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
107633
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
108027
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_23__["default"], { variant: "contained", color: "success", startIcon: uploadingProduct ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_19__["default"], { size: 20, color: "inherit" }) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_49__["default"], null), onClick: handleUploadProductFile, disabled: uploadingProduct || !accessToken || !driveFolderUrl.trim(), sx: { flexGrow: 1 }, size: "large" }, uploadingProduct ? 'Загрузка...' : 'Загрузить product.png/jpg/webp'),
|
|
108028
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_23__["default"], { variant: "contained", color: "info", startIcon: generatingLanding ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_19__["default"], { size: 20, color: "inherit" }) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_57__["default"], null), onClick: handleCreateLanding, disabled: generatingLanding ||
|
|
107634
108029
|
!openaiApiKey ||
|
|
107635
108030
|
!accessToken ||
|
|
107636
108031
|
!driveFolderUrl.trim() ||
|
|
@@ -107647,8 +108042,20 @@ ${imageData.originalPrompt}
|
|
|
107647
108042
|
checkingImages && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { sx: { display: 'flex', alignItems: 'center', gap: 1, mb: 2 } },
|
|
107648
108043
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_19__["default"], { size: 16 }),
|
|
107649
108044
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_7__["default"], { variant: "caption", sx: { color: 'text.secondary' } }, "\u041F\u0440\u043E\u0432\u0435\u0440\u043A\u0430 \u043A\u0430\u0447\u0435\u0441\u0442\u0432\u0430..."))),
|
|
107650
|
-
|
|
107651
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
108045
|
+
pendingDriveUploadCreos.length > 0 && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_13__["default"], { direction: { xs: 'column', sm: 'row' }, spacing: 1, sx: { mb: 2 }, useFlexGap: true },
|
|
108046
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_23__["default"], { variant: "contained", color: "primary", onClick: () => void handleUploadAllImages(), disabled: uploadingImages || generatingImages || !driveFolderUrl.trim(), startIcon: uploadingImages ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_19__["default"], { size: 20 }) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_49__["default"], null), fullWidth: true, sx: { flex: 1 } }, uploadingImages
|
|
108047
|
+
? 'Загрузка...'
|
|
108048
|
+
: `Загрузить все (${pendingDriveUploadCreos.length})`),
|
|
108049
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_9__["default"], { title: pendingValidatorOkDriveUploadCreos.length === 0
|
|
108050
|
+
? 'Нет незагруженных крео с успешной проверкой валидатором (ожидайте проверки или исправьте ошибки).'
|
|
108051
|
+
: 'Только крео со статусом «Проверка пройдена», как в карточке (валидатор вернул OK).' },
|
|
108052
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", { style: { flex: 1, display: 'flex' } },
|
|
108053
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_23__["default"], { variant: "contained", color: "success", onClick: () => void handleUploadAllImages({ correctOnly: true }), disabled: uploadingImages ||
|
|
108054
|
+
generatingImages ||
|
|
108055
|
+
!driveFolderUrl.trim() ||
|
|
108056
|
+
pendingValidatorOkDriveUploadCreos.length === 0, startIcon: uploadingImages ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_19__["default"], { size: 20 }) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_47__["default"], null), fullWidth: true, sx: { flex: 1 } }, uploadingImages
|
|
108057
|
+
? 'Загрузка...'
|
|
108058
|
+
: `Загрузить правильные (${pendingValidatorOkDriveUploadCreos.length})`))))),
|
|
107652
108059
|
generatedImagesData.length > 0 && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { sx: {
|
|
107653
108060
|
display: 'grid',
|
|
107654
108061
|
gridTemplateColumns: { xs: '1fr', sm: 'repeat(2, 1fr)', md: 'repeat(3, 1fr)' },
|
|
@@ -107797,13 +108204,13 @@ ${imageData.originalPrompt}
|
|
|
107797
108204
|
} },
|
|
107798
108205
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_7__["default"], { variant: "body2", color: "text.secondary", align: "center", sx: { px: 1 } }, "\u0417\u0430\u0433\u0440\u0443\u0436\u0435\u043D\u043E \u043D\u0430 Google \u0414\u0438\u0441\u043A \u2014 \u043F\u0440\u0435\u0432\u044C\u044E \u0441\u043A\u0440\u044B\u0442\u043E"),
|
|
107799
108206
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_13__["default"], { direction: "row", spacing: 1, flexWrap: "wrap", justifyContent: "center" },
|
|
107800
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
108207
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_23__["default"], { size: "small", variant: "contained", onClick: () => setGeneratedImagesData(prev => prev.map(img => img.index === imageData.index
|
|
107801
108208
|
? { ...img, uploadedPreviewHidden: false }
|
|
107802
108209
|
: img)) }, "\u041F\u043E\u043A\u0430\u0437\u0430\u0442\u044C \u043F\u0440\u0435\u0432\u044C\u044E"),
|
|
107803
|
-
imageData.driveUploadedFileId ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
108210
|
+
imageData.driveUploadedFileId ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_23__["default"], { size: "small", variant: "outlined", color: "error", disabled: deletingDriveImageIndex === imageData.index, onClick: () => void handleDeleteCreativeFromDrive(imageData) }, deletingDriveImageIndex === imageData.index
|
|
107804
108211
|
? 'Удаление…'
|
|
107805
108212
|
: 'Удалить с Диска')) : null,
|
|
107806
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
108213
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_23__["default"], { size: "small", variant: "outlined", startIcon: react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_54__["default"], null), onClick: () => setCreoFullscreen({
|
|
107807
108214
|
url: imageData.imageUrl,
|
|
107808
108215
|
title: `${imageData.index}. ${imageData.approach}`
|
|
107809
108216
|
}), disabled: !!imageData.uploading || deletingDriveImageIndex === imageData.index }, "\u041D\u0430 \u0432\u0435\u0441\u044C \u044D\u043A\u0440\u0430\u043D")))) : (react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null,
|
|
@@ -107829,10 +108236,10 @@ ${imageData.originalPrompt}
|
|
|
107829
108236
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_19__["default"], { size: 40, sx: { color: 'primary.main' } }),
|
|
107830
108237
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_7__["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..."))),
|
|
107831
108238
|
imageData.uploaded && !imageData.regenerating ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { sx: { display: 'flex', justifyContent: 'center', mt: 0.5 } },
|
|
107832
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
108239
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_23__["default"], { size: "small", variant: "text", onClick: () => setGeneratedImagesData(prev => prev.map(img => img.index === imageData.index
|
|
107833
108240
|
? { ...img, uploadedPreviewHidden: true }
|
|
107834
108241
|
: img)) }, "\u0421\u043A\u0440\u044B\u0442\u044C \u043F\u0440\u0435\u0432\u044C\u044E"),
|
|
107835
|
-
imageData.driveUploadedFileId ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
108242
|
+
imageData.driveUploadedFileId ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_23__["default"], { size: "small", variant: "outlined", color: "error", sx: { ml: 1 }, disabled: deletingDriveImageIndex === imageData.index, onClick: () => void handleDeleteCreativeFromDrive(imageData) }, deletingDriveImageIndex === imageData.index
|
|
107836
108243
|
? 'Удаление…'
|
|
107837
108244
|
: 'Удалить с Диска')) : null)) : null)))) : imageData.failed ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { sx: {
|
|
107838
108245
|
width: '100%',
|
|
@@ -107910,7 +108317,7 @@ ${imageData.originalPrompt}
|
|
|
107910
108317
|
: '');
|
|
107911
108318
|
if (!body)
|
|
107912
108319
|
return null;
|
|
107913
|
-
return (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
108320
|
+
return (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_23__["default"], { size: "small", variant: "text", sx: { mt: 0.5, p: 0, minHeight: 'auto', fontSize: '0.7rem', textTransform: 'none', alignSelf: 'flex-start', display: 'block' }, onClick: () => setValidatorDebugDialog({
|
|
107914
108321
|
kind: imageData.checkFailed ? 'transport' : 'validator',
|
|
107915
108322
|
subtitle: `${imageData.index}. ${imageData.approach}`,
|
|
107916
108323
|
text: body
|
|
@@ -107939,7 +108346,7 @@ ${imageData.originalPrompt}
|
|
|
107939
108346
|
}
|
|
107940
108347
|
} }),
|
|
107941
108348
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_13__["default"], { direction: "row", spacing: 1, sx: { width: '100%', alignItems: 'stretch' } },
|
|
107942
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
108349
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_23__["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_19__["default"], { size: 16 }) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_43__["default"], null), onClick: () => handleRegenerateImage(imageData), disabled: imageData.regenerating ||
|
|
107943
108350
|
imageData.uploading ||
|
|
107944
108351
|
imageData.checkStatus === 'checking' ||
|
|
107945
108352
|
!imageData.originalPrompt ||
|
|
@@ -107949,24 +108356,36 @@ ${imageData.originalPrompt}
|
|
|
107949
108356
|
: ((generatingImages && !imageData.imageUrl && !imageData.failed && !imageData.generating)
|
|
107950
108357
|
? 'В очереди'
|
|
107951
108358
|
: (!imageData.imageUrl ? 'Сгенерировать' : 'Переделать'))),
|
|
107952
|
-
imageData.imageUrl ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
108359
|
+
imageData.imageUrl ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_23__["default"], { size: "small", variant: "outlined", color: "secondary", startIcon: react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_59__["default"], null), onClick: () => handleRegenerateImageFresh(imageData), disabled: imageData.regenerating ||
|
|
107953
108360
|
imageData.uploading ||
|
|
107954
108361
|
imageData.checkStatus === 'checking' ||
|
|
107955
108362
|
!imageData.originalPrompt ||
|
|
107956
108363
|
!imageData.productImageUrl, sx: { flex: 1, minWidth: 0, py: 1, lineHeight: 1.2, whiteSpace: 'normal' } }, "\u041F\u0435\u0440\u0435\u0434\u0435\u043B\u0430\u0442\u044C \u0437\u0430\u043D\u043E\u0432\u043E")) : null),
|
|
107957
|
-
imageData.imageUrl && !validationDisabled && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
108364
|
+
imageData.imageUrl && !validationDisabled && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_23__["default"], { size: "small", variant: "outlined", color: "warning", startIcon: imageData.checkStatus === 'checking' ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_19__["default"], { size: 16, color: "inherit" })) : (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_59__["default"], null)), onClick: () => handleRetryCheck(imageData), disabled: imageData.regenerating ||
|
|
107958
108365
|
imageData.uploading ||
|
|
107959
108366
|
imageData.generating ||
|
|
107960
108367
|
imageData.checkStatus === 'checking', fullWidth: true }, imageData.checkStatus === 'checking' ? 'Проверка…' : 'Перепроверить')),
|
|
107961
|
-
!imageData.uploaded && imageData.imageUrl && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
108368
|
+
!imageData.uploaded && imageData.imageUrl && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_23__["default"], { size: "small", variant: "outlined", startIcon: react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_49__["default"], null), onClick: () => {
|
|
107962
108369
|
const folderId = extractFolderId(driveFolderUrl);
|
|
107963
108370
|
if (folderId) {
|
|
107964
108371
|
handleUploadImage(imageData, folderId);
|
|
107965
108372
|
}
|
|
107966
108373
|
}, disabled: imageData.uploading || imageData.regenerating || !driveFolderUrl.trim(), fullWidth: true }, imageData.uploading ? 'Загрузка...' : 'Загрузить'))))));
|
|
107967
108374
|
}))),
|
|
107968
|
-
|
|
107969
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
108375
|
+
pendingDriveUploadCreos.length > 0 && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_13__["default"], { direction: { xs: 'column', sm: 'row' }, spacing: 1, sx: { mt: 2 }, useFlexGap: true },
|
|
108376
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_23__["default"], { variant: "contained", color: "primary", onClick: () => void handleUploadAllImages(), disabled: uploadingImages || generatingImages || !driveFolderUrl.trim(), startIcon: uploadingImages ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_19__["default"], { size: 20 }) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_49__["default"], null), fullWidth: true, sx: { flex: 1 } }, uploadingImages
|
|
108377
|
+
? 'Загрузка...'
|
|
108378
|
+
: `Загрузить все (${pendingDriveUploadCreos.length})`),
|
|
108379
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_9__["default"], { title: pendingValidatorOkDriveUploadCreos.length === 0
|
|
108380
|
+
? 'Нет незагруженных крео с успешной проверкой валидатором (ожидайте проверки или исправьте ошибки).'
|
|
108381
|
+
: 'Только крео со статусом «Проверка пройдена», как в карточке (валидатор вернул OK).' },
|
|
108382
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", { style: { flex: 1, display: 'flex' } },
|
|
108383
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_23__["default"], { variant: "contained", color: "success", onClick: () => void handleUploadAllImages({ correctOnly: true }), disabled: uploadingImages ||
|
|
108384
|
+
generatingImages ||
|
|
108385
|
+
!driveFolderUrl.trim() ||
|
|
108386
|
+
pendingValidatorOkDriveUploadCreos.length === 0, startIcon: uploadingImages ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_19__["default"], { size: 20 }) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_47__["default"], null), fullWidth: true, sx: { flex: 1 } }, uploadingImages
|
|
108387
|
+
? 'Загрузка...'
|
|
108388
|
+
: `Загрузить правильные (${pendingValidatorOkDriveUploadCreos.length})`))))),
|
|
107970
108389
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_32__["default"], { fullScreen: true, open: Boolean(creoFullscreen), onClose: () => setCreoFullscreen(null), PaperProps: {
|
|
107971
108390
|
sx: {
|
|
107972
108391
|
m: 0,
|
|
@@ -108021,12 +108440,12 @@ ${imageData.originalPrompt}
|
|
|
108021
108440
|
}
|
|
108022
108441
|
} })),
|
|
108023
108442
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_35__["default"], { sx: { px: 2, py: 1.5 } },
|
|
108024
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
108443
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_23__["default"], { startIcon: react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_50__["default"], null), onClick: () => {
|
|
108025
108444
|
const t = validatorDebugDialog?.text;
|
|
108026
108445
|
if (t)
|
|
108027
108446
|
void navigator.clipboard.writeText(t);
|
|
108028
108447
|
}, disabled: !validatorDebugDialog?.text }, "\u041A\u043E\u043F\u0438\u0440\u043E\u0432\u0430\u0442\u044C"),
|
|
108029
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
108448
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_23__["default"], { variant: "contained", onClick: () => setValidatorDebugDialog(null) }, "\u0417\u0430\u043A\u0440\u044B\u0442\u044C"))))),
|
|
108030
108449
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_21__["default"], { sx: { my: 2 } }),
|
|
108031
108450
|
(generatedTitlesData.length > 0 || generatedTextsData.length > 0 || loadingContentFromDrive) && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { sx: { mb: 2 } },
|
|
108032
108451
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { sx: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 1, mb: 1 } },
|
|
@@ -108061,7 +108480,7 @@ ${imageData.originalPrompt}
|
|
|
108061
108480
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_19__["default"], { size: 40, sx: { color: 'primary.main' } }),
|
|
108062
108481
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_7__["default"], { variant: "body1", sx: { color: 'text.secondary', fontWeight: 'bold' } }, "\u0417\u0430\u0433\u0440\u0443\u0437\u043A\u0430 \u043A\u043E\u043D\u0442\u0435\u043D\u0442\u0430 \u0438\u0437 Google Drive..."))),
|
|
108063
108482
|
(generatedTitlesData.length > 0 || generatedTextsData.length > 0) && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_13__["default"], { spacing: 2 },
|
|
108064
|
-
pairTranslationFailed && !translatingPairs && !generating ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_20__["default"], { severity: "warning", action: react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
108483
|
+
pairTranslationFailed && !translatingPairs && !generating ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_20__["default"], { severity: "warning", action: react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_23__["default"], { color: "inherit", size: "small", onClick: handleRetryPairTranslation, sx: { textTransform: 'none', whiteSpace: 'nowrap' } }, "\u0417\u0430\u043F\u0440\u043E\u0441\u0438\u0442\u044C \u043F\u0435\u0440\u0435\u0432\u043E\u0434") }, "\u041D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u043F\u043E\u043B\u0443\u0447\u0438\u0442\u044C \u043F\u0435\u0440\u0435\u0432\u043E\u0434 \u043F\u0430\u0440 \u043D\u0430 \u0440\u0443\u0441\u0441\u043A\u0438\u0439 (\u043E\u0442\u0434\u0435\u043B\u044C\u043D\u044B\u0439 \u0437\u0430\u043F\u0440\u043E\u0441 \u043A \u043C\u043E\u0434\u0435\u043B\u0438).")) : null,
|
|
108065
108484
|
Array.from({
|
|
108066
108485
|
length: Math.max(generatedTitlesData.length, generatedTextsData.length)
|
|
108067
108486
|
}, (_, i) => i).map((i) => {
|
|
@@ -108220,7 +108639,7 @@ ${imageData.originalPrompt}
|
|
|
108220
108639
|
generatingLanding && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { sx: { display: 'flex', alignItems: 'center', gap: 1, mb: 2 } },
|
|
108221
108640
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_19__["default"], { size: 20 }),
|
|
108222
108641
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_7__["default"], { variant: "body2", sx: { color: 'text.secondary' } }, formatElapsedTime(elapsedTime.landing)))),
|
|
108223
|
-
!generatingLanding && generatedLandingHTML && generatedLandingImageBlob && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
108642
|
+
!generatingLanding && generatedLandingHTML && generatedLandingImageBlob && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_23__["default"], { variant: "outlined", color: "primary", onClick: handlePreviewLanding, startIcon: react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_61__["default"], null), fullWidth: true }, "\u041F\u0440\u0435\u0434\u043F\u0440\u043E\u0441\u043C\u043E\u0442\u0440 \u043B\u0435\u043D\u0434\u0438\u043D\u0433\u0430"))))))))),
|
|
108224
108643
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_32__["default"], { open: approachLoadChoice !== null, onClose: handleApproachLoadKeepCurrent, maxWidth: "md", fullWidth: true }, approachLoadChoice ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null,
|
|
108225
108644
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_33__["default"], null, "\u041F\u043E\u0434\u0445\u043E\u0434\u044B \u0438\u0437 \u0444\u0430\u0439\u043B\u0430 \u043E\u0444\u0444\u0435\u0440\u0430"),
|
|
108226
108645
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_34__["default"], null,
|
|
@@ -108247,8 +108666,8 @@ ${imageData.originalPrompt}
|
|
|
108247
108666
|
? formatImageCountsForDisplay(approachLoadChoice.savedCounts)
|
|
108248
108667
|
: '— не указано (количества крео не изменятся)'))))),
|
|
108249
108668
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_35__["default"], null,
|
|
108250
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
108251
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
108669
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_23__["default"], { onClick: handleApproachLoadKeepCurrent }, "\u041E\u0441\u0442\u0430\u0432\u0438\u0442\u044C \u043A\u0430\u043A \u0441\u0435\u0439\u0447\u0430\u0441"),
|
|
108670
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_23__["default"], { variant: "contained", onClick: handleApproachLoadApplyFromFile }, "\u041F\u0440\u0438\u043C\u0435\u043D\u0438\u0442\u044C \u0438\u0437 \u0444\u0430\u0439\u043B\u0430")))) : null),
|
|
108252
108671
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_32__["default"], { open: settingsFileMissingDialog.open, onClose: (_, reason) => {
|
|
108253
108672
|
if (settingsFileMissingDialog.retrying)
|
|
108254
108673
|
return;
|
|
@@ -108270,8 +108689,8 @@ ${imageData.originalPrompt}
|
|
|
108270
108689
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_7__["default"], { variant: "body2", color: "text.secondary", sx: { mb: 1 } }, "\u041C\u043E\u0436\u043D\u043E \u043F\u043E\u0432\u0442\u043E\u0440\u0438\u0442\u044C \u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0443 (\u0438\u043D\u043E\u0433\u0434\u0430 Google \u0414\u0438\u0441\u043A \u0435\u0449\u0451 \u043D\u0435 \u043E\u0442\u0434\u0430\u043B \u0441\u043F\u0438\u0441\u043E\u043A \u0444\u0430\u0439\u043B\u043E\u0432) \u0438\u043B\u0438 \u043E\u0441\u0442\u0430\u0432\u0438\u0442\u044C \u043A\u0430\u043A \u0435\u0441\u0442\u044C, \u0435\u0441\u043B\u0438 \u0434\u043B\u044F \u044D\u0442\u043E\u0439 \u043F\u0430\u043F\u043A\u0438 \u0444\u0430\u0439\u043B\u0430 \u0438 \u043D\u0435 \u0434\u043E\u043B\u0436\u043D\u043E \u0431\u044B\u0442\u044C."),
|
|
108271
108690
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_7__["default"], { variant: "body2", color: "text.secondary" }, "\u041F\u043E\u043A\u0430 \u043E\u043A\u043D\u043E \u043E\u0442\u043A\u0440\u044B\u0442\u043E, \u0430\u0432\u0442\u043E\u0441\u043E\u0445\u0440\u0430\u043D\u0435\u043D\u0438\u0435 \u0438 \u0437\u0430\u043F\u0438\u0441\u044C \u043D\u0430\u0441\u0442\u0440\u043E\u0435\u043A \u0432 \u044D\u0442\u0443 \u043F\u0430\u043F\u043A\u0443 \u043D\u0430 \u0414\u0438\u0441\u043A\u0435 \u043D\u0435 \u0432\u044B\u043F\u043E\u043B\u043D\u044F\u044E\u0442\u0441\u044F \u2014 \u0447\u0442\u043E\u0431\u044B \u043D\u0435 \u0441\u043E\u0437\u0434\u0430\u0442\u044C \u043D\u043E\u0432\u044B\u0439 \u0444\u0430\u0439\u043B, \u043F\u043E\u043A\u0430 \u0432\u044B \u043D\u0435 \u0440\u0435\u0448\u0438\u0442\u0435, \u0435\u0441\u0442\u044C \u043B\u0438 \u0443\u0436\u0435 \u043D\u0430\u0441\u0442\u0440\u043E\u0439\u043A\u0438.")),
|
|
108272
108691
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_35__["default"], { sx: { px: 3, pb: 2, gap: 1 } },
|
|
108273
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
108274
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
108692
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_23__["default"], { onClick: handleSettingsFileMissingRetry, variant: "outlined", disabled: settingsFileMissingDialog.retrying, startIcon: settingsFileMissingDialog.retrying ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_19__["default"], { size: 16, color: "inherit" }) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_59__["default"], null) }, "\u041F\u0435\u0440\u0435\u043F\u0440\u043E\u0432\u0435\u0440\u0438\u0442\u044C"),
|
|
108693
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_23__["default"], { onClick: handleSettingsFileMissingDismissOk, variant: "contained", disabled: settingsFileMissingDialog.retrying }, "\u044D\u0442\u043E \u043D\u043E\u0440\u043C\u0430\u043B\u044C\u043D\u043E"))),
|
|
108275
108694
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_PromptManagerDialog__WEBPACK_IMPORTED_MODULE_62__["default"], { open: promptManagerOpen, onClose: () => setPromptManagerOpen(false) }),
|
|
108276
108695
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_32__["default"], { open: settingsBackupDialogOpen, onClose: () => {
|
|
108277
108696
|
setSettingsBackupDialogOpen(false);
|
|
@@ -108305,11 +108724,12 @@ ${imageData.originalPrompt}
|
|
|
108305
108724
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_24__["default"], { control: react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_25__["default"], { checked: settingsExportFlags.localStorageUi, onChange: e => setSettingsExportFlags(f => ({ ...f, localStorageUi: e.target.checked })) }), label: "\u041C\u043E\u0434\u0435\u043B\u0438, \u0432\u0430\u043B\u0438\u0434\u0430\u0442\u043E\u0440, \u0442\u0435\u043C\u0430, \u0441\u043E\u043E\u0442\u043D\u043E\u0448\u0435\u043D\u0438\u0435 \u0441\u0442\u043E\u0440\u043E\u043D" }),
|
|
108306
108725
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_24__["default"], { control: react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_25__["default"], { checked: settingsExportFlags.googleOAuth, onChange: e => setSettingsExportFlags(f => ({ ...f, googleOAuth: e.target.checked })) }), label: "Google Client ID / Secret (\u0438\u0437 config)" }),
|
|
108307
108726
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_24__["default"], { control: react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_25__["default"], { checked: settingsExportFlags.openRouterKey, onChange: e => setSettingsExportFlags(f => ({ ...f, openRouterKey: e.target.checked })) }), label: "\u041A\u043B\u044E\u0447 OpenRouter (\u0438\u0437 config; \u0445\u0440\u0430\u043D\u0438\u0442\u0435 \u0444\u0430\u0439\u043B \u0432 \u0431\u0435\u0437\u043E\u043F\u0430\u0441\u043D\u043E\u0441\u0442\u0438)" }),
|
|
108727
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_24__["default"], { control: react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_25__["default"], { checked: settingsExportFlags.flexCardKey, onChange: e => setSettingsExportFlags(f => ({ ...f, flexCardKey: e.target.checked })) }), label: "\u041A\u043B\u044E\u0447 FlexCard API (\u0438\u0437 config)" }),
|
|
108308
108728
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_24__["default"], { control: react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_25__["default"], { checked: settingsExportFlags.googleTokens, onChange: e => setSettingsExportFlags(f => ({ ...f, googleTokens: e.target.checked })) }), label: "\u0422\u043E\u043A\u0435\u043D\u044B Google (\u0434\u043E\u0441\u0442\u0443\u043F/\u043E\u0431\u043D\u043E\u0432\u043B\u0435\u043D\u0438\u0435) \u2014 \u043F\u043E \u0443\u043C\u043E\u043B\u0447\u0430\u043D\u0438\u044E \u0432\u044B\u043A\u043B., \u0440\u0438\u0441\u043A \u0443\u0442\u0435\u0447\u043A\u0438" })),
|
|
108309
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
108729
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_23__["default"], { variant: "outlined", sx: { mt: 2 }, onClick: handleSettingsExport }, "\u0421\u043E\u0445\u0440\u0430\u043D\u0438\u0442\u044C JSON\u2026")),
|
|
108310
108730
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { sx: { flex: 1, minWidth: 260 } },
|
|
108311
108731
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_7__["default"], { variant: "subtitle2", sx: { mb: 1, fontWeight: 600 } }, "\u0418\u043C\u043F\u043E\u0440\u0442"),
|
|
108312
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
108732
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_23__["default"], { variant: "outlined", onClick: () => settingsImportFileInputRef.current?.click() }, "\u0412\u044B\u0431\u0440\u0430\u0442\u044C JSON\u2026"),
|
|
108313
108733
|
settingsImportBundle && settingsImportFlags && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { sx: { mt: 2, p: 1.5, border: 1, borderColor: 'divider', borderRadius: 1 } },
|
|
108314
108734
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_7__["default"], { variant: "caption", color: "text.secondary", display: "block", sx: { mb: 1 } },
|
|
108315
108735
|
"\u0424\u0430\u0439\u043B: ",
|
|
@@ -108319,13 +108739,13 @@ ${imageData.originalPrompt}
|
|
|
108319
108739
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_24__["default"], { control: react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_25__["default"], { checked: settingsImportFlags.localStorage, disabled: !(0,_appSettingsBundle__WEBPACK_IMPORTED_MODULE_64__.getPresentSections)(settingsImportBundle).localStorage, onChange: e => setSettingsImportFlags(f => f ? { ...f, localStorage: e.target.checked } : f) }), label: "LocalStorage (\u043C\u043E\u0434\u0435\u043B\u0438, \u0442\u0435\u043C\u0430, \u043A\u044D\u0448 \u043F\u0430\u043F\u043E\u043A, \u2026)" }),
|
|
108320
108740
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_24__["default"], { control: react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_25__["default"], { checked: settingsImportFlags.electronConfig, disabled: !(0,_appSettingsBundle__WEBPACK_IMPORTED_MODULE_64__.getPresentSections)(settingsImportBundle).electronConfig, onChange: e => setSettingsImportFlags(f => f ? { ...f, electronConfig: e.target.checked } : f) }), label: "Config: OAuth, \u043A\u043B\u044E\u0447, \u0442\u043E\u043A\u0435\u043D\u044B (\u0435\u0441\u043B\u0438 \u0435\u0441\u0442\u044C \u0432 \u0444\u0430\u0439\u043B\u0435)" })),
|
|
108321
108741
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_13__["default"], { direction: "row", spacing: 1, sx: { mt: 2 } },
|
|
108322
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
108323
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
108742
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_23__["default"], { variant: "contained", onClick: handleSettingsImportApply }, "\u041F\u0440\u0438\u043C\u0435\u043D\u0438\u0442\u044C"),
|
|
108743
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_23__["default"], { onClick: () => {
|
|
108324
108744
|
setSettingsImportBundle(null);
|
|
108325
108745
|
setSettingsImportFlags(null);
|
|
108326
108746
|
} }, "\u041E\u0442\u043C\u0435\u043D\u0430"))))))),
|
|
108327
108747
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_35__["default"], null,
|
|
108328
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
108748
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_23__["default"], { onClick: () => {
|
|
108329
108749
|
setSettingsBackupDialogOpen(false);
|
|
108330
108750
|
setSettingsImportBundle(null);
|
|
108331
108751
|
setSettingsImportFlags(null);
|
|
@@ -109292,6 +109712,7 @@ const LOCAL_STORAGE_UI_KEYS = [
|
|
|
109292
109712
|
'selectedLandingModel',
|
|
109293
109713
|
'validationDisabled',
|
|
109294
109714
|
'autoRemakeOnValidatorError',
|
|
109715
|
+
'uploadAfterValidatorOk',
|
|
109295
109716
|
'imageAspectRatio',
|
|
109296
109717
|
];
|
|
109297
109718
|
const DEFAULT_EXPORT_FLAGS = {
|
|
@@ -109299,6 +109720,7 @@ const DEFAULT_EXPORT_FLAGS = {
|
|
|
109299
109720
|
localStorageUi: true,
|
|
109300
109721
|
googleOAuth: false,
|
|
109301
109722
|
openRouterKey: false,
|
|
109723
|
+
flexCardKey: false,
|
|
109302
109724
|
googleTokens: false,
|
|
109303
109725
|
};
|
|
109304
109726
|
function collectLocalStorageKeys(keys) {
|
|
@@ -109350,6 +109772,9 @@ function buildSettingsBundle(flags, fullElectronConfig) {
|
|
|
109350
109772
|
if (flags.openRouterKey && typeof fullElectronConfig.openaiApiKey === 'string') {
|
|
109351
109773
|
ec.openaiApiKey = fullElectronConfig.openaiApiKey;
|
|
109352
109774
|
}
|
|
109775
|
+
if (flags.flexCardKey && typeof fullElectronConfig.flexcardApiKey === 'string') {
|
|
109776
|
+
ec.flexcardApiKey = fullElectronConfig.flexcardApiKey;
|
|
109777
|
+
}
|
|
109353
109778
|
if (flags.googleTokens) {
|
|
109354
109779
|
if (typeof fullElectronConfig.accessToken === 'string')
|
|
109355
109780
|
ec.accessToken = fullElectronConfig.accessToken;
|
|
@@ -109434,7 +109859,16 @@ function mergeElectronImport(current, bundle, on) {
|
|
|
109434
109859
|
return current;
|
|
109435
109860
|
const next = { ...current };
|
|
109436
109861
|
const ec = bundle.electronConfig;
|
|
109437
|
-
[
|
|
109862
|
+
[
|
|
109863
|
+
'clientId',
|
|
109864
|
+
'clientSecret',
|
|
109865
|
+
'openaiApiKey',
|
|
109866
|
+
'flexcardApiKey',
|
|
109867
|
+
'telegramBotToken',
|
|
109868
|
+
'telegramChatId',
|
|
109869
|
+
'accessToken',
|
|
109870
|
+
'refreshToken',
|
|
109871
|
+
].forEach(f => {
|
|
109438
109872
|
if (ec[f] !== undefined)
|
|
109439
109873
|
next[f] = ec[f];
|
|
109440
109874
|
});
|
|
@@ -109442,6 +109876,90 @@ function mergeElectronImport(current, bundle, on) {
|
|
|
109442
109876
|
}
|
|
109443
109877
|
|
|
109444
109878
|
|
|
109879
|
+
/***/ }),
|
|
109880
|
+
|
|
109881
|
+
/***/ "./src/flexcardBalance.ts":
|
|
109882
|
+
/*!********************************!*\
|
|
109883
|
+
!*** ./src/flexcardBalance.ts ***!
|
|
109884
|
+
\********************************/
|
|
109885
|
+
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
|
|
109886
|
+
|
|
109887
|
+
"use strict";
|
|
109888
|
+
__webpack_require__.r(__webpack_exports__);
|
|
109889
|
+
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
|
109890
|
+
/* harmony export */ FLEXCARD_FINANCE_ACCOUNTS_URL: () => (/* binding */ FLEXCARD_FINANCE_ACCOUNTS_URL),
|
|
109891
|
+
/* harmony export */ fetchFlexCardFinanceAccountsUsdTotal: () => (/* binding */ fetchFlexCardFinanceAccountsUsdTotal)
|
|
109892
|
+
/* harmony export */ });
|
|
109893
|
+
/**
|
|
109894
|
+
* FlexCard — `GET /api/v1/finance/accounts/` с `X-API-Key`.
|
|
109895
|
+
* Суммируем только поле `balance` (строка или число) по строкам с `currency` === USD.
|
|
109896
|
+
*/
|
|
109897
|
+
const FLEXCARD_FINANCE_ACCOUNTS_URL = 'https://flexcard.cards/api/v1/finance/accounts/';
|
|
109898
|
+
function num(v) {
|
|
109899
|
+
if (typeof v === 'number' && !Number.isNaN(v))
|
|
109900
|
+
return v;
|
|
109901
|
+
const n = parseFloat(String(v));
|
|
109902
|
+
return Number.isFinite(n) ? n : 0;
|
|
109903
|
+
}
|
|
109904
|
+
async function fetchPaginatedResults(apiKey, initialUrl) {
|
|
109905
|
+
const trimmed = apiKey.trim();
|
|
109906
|
+
const out = [];
|
|
109907
|
+
let url = initialUrl;
|
|
109908
|
+
for (let page = 0; page < 50 && url; page++) {
|
|
109909
|
+
const res = await fetch(url, {
|
|
109910
|
+
method: 'GET',
|
|
109911
|
+
headers: {
|
|
109912
|
+
'X-API-Key': trimmed,
|
|
109913
|
+
Accept: 'application/json',
|
|
109914
|
+
},
|
|
109915
|
+
});
|
|
109916
|
+
if (!res.ok)
|
|
109917
|
+
return null;
|
|
109918
|
+
const data = (await res.json());
|
|
109919
|
+
let batch;
|
|
109920
|
+
let next;
|
|
109921
|
+
if (Array.isArray(data)) {
|
|
109922
|
+
batch = data;
|
|
109923
|
+
next = null;
|
|
109924
|
+
}
|
|
109925
|
+
else if (data && typeof data === 'object') {
|
|
109926
|
+
const o = data;
|
|
109927
|
+
const r = o.results;
|
|
109928
|
+
batch = Array.isArray(r) ? r : [];
|
|
109929
|
+
next = o.next ?? null;
|
|
109930
|
+
if (!Array.isArray(r))
|
|
109931
|
+
return null;
|
|
109932
|
+
}
|
|
109933
|
+
else {
|
|
109934
|
+
return null;
|
|
109935
|
+
}
|
|
109936
|
+
out.push(...batch);
|
|
109937
|
+
url = next ?? null;
|
|
109938
|
+
}
|
|
109939
|
+
return out;
|
|
109940
|
+
}
|
|
109941
|
+
/** Сумма `balance` по всем счетам с валютой USD. */
|
|
109942
|
+
async function fetchFlexCardFinanceAccountsUsdTotal(apiKey) {
|
|
109943
|
+
const trimmed = apiKey.trim();
|
|
109944
|
+
if (!trimmed)
|
|
109945
|
+
return null;
|
|
109946
|
+
const rows = await fetchPaginatedResults(trimmed, FLEXCARD_FINANCE_ACCOUNTS_URL);
|
|
109947
|
+
if (rows === null)
|
|
109948
|
+
return null;
|
|
109949
|
+
let sum = 0;
|
|
109950
|
+
for (const raw of rows) {
|
|
109951
|
+
if (!raw || typeof raw !== 'object')
|
|
109952
|
+
continue;
|
|
109953
|
+
const r = raw;
|
|
109954
|
+
const cur = String(r.currency ?? '').toUpperCase();
|
|
109955
|
+
if (cur !== 'USD' && cur !== 'US')
|
|
109956
|
+
continue;
|
|
109957
|
+
sum += num(r.balance);
|
|
109958
|
+
}
|
|
109959
|
+
return sum;
|
|
109960
|
+
}
|
|
109961
|
+
|
|
109962
|
+
|
|
109445
109963
|
/***/ }),
|
|
109446
109964
|
|
|
109447
109965
|
/***/ "./src/index.css":
|
|
@@ -110544,12 +111062,16 @@ ${priceBriefTrim}
|
|
|
110544
111062
|
1) ВНУТРЕННЯЯ ЛОГИКА НА МАКЕТЕ (главное):
|
|
110545
111063
|
- Должны быть видны две суммы: новая (акционная) и старая (зачёркнутая). Числовое отношение: старая ≈ вдвое новой при скидке -50% (допуск до ~2% из‑за округления; «1 180» и «1180» — одно и то же). На макете **не должно** быть текста «2×»/«2x» перед суммой как множитель — только две суммы (см. ШАГ 4).
|
|
110546
111064
|
- Если отношение старая/новая ≈ 2 (в пределах допуска) — это уже доказательство корректной пары -50% на макете. В этом случае ЗАПРЕЩЕНО выводить ОШИБКУ формулировками вроде «выдуманные цены», «неверные суммы», «не соответствуют брифу» — даже если цифры в брифе другие или бриф кажется не тем.
|
|
110547
|
-
- Если пара математически согласована с -50% и процент «-50%» где‑либо читаем в зоне оффера (см. ШАГ 4) — не придумывай расхождение с брифом из‑за
|
|
111065
|
+
- Если пара математически согласована с -50% и процент «-50%» где‑либо читаем в зоне оффера (см. ШАГ 4) — не придумывай расхождение с брифом из‑за **эквивалентного написания той же валюты**, что в брифе: символ ↔ код ↔ локальное слово для **одной** валюты (например € / EUR / «евро» для евро; $ / USD; MXN и т.п.) и из‑за пробелов/типографики. Это **не** отменяет пункт 1a ниже: другая денежная единица — всегда ошибка.
|
|
111066
|
+
|
|
111067
|
+
1a) ВАЛЮТА ОБЯЗАТЕЛЬНО КАК В БРИФЕ (критично):
|
|
111068
|
+
- В брифе указана конкретная валюта (например EUR). На макете в блоке цен должна быть **именно она** (символ €, код EUR, или привычное для GEO написание «евро» **как валюта цены**, если это явно евро). **ОШИБКА, НУЖНА ПЕРЕСБОРКА**, если читается **иная** национальная валюта или её сокращение: при брифе EUR — **лв**, **лв.**, BGN, **лев**, руб/₽, zł, lei, kn, Kč и любые другие явные обозначения **не евро** рядом с суммами. Пример из практики: «50 лв» / «25 лв» при брифе в EUR — **недопустимо**, даже если 50/25 математически дают -50%.
|
|
111069
|
+
- Если валюту на макете нельзя прочитать уверенно — не гадай в пользу OK: при явном брифе с кодом валюты лучше отметь риск; при двусмысленности между двумя валютами — **ОШИБКА** или явное требование пересборки с читаемой валютой из брифа.
|
|
110548
111070
|
|
|
110549
111071
|
2) СВЕРКА С БРИФОМ (только когда сопоставимо):
|
|
110550
111072
|
- Сравнивай число НОВОЙ цены с брифом ТОЛЬКО если валюта на макете явно та же, что в брифе (EUR↔EUR, MXN↔MXN и т.д.; символ € и код EUR — одна валюта). Допускается разное оформление числа (пробелы тысяч, запятая/точка).
|
|
110551
|
-
- Если валюта на креативе
|
|
110552
|
-
- Ошибку по ценам ставь
|
|
111073
|
+
- Если валюта на креативе **однозначно другая**, чем в брифе — это уже **ОШИБКА** по п. 1a; совпадение цифр не спасает. Если валюта нечитаема — см. п. 1a. Если валюта совпадает с брифом — сравнивай числа как раньше.
|
|
111074
|
+
- Ошибку по ценам ставь если: (а) на макете нет двух цен / нет согласованности -50%, ИЛИ (а') **неверная валюта относительно брифа** (п. 1a), ИЛИ (б) валюта однозначно совпадает с брифом, а число новой цены явно другое (не в пределах округления).
|
|
110553
111075
|
|
|
110554
111076
|
3) Цена не должна быть оформлена как строка буллета с галочкой — отдельный блок.`
|
|
110555
111077
|
: `ШАГ P — ЦЕНЫ (бриф числом не задан):
|
|
@@ -110610,10 +111132,11 @@ ${step3OtherText}
|
|
|
110610
111132
|
- Если скидка указана и она не равна -50% — ошибка.
|
|
110611
111133
|
|
|
110612
111134
|
ШАГ 5 — ЯЗЫК (критично):
|
|
110613
|
-
- В рекламном тексте (HOOK/HEADLINE, текст на буллетах если есть, CTA
|
|
110614
|
-
-
|
|
111135
|
+
- В рекламном тексте (HOOK/HEADLINE, текст на буллетах если есть, CTA, PRICE, OTHER_TEXT) НЕТ произвольных английских слов и фраз. Если есть — ошибка.
|
|
111136
|
+
- **ИСКЛЮЧЕНИЕ — бейдж скидки (DISCOUNT):** на малой плашке с процентом допустимы привычные глобальные маркеры **OFF**, **SALE** рядом с «-50%» / числом процента (например «-50% OFF», «SALE −50%») — **не** считать смешением языков и **не** ставить ОШИБКУ только из‑за этих слов **в этом блоке скидки**. HOOK, CTA, буллеты и прочий рекламный текст по-прежнему строго на языке GEO.
|
|
111137
|
+
- ИСКЛЮЧЕНИЕ: внутри **графики интерфейса телефона** (шапка окна приложения, подпись вкладки вроде «Reviews», «App Store»-стиль бейджа в углу рамки) английские слова **не** считать ошибкой — это имитация ОС/магазина, не рекламный текст баннера. Ошибкой остаётся английский в HOOK над макетом, в CTA, в буллетах, на строках **сумм** (кроме кода валюты ISO и символа €/$ и т.п.), в теле отзыва как пользовательском тексте (не в подписи UI). Бейдж скидки — см. исключение OFF/SALE выше.
|
|
110615
111138
|
- ЗАПРЕЩЁННЫЕ служебные подписи на макете (частая ошибка модели): слова HOOK, CTA, CAPS, BULLET, HEADLINE, PRICE, DISCOUNT как видимый текст на плашках или кнопке — ОШИБКА (это метки из брифа, не для читателя).
|
|
110616
|
-
- Все слова соответствуют GEO/языку ${geo}.
|
|
111139
|
+
- Все слова соответствуют GEO/языку ${geo}. Смешение языков — ошибка, **кроме** исключений выше (OFF/SALE на бейдже скидки; UI телефона).
|
|
110617
111140
|
- ПСЕВДОСЛОВА И ОПЕЧАТКИ: если на плашке скидки или в буллетах видно **несуществующее** или явно ошибочное слово для языка GEO (не словарное), либо «калька» под английский без нормы (пример для испанского: «DISCONTA» вместо «DESCUENTO»; на буллете англ. «COMFORT» вместо исп. «CONFORT»/«COMODIDAD») — ОШИБКА языка (приземлённая формулировка в строке ОШИБКА).
|
|
110618
111141
|
|
|
110619
111142
|
ШАГ 6 — КОМПОЗИЦИЯ:
|