Метка: Отладка

  • Третий день с DeepSeek: как мы победили 13 ошибок и приблизились к идеалу

    Третий день с DeepSeek: как мы победили 13 ошибок и приблизились к идеалу

    Привет, друг!

    Меня зовут Константин Милютин. Если ты следишь за моим блогом, то знаешь: мы с DeepSeek уже второй день боремся с плагином «Autonews Publisher». Первый день мы создавали архитектуру, второй — ловили баги с сохранением настроек и ошибкой 404. А сегодня… сегодня мы разобрали 13 ошибок! Тринадцать! И каждая из них была маленьким кирпичиком в стене, которую мы упорно разбирали, чтобы построить работающий инструмент.

    И да, плагин всё ещё не идеален. Но мы на верном пути — и это главное. Сегодня я расскажу, как мы с DeepSeek исправляли каждую проблему, какие решения находили и чему научились за этот продуктивный день.

    Если ты не читал предыдущие части, вот ссылка: Второй день с DeepSeek. А сейчас — погнали!


    Утро третьего дня: список задач

    DeepSeek
    Создано с помощью нейросети Алисы YandexART для milyutin-codes.ru

    Я открыл чат с DeepSeek и сказал: «Сегодня мы проделали большую работу по исправлению ошибок. Давай систематизируем их для отчёта». И мы начали перебирать каждую проблему, которую обнаружили за предыдущие дни. Их оказалось 13. Тринадцать! Некоторые — крошечные, как лишние звёздочки в тексте, другие — серьёзные, как дублирование постов или неработающий Rank Math.

    Но вместо паники я почувствовал азарт. Каждая ошибка — это вызов, а с DeepSeek любой вызов превращается в увлекательное расследование. Мы взяли список и пошли по пунктам.


    1. Настройки слетали — галки не сохранялись

    DeepSeek
    Создано с помощью нейросети Алисы YandexART для milyutin-codes.ru

    Проблема. Когда я сохранял настройки на одной вкладке, галки на других вкладках сбрасывались. Это происходило потому, что каждая вкладка отправляла только свои поля, и при сохранении они затирали остальные.

    Решение. DeepSeek предложил переписать sanitize_settings() так, чтобы он сохранял ВСЕ поля, даже те, которые не были переданы в запросе. Для чекбоксов, если галка отсутствует, мы явно ставим 0. Для остальных — берём старые значения или дефолтные.

    php

    foreach ( self::$fields as $key => $field ) {
        if ( array_key_exists( $key, $input ) ) {
            $value = $input[ $key ];
        } else {
            if ( $field['type'] === 'checkbox' ) {
                $value = 0; // отсутствие галки = 0
            } else {
                $value = isset( $old[ $key ] ) ? $old[ $key ] : $field['default'];
            }
        }
        // валидация и сохранение
    }

    Теперь настройки сохраняются все и сразу. Магия!


    2. RSS-источники не добавлялись / исчезали

    Проблема. Я добавлял RSS-ленту через кастомную форму, но после сохранения других вкладок список обнулялся. Виновник — стандартная кнопка «Сохранить» на вкладке RSS, которая отправляла пустой массив.

    Решение. Мы убрали стандартную кнопку на вкладке RSS и оставили только кастомное управление. Теперь добавление и удаление происходит напрямую через update_option(), без лишних сохранений.

    php

    if ( $active_tab === 'rss' ) {
        $this->render_rss_tab(); // без стандартной формы
    }

    И вот, RSS-источники стали жить своей жизнью — стабильной и предсказуемой.


    3. Ошибка 404 при запросе к YandexGPT

    Проблема. При тестовом запуске плагин падал с ошибкой 404. Причина — устаревший URL https://llm.api.cloud.yandex.net/llm/v1alpha/instruct. Яндекс обновил API, и старый эндпоинт перестал работать.

    Решение. DeepSeek нашёл актуальный URL https://llm.api.cloud.yandex.net/foundationModels/v1/completion и обновил формат запроса на messages с ролями system и user.

    php

    private $api_url = 'https://llm.api.cloud.yandex.net/foundationModels/v1/completion';
    $body = array(
        'modelUri' => 'gpt://' . $this->folder_id . '/yandexgpt-lite',
        'messages' => array(
            array( 'role' => 'system', 'text' => $system_instruction ),
            array( 'role' => 'user', 'text' => $user_text ),
        ),
    );

    Теперь YandexGPT отвечает как часы.


    4. Парсер брал только краткое описание, а не полный текст

    Проблема. В статьях появлялись только первые два предложения, а не весь текст. Парсер брал <description>, а не <content:encoded>.

    Решение. Изменили приоритет полей: сначала ищем content:encoded, потом descriptioncontentsummary.

    php

    if ( isset( $item->children( 'http://purl.org/rss/1.0/modules/content/' )->encoded ) ) {
        $content = (string) $item->children( 'http://purl.org/rss/1.0/modules/content/' )->encoded;
    } elseif ( isset( $item->description ) ) {
        $content = (string) $item->description;
    }

    Теперь статьи выходят полными — от заголовка до последнего абзаца.


    5. В контенте оставались символы **

    Проблема. В тексте встречались **, которые, видимо, были маркерами выделения в оригинальном RSS.

    Решение. Просто удаляем их через str_replace().

    php

    $new_content = str_replace( '**', '', $new_content );

    Чистота!


    6. Заголовок содержал кавычки и многоточие

    Проблема. Заголовки выглядели неряшливо: кавычки, лишние точки.

    Решение. Удаляем все виды кавычек, обрезаем до 60 символов, но так, чтобы не обрезать слово посередине.

    php

    $new_title = str_replace( ['«', '»', '"', "'", '“', '”'], '', $new_title );
    if ( mb_strlen( $new_title ) > 60 ) {
        $new_title = mb_substr( $new_title, 0, 60 );
        $new_title = preg_replace( '/\s+\S*$/', '', $new_title );
    }

    Теперь заголовки — как на подбор.


    7. Ссылка на источник отображалась полным URL

    Проблема. В посте появлялось https://www.technologyreview.com/..., что выглядело громоздко.

    Решение. Извлекаем только домен, без www.

    php

    $host = parse_url( $source_url, PHP_URL_HOST );
    $display_host = str_replace( 'www.', '', $host );
    $link_html = '<a href="' . esc_url( $source_url ) . '" rel="nofollow">' . esc_html( $display_host ) . '</a>';

    Коротко и ясно.


    8. SEO-ошибки: фокусный ключевик отсутствовал в первом абзаце, H2 и URL

    Rank Math
    Создано с помощью нейросети Алисы YandexART для milyutin-codes.ru

    Проблема. Rank Math ругался, что ключевое слово не встречается в первых 100 словах, нет подзаголовков с ключевиком, и URL не содержит ключа.

    Решение. Мы вставили ключевик в первый абзац (если его там не было), добавили H2 с ключевиком, и сформировали slug из заголовка.

    php

    // Вставляем в первый абзац
    if ( stripos( $first_p, $focus_keyword ) === false ) {
        $new_first_p = '<p><strong>' . $focus_keyword . '</strong> — ' . $first_p . '</p>';
    }
    // Добавляем H2
    if ( stripos( $content, '<h2' ) === false ) {
        $content = '<h2>' . $focus_keyword . ': ключевые аспекты</h2>' . $content;
    }
    // Формируем slug
    $slug = sanitize_title( $new_title );

    Теперь SEO-показатели должны улучшиться.


    9. Контент был слишком коротким (<600 слов)

    Проблема. YandexGPT выдавал статьи по 300–400 слов, а хотелось минимум 600.

    Решение. Мы изменили промпт для нейросети, добавив явное требование к объёму.

    php

    $system = '... Постарайся создать статью объёмом не менее 600 слов, но не более 800 слов. Разбей текст на абзацы, используй подзаголовки (H2, H3).';

    Теперь статьи стали объёмными и структурированными.


    10. Плагин публиковал одну и ту же новость несколько раз

    YandexGPT
    Создано с помощью нейросети Алисы YandexART для milyutin-codes.ru

    Проблема. При каждом запуске плагин публиковал уже опубликованные новости, создавая дубли.

    Решение. Мы добавили механизм запоминания ссылок в отдельной опции autonews_published_links. Перед публикацией проверяем, не была ли ссылка уже использована.

    php

    private $published_links_key = 'autonews_published_links';
    private function is_already_published( $link ) {
        $published = get_option( $this->published_links_key, array() );
        return in_array( $link, $published );
    }
    private function mark_as_published( $link ) {
        $published = get_option( $this->published_links_key, array() );
        if ( ! in_array( $link, $published ) ) {
            $published[] = $link;
            update_option( $this->published_links_key, $published );
        }
    }

    Дублей больше нет!


    11. Изображение не извлекалось из RSS

    Проблема. В статьях не было обложек, хотя в RSS-ленте они были.

    Решение. Мы написали метод extract_image(), который ищет картинку в трёх местах: media:contentenclosure (если это изображение), или первое изображение в HTML-контенте.

    php

    private function extract_image( $item, $content ) {
        // media:content
        if ( isset( $item->children( 'http://search.yahoo.com/mrss/' )->content ) ) { ... }
        // enclosure
        if ( isset( $item->enclosure ) && strpos( $type, 'image/' ) === 0 ) { ... }
        // первое изображение в HTML
        if ( preg_match( '/<img[^>]+src=["\']([^"\']+)["\']/i', $html, $matches ) ) { ... }
    }

    Теперь каждая статья получает обложку.


    12. Ошибка соединения при тестовом запуске — не было логов

    Проблема. Иногда тестовый запуск падал с непонятной ошибкой, но в логах ничего не было.

    Решение. Мы добавили логи перед каждым вызовом YandexGPT, чтобы отследить, на каком именно шаге происходит сбой.

    php

    $this->logger->log( 'Перед генерацией заголовка', 'info' );
    $new_title = $this->gpt->generate_title( $raw_title );
    $this->logger->log( 'После генерации заголовка', 'info' );

    Теперь мы видим, где именно плагин спотыкается.


    13. Rank Math заполнялся некорректно — описание без ключевика, заголовок с %sitename%

    Проблема. В SEO-полях Rank Math было пустое описание или заголовок с лишним %sitename%.

    Решение. Мы убрали %sitename% из заголовка и добавили ключевик в описание, если его там не было.

    php

    $seo_title = str_replace( '%sitename%', '', $seo_title );
    if ( $focus_keyword && stripos( $description, $focus_keyword ) === false ) {
        $description = $focus_keyword . ' — ' . $description;
    }

    Итог: что мы исправили сегодня

    YandexGPT
    Создано с помощью нейросети Алисы YandexART для milyutin-codes.ru

    После нашего марафона были обновлены следующие файлы:

    • autonews-publisher.php – добавлен AJAX-обработчик и проверка включения.
    • includes/class-settings.php – полная переработка сохранения, одна форма, вкладки-навигация.
    • includes/class-rss-fetcher.php – извлечение полного контента, очистка от рекламы, поиск изображения.
    • includes/class-yandex-gpt.php – обновлённый URL, формат, промпт на 600+ слов.
    • includes/class-publisher.php – предотвращение дублей, SEO-оптимизация, ссылка-домен, заголовок без кавычек.
    • includes/class-cron.php – проверка включения плагина.
    • assets/js/admin.js – AJAX для тестовой кнопки.

    Плагин стал значительно стабильнее. Он сохраняет настройки, парсит RSS, генерирует контент через YandexGPT, создаёт посты с SEO-полями, изображениями и без дублей. Да, он всё ещё не идеален — иногда изображения не загружаются, иногда теги генерируются не совсем точно. Но мы на верном пути.


    Чему я научился в третий день

    DeepSeek
    Создано с помощью нейросети Алисы YandexART для milyutin-codes.ru
    1. Системный подход — когда у тебя 13 ошибок, важно не паниковать, а разбирать их по одной, от простых к сложным.
    2. DeepSeek — гениальный напарник — он не просто даёт код, он объясняет логику, предлагает альтернативы, помогает увидеть картину целиком.
    3. Отладка — это творчество — каждая ошибка — это загадка, а её решение — маленькая победа.
    4. SEO-оптимизация требует внимания — даже если контент хорош, без правильного ключевика в нужных местах его не увидят.
    5. Дубли — зло — механизм запоминания ссылок должен быть в любом парсере.

    Что дальше?

    Плагин почти готов. Осталось отладить генерацию изображений через YandexART, добавить поддержку нескольких языков и, возможно, сделать веб-интерфейс для ручного запуска. Но основа уже есть — и она работает.

    Я продолжу вести дневник разработки, чтобы ты видел весь путь — от первой строки кода до готового продукта.


    Призыв к действию

    Друг, если ты тоже разрабатываешь что-то сложное и боишься ошибок — не бойся. Ошибки — это часть пути. С DeepSeek ты никогда не останешься один на один с проблемой. Он поможет, подскажет, объяснит.

    Подписывайся на мой блог, чтобы не пропустить следующую статью — в ней я расскажу, как мы наконец-то запустили плагин в боевом режиме.


    Контакты

    📧 Email: milyutinkv@gmail.com
    🌐 Сайт: milyutin-codes.ru
    💬 Группа ВК: vk.ru/milyutin_codes

    Задавай вопросы, делись идеями, давай расти вместе.


    Продолжение следует. Мы приближаемся к финалу.

    Константин Милютин
    Автор блога «Милютин Код»