Автор Тема: LLM в жизни людей и моделистов  (Прочитано 7384 раз)

0 Пользователей и 1 Гость просматривают эту тему.

Оффлайн Gematogen

  • Глобальный модератор
  • Ветеран
  • *****
  • Сообщений: 6993
  • Репутация: +258/-1
  • Имя: Михаил
Re: LLM в жизни людей и моделистов
« Ответ #60 : 20 Августа 2026, 03:05:07 »
Чтобы сделать конкретную вещь, нужен контроль. Чтобы был полный контроль - тебе нужно конкретно описывать каждую деталь итоговой модели.
Ну то-есть мы с тобой мыслим одинаково.

Просто у меня есть подозрение, что это либо достижимо, либо скоро будет достижимо с ИИ. Поэтому я иногда пробую разные штуки.
Соблазн потратить на модель день а не месяц - велик.
А темпы развития и доступность моделей быстро меняются.
Михаил, DCC

Оффлайн Knallfrosch

  • Администратор
  • Ветеран
  • *****
  • Сообщений: 7460
  • Репутация: +325/-46
  • САМОЗВАНЕЦ
    • NSCALECLUB.RU
Re: LLM в жизни людей и моделистов
« Ответ #61 : 21 Августа 2026, 15:32:03 »
Коллеги на "западе" уже страдают от повального увлечения генеративным ИИ:





Оффлайн BR95009

  • Ветеран
  • *****
  • Сообщений: 1079
  • Репутация: +73/-1
  • Аналог. Озвучиваю сам!
    • www.br95009.ru
  • Откуда: Москва
  • Имя: Дима
Re: LLM в жизни людей и моделистов
« Ответ #62 : 27 Сентября 2026, 10:06:20 »
Ну... AI можно использовать по разному. Например.

Все мы знает сайт https://www.spurweite-n.de/. Он хорош всем, только вот в результатх поиска нет картинок, и это делает его на половину бесполезным лично для меня. Так было до момента, пока я не узнал, что AI мозет написать любой скрипт, который ты попросишь, и существует дополнение для броузеров Tampermonkey, которое позволяет запускать пользовательские скрипты.

Промпт для ChatGPT был такой:

Цитировать
Для любой страницы результатами поиска с сайта https://www.spurweite-n.de/  сделай скрипт для tempermonkey extention, который:
1) добавит на страницу кнопку "показать картинки"
2) при нажатии зайдет по каждой ссылке в списке на страницу с описание модели, получит ссылку на картинку модели(в разделе после строки "Bild zum Produkt für", первое фото)
3) вставит или добавит эту картинку в таблицу поиска на странице с результатами поиска.

Адрес страницы:  https://www.spurweite-n.de/ncontent/ndb/ndb-searchresult.asp?MSel_Bezeichnung_VString=&Sel_Hersteller_VString=&Sel_Vertrieb_VString=&MSel_ArtikelNr_VString=&Sel_Baureihe_VString=&Sel_Produktdatum_VString=&Sel_KatQuelle_FString=&Sel_Produktstatus_FString=&Sel_MitBild_Bool=&Sel_Digitalschnittstelle_FString=&Sel_SoundTyp_FString=&Sel_Mixed_Full=&Sel_Epoche_FString=III&Sel_Gesellschaft_FString=DB+-+Deutsche+Bundesbahn&Sel_HerkunftLand_FString=&Sel_Gattung1_FString=Wagen&Sel_Gattung2_FString=Personen&Sel_produktsammlung__KaufOrt_VString=&DispCount=50&Sel_ORDERBY=Bezeichnung&B1=Suche+starten

Резкльтат:

Цитировать
Ниже — скрипт для Tampermonkey, который добавляет кнопку «Показать картинки» на страницы результатов поиска Spurweite-n.de. При нажатии он последовательно открывает страницы моделей в фоновом режиме, находит первое фото в разделе Bild zum Produkt für и добавляет его в таблицу результатов.
Скрипт рассчитан на указанный сайт и поиск вагонов DB эпохи III. Он также должен работать на других страницах результатов поиска этого же сайта.

// ==UserScript==
// @name         Spurweite-n.de - Show model pictures
// @namespace    https://www.spurweite-n.de/
// @version      1.0
// @description  Add model pictures to search results
// @match        https://www.spurweite-n.de/ncontent/ndb/ndb-searchresult.asp*
// @grant        GM_xmlhttpRequest
// @connect      www.spurweite-n.de
// ==/UserScript==

(function () {
    'use strict';

    const IMG_WIDTH = 130;
    const DELAY = 200;

    // Button
    const btn = document.createElement('button');
    btn.textContent = 'Показать картинки';
    Object.assign(btn.style, {
        position: 'fixed',
        top: '15px',
        right: '20px',
        zIndex: 99999,
        padding: '12px 20px',
        background: '#1769aa',
        color: 'white',
        border: '0',
        borderRadius: '5px',
        cursor: 'pointer',
        fontSize: '15px',
        fontWeight: 'bold',
        boxShadow: '0 2px 8px #777'
    });
    document.body.appendChild(btn);

    const sleep = ms =>
        new Promise(resolve => setTimeout(resolve, ms));

    function getProductLinks() {
        const links = [...document.querySelectorAll('a[href]')];
        const seen = new Set();
        const result = [];

        for (const a of links) {
            const href = new URL(a.href, location.href);

            if (href.hostname !== location.hostname) continue;
            if (href.pathname.toLowerCase().includes(
                'ndb-searchresult.asp'
            )) continue;

            // Only links that appear to lead to model descriptions
            if (!/ndb-/i.test(href.pathname)) continue;

            const row = a.closest('tr');
            if (!row || !row.closest('table')) continue;
            if (seen.has(href.href)) continue;

            // Avoid navigation and empty links
            if (!a.textContent.trim()) continue;

            seen.add(href.href);
            result.push({ url: href.href, row });
        }

        return result;
    }

    function findFirstProductImage(doc) {
        const normalize = s =>
            s.replace(/\s+/g, ' ').trim().toLowerCase();

        // Find the section heading
        const candidates = [...doc.querySelectorAll(
            'h1,h2,h3,h4,b,strong,td,th,p,div,span'
        )];

        const heading = candidates.find(el =>
            normalize(el.textContent).includes(
                'bild zum produkt für'
            ) &&
            el.children.length < 5
        );

        if (!heading) return null;

        // Search for the first image after the heading
        // within its surrounding content.
        let container = heading.parentElement;

        for (let i = 0; i < 4 && container; i++) {
            const images = [...container.querySelectorAll('img')]
                .filter(img => img.getAttribute('src'));

            if (images.length) {
                return images[0].src;
            }

            container = container.parentElement;
        }

        // Fallback: locate the heading in document order
        const all = [...doc.querySelectorAll('*')];
        const index = all.indexOf(heading);

        for (let i = index + 1; i < all.length; i++) {
            const el = all[i];
            if (el.tagName === 'IMG' && el.getAttribute('src')) {
                return el.src;
            }
        }

        return null;
    }

    function fetchPage(url) {
        return new Promise(resolve => {
            GM_xmlhttpRequest({
                method: 'GET',
                url,
                timeout: 20000,
                onload(response) {
                    if (response.status < 200 ||
                        response.status >= 300) {
                        resolve(null);
                        return;
                    }

                    const doc = new DOMParser().parseFromString(
                        response.responseText,
                        'text/html'
                    );

                    resolve(findFirstProductImage(doc));
                },
                onerror() {
                    resolve(null);
                },
                ontimeout() {
                    resolve(null);
                }
            });
        });
    }

    function addImageColumn(rows) {
        const tables = [...document.querySelectorAll('table')];

        // Find the table containing the most product links
        let table = null;
        let max = 0;

        for (const t of tables) {
            const count = rows.filter(item =>
                item.row.closest('table') === t
            ).length;

            if (count > max) {
                max = count;
                table = t;
            }
        }

        if (!table) return;

        // Add a header cell to the first suitable header row
        const header = table.querySelector('tr');
        if (header) {
            const th = document.createElement(
                header.querySelector('th') ? 'th' : 'td'
            );
            th.textContent = 'Bild';
            th.style.textAlign = 'center';
            header.appendChild(th);
        }

        for (const item of rows) {
            if (item.row.dataset.pictureCell) continue;

            const cell = document.createElement('td');
            cell.style.textAlign = 'center';
            cell.style.verticalAlign = 'middle';
            cell.style.minWidth = IMG_WIDTH + 'px';
            cell.textContent = 'Загрузка...';

            item.row.appendChild(cell);
            item.cell = cell;
            item.row.dataset.pictureCell = '1';
        }
    }

    btn.addEventListener('click', async () => {
        btn.disabled = true;

        const rows = getProductLinks();
        if (!rows.length) {
            btn.textContent = 'Ссылки не найдены';
            btn.disabled = false;
            return;
        }

        addImageColumn(rows);

        let done = 0;
        let found = 0;

        for (const item of rows) {
            btn.textContent =
                `Загрузка ${done + 1}/${rows.length}`;

            try {
                const imageUrl = await fetchPage(item.url);

                if (imageUrl && item.cell) {
                    const img = document.createElement('img');
                    img.src = imageUrl;
                    img.alt = 'Фото модели';
                    img.loading = 'lazy';

                    Object.assign(img.style, {
                        maxWidth: IMG_WIDTH + 'px',
                        maxHeight: '110px',
                        objectFit: 'contain',
                        display: 'block',
                        margin: 'auto'
                    });

                    item.cell.textContent = '';
                    item.cell.appendChild(img);
                    found++;
                } else if (item.cell) {
                    item.cell.textContent = 'Нет фото';
                }
            } catch (e) {
                if (item.cell) {
                    item.cell.textContent = 'Ошибка';
                }
            }

            done++;
            await sleep(DELAY);
        }

        btn.textContent = `Готово: ${found}/${rows.length}`;
        btn.disabled = false;
    });
})();

Все прекрасно работает.




... и добавил:
Модифицированный код, добавляющий 3 картинки, а не одну.


// ==UserScript==
// @name         Spurweite-n.de - Show 3 model pictures
// @namespace    https://www.spurweite-n.de/
// @version      1.1
// @description  Add first 3 model pictures to search results
// @match        https://www.spurweite-n.de/ncontent/ndb/ndb-searchresult.asp*
// @grant        GM_xmlhttpRequest
// @connect      www.spurweite-n.de
// ==/UserScript==

(function () {
    'use strict';

    const IMG_WIDTH = 130;
    const MAX_IMAGES = 3;
    const DELAY = 200;

    const btn = document.createElement('button');
    btn.textContent = 'Показать картинки';
    Object.assign(btn.style, {
        position: 'fixed',
        top: '15px',
        right: '20px',
        zIndex: 99999,
        padding: '12px 20px',
        background: '#1769aa',
        color: 'white',
        border: '0',
        borderRadius: '5px',
        cursor: 'pointer',
        fontSize: '15px',
        fontWeight: 'bold',
        boxShadow: '0 2px 8px #777'
    });
    document.body.appendChild(btn);

    const sleep = ms =>
        new Promise(resolve => setTimeout(resolve, ms));

    function getProductLinks() {
        const links = [...document.querySelectorAll('a[href]')];
        const seen = new Set();
        const result = [];

        for (const a of links) {
            const href = new URL(a.href, location.href);

            if (href.hostname !== location.hostname) continue;
            if (href.pathname.toLowerCase().includes(
                'ndb-searchresult.asp'
            )) continue;
            if (!/ndb-/i.test(href.pathname)) continue;

            const row = a.closest('tr');
            if (!row || !row.closest('table')) continue;
            if (seen.has(href.href)) continue;
            if (!a.textContent.trim()) continue;

            seen.add(href.href);
            result.push({ url: href.href, row });
        }

        return result;
    }

    function findFirstProductImages(doc) {
        const normalize = s =>
            s.replace(/\s+/g, ' ').trim().toLowerCase();

        const candidates = [...doc.querySelectorAll(
            'h1,h2,h3,h4,b,strong,td,th,p,div,span'
        )];

        const heading = candidates.find(el =>
            normalize(el.textContent).includes(
                'bild zum produkt für'
            ) &&
            el.children.length < 5
        );

        if (!heading) return [];

        // Search near the section heading first
        let container = heading.parentElement;

        for (let i = 0; i < 4 && container; i++) {
            const images = [...container.querySelectorAll('img')]
                .filter(img => img.getAttribute('src'));

            if (images.length) {
                return [...new Set(
                    images.map(img => img.src)
                )].slice(0, MAX_IMAGES);
            }

            container = container.parentElement;
        }

        // Fallback: collect the first images after the heading
        const all = [...doc.querySelectorAll('*')];
        const index = all.indexOf(heading);
        const found = [];

        for (let i = index + 1;
             i < all.length && found.length < MAX_IMAGES;
             i++) {
            const el = all[i];

            if (el.tagName === 'IMG' &&
                el.getAttribute('src')) {
                const src = el.src;
                if (!found.includes(src)) found.push(src);
            }
        }

        return found;
    }

    function fetchPage(url) {
        return new Promise(resolve => {
            GM_xmlhttpRequest({
                method: 'GET',
                url,
                timeout: 20000,

                onload(response) {
                    if (response.status < 200 ||
                        response.status >= 300) {
                        resolve([]);
                        return;
                    }

                    const doc = new DOMParser().parseFromString(
                        response.responseText,
                        'text/html'
                    );

                    resolve(findFirstProductImages(doc));
                },

                onerror() {
                    resolve([]);
                },

                ontimeout() {
                    resolve([]);
                }
            });
        });
    }

    function addImageColumn(rows) {
        const tables = [...document.querySelectorAll('table')];
        let table = null;
        let max = 0;

        for (const t of tables) {
            const count = rows.filter(item =>
                item.row.closest('table') === t
            ).length;

            if (count > max) {
                max = count;
                table = t;
            }
        }

        if (!table) return;

        const header = table.querySelector('tr');

        if (header && !header.dataset.pictureHeader) {
            const th = document.createElement(
                header.querySelector('th') ? 'th' : 'td'
            );

            th.textContent = 'Bilder';
            th.style.textAlign = 'center';
            header.appendChild(th);
            header.dataset.pictureHeader = '1';
        }

        for (const item of rows) {
            if (item.row.dataset.pictureCell) {
                item.cell = item.row.lastElementChild;
                continue;
            }

            const cell = document.createElement('td');
            cell.style.textAlign = 'center';
            cell.style.verticalAlign = 'middle';
            cell.style.minWidth = IMG_WIDTH + 'px';
            cell.textContent = 'Загрузка...';

            item.row.appendChild(cell);
            item.cell = cell;
            item.row.dataset.pictureCell = '1';
        }
    }

    btn.addEventListener('click', async () => {
        btn.disabled = true;

        const rows = getProductLinks();

        if (!rows.length) {
            btn.textContent = 'Ссылки не найдены';
            btn.disabled = false;
            return;
        }

        addImageColumn(rows);

        let done = 0;
        let found = 0;

        for (const item of rows) {
            btn.textContent =
                `Загрузка ${done + 1}/${rows.length}`;

            try {
                const imageUrls = await fetchPage(item.url);

                if (imageUrls.length && item.cell) {
                    item.cell.textContent = '';

                    for (const imageUrl of imageUrls) {
                        const img = document.createElement('img');
                        img.src = imageUrl;
                        img.alt = 'Фото модели';
                        img.loading = 'lazy';

                        Object.assign(img.style, {
                            maxWidth: IMG_WIDTH + 'px',
                            maxHeight: '110px',
                            objectFit: 'contain',
                            display: 'block',
                            margin: '4px auto'
                        });

                        item.cell.appendChild(img);
                    }

                    found++;
                } else if (item.cell) {
                    item.cell.textContent = 'Нет фото';
                }
            } catch (e) {
                if (item.cell) {
                    item.cell.textContent = 'Ошибка';
                }
            }

            done++;
            await sleep(DELAY);
        }

        btn.textContent =
            `Готово: ${found}/${rows.length}`;
        btn.disabled = false;
    });
})();

... и добавил:


Ну стоит ли говорить, что такая связка: чатГПТ + тампермонкей позволяет делать все что угодно с любыми страницами в сети.
IIm, G, H0, H0m, H0e, N (DB-III), live steam. MMH0. WWW.BR95009.RU

Оффлайн Кёф

  • Ветеран
  • *****
  • Сообщений: 2527
  • Репутация: +140/-1
    • Блог Александра a.k.a. Кёф
  • Откуда: Балашиха
  • Имя: Александр/Кёф
Re: LLM в жизни людей и моделистов
« Ответ #63 : 18 Октября 2026, 14:09:04 »
Все мы знает сайт https://www.spurweite-n.de/. Он хорош всем, только вот в результатах поиска нет картинок, и это делает его на половину бесполезным лично для меня.

Добрый день, Дмитрий!
Да, есть такое дело, штука полезная, можно "совершенствовать" некоторые чужие сайты самостоятельно.
Кстати, Spurweite-n.de явно отстаёт в плане защиты, учитывая уровень и уникальность контента, чувствуется как его "тибидохают" и какие иногда задержки (это не в упрёк, предлагаемые скрипты не создадут серьёзной нагрузки).

Я думаю, что или скоро этот ресурс закончится или они всё-таки доработают сайт и защитятся симметричными технологиями, что скорее всего дороговато будет, хотя я не знаю их коммерции но не думаю, что "гребут бабло лопатой".

Кажется, что уже ситуация меняется, например в том-же поиске, они, наконец начали ограничивать выдачу и писать "Sie haben eine Suche eingestellt, die sehr viele Ergebnisse zeigt. Es wurden 7253 Einträge augewählt. Erlaubt sind maximal 500 Suchergebnisse. Bitte verfeinern sie ihre Suche" (Вы задали параметры поиска, которые привели к слишком большому количеству результатов: было найдено 7253 записи. Допускается не более 500 результатов поиска. Пожалуйста, уточните условия поиска). Ранее так не было и можно было ввести "*" и сайт делал пагинацию (возможность выбора тысяч страниц в результате поиска).

Но, надеюсь, ресурс останется жить.

... и добавил:


В свою очередь, я тут воспользовался ещё одним или даже двумя способами применения LLM - технологий.

Я попробовал сделать русские субтитры для англоязычного ролика который болтался у меня в AVI на компе. Получилось вполне норм.

Так вот, конвейер такой:
1. из локального видео, локально-же, при помощи "Subtitle Edit" и скачиваемыми им локальными моделями делаются субтитры на английском.
2. эти субтитры прямо из "Subtitle Edit" переводятся Google Translate v.1 (не требует никакой регистрации).
3. уже русские субтитры жёстко вшиваются в видеоряд.
4. потом эти же русские субтитры скармливаются в Google режим ИИ (Gemini) и в один клик делаются временные метки.
5. видео загружается на RuTube и в комментарий скармливаются эти самые временные метки.

Приведу ссылку на ролик тут т.к. оффтопик для нашего форума, а в "иные хобби" не рискну отправлять, это скорее круг моих интересов и такой темы на форуме нет
Спойлер (кликните для показа/скрытия)

Ну и к слову про копирайт.
Спойлер (кликните для показа/скрытия)