{{ error }}
{{ success }}
Дашборд
↻ Обновить
{{ stats.total_today }}
Звонков сегодня
{{ stats.inbound_today }}
Входящих
{{ stats.outbound_today }}
Исходящих
{{ fmtDuration(stats.avg_duration) }}
Средняя длительность
{{ stats.resolved_today }}
Успешные
{{ stats.errors_today }}
Ошибки
Последние звонки
ID Телефон Напр. Статус Итог Время
#{{ c.id }} {{ c.phone || '—' }}
{{ dirLabel(c.direction) }}
{{ statusLabel(c.status) }}
{{ outcomeLabel(c.outcome) }} —
{{ fmtDateFull(c.created_at) }}
AI Агенты
+ Создать агента
{{ a.name }}
{{ a.is_active ? 'активен' : 'выключен' }}
{{ a.description || 'Без описания' }}
Язык
{{ a.language }}
Провайдер
{{ a.voice_provider }}
Голос
{{ a.voice_id || '—' }}
Модель
{{ a.model }}
Редактировать
{{ a.is_active ? 'Выключить' : 'Включить' }}
Тест
Удалить
{{ testResult.msg }}
← Назад
Сгенерировать summary
Записать в KeepinCRM
Звонок #{{ currentCall.id }}
{{ dirLabel(currentCall.direction) }}
{{ statusLabel(currentCall.status) }}
Телефон
{{ currentCall.phone || '—' }}
Агент
{{ currentCall.agent_name || '—' }}
Провайдер
{{ currentCall.provider || '—' }}
Начат
{{ fmtDateFull(currentCall.started_at) }}
Завершён
{{ fmtDateFull(currentCall.ended_at) }}
Длительность
{{ fmtDuration(currentCall.duration_seconds) }}
Итог
{{ outcomeLabel(currentCall.outcome) }} —
Тональность
{{ currentCall.sentiment || '—' }}
KeepinCRM
Сделка
{{ currentCall.keepin_agreement_id || '—' }}
Клиент
{{ currentCall.keepin_client_id || '—' }}
Синхр.
{{ currentCall.keepin_synced_at ? fmtDateFull(currentCall.keepin_synced_at) : 'нет' }}
+ Комментарий в CRM
+ Задача менеджеру
Резюме
{{ currentCall.summary }}
Классификация
Итог
{{ currentCall.outcome_label || '—' }}
Причина
{{ currentCall.call_reason_label || '—' }}
ТТН
{{ currentCall.ttn_number || (currentCall.ttn_created ? 'создана' : '—') }}
Качество и изменения
Оценка AI
{{ currentCall.quality_score }}/100
Риски
{{ qualityFlags(currentCall.quality_flags_json) || 'нет' }}
Изменения заказа AI:
{{ changeType(ch.change_type) }} · {{ ch.confirmed_by_customer ? 'подтверждено клиентом' : 'без подтверждения' }} · {{ fmtDateFull(ch.created_at) }}
Оценка менеджера
Статус
— AI ответил правильно
AI ошибся Нужен повторный звонок
Проблемный звонок
Оценка (1–5)
— {{ n }}
Комментарий
Сохранить оценку
Диалог
Транскрипт
Действия ({{ callTools.length }})
{{ roleLabel(m.role) }} · {{ m.tool_name }}
{{ m.content || (m.tool_name ? ('→ ' + m.tool_name) : '') }}
Tool OK Время
{{ t.tool_name }}
{{ t.success ? 'ok' : 'err' }}
{{ fmtDateFull(t.created_at) }}
Настройки
Статус интеграций
KeepinCRM
{{ integrations.keepin ? 'настроено' : 'не настроено' }}
OpenAI Realtime
{{ integrations.openai ? 'настроено' : 'не настроено' }}
Телефония
{{ integrations.voice ? (integrations.voice.provider + (integrations.voice.configured ? ' · ok' : ' · нет')) : '—' }}
API-ключи задаются в .env на сервере и не отображаются здесь из соображений безопасности.
Общие настройки
Агент по умолчанию (для входящих)
{{ a.name }}
Приветствие
Сохранить
Логи действий (tool calls)
↻ Обновить
ID Звонок Tool Аргументы OK Ошибка Время
#{{ l.id }}
{{ l.call_id ? ('#'+l.call_id) : '—' }}
{{ l.tool_name }}
{{ l.arguments }}
{{ l.success ? 'ok':'err' }}
{{ l.error || '' }}
{{ fmtDateFull(l.created_at) }}
📷 Распознавание фото
↻ Обновить
Логи распознавания
Калибровка
Посты
Индекс фото
Обучение
Настройки
Уверенность
Все high
medium low
Тип изображения
Все скриншот
фото другое
Ручная пометка
Все верно
неверно непонятно
Conversation ID
показать фото
нет файла
#{{ a.id }}
{{ a.status }}
{{ a.confidence_level }} {{ a.confidence !== null ? a.confidence.toFixed(2) : '' }}
{{ a.image_kind }}
{{ a.match_source }}
{{ a.guard }}
старый пайплайн
артикул с фото: {{ a.detected_sku }}
{{ fmtDateFull(a.created_at) }}
{{ a.error }}
{{ a.vision_description }}
текст на фото: {{ a.vision_text }}
Кандидаты:
{{ t.sku }}
{{ t.name }}
{{ t.similarity }}≡
cos {{ t.cosine }}
spec ✓
spec ✗
цвет ✗
{{ t.match_source }}
{{ visIsLinked(a, t.sku) ? '✓ Выбран' : '✓ этот' }}
✓ Верно
✗ Неверно
Добавить SKU
Переанализировать
исправлено на {{ a.manual_sku }}
Привязано ({{ a.product_links.length }}):
{{ l.sku }}
· товар не найден
×
Показано {{ visItems.length }} из {{ visTotal }}
← Назад
Вперёд →
Пороги 0.88 / 0.70 взяты из ТЗ и являются заглушками. Разметьте разборы на вкладке
«Логи распознавания» — и здесь появится обоснованная рекомендация. Считаются только
разборы текущей ревизии пайплайна
{{ visCalib && visCalib.pipeline_rev }} :
у прежней визуальной модели другая шкала косинусов, складывать их в одну гистограмму нельзя.
Размечено
{{ visCalib.verified_total }}
Верно
{{ visCalib.correct }}
Неверно
{{ visCalib.wrong }}
{{ visCalib.note }}
Вердикты прежних ревизий (не участвуют):
{{ visCalib.legacy.total }}
(верно {{ visCalib.legacy.correct }}, неверно {{ visCalib.legacy.wrong }}).
Чтобы посмотреть их — фильтр «Только прежние» на вкладке логов.
Порог и выше Верно Неверно Всего Точность
≥ {{ b.from.toFixed(2) }}
{{ b.correct }}
{{ b.wrong }}
{{ b.cum_n }}
{{ b.cum_accuracy !== null ? (b.cum_accuracy*100).toFixed(0)+'%' : '—' }}
Точность по источникам матчинга
Источник Верно Неверно Всего Диапазон conf Точность
{{ s.match_source }}
{{ s.correct }}
{{ s.wrong }}
{{ s.n }}
{{ s.conf_min }} … {{ s.conf_max }}
{{ s.accuracy !== null ? (s.accuracy*100).toFixed(0)+'%' : '—' }}
Потолок {{ visCalib.no_high_cap }} : схлопывание кандидатов
Случаев, где потолок уравнял кандидатов с разным косинусом:
{{ visCalib.ceiling_collapse.cases }} ,
из них размечено {{ visCalib.ceiling_collapse.resolvable }} .
Косинус указал на верный товар:
{{ visCalib.ceiling_collapse.cosine_right }} ,
на неверный:
{{ visCalib.ceiling_collapse.cosine_wrong }} .
Косинус не ошибся ни разу — потолок уничтожает информацию, которая у нас была.
sim {{ e.similarity }} →
{{ c.sku }} {{ c.cosine }} ✓
Эффект механизмов. «Помог» — пометка попала в неверного кандидата,
«навредил» — в верного.
Механизм Помог Навредил Не сработал Разборов
{{ k }}
{{ m.helped }}
{{ m.hurt }}
{{ m.neutral }}
{{ m.n }}
Сейчас: high = {{ visCalib.current.high }}, medium = {{ visCalib.current.medium }}
Рекомендация:
high = {{ visCalib.suggested.high !== null ? visCalib.suggested.high : '—' }} ,
medium = {{ visCalib.suggested.medium !== null ? visCalib.suggested.medium : '—' }}
Применить рекомендацию
— выберите аккаунт —
{{ ac.instagram_username || ('аккаунт #' + ac.id) }}
10 постов
25 постов
50 постов
{{ loading.visSync ? 'Синхронизация…' : 'Синхронизировать' }}
Обновить
Просмотрено {{ visSyncResult.seen }},
распознано {{ visSyncResult.recognized }},
низкая уверенность {{ visSyncResult.low }},
подтверждённых пропущено {{ visSyncResult.skipped_confirmed }},
сбоев {{ visSyncResult.failed }}.
Синхронизация тянет посты из Graph API и сопоставляет с каталогом
по подписи и фото. Подтверждённые вручную связи не перезаписываются.
Загрузка…
🖼️
Связей пост→товар пока нет. Выберите аккаунт и нажмите «Синхронизировать».
нет медиа
#{{ p.id }}
{{ p.media_type }}
{{ p.confidence_level }} {{ p.confidence !== null ? Number(p.confidence).toFixed(2) : '' }}
{{ p.match_source }}
подтверждён
{{ fmtDateFull(p.updated_at) }}
{{ p.error }}
{{ p.caption }}
товар: {{ p.selected_sku }}
Кандидаты:
{{ t.sku }}
{{ t.name }}
{{ t.similarity }}
{{ visPostIsLinked(p, t.sku) ? '✓ Выбран' : '✓ этот' }}
Подтвердить
Переанализировать
Добавить SKU
Привязано ({{ p.product_links.length }}):
{{ l.sku }}
· товар не найден
×
Товаров
{{ visIndex.products }}
С фото
{{ visIndex.products_with_img }}
Фото всего
{{ visIndex.images_total }}
Проиндексировано
{{ visIndex.images_indexed }}
{{ visIndex.note }}
Провайдер: {{ visIndex.provider }}
SKU Название
Каталог Референсы
{{ it.sku }}
{{ it.name }}
{{ it.catalog_count }}
{{ it.manual_count }}
{{ it.manual_pending }}⏳
+ фото
{{ covOpen===it.sku ? '▲':'▼' }}
#{{ r.id }}
{{ r.status }}
{{ r.error }}
✕
Ручных референсов нет — жми «+ фото».
Ничего не найдено.
←
{{ covPage*covPageSize+1 }}–{{ Math.min((covPage+1)*covPageSize, covFilteredTotal) }} из {{ covFilteredTotal }}
→
Распознавать фото в Direct
Да Нет
Сколько кандидатов искать
Скачивать вложения
Да Нет
Сохранить
🔬 Логи Instagram-диалогов
⬇ CSV
↻ Обновить
Всего
{{ igLogSummary.total || 0 }}
Ошибки
{{ (igLogSummary.by_level && (igLogSummary.by_level.error||0) + (igLogSummary.by_level.critical||0)) || 0 }}
Предупреждения
{{ (igLogSummary.by_level && igLogSummary.by_level.warning) || 0 }}
Info / Debug
{{ (igLogSummary.by_level && (igLogSummary.by_level.info||0) + (igLogSummary.by_level.debug||0)) || 0 }}
Время Диалог Клиент Событие Ур.
Статус Причина Tool Ошибка
{{ fmtDateFull(l.created_at) }}
#{{ l.conversation_id }}
{{ l.ig_username ? ('@'+l.ig_username) : '—' }}
{{ l.event_type }}
{{ l.level }}
{{ igLogStatusCell(l) }}
{{ l.reason_label || l.reason_code || '' }}
{{ l.tool_name || '—' }}
{{ l.error || '' }}
Показано {{ igLogs.length }} из {{ igLogTotal }}
← Назад
Вперёд →
Максимальный размер JSON в логе, байт
Сейчас в логе: {{ igLogSettings.rows_total }} событий. Самое старое: {{ igLogSettings.oldest || '—' }}
Сохранить
Очистить старые сейчас
{{ igLogView.level }}
{{ igLogView.event_type }}
✕
Событие ID: #{{ igLogView.id }}
Время: {{ fmtDateFull(igLogView.created_at) }}
Клиент: @{{ igLogView.ig_username || '—' }}
Аккаунт: {{ igLogView.account_name || '—' }}
Статус диалога: {{ igLogView.conversation_status || '—' }}
Статус: {{ igLogView.status_before || '—' }} → {{ igLogView.status_after || '—' }}
Причина: {{ igLogView.reason_label || igLogView.reason_code || '—' }}
Tool: {{ igLogView.tool_name || '—' }}
Tool call ID: {{ igLogView.tool_call_id || '—' }}
Message ID: {{ igLogView.message_id || '—' }}
Queue ID: {{ igLogView.ai_queue_id || '—' }}
🩺 Диагностика звонков
↻ Обновить
Технические метрики каждого звонка: стабильность аудио (output buffer, обрывы), интервалы кадров, паузы OpenAI, event loop, инструменты. WAV-файлы и авто-диагноз — для анализа причин прерываний.
🩺
Диагностик пока нет. Сделайте звонок — метрики появятся автоматически.
Call ID Тип Длит. Обрывы (glitch) Проблема Серьёзность
#{{ d.call_id }}
{{ d.test_type }}
{{ d.duration_ms ? (Math.round(d.duration_ms/1000)+' с') : '—' }}
{{ d.glitch_underruns ?? '—' }}
{{ diagProblemLabel(d.suspected_problem) }}
{{ diagSevLabel(d.severity) }}
Открыть
ZIP
🗑
← Назад
⬇ Скачать ZIP
Общий вывод
{{ diagSevLabel(diagDetail.diagnosis.severity) }}
{{ diagProblemLabel(diagDetail.diagnosis.suspected_problem) }}
{{ diagDetail.diagnosis.explanation_ru }}
Output buffer (стабильность голоса)
Обрывы посреди речи (glitch): {{ diagDetail.metrics.output_buffer?.glitch_underrun_count }}
Вставлено тишины (кадров): {{ diagDetail.metrics.output_buffer?.silence_frames_inserted }}
AudioSocket (кадры в Asterisk)
Интервал кадров avg/max/p95: {{ diagDetail.metrics.audiosocket?.out_frame_interval_avg_ms }} / {{ diagDetail.metrics.audiosocket?.out_frame_interval_max_ms }} / {{ diagDetail.metrics.audiosocket?.out_frame_interval_p95_ms }} мс
Кадров in/out: {{ diagDetail.metrics.audiosocket?.frames_in }} / {{ diagDetail.metrics.audiosocket?.frames_out }}
OpenAI Realtime
Аудио-дельт: {{ diagDetail.metrics.openai?.audio_delta_count }}
Пауза дельт avg/max: {{ diagDetail.metrics.openai?.audio_delta_avg_gap_ms }} / {{ diagDetail.metrics.openai?.audio_delta_max_gap_ms }} мс
Первый звук: {{ diagDetail.metrics.openai?.first_audio_delta_ms }} мс
Ошибки: {{ diagDetail.metrics.openai?.errors?.length || 0 }}
Node.js / Инструменты
Event loop avg/max/p95: {{ diagDetail.metrics.node?.event_loop_delay_avg_ms }} / {{ diagDetail.metrics.node?.event_loop_delay_max_ms }} / {{ diagDetail.metrics.node?.event_loop_delay_p95_ms }} мс
Память: {{ diagDetail.metrics.node?.memory_mb }} МБ
Инструментов: {{ diagDetail.metrics.tools?.total_calls }} (макс {{ diagDetail.metrics.tools?.max_duration_ms }} мс)
Аудио (сравнение участков, раздел 22 ТЗ)
{{ diagAudioLabel(f.type) }} ({{ Math.round(f.size/1024) }} КБ)
Если «от OpenAI» чистый, а «в Asterisk» рваный — проблема в bridge/буфере. Если оба чистые, а в звонке рвётся — ближе к Asterisk/StreamTele/SIP.
t, мс Событие Детали
{{ e.t }}
{{ e.type }}
{{ diagEventDetail(e) }}
Live-звонки
↻ Обновить
🎧
Сейчас активных звонков нет
📞 {{ c.phone || '—' }}
{{ statusLabel(c.status) }}
#{{ c.id }}
Агент
{{ c.agent_name || '—' }}
Сделка
{{ c.keepin_agreement_id || '—' }}
Направление
{{ dirLabel(c.direction) }}
Открыть
На менеджера
Запретить изменения
Завершить
Последние реплики:
{{ roleLabel(m.role) }}
{{ m.content }}
Изменения заказа: {{ liveSnapshot.changes.length }}
Кампании обзвона
+ Создать кампанию
ID Название Тип Агент Статус Номера
#{{ c.id }} {{ c.name }}
{{ campaignType(c.type) }}
{{ c.agent_name || '—' }}
{{ campaignStatus(c.status) }}
{{ c.done_numbers }}/{{ c.total_numbers }}
▶
⏸
← Назад
▶ Запустить
⏸ Пауза
+ Номера
{{ currentCampaign.name }}
{{ campaignStatus(currentCampaign.status) }}
Тип
{{ campaignType(currentCampaign.type) }}
Агент
{{ currentCampaign.agent_name || '—' }}
{{ n }}
{{ campaignCallStatus(s) }}
Телефон Сделка Статус Попытки След. попытка Итог
{{ n.phone }} {{ n.agreement_id || '—' }}
{{ campaignCallStatus(n.status) }}
{{ n.attempts }}
{{ n.next_attempt_at ? fmtDateFull(n.next_attempt_at) : '—' }}
{{ n.last_outcome_code ? outcomeLabel(n.last_outcome_code) : '—' }}
База товаров
Товары
Категории
Импорт XML
Синхронизация остатков
Логи импорта
{{ productStats.total || 0 }}
Всего товаров
{{ productStats.in_stock || 0 }}
В наличии
{{ productStats.with_photo || 0 }}
С фото
Последний импорт: {{ fmtDateFull(productStats.last_import) }}
Все категории
{{ c }}
📦
Товаров не найдено. Импортируйте XML.
SKU Название Категория Цена Наличие
{{ p.sku }} {{ p.name }}
{{ p.category || '—' }}
{{ p.price ? (p.price + ' ' + (p.currency||'UAH')) : '—' }}
{{ stockLabel(p.stock_status) }}
Всего категорий: {{ prodCategories.length }}
🗂
Категорий нет. Импортируйте XML с категориями.
ID External ID Название Родитель Товаров
{{ c.id }} {{ c.external_id }}
{{ c.name }}
{{ c.parent_name || '—' }}
{{ c.product_count != null ? c.product_count : '—' }}
Импорт из файла
Загрузите XML-фид (prom.xml) с товарами, категориями, фото, ценами и остатками.
⬆ Загрузить XML-файл
Импортов ещё не было
Дата Источник Режим Всего Создано Обновлено OOS Катег. Ошибки Длит.
{{ fmtDateFull(l.created_at) }}
{{ l.source || l.filename || '—' }}
{{ l.mode || '—' }}
{{ l.total }} {{ l.created_count }}
{{ l.updated_count }}
{{ l.out_of_stock_count != null ? l.out_of_stock_count : '—' }}
{{ l.categories_count != null ? l.categories_count : '—' }}
{{ l.errors }}
{{ l.duration_ms != null ? (l.duration_ms + ' мс') : '—' }}
{{ fmtDateFull(l.created_at) }}: {{ l.error_detail }}
Правила допродаж
+ Добавить правило
Например: к power bank → кабель; к микроскопу → набор препаратов. AI предлагает по этим правилам.
Базовый SKU → Допродажа SKU Приоритет Комментарий Активно
{{ r.base_sku }}{{ r.base_name }}
{{ it.sku }} (нет в базе) (нет в наличии)
— {{ it.name || '?' }}
{{ r.upsell_sku }}
{{ r.upsell_name }}
{{ r.priority }}
{{ r.comment || '—' }}
{{ r.active?'да':'нет' }}
✎
✕
Качество звонков
↻ Обновить
ID Телефон Итог Оценка AI Риски Ревью Дата
#{{ c.id }} {{ c.phone || '—' }}
{{ c.outcome_label || outcomeLabel(c.outcome_code) }} —
{{ c.quality_score!=null ? c.quality_score+'/100' : '—' }}
{{ qualityFlags(c.quality_flags_json) }}
{{ c.manager_review_status }} —
{{ fmtDateFull(c.created_at) }}
Instagram — Диалоги
Все статусы
{{ label }}
↻ Обновить
Клиент Аккаунт Последнее сообщение Статус Язык CRM Обновлён
@{{ c.ig_username || c.ig_user_id }}
{{ c.unread_count }}
@{{ c.account_username || '—' }}
{{ c.last_message_text || '—' }}
{{ igStatuses[c.status] || c.status }}
{{ c.language || '—' }}
сделка
клиент
—
{{ fmtDateFull(c.updated_at) }}
← Назад
↻ Обновить
@{{ igDialog.ig_username || igDialog.ig_user_id }}
@{{ igDialog.account_username || '' }} · {{ igStatuses[igDialog.status] || igDialog.status }}
⏸ AI на паузе до {{ fmtDateFull(igDialog.ai_paused_until) }}
Диалог
Логи
{{ igDialogLogErrors }}
Событий пока нет. Логи пишутся с момента установки L1.
{{ fmtTimeOnly(ev.created_at) }}
{{ ev.event_type }}
· {{ ev.tool_name }}
· {{ ev.status_before }} → {{ ev.status_after }}
{{ ev.error }}
{{ ev.reason_label }}
{{ ev.debug_message }}
JSON
{{ igSenderLabel(msg.sender_type) }}
черновик
ошибка
{{ msg.text || ('['+ (msg.message_type||'attachment') +']') }}
{{ fmtDateFull(msg.created_at) }}
Сообщений пока нет
Действия менеджера
Взять на себя
Вернуть AI
Передать менеджеру
Пометить решённым
Черновик AI
Подтвердить и отправить
Отклонить
KeepinCRM
Клиент: {{ igDialog.keepin_client_id || '—' }}
Сделка: {{ igDialog.keepin_agreement_id || '—' }}
Summary
{{ igDialog.summary }}
Вызовы инструментов
{{ t.success ? '✓' : '✕' }}
{{ t.tool_name }}
Instagram — Подключения
↻ Обновить
+ Добавить аккаунт
🔌
Нет подключённых аккаунтов
Аккаунт IG user id Агент Режим Токен Активен Последнее
@{{ a.instagram_username || a.name || '—' }}
{{ a.instagram_user_id }}
{{ a.agent_name || '—' }}
{{ a.reply_mode }}
есть нет
да нет
{{ a.last_message_at ? fmtDateFull(a.last_message_at) : '—' }}
Проверить
✎
🗑
{{ a.last_error }}
Instagram — Комментарии
↻ Обновить
Автор Аккаунт Текст Статус Публ. Direct Дата
@{{ c.ig_username || c.ig_user_id || '—' }}
@{{ c.account_username || '—' }}
{{ c.text }}
{{ igCommentLabel(c.status) }}
{{ c.public_reply_sent==1 ? '✓' : '—' }}
{{ c.private_reply_sent==1 ? '✓' : '—' }}
{{ fmtDateFull(c.created_at) }}
Instagram — Качество диалогов
↻ Обновить
Клиент Статус Оценка AI Проблемы Резюме Ревью
@{{ d.ig_username || '—' }}
{{ igStatuses[d.status] || d.status }}
{{ d.quality_score!=null ? d.quality_score+'/100' : '—' }}
{{ qualityFlags(d.quality_flags_json) }}
{{ d.summary || '—' }}
{{ igReviewStatus(d) }} —
Открыть
✓ Ревью
↻ Переоценить
Instagram — Аналитика
↻ Обновить
{{ m.label }}
{{ m.value }}
Настройки Instagram
Поведение AI
Подключение Meta
Уведомления — Telegram
Бот
Получатели
Шаблоны
Правила
Логи
Настройки Telegram-бота
Bot Username
Webhook URL
Webhook Secret
Webhook: {{ ntfSettings.is_active ? 'активен' : 'не активен' }}
Проверка: {{ ntfSettings.last_check_at }} — {{ ntfSettings.last_check_result }}
Сохранить
Проверить бота
Установить webhook
Удалить webhook
Инфо webhook
✅ Бот подключён
Username: {{ ntfBotInfo.username }}
Bot ID: {{ ntfBotInfo.bot_id }}
Can join groups: {{ ntfBotInfo.can_join_groups ? 'yes' : 'no' }}
Can read all group messages: {{ ntfBotInfo.can_read_all_group_messages ? 'yes' : 'no' }}
Webhook info
URL: {{ ntfWebhookInfo.url || '—' }}
Pending updates: {{ ntfWebhookInfo.pending_update_count ?? 0 }}
Последняя ошибка: {{ ntfWebhookInfo.last_error_message }}
🆕 Новые Telegram-пользователи
Написали боту /start или /connect и ждут привязки.
Тип Кто chat_id Когда
{{ p.recipient_type==='group' ? 'группа' : 'личный' }}
{{ p.title || ((p.first_name||'') + ' ' + (p.last_name||'')).trim() || '—' }}
@{{ p.username }}
{{ p.chat_id }}
{{ p.created_at }}
Привязать
Отклонить
Получатели уведомлений
+ Добавить вручную
Пока нет получателей. Попросите менеджера написать боту /start (или добавьте бота в группу и напишите /connect) — заявка появится здесь. Либо добавьте получателя вручную по chat_id.
Название Тип chat_id username Активен Последнее уведомл. Ошибка
{{ r.name }}{{ r.comment }}
{{ r.recipient_type==='group' ? 'группа' : 'личный' }}
{{ r.chat_id }}
{{ r.username ? '@'+r.username : '—' }}
{{ r.is_active==1 ? '✅' : '⛔' }}
{{ r.last_message_at || '—' }}
{{ r.last_error || '' }}
Тест
{{ r.is_active==1 ? 'Отключить' : 'Включить' }}
✏️
🗑
Шаблоны уведомлений
+ Новый шаблон
Название Событие Parse mode Посл. сообщ. Кнопка Активен
{{ t.name }}
{{ ntfEvents[t.event_type] || t.event_type }}
{{ t.parse_mode }}
{{ t.include_last_messages==1 ? t.last_messages_count : '—' }}
{{ t.include_open_dialog_button==1 ? '✅' : '—' }}
{{ t.is_active==1 ? '✅' : '⛔' }}
Предпросмотр
✏️
🗑
Нет шаблонов. После деплоя запустите сид — появится дефолтный шаблон «Нужен менеджер».
Предпросмотр (диалог #{{ ntfPreviewConvId }})
✕
{{ ntfPreviewText }}
Правила уведомлений
+ Новое правило
Название Событие Шаблон Получатели Throttle Активно
{{ r.name }}
{{ ntfEvents[r.event_type] || r.event_type }}
{{ r.template_name || ('#'+r.template_id) }}
{{ ntfRuleRecipientsLabel(r) }}
{{ r.throttle_minutes }} мин{{ r.send_once_per_status==1 ? ', 1 раз/статус' : '' }}
{{ r.is_active==1 ? '✅' : '⛔' }}
Проверить
{{ r.is_active==1 ? 'Выкл' : 'Вкл' }}
✏️
🗑
Нет правил. После деплоя запустите сид — появится правило «Нужен менеджер — всем активным».
Проверка правила (диалог #{{ ntfRuleTest.conversation_id }}) — {{ ntfRuleTest.would_send ? '🟢 отправилось бы' : '🔴 НЕ отправилось бы' }}
✕
{{ c }}
{{ ntfRuleTest.text }}
Отправленный текст
{{ ntfLogView.created_at }} · {{ ntfLogView.status }}
· tg_msg_id: {{ ntfLogView.telegram_message_id }}
{{ ntfLogView.message_text || '(пусто)' }}
Ошибка: {{ ntfLogView.error }}
Закрыть
OpenAI — модели и расходы
Расходы
Модель AI
Цены моделей
7 дней
30 дней
90 дней
${{ (oaUsage.totals.cost_usd||0).toFixed(4) }}
расходы за {{ oaUsage.period_days }} дн.
{{ (oaUsage.totals.tokens||0).toLocaleString() }}
токенов
{{ oaUsage.totals.calls||0 }}
вызовов
По моделям
Модель Выз. Токены $
{{ m.model }} {{ m.calls }}
{{ (m.tokens||0).toLocaleString() }} ${{ (m.cost||0).toFixed(4) }}
нет данных
По операциям
Операция Выз. $
{{ oaOpLabel(o.operation) }} {{ o.calls }} ${{ (o.cost||0).toFixed(4) }}
нет данных
По дням
наведите на столбец для суммы · всего {{ oaUsage.by_day.length }} дн.
Учитываются текстовые вызовы (Instagram AI + голосовые summary). Realtime-аудио тарифицируется отдельно и здесь не отражается.
Модель для Instagram AI
{{ m.model }} (${{ m.input_per_1k }}/${{ m.output_per_1k }} за 1K)
Применить
Смена вступит в силу для новых сообщений сразу. Голосовой агент использует свою модель (OPENAI_SUMMARY_MODEL).
Цены в USD за 1000 токенов. Правьте под актуальный прайс OpenAI.
+ Модель
Модель Input/1K Output/1K Доступна для AI Заметка
{{ m.model }}
${{ m.input_per_1k }} ${{ m.output_per_1k }}
{{ m.is_available==1?'да':'нет' }}
{{ m.note }}
✎
🗑
Настройки AI-заказов
Ответственный и источник
Типы оплаты
↻ Обновить сотрудников
↻ Обновить источники
Главный ответственный по умолчанию
— не задан —
{{ u.name }} ({{ u.email }})
Источник заказа (джерело) настраивается через .env (KEEPIN_SOURCE_INSTAGRAM_ID). Доступные источники:
id {{ sc.id }} — {{ sc.name }}
Сохранить
Синонимы через запятую. Бот определяет тип по тексту клиента и пишет crm_value в поле «Тип оплати».
+ Тип оплаты
Название Значение в CRM Синонимы Приоритет Статус
{{ p.name }} {{ p.crm_value }}
{{ p.synonyms }} {{ p.priority }}
{{ p.active==1?'вкл':'выкл' }}
✎
🗑
Новая Почта
Настройки
Тест поиска
Резолвы адресов
API base: {{ npSettings.api_base }}
API ключ:
задан
не задан
{{ npSettings.key_masked }}
{{ npSettings.note }}
Проверить ключ
{{ npKeyResult.message }}
Город (в CRM): {{ npResolveResult.city_name }}
({{ npResolveResult.city_present }})
Отделение: {{ npResolveResult.warehouse || '—' }}
Тип: {{ npResolveResult.delivery_type }}
Точность:
{{ npResolveResult.confidence }}
📮
Резолвов адресов пока нет
Время Канал Ввод (город/отд.) Сматчено Тип Точность
{{ fmtDateFull(r.created_at) }}
{{ r.channel }}
{{ r.raw_city }} / {{ r.raw_warehouse }}
{{ r.matched_city_name }}{{ r.matched_warehouse }}
{{ r.delivery_type }}
{{ r.confidence }}
Синонимы поиска
⬇ Экспорт CSV
⬆ Импорт CSV
+ Группа
Группы
Тест поиска
Нераспознанные {{ synMissed.length }}
Логи поиска
🔤
Групп синонимов пока нет
Группа Синонимы Категории SKU-маски Товары Приоритет Статус
{{ g.name }} {{ g.description }}
{{ g.terms_count }} {{ g.cats_count }} {{ g.masks_count }} {{ g.skus_count }}
{{ g.priority }}
{{ g.active==1?'вкл':'выкл' }}
✎
🗑
Найдено: {{ synTestResult.total_found }}
Показано: {{ synTestResult.returned_count }}
Синонимы: {{ synTestResult.matched_groups.map(g=>g.name).join(', ') }}
→ {{ synTestResult.expanded_terms.join(', ') }}
Модели ({{ synTestResult.grouped_models.length }}):
{{ gm.model_name }}
— {{ gm.colors.join(', ') }}
· від {{ gm.price_from }} {{ gm.currency }} · {{ gm.items.length }} шт
SKU Название Цена Наличие Score
{{ p.sku }} {{ p.name }}
{{ p.price }} {{ p.currency }}
{{ p.stock_status==='in_stock'?'є':'немає' }}
{{ p.score }}
🔍
Нераспознанных запросов нет
Запрос Канал Найдено Повторов Последний
{{ m.query }} {{ m.channel || '—' }}
{{ m.found_count }} {{ m.count }}
{{ fmtDateFull(m.last_seen_at) }}
+ в синонимы
🗑
Время Канал Запрос Найдено Показано Группы
{{ fmtDateFull(l.created_at) }} {{ l.channel }}
{{ l.query }} {{ l.total_found }} {{ l.returned_count }}
{{ synParseGroups(l.matched_groups) }}
Импорт синонимов (CSV)
Формат: group_name,priority,active,term (заголовок опционален)
Отмена
Импортировать