AI Аналитика продуктов Ozon

Анализирует показатели продуктов (показы, клики, конверсии, заказы, ДРР) с помощью AI и дает рекомендации по улучшению

Size

31.4 KB

Version

1.0.1

Created

Dec 3, 2025

Updated

9 days ago

1// ==UserScript==
2// @name		AI Аналитика продуктов Ozon
3// @description		Анализирует показатели продуктов (показы, клики, конверсии, заказы, ДРР) с помощью AI и дает рекомендации по улучшению
4// @version		1.0.1
5// @match		https://*.seller.ozon.ru/*
6// @icon		https://st.ozone.ru/s3/seller-ui-static/icon/favicon32.png
7// @grant		GM.xmlhttpRequest
8// ==/UserScript==
9(function() {
10    'use strict';
11
12    console.log('AI Аналитика продуктов Ozon запущена');
13
14    // Функция для парсинга значения и дельты из текста ячейки
15    function parseValueAndDelta(text) {
16        if (!text || text === '—' || text.trim() === '') {
17            return { value: null, delta: null };
18        }
19        
20        // Убираем пробелы и символы валюты для парсинга
21        const cleanText = text.trim();
22        
23        // Ищем число (может быть с пробелами как разделителями тысяч)
24        const valueMatch = cleanText.match(/^([\d\s]+(?:[.,]\d+)?)/);
25        const value = valueMatch ? parseFloat(valueMatch[1].replace(/\s/g, '').replace(',', '.')) : null;
26        
27        // Ищем дельту (процент со знаком + или -)
28        const deltaMatch = cleanText.match(/([+-]?\d+(?:[.,]\d+)?)%/);
29        const delta = deltaMatch ? parseFloat(deltaMatch[1].replace(',', '.')) : null;
30        
31        return { value, delta };
32    }
33
34    // Функция для извлечения данных о продуктах из таблицы
35    function extractProductData() {
36        console.log('Начинаем извлечение данных о продуктах...');
37        const products = [];
38        
39        // Находим все строки таблицы с продуктами
40        const rows = document.querySelectorAll('table.ct590-a tbody tr.ct590-c0');
41        console.log(`Найдено строк в таблице: ${rows.length}`);
42        
43        rows.forEach((row, index) => {
44            try {
45                const cells = row.querySelectorAll('td');
46                if (cells.length === 0) return;
47                
48                // Извлекаем название продукта и артикул
49                const productCell = cells[0];
50                const productLink = productCell.querySelector('a[href*="ozon.ru/product"]');
51                const productName = productLink ? productLink.getAttribute('title') || productLink.textContent.trim() : 'Неизвестный товар';
52                const articleElement = productCell.querySelector('.styles_productCaption_7MqtH');
53                const article = articleElement ? articleElement.textContent.trim() : '';
54                
55                // Извлекаем метрики согласно структуре таблицы
56                // Индексы ячеек (из анализа DOM):
57                // 2: Заказано на сумму
58                // 4: Позиция в поиске
59                // 5: Показы всего
60                // 6: Уникальные посетители всего
61                // 8: Показы в поиске и каталоге
62                // 12: Конверсия из показа в заказ
63                // 13: Показы в поиске и каталоге (добавления)
64                // 15: Конверсия из поиска в корзину
65                // 18: Посещения карточки
66                // 20: Уникальные посетители карточки
67                // 28: Средняя цена
68                // 32: Общая ДРР
69                
70                const orderSum = parseValueAndDelta(cells[2]?.textContent || '');
71                const position = parseValueAndDelta(cells[4]?.textContent || '');
72                const impressionsTotal = parseValueAndDelta(cells[5]?.textContent || '');
73                const visitorsTotal = parseValueAndDelta(cells[6]?.textContent || '');
74                const conversionShowToOrder = parseValueAndDelta(cells[12]?.textContent || '');
75                const ordersCount = parseValueAndDelta(cells[13]?.textContent || '');
76                const conversionSearchToCart = parseValueAndDelta(cells[15]?.textContent || '');
77                const cardVisits = parseValueAndDelta(cells[18]?.textContent || '');
78                const cardVisitorsUnique = parseValueAndDelta(cells[20]?.textContent || '');
79                const avgPrice = parseValueAndDelta(cells[28]?.textContent || '');
80                const drr = parseValueAndDelta(cells[32]?.textContent || '');
81                
82                const product = {
83                    name: productName,
84                    article: article,
85                    orderSum: orderSum.value,
86                    orderSumDelta: orderSum.delta,
87                    position: position.value,
88                    positionDelta: position.delta,
89                    impressionsTotal: impressionsTotal.value,
90                    impressionsTotalDelta: impressionsTotal.delta,
91                    visitorsTotal: visitorsTotal.value,
92                    visitorsTotalDelta: visitorsTotal.delta,
93                    conversionShowToOrder: conversionShowToOrder.value,
94                    conversionShowToOrderDelta: conversionShowToOrder.delta,
95                    ordersCount: ordersCount.value,
96                    ordersCountDelta: ordersCount.delta,
97                    conversionSearchToCart: conversionSearchToCart.value,
98                    conversionSearchToCartDelta: conversionSearchToCart.delta,
99                    cardVisits: cardVisits.value,
100                    cardVisitsDelta: cardVisits.delta,
101                    cardVisitorsUnique: cardVisitorsUnique.value,
102                    cardVisitorsUniqueDelta: cardVisitorsUnique.delta,
103                    avgPrice: avgPrice.value,
104                    avgPriceDelta: avgPrice.delta,
105                    drr: drr.value,
106                    drrDelta: drr.delta
107                };
108                
109                console.log(`Продукт ${index + 1}:`, product);
110                products.push(product);
111                
112            } catch (error) {
113                console.error(`Ошибка при обработке строки ${index}:`, error);
114            }
115        });
116        
117        console.log(`Всего извлечено продуктов: ${products.length}`);
118        return products;
119    }
120
121    // Функция для фильтрации продуктов со значительными изменениями
122    function filterSignificantChanges(products) {
123        console.log('Фильтруем продукты со значительными изменениями...');
124        
125        const significantProducts = products.filter(product => {
126            // Критерии значительных изменений:
127            
128            // 1. Сильное падение выручки (более -20%)
129            const revenueDropped = product.orderSumDelta !== null && product.orderSumDelta <= -20;
130            
131            // 2. Сильный рост выручки (более +20%)
132            const revenueGrew = product.orderSumDelta !== null && product.orderSumDelta >= 20;
133            
134            // 3. Сильный рост ДРР (более +10% или если ДРР стал выше 25%)
135            const drrGrew = (product.drrDelta !== null && product.drrDelta >= 10) || 
136                           (product.drr !== null && product.drr >= 25);
137            
138            // 4. Сильное падение конверсии (более -15%)
139            const conversionDropped = product.conversionShowToOrderDelta !== null && 
140                                     product.conversionShowToOrderDelta <= -15;
141            
142            // 5. Сильное падение показов (более -30%)
143            const impressionsDropped = product.impressionsTotalDelta !== null && 
144                                      product.impressionsTotalDelta <= -30;
145            
146            // 6. Сильное падение заказов (более -25%)
147            const ordersDropped = product.ordersCountDelta !== null && 
148                                 product.ordersCountDelta <= -25;
149            
150            return revenueDropped || revenueGrew || drrGrew || conversionDropped || 
151                   impressionsDropped || ordersDropped;
152        });
153        
154        console.log(`Найдено продуктов со значительными изменениями: ${significantProducts.length}`);
155        return significantProducts;
156    }
157
158    // Функция для анализа продуктов с помощью AI
159    async function analyzeProductsWithAI(products) {
160        console.log('Начинаем AI-анализ продуктов...');
161        
162        if (products.length === 0) {
163            return { error: 'Нет продуктов со значительными изменениями для анализа' };
164        }
165        
166        // Сортируем продукты по абсолютному значению изменения выручки
167        const sortedProducts = [...products].sort((a, b) => {
168            const deltaA = Math.abs(a.orderSumDelta || 0);
169            const deltaB = Math.abs(b.orderSumDelta || 0);
170            return deltaB - deltaA;
171        });
172        
173        // Берем топ-15 продуктов для анализа
174        const topProducts = sortedProducts.slice(0, 15);
175        
176        const prompt = `Ты эксперт по e-commerce аналитике на маркетплейсе Ozon. Проанализируй следующие данные о продуктах, которые показали ЗНАЧИТЕЛЬНЫЕ ИЗМЕНЕНИЯ по сравнению с предыдущим периодом.
177
178Данные о продуктах (отсортированы по величине изменения выручки):
179${JSON.stringify(topProducts, null, 2)}
180
181Метрики и их дельты (изменения в %):
182- orderSum: сумма заказов (₽)
183- orderSumDelta: изменение суммы заказов (%)
184- impressionsTotal: показы всего
185- impressionsTotalDelta: изменение показов (%)
186- visitorsTotal: уникальные посетители
187- visitorsTotalDelta: изменение посетителей (%)
188- conversionShowToOrder: конверсия из показа в заказ (%)
189- conversionShowToOrderDelta: изменение конверсии (%)
190- ordersCount: количество заказов
191- ordersCountDelta: изменение количества заказов (%)
192- cardVisits: посещения карточки товара
193- cardVisitsDelta: изменение посещений (%)
194- avgPrice: средняя цена (₽)
195- avgPriceDelta: изменение цены (%)
196- drr: ДРР - доля рекламных расходов (%)
197- drrDelta: изменение ДРР (%)
198
199ВАЖНО! Фокусируйся на ИЗМЕНЕНИЯХ (дельтах):
200
2011. Если выручка УПАЛА (orderSumDelta отрицательная):
202   - Найди причину: упали показы? упала конверсия? выросла цена? вырос ДРР?
203   - Дай конкретные рекомендации как вернуть продажи
204
2052. Если выручка ВЫРОСЛА (orderSumDelta положительная):
206   - Найди причину роста: выросли показы? улучшилась конверсия? снизилась цена?
207   - Дай рекомендации как закрепить и усилить рост
208
2093. Если ДРР сильно ВЫРОС (drrDelta положительная или drr > 25%):
210   - Это КРИТИЧНО! Реклама стала неэффективной
211   - Объясни почему это произошло и как снизить ДРР
212
2134. Если конверсия УПАЛА:
214   - Проблемы с карточкой товара, ценой или конкурентами
215   - Дай рекомендации по улучшению
216
217Для каждого продукта укажи:
218- Название продукта (кратко)
219- Что произошло (рост/падение и почему)
220- Конкретные действия для исправления или усиления
221- Приоритет (критический/высокий/средний)`;
222
223        try {
224            const response = await RM.aiCall(prompt, {
225                type: "json_schema",
226                json_schema: {
227                    name: "product_changes_analysis",
228                    schema: {
229                        type: "object",
230                        properties: {
231                            summary: {
232                                type: "string",
233                                description: "Общий вывод по всем изменениям"
234                            },
235                            products: {
236                                type: "array",
237                                items: {
238                                    type: "object",
239                                    properties: {
240                                        name: { type: "string" },
241                                        change: { 
242                                            type: "string",
243                                            description: "Что произошло с товаром"
244                                        },
245                                        reasons: {
246                                            type: "array",
247                                            items: { type: "string" },
248                                            description: "Причины изменений"
249                                        },
250                                        actions: {
251                                            type: "array",
252                                            items: { type: "string" },
253                                            description: "Конкретные действия"
254                                        },
255                                        priority: {
256                                            type: "string",
257                                            enum: ["критический", "высокий", "средний"]
258                                        }
259                                    },
260                                    required: ["name", "change", "reasons", "actions", "priority"]
261                                }
262                            }
263                        },
264                        required: ["summary", "products"]
265                    }
266                }
267            });
268            
269            console.log('AI-анализ завершен:', response);
270            return response;
271            
272        } catch (error) {
273            console.error('Ошибка при AI-анализе:', error);
274            return { error: 'Ошибка при анализе: ' + error.message };
275        }
276    }
277
278    // Функция для отображения результатов анализа
279    function displayAnalysisResults(analysis) {
280        console.log('Отображаем результаты анализа...');
281        
282        // Удаляем предыдущую панель, если есть
283        const existingPanel = document.getElementById('ai-analysis-panel');
284        if (existingPanel) {
285            existingPanel.remove();
286        }
287        
288        // Создаем панель с результатами
289        const panel = document.createElement('div');
290        panel.id = 'ai-analysis-panel';
291        panel.style.cssText = `
292            position: fixed;
293            top: 80px;
294            right: 20px;
295            width: 500px;
296            max-height: 85vh;
297            background: #ffffff;
298            border: 2px solid #005bff;
299            border-radius: 12px;
300            box-shadow: 0 8px 32px rgba(0, 91, 255, 0.2);
301            z-index: 10000;
302            overflow: hidden;
303            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
304        `;
305        
306        // Заголовок панели
307        const header = document.createElement('div');
308        header.style.cssText = `
309            background: linear-gradient(135deg, #005bff 0%, #0041b8 100%);
310            color: white;
311            padding: 16px 20px;
312            font-weight: 600;
313            font-size: 16px;
314            display: flex;
315            justify-content: space-between;
316            align-items: center;
317        `;
318        header.innerHTML = `
319            <span>🤖 AI Анализ изменений</span>
320            <button id="close-analysis-panel" style="
321                background: rgba(255, 255, 255, 0.2);
322                border: none;
323                color: white;
324                width: 28px;
325                height: 28px;
326                border-radius: 6px;
327                cursor: pointer;
328                font-size: 18px;
329                display: flex;
330                align-items: center;
331                justify-content: center;
332                transition: background 0.2s;
333            ">×</button>
334        `;
335        
336        // Контент панели
337        const content = document.createElement('div');
338        content.style.cssText = `
339            padding: 20px;
340            max-height: calc(85vh - 60px);
341            overflow-y: auto;
342        `;
343        
344        if (analysis.error) {
345            content.innerHTML = `
346                <div style="color: #d32f2f; padding: 16px; background: #ffebee; border-radius: 8px; text-align: center;">
347                    <strong>Внимание:</strong> ${analysis.error}
348                </div>
349            `;
350        } else {
351            // Общий вывод
352            content.innerHTML = `
353                <div style="background: #f5f7fa; padding: 16px; border-radius: 8px; margin-bottom: 20px; border-left: 4px solid #005bff;">
354                    <div style="font-weight: 600; color: #1a1a1a; margin-bottom: 8px; font-size: 14px;">📊 Общий вывод</div>
355                    <div style="color: #4a4a4a; font-size: 13px; line-height: 1.6;">${analysis.summary}</div>
356                </div>
357            `;
358            
359            // Продукты
360            analysis.products.forEach((product) => {
361                const priorityColors = {
362                    'критический': { bg: '#ffebee', border: '#d32f2f', text: '#d32f2f', icon: '🔴' },
363                    'высокий': { bg: '#fff3e0', border: '#f57c00', text: '#f57c00', icon: '🟡' },
364                    'средний': { bg: '#e3f2fd', border: '#1976d2', text: '#1976d2', icon: '🔵' }
365                };
366                
367                const colors = priorityColors[product.priority] || priorityColors['средний'];
368                
369                const productCard = document.createElement('div');
370                productCard.style.cssText = `
371                    background: white;
372                    border: 2px solid ${colors.border};
373                    border-radius: 8px;
374                    padding: 16px;
375                    margin-bottom: 16px;
376                    transition: box-shadow 0.2s;
377                `;
378                productCard.onmouseenter = () => {
379                    productCard.style.boxShadow = '0 4px 12px rgba(0, 0, 0, 0.15)';
380                };
381                productCard.onmouseleave = () => {
382                    productCard.style.boxShadow = 'none';
383                };
384                
385                productCard.innerHTML = `
386                    <div style="display: flex; justify-content: space-between; align-items: start; margin-bottom: 12px;">
387                        <div style="font-weight: 600; color: #1a1a1a; font-size: 13px; flex: 1; line-height: 1.4;">
388                            ${product.name.length > 70 ? product.name.substring(0, 70) + '...' : product.name}
389                        </div>
390                        <div style="
391                            background: ${colors.bg};
392                            color: ${colors.text};
393                            padding: 4px 10px;
394                            border-radius: 12px;
395                            font-size: 11px;
396                            font-weight: 600;
397                            white-space: nowrap;
398                            margin-left: 8px;
399                            border: 1px solid ${colors.border};
400                        ">
401                            ${colors.icon} ${product.priority}
402                        </div>
403                    </div>
404                    
405                    <div style="background: ${colors.bg}; padding: 12px; border-radius: 6px; margin-bottom: 12px; border-left: 3px solid ${colors.border};">
406                        <div style="font-weight: 600; color: ${colors.text}; font-size: 12px; margin-bottom: 4px;">📈 Что произошло:</div>
407                        <div style="color: #2c2c2c; font-size: 12px; line-height: 1.5;">${product.change}</div>
408                    </div>
409                    
410                    <div style="margin-bottom: 12px;">
411                        <div style="font-weight: 600; color: #d32f2f; font-size: 12px; margin-bottom: 6px;">🔍 Причины:</div>
412                        <ul style="margin: 0; padding-left: 20px; color: #4a4a4a; font-size: 12px; line-height: 1.6;">
413                            ${product.reasons.map(r => `<li>${r}</li>`).join('')}
414                        </ul>
415                    </div>
416                    
417                    <div>
418                        <div style="font-weight: 600; color: #388e3c; font-size: 12px; margin-bottom: 6px;">✅ Действия:</div>
419                        <ul style="margin: 0; padding-left: 20px; color: #4a4a4a; font-size: 12px; line-height: 1.6;">
420                            ${product.actions.map(a => `<li>${a}</li>`).join('')}
421                        </ul>
422                    </div>
423                `;
424                
425                content.appendChild(productCard);
426            });
427        }
428        
429        panel.appendChild(header);
430        panel.appendChild(content);
431        document.body.appendChild(panel);
432        
433        // Обработчик закрытия панели
434        document.getElementById('close-analysis-panel').addEventListener('click', () => {
435            panel.remove();
436        });
437        
438        console.log('Панель с результатами отображена');
439    }
440
441    // Функция для создания кнопки AI-анализа
442    function createAnalysisButton() {
443        console.log('Создаем кнопку AI-анализа...');
444        
445        // Проверяем, не создана ли уже кнопка
446        if (document.getElementById('ai-analysis-button')) {
447            console.log('Кнопка уже существует');
448            return;
449        }
450        
451        // Ищем место для размещения кнопки
452        const targetContainer = document.querySelector('.styles_rightColumn_1dd5d') || 
453                               document.querySelector('.styles_dropdown_Fhu9J') ||
454                               document.querySelector('div[class*="rightColumn"]');
455        
456        if (!targetContainer) {
457            console.log('Контейнер для кнопки не найден, создаем фиксированную кнопку');
458            createFloatingButton();
459            return;
460        }
461        
462        // Создаем кнопку
463        const button = document.createElement('button');
464        button.id = 'ai-analysis-button';
465        button.type = 'button';
466        button.style.cssText = `
467            background: linear-gradient(135deg, #005bff 0%, #0041b8 100%);
468            color: white;
469            border: none;
470            padding: 10px 20px;
471            border-radius: 8px;
472            font-size: 14px;
473            font-weight: 600;
474            cursor: pointer;
475            display: flex;
476            align-items: center;
477            gap: 8px;
478            transition: all 0.3s;
479            box-shadow: 0 2px 8px rgba(0, 91, 255, 0.3);
480            margin-left: 12px;
481        `;
482        button.innerHTML = '🤖 AI Анализ изменений';
483        
484        button.addEventListener('mouseenter', () => {
485            button.style.transform = 'translateY(-2px)';
486            button.style.boxShadow = '0 4px 12px rgba(0, 91, 255, 0.4)';
487        });
488        
489        button.addEventListener('mouseleave', () => {
490            button.style.transform = 'translateY(0)';
491            button.style.boxShadow = '0 2px 8px rgba(0, 91, 255, 0.3)';
492        });
493        
494        button.addEventListener('click', async () => {
495            console.log('Кнопка AI-анализа нажата');
496            
497            // Показываем индикатор загрузки
498            button.disabled = true;
499            button.innerHTML = '⏳ Анализируем изменения...';
500            button.style.background = '#9e9e9e';
501            
502            try {
503                // Извлекаем данные
504                const allProducts = extractProductData();
505                
506                if (allProducts.length === 0) {
507                    alert('Не удалось найти данные о продуктах. Убедитесь, что вы находитесь на странице аналитики с таблицей продуктов.');
508                    return;
509                }
510                
511                // Фильтруем продукты со значительными изменениями
512                const significantProducts = filterSignificantChanges(allProducts);
513                
514                if (significantProducts.length === 0) {
515                    alert('Не найдено продуктов со значительными изменениями. Все показатели стабильны.');
516                    return;
517                }
518                
519                console.log(`Анализируем ${significantProducts.length} продуктов со значительными изменениями`);
520                
521                // Анализируем с помощью AI
522                const analysis = await analyzeProductsWithAI(significantProducts);
523                
524                // Отображаем результаты
525                displayAnalysisResults(analysis);
526                
527            } catch (error) {
528                console.error('Ошибка при анализе:', error);
529                alert('Произошла ошибка при анализе: ' + error.message);
530            } finally {
531                // Восстанавливаем кнопку
532                button.disabled = false;
533                button.innerHTML = '🤖 AI Анализ изменений';
534                button.style.background = 'linear-gradient(135deg, #005bff 0%, #0041b8 100%)';
535            }
536        });
537        
538        // Вставляем кнопку
539        targetContainer.appendChild(button);
540        console.log('Кнопка AI-анализа создана');
541    }
542
543    // Функция для создания плавающей кнопки
544    function createFloatingButton() {
545        const button = document.createElement('button');
546        button.id = 'ai-analysis-button';
547        button.type = 'button';
548        button.style.cssText = `
549            position: fixed;
550            top: 100px;
551            right: 20px;
552            background: linear-gradient(135deg, #005bff 0%, #0041b8 100%);
553            color: white;
554            border: none;
555            padding: 12px 24px;
556            border-radius: 8px;
557            font-size: 14px;
558            font-weight: 600;
559            cursor: pointer;
560            z-index: 9999;
561            box-shadow: 0 4px 16px rgba(0, 91, 255, 0.4);
562            transition: all 0.3s;
563        `;
564        button.innerHTML = '🤖 AI Анализ';
565        
566        button.addEventListener('mouseenter', () => {
567            button.style.transform = 'scale(1.05)';
568        });
569        
570        button.addEventListener('mouseleave', () => {
571            button.style.transform = 'scale(1)';
572        });
573        
574        button.addEventListener('click', async () => {
575            button.disabled = true;
576            button.innerHTML = '⏳ Анализируем...';
577            button.style.background = '#9e9e9e';
578            
579            try {
580                const allProducts = extractProductData();
581                if (allProducts.length === 0) {
582                    alert('Не удалось найти данные о продуктах.');
583                    return;
584                }
585                
586                const significantProducts = filterSignificantChanges(allProducts);
587                if (significantProducts.length === 0) {
588                    alert('Не найдено продуктов со значительными изменениями.');
589                    return;
590                }
591                
592                const analysis = await analyzeProductsWithAI(significantProducts);
593                displayAnalysisResults(analysis);
594                
595            } catch (error) {
596                console.error('Ошибка:', error);
597                alert('Ошибка при анализе: ' + error.message);
598            } finally {
599                button.disabled = false;
600                button.innerHTML = '🤖 AI Анализ';
601                button.style.background = 'linear-gradient(135deg, #005bff 0%, #0041b8 100%)';
602            }
603        });
604        
605        document.body.appendChild(button);
606    }
607
608    // Функция инициализации
609    function init() {
610        console.log('Инициализация AI Аналитики продуктов Ozon...');
611        
612        // Проверяем, что мы на странице аналитики
613        if (window.location.href.includes('seller.ozon.ru/app/analytics')) {
614            console.log('Страница аналитики обнаружена');
615            
616            // Ждем загрузки таблицы
617            const checkTable = setInterval(() => {
618                const table = document.querySelector('table.ct590-a');
619                if (table) {
620                    console.log('Таблица найдена, создаем кнопку');
621                    clearInterval(checkTable);
622                    setTimeout(createAnalysisButton, 1000);
623                }
624            }, 1000);
625            
626            // Останавливаем проверку через 30 секунд
627            setTimeout(() => clearInterval(checkTable), 30000);
628        }
629    }
630
631    // Запускаем инициализацию
632    if (document.readyState === 'loading') {
633        document.addEventListener('DOMContentLoaded', init);
634    } else {
635        init();
636    }
637
638    // Наблюдаем за изменениями в DOM для поддержки SPA навигации
639    const observer = new MutationObserver(() => {
640        if (window.location.href.includes('seller.ozon.ru/app/analytics') && 
641            !document.getElementById('ai-analysis-button')) {
642            const table = document.querySelector('table.ct590-a');
643            if (table) {
644                createAnalysisButton();
645            }
646        }
647    });
648
649    observer.observe(document.body, {
650        childList: true,
651        subtree: true
652    });
653
654})();
AI Аналитика продуктов Ozon | Robomonkey