feat: Зеро-персонаж, auto-publish, auto-series, channel-stats, fallback covers
- Персонаж Зеро: 23 позы (zeroCharacter.js), скрипты генерации - Auto-publish статей в TG: multipart upload, кнопки, режим alternating Zero/cover - Fallback цепочка обложек: aiprimetech gpt-5.5 → Pollinations → local SVG (6 палитр) - Auto-series: Claude haiku определяет серию для каждой статьи автоматически - Channel stats: подписчики, история, delta 24h/7d - Photo-search: Yandex API, профили доменов, Redis лимиты - Scheduled posts runner: backfill, preview, queue, cancel - promptBuilder: author_persona Зеро, голос от первого лица - Fixes: dollar-placeholder bugs в PATCH channels/autogen, listArticles фильтры - AI model: gpt-5.5 для image generation
This commit is contained in:
@@ -0,0 +1,63 @@
|
||||
// Welcome-пост от имени Зеро.
|
||||
// Использует готовый zero-avatar.webp.
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const axios = require('axios');
|
||||
const FormData = require('form-data');
|
||||
|
||||
process.chdir('/var/www/zeropost-engine');
|
||||
require('dotenv').config({ path: '/var/www/zeropost-engine/.env' });
|
||||
const settings = require('/var/www/zeropost-engine/src/services/settings');
|
||||
const { query } = require('/var/www/zeropost-engine/src/config/db');
|
||||
|
||||
const TEXT = `Привет! Я Зеро 👋
|
||||
|
||||
Веду этот канал — пишу про ИИ, кибербезопасность, автоматизацию и разработку. Каждый день — короткая заметка про что-то, что я попробовал.
|
||||
|
||||
Что внутри:
|
||||
🤖 ИИ-инструменты, которые реально работают
|
||||
💻 Разработка с ИИ-помощниками
|
||||
⚡ Автоматизация без боли
|
||||
🔒 Безопасность для обычных людей
|
||||
|
||||
Без хайпа, без «революционных открытий», без картинок с роботами. Только то, что заходит в работе.
|
||||
|
||||
🌐 Полная версия каждой заметки — на сайте
|
||||
📌 Закрепи этот пост, чтобы не потерять`;
|
||||
|
||||
(async () => {
|
||||
try {
|
||||
const { rows: chs } = await query(`SELECT * FROM channels WHERE id=1`);
|
||||
const channel = chs[0];
|
||||
const tgBase = await settings.get('TELEGRAM_API_BASE', 'https://api.telegram.org');
|
||||
|
||||
const localPath = '/var/www/zeropost-uploads/zero-avatar.webp';
|
||||
if (!fs.existsSync(localPath)) throw new Error('zero-avatar.webp not found');
|
||||
|
||||
const form = new FormData();
|
||||
form.append('chat_id', String(channel.tg_channel_id));
|
||||
form.append('caption', TEXT.slice(0, 1024));
|
||||
form.append('parse_mode', 'Markdown');
|
||||
form.append('reply_markup', JSON.stringify({
|
||||
inline_keyboard: [[{ text: '🌐 Открыть сайт', url: 'https://zeropost.ru' }]],
|
||||
}));
|
||||
form.append('photo', fs.createReadStream(localPath));
|
||||
|
||||
const res = await axios.post(`${tgBase}/bot${channel.bot_token}/sendPhoto`, form, {
|
||||
headers: form.getHeaders(),
|
||||
timeout: 60000, maxContentLength: Infinity, maxBodyLength: Infinity,
|
||||
});
|
||||
const messageId = res.data?.result?.message_id;
|
||||
console.log(`sent message_id=${messageId}, длина caption=${TEXT.length}`);
|
||||
|
||||
await query(
|
||||
`INSERT INTO posts (channel_id, content, status, published_at, tg_message_id)
|
||||
VALUES ($1,$2,'published',NOW(),$3)`,
|
||||
[channel.id, TEXT, messageId]
|
||||
);
|
||||
} catch (err) {
|
||||
console.error('FAIL:', err.response?.data || err.message);
|
||||
process.exit(1);
|
||||
}
|
||||
})();
|
||||
Reference in New Issue
Block a user