Щоденний конвеєр GitHub → локальна LLM, який пише мої проєктні картки
Розділ "Проекти" на цьому сайті не підтримується вручну. Раз на день робота переглядає мої репозиторії GitHub, виявляє зміни, просить локальну мовну модель написати короткий опис кожного зміненого проєкту та зберігає результат. Я публікую ті, що варті показу; решта залишаються чернетками.
Ось як це працює — і, що важливіше, три правила, які не дають йому робити нічого дурного.
Потік роботи
cron (03:30)
→ GET /api/internal/repos (що я вже знаю: repo → останній SHA)
→ GET api.github.com/user/repos (тонкий, ТІЛЬКИ ЧИТАННЯ токен)
→ diff by default-branch SHA (далі йдуть лише змінені репозиторії)
→ fetch README + languages
→ POST {OLLAMA}/api/chat (gemma, формат: json, think: false)
→ POST /api/internal/projects (злиття в SQLite)
LLM є локальним — екземпляр Ollama, що працює з Gemma у локальній мережі. Жоден код, README чи метадані репозиторію ніколи не залишають мережу. Моделі задано в суворому системному промпті поводитися як "точний технічний копірайтер" та повертати лише JSON-об'єкт:
{ "title": "…", "blurb": "…", "tags": ["…"], "highlight": true }
format: "json" від Ollama гарантує парсируваний вивід, а think: false вимикає трасування міркувань моделі — це швидше (~5–6 с/репо) та чистіше.
Правило 1 — торкатися лише того, що змінилося
Кожен репозиторій, який я бачив, записаний у таблицю repo_state з його останнім SHA для основної гілки. Кожен запуск порівнює поточний SHA зі збереженим; незмінені репозиторії пропускаються до виклику моделі. LLM — це дорогий крок, тому він виконується лише для репозиторіїв, які насправді змінилися. Другий запуск через кілька хвилин нічого не робить і викликає модель нуль разів.
Правило 2 — ніколи перезаписувати мої правки
Вивід моделі — це автоматичні дані. У SQLite кожен проєкт має два паралельні набори полів: автоматичні значення (з GitHub/LLM) та значення перевизначення (те, що я ввів в адмінці). Публічний сайт показує значення перевизначення, якщо воно існує, інакше — автоматичне.
Ендпоінт злиття це забезпечує. Коли репозиторій змінюється і конвеєр надсилає нові дані, він оновлює автоматичні колонки та залишає *_override, published та sort_order недоторканими. Таким чином я можу вручну переписати опис, а запуск завтра оновить метадані GitHub під ним, ніколи не торкаючись моїх слів. LLM — це двигун пропозицій, а не джерело істини.
Правило 3 — приватне залишається приватним
Усі мої репозиторії є приватними, і приватний README може містити контекст клієнта чи внутрішній контекст, який я ніколи не захочу на публічній сторінці. Тому імпорт конфіденційний за замовчуванням: нововиявлений репозиторій вставляється як неопублікована чернетка (published = 0). Ніщо, що створює конвеєр, не видно на сайті, доки я явно не перемкну цей вимикач в адмінці. Сам токен є тільки для читання (Contents + Metadata, без прав запису) — він може дивитися, але не може надсилати.
Що робити, якщо модель недоступна
Оскільки LLM знаходиться у цьому офлайн-пакетному шляху, а не в шляху запиту, збій є незначною подією для відвідувачів — сайт продовжує обслуговувати дані зі SQLite. Конвеєр також обробляє це коректно: якщо Ollama недоступний, цей репозиторій пропускається (його SHA не оновлюється, тому він повторюється наступним запуском), і я отримую єдине сповіщення в Telegram зі списком того, що було пропущено. Жодних збоїв, жодних напівзаписаних даних, жодних тихих прогалин.
Навіщо це робити
Я постійно випускаю невеликі інструменти. Підтримка портфоліо в синхроні вручну — це саме та рутина, яка тихо гниє. Це перекладає нудну частину — "що я створив і який одинрядковий опис" — на машину, яка працює щоночі, зберігаючи при цьому всі редакційні та конфіденційні рішення твердо за собою.
Ця цікава автоматизація ніколи не стоїть між вами та цією сторінкою. Це вся концепція.
Прозорість: більшість дописів тут створено за допомогою ШІ, а неанглійські версії перекладені локальною LLM і вичитані. Помітили помилку? Напишіть мені.