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

DeepSeek

Написано

в

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

Меня зовут Константин Милютин. Если ты следишь за моим блогом, то знаешь: мы с 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

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


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

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

Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *