feat: initial zeropost-engine structure
- AI service with Anthropic claude-sonnet-4-6 - Bull queue for async generation jobs - Routes: /api/generate, /api/channels, /api/posts - PostgreSQL schema: users, channels, posts, generation_jobs - Supports: post, article, topics generation types
This commit is contained in:
@@ -0,0 +1,80 @@
|
||||
const axios = require('axios');
|
||||
const config = require('../config');
|
||||
|
||||
const ANTHROPIC_URL = 'https://api.anthropic.com/v1/messages';
|
||||
const MODEL = 'claude-sonnet-4-6';
|
||||
|
||||
/**
|
||||
* Generate text via Anthropic API
|
||||
* @param {string} systemPrompt
|
||||
* @param {string} userPrompt
|
||||
* @param {object} options - { maxTokens, temperature }
|
||||
*/
|
||||
const generate = async (systemPrompt, userPrompt, options = {}) => {
|
||||
const { maxTokens = 2000 } = options;
|
||||
|
||||
const res = await axios.post(ANTHROPIC_URL, {
|
||||
model: MODEL,
|
||||
max_tokens: maxTokens,
|
||||
system: systemPrompt,
|
||||
messages: [{ role: 'user', content: userPrompt }],
|
||||
}, {
|
||||
headers: {
|
||||
'x-api-key': config.anthropicApiKey,
|
||||
'anthropic-version': '2023-06-01',
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
|
||||
const text = res.data.content?.[0]?.text;
|
||||
if (!text) throw new Error('Empty response from Anthropic');
|
||||
return text;
|
||||
};
|
||||
|
||||
/**
|
||||
* Generate a Telegram post
|
||||
*/
|
||||
const generatePost = async ({ topic, tone = 'neutral', language = 'ru', channelContext = '' }) => {
|
||||
const system = `Ты — профессиональный автор Telegram-каналов. Пишешь посты на ${language === 'ru' ? 'русском' : 'английском'} языке.
|
||||
Тон: ${tone}.
|
||||
${channelContext ? `Контекст канала: ${channelContext}` : ''}
|
||||
Правила:
|
||||
- Пост 150-400 слов
|
||||
- Используй эмодзи уместно
|
||||
- Не используй markdown заголовки (##, **), только текст и эмодзи
|
||||
- В конце добавь 2-4 релевантных хэштега`;
|
||||
|
||||
const user = `Напиши пост на тему: "${topic}"`;
|
||||
return generate(system, user, { maxTokens: 1000 });
|
||||
};
|
||||
|
||||
/**
|
||||
* Generate a blog article
|
||||
*/
|
||||
const generateArticle = async ({ topic, language = 'ru', keywords = [] }) => {
|
||||
const system = `Ты — эксперт по искусственному интеллекту, пишешь SEO-оптимизированные статьи на ${language === 'ru' ? 'русском' : 'английском'} языке.
|
||||
Правила:
|
||||
- Статья 800-1500 слов
|
||||
- Структура: заголовок H1, введение, 3-5 разделов H2, заключение
|
||||
- Используй ключевые слова органично
|
||||
- Простой и понятный язык`;
|
||||
|
||||
const user = `Напиши статью на тему: "${topic}"${keywords.length ? `\nКлючевые слова: ${keywords.join(', ')}` : ''}`;
|
||||
return generate(system, user, { maxTokens: 3000 });
|
||||
};
|
||||
|
||||
/**
|
||||
* Generate topic ideas for a channel
|
||||
*/
|
||||
const generateTopics = async ({ channelContext, count = 10, language = 'ru' }) => {
|
||||
const system = `Генерируй идеи для постов в Telegram-канале. Отвечай только JSON массивом строк, без пояснений.`;
|
||||
const user = `Придумай ${count} идей для постов. Контекст канала: "${channelContext}". Язык: ${language}. Формат: ["тема1","тема2",...]`;
|
||||
const raw = await generate(system, user, { maxTokens: 800 });
|
||||
try {
|
||||
return JSON.parse(raw.replace(/```json|```/g, '').trim());
|
||||
} catch {
|
||||
return raw.split('\n').filter(Boolean).slice(0, count);
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = { generate, generatePost, generateArticle, generateTopics };
|
||||
Reference in New Issue
Block a user