#AI-ассистент с OpenAI

🧠 Сложность: advanced | Скоупы: crm, task | Стек: Node.js, openai SDK

#Что делаем

Создаём интеллектуального помощника, который анализирует историю сделки в CRM (активности, таймлайн) с помощью GPT и предлагает следующее действие. На основе рекомендации ассистент автоматически создаёт задачу с конкретным описанием. Это ускоряет работу менеджеров и повышает конверсию сделок.

#Необходимо

  • API-ключ Вайбкод с правами crm, task
  • OpenAI API Key
  • Node.js 18+
  • Пакеты: openai

#Полный код

javascript
// ai-crm-assistant.js
// AI-ассистент: анализирует сделку и создаёт задачу с рекомендацией

import OpenAI from 'openai';

const API_KEY = process.env.VIBE_API_KEY;
const BASE_URL = process.env.VIBE_BASE_URL;
const OPENAI_API_KEY = process.env.OPENAI_API_KEY;

const openai = new OpenAI({ apiKey: OPENAI_API_KEY });

const HEADERS = {
  'X-Api-Key': API_KEY,
  'Content-Type': 'application/json',
};

// Получаем данные сделки через Entity API
async function getDeal(dealId) {
  const response = await fetch(`${BASE_URL}/v1/deals/${dealId}`, {
    headers: { 'X-Api-Key': API_KEY },
  });

  const { data } = await response.json();
  return data;
}

// Получаем активности сделки через Entity API
async function getDealActivities(dealId) {
  const response = await fetch(`${BASE_URL}/v1/activities/search`, {
    method: 'POST',
    headers: HEADERS,
    body: JSON.stringify({
      filter: {
        ownerTypeId: 2, // Сделка
        ownerId: dealId,
      },
      select: ['id', 'subject', 'description', 'typeId', 'createdAt', 'completed'],
      sort: { createdAt: 'desc' },
    }),
  });

  const { data } = await response.json();
  return data || [];
}

// Отправляем контекст сделки в GPT для анализа
async function analyzeWithGPT(deal, activities) {
  // Формируем текстовое описание истории сделки
  const activitiesText = activities
    .map((item) => {
      const status = item.completed ? 'завершено' : 'в работе';
      return `- [${item.createdAt}] ${item.subject} (${status})`;
    })
    .join('\n');

  const prompt = `Ты — опытный менеджер по продажам. Проанализируй сделку и предложи конкретное следующее действие.

Сделка:
- Название: ${deal.title}
- Стадия: ${deal.stageId}
- Сумма: ${deal.amount} ${deal.currency}
- Дата создания: ${deal.createdAt}

История активностей:
${activitiesText || 'Активностей пока нет'}

Ответь в формате JSON:
{
  "analysis": "краткий анализ текущей ситуации (2-3 предложения)",
  "nextAction": "конкретное следующее действие",
  "taskTitle": "заголовок задачи для менеджера",
  "taskDescription": "подробное описание задачи",
  "priority": "high/medium/low",
  "deadlineDays": число дней на выполнение
}`;

  const completion = await openai.chat.completions.create({
    model: 'gpt-4o',
    messages: [{ role: 'user', content: prompt }],
    response_format: { type: 'json_object' },
    temperature: 0.3,
  });

  return JSON.parse(completion.choices[0].message.content);
}

// Создаём задачу через Entity API
async function createTask(recommendation, dealId, responsibleId) {
  const deadline = new Date();
  deadline.setDate(deadline.getDate() + (recommendation.deadlineDays || 3));

  const priorityMap = { high: 2, medium: 1, low: 0 };

  const response = await fetch(`${BASE_URL}/v1/tasks`, {
    method: 'POST',
    headers: HEADERS,
    body: JSON.stringify({
      title: `[AI] ${recommendation.taskTitle}`,
      description: [
        recommendation.taskDescription,
        '',
        '---',
        `Анализ AI: ${recommendation.analysis}`,
        `Сделка ID: ${dealId}`,
      ].join('\n'),
      responsibleId: responsibleId,
      priority: priorityMap[recommendation.priority] || 1,
      deadline: deadline.toISOString(),
      ufCrmTask: [`D_${dealId}`], // Привязка к сделке
    }),
  });

  const { data } = await response.json();
  return data;
}

// Основная функция: анализ сделки и создание задачи
async function processDeal(dealId) {
  console.log(`\n📋 Загружаем сделку #${dealId}...`);
  const deal = await getDeal(dealId);

  if (!deal) {
    console.error('Сделка не найдена');
    return;
  }

  console.log(`   Название: ${deal.title}`);
  console.log(`   Стадия: ${deal.stageId}, Сумма: ${deal.amount}`);

  console.log('📜 Загружаем историю активностей...');
  const activities = await getDealActivities(dealId);
  console.log(`   Найдено активностей: ${activities.length}`);

  console.log('🧠 Анализируем с помощью GPT...');
  const recommendation = await analyzeWithGPT(deal, activities);

  console.log('\n💡 Рекомендация AI:');
  console.log(`   Анализ: ${recommendation.analysis}`);
  console.log(`   Действие: ${recommendation.nextAction}`);
  console.log(`   Приоритет: ${recommendation.priority}`);

  console.log('\n📝 Создаём задачу...');
  const task = await createTask(recommendation, dealId, deal.assignedById);
  console.log(`   Задача создана, ID: ${task.id}`);
}

// Запуск: передаём ID сделки аргументом
const dealId = process.argv[2];
if (!dealId) {
  console.log('Использование: node ai-crm-assistant.js <DEAL_ID>');
  process.exit(1);
}

processDeal(dealId).catch(console.error);

#Как это работает

  1. Скрипт принимает ID сделки и загружает её данные через Entity API (GET /v1/deals/:id).
  2. Далее через Entity API (POST /v1/activities/search) запрашиваются активности сделки — звонки, письма, встречи, комментарии.
  3. Вся информация о сделке и её истории формируется в промпт и отправляется в GPT-4o с запросом на анализ и рекомендацию.
  4. GPT возвращает структурированный JSON с анализом ситуации, рекомендованным действием и параметрами задачи.
  5. На основе ответа GPT автоматически создаётся задача через Entity API (POST /v1/tasks), привязанная к сделке.
  6. Задача назначается ответственному менеджеру из сделки с дедлайном и приоритетом по рекомендации AI.

#Что можно улучшить

  • Запускать анализ автоматически при смене стадии сделки (через polling или webhooks)
  • Добавить память: сохранять предыдущие рекомендации и учитывать их при следующем анализе
  • Использовать Function Calling в OpenAI для более точного управления действиями (создание звонков, писем)
  • Добавить Slack/Telegram уведомление менеджеру с кратким описанием рекомендации