Привет, Хабр! Представим ситуацию: вы клиент. Разговор с менеджером завершён, он предложил вам что-то полезное — услугу, продукт или подписку — и, допустим, вы соглашаетесь: «Почему бы и нет, отличная идея». Менеджер записал ваше согласие и обещал напомнить вам через месяц. Звучит просто.
Но вот в реальности ни один менеджер не помнит про сотни обещаний клиентам. И здесь на помощь приходит автоматизация. В этой статье рассмотрим, как построить систему автоматического напоминания, которая избавит менеджеров от лишней работы и увеличит количество сделок, которые могли бы улетучиться.
Для реализации понадобятся:
-
Golang — основная платформа, на которой будем писать все сервисы.
-
Exolve API — для обработки звонков и получения текстовой расшифровки разговоров.
-
SQLite с GORM — база данных для хранения согласий клиентов, анализа и отчётности.
-
Webhook — для автоматического запуска цепочки при готовности транскрибации.
-
HTTP и JSON — для работы с API и передачи данных в запросах.
Активация транскрибации
Чтобы система могла анализировать согласие клиента, нужна текстовая расшифровка звонков.
Для начала активируем транскрибацию на номере, с которого идут звонки.
package main import ( "bytes" "encoding/json" "fmt" "log" "net/http" "os" ) // Загружаем API-ключ из переменных окружения var apiKey = os.Getenv("EXOLVE_API_KEY") // enableTranscription включает транскрибацию на указанном номере func enableTranscription(numberCode uint64) error { endpoint := "https://api.exolve.ru/number/v1/SetCallTranscribationState" payload := map[string]interface{}{ "number_code": numberCode, "call_transcribation": true, } body, err := json.Marshal(payload) if err != nil { return fmt.Errorf("ошибка сериализации: %w", err) } req, err := http.NewRequest("POST", endpoint, bytes.NewBuffer(body)) if err != nil { return fmt.Errorf("ошибка создания запроса: %w", err) } req.Header.Set("Authorization", "Bearer "+apiKey) req.Header.Set("Content-Type", "application/json") client := &http.Client{} resp, err := client.Do(req) if err != nil { return fmt.Errorf("ошибка отправки запроса: %w", err) } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { return fmt.Errorf("не удалось включить транскрибацию, статус: %d", resp.StatusCode) } log.Println("Транскрибация включена успешно.") return nil } func main() { err := enableTranscription(79991112233) if err != nil { log.Fatalf("Ошибка активации транскрибации: %v", err) } }
Функция enableTranscription отправляет запрос на активацию транскрибации для указанного номера. Передаём API-ключ в заголовке авторизации, чтобы подтвердить права. Если что-то пошло не так — код выведет понятное сообщение об ошибке. Основное здесь — отлавливать ошибки на каждом этапе, чтобы, если что-то пошло не так, система не просто «глохла», а давала обратную связь.
Получение текста разговора и анализ согласия
Теперь есть возможность получать текстовую расшифровку каждого звонка. Настало время разобраться, сказал ли клиент «да» или «нет». Для этого напишем функцию getTranscription, которая извлекает текст, и функцию analyzeConsent, проверяющую наличие согласия клиента.
func getTranscription(uid uint64) (string, error) { endpoint := "https://api.exolve.ru/statistics/call-record/v1/GetTranscribation" payload := map[string]interface{}{ "uid": uid, } body, err := json.Marshal(payload) if err != nil { return "", fmt.Errorf("ошибка сериализации: %w", err) } req, err := http.NewRequest("POST", endpoint, bytes.NewBuffer(body)) if err != nil { return "", fmt.Errorf("ошибка создания запроса: %w", err) } req.Header.Set("Authorization", "Bearer "+apiKey) req.Header.Set("Content-Type", "application/json") client := &http.Client{} resp, err := client.Do(req) if err != nil { return "", fmt.Errorf("ошибка получения транскрибации: %w", err) } defer resp.Body.Close() var result map[string]interface{} if err := json.NewDecoder(resp.Body).Decode(&result); err != nil { return "", fmt.Errorf("ошибка декодирования ответа: %w", err) } chunks := result["transcribation"].([]interface{})[0].(map[string]interface{})["chunks"].(map[string]interface{}) text := chunks["text"].(string) return text, nil } func analyzeConsent(text string) bool { consentKeywords := []string{"да", "согласен", "конечно"} for _, keyword := range consentKeywords { if strings.Contains(strings.ToLower(text), keyword) { return true } } return false }
getTranscription извлекает текстовую расшифровку по uid звонка. Ошибки обрабатываются на каждом этапе, так что если произойдет сбой — точно узнаем об этом.
analyzeConsent проверяет, есть ли в тексте слова, указывающие на согласие. Функция возвращает true, если одно из слов найдено.
Теперь есть текст разговора, и можно понять, хочет ли клиент напоминание. Дальше подключаем БД.
Сохраняем данные о согласии в базе данных
Если клиент согласился на напоминание, хочется сохранить это в базе данных для последующего анализа. Это позволит отслеживать конверсию, считать успешные напоминания и вести отчётность.
import ( "gorm.io/driver/sqlite" "gorm.io/gorm" "log" ) type Consent struct { ID uint `gorm:"primaryKey"` UID uint64 `gorm:"unique;not null"` Text string `gorm:"not null"` Agreed bool `gorm:"not null"` } func initDB() (*gorm.DB, error) { db, err := gorm.Open(sqlite.Open("consents.db"), &gorm.Config{}) if err != nil { return nil, err } db.AutoMigrate(&Consent{}) return db, nil } func saveConsent(db *gorm.DB, uid uint64, text string, agreed bool) error { consent := Consent{UID: uid, Text: text, Agreed: agreed} return db.Create(&consent).Error }
Используем SQLite для простоты, но можно использовать любую базу данных. Функция saveConsent сохраняет UID звонка, текст и результат анализа (согласие или отказ) в базу. Это пригодится, если нужно строить аналитику по клиентам.
Отправка SMS с поддержкой повторных попыток
Допустим, клиент согласился на напоминание. Теперь задача — отправить ему SMS через месяц. Но, как известно, отправка SMS может быть не всегда надёжной: сбои сети, проблемы на стороне оператора. Поэтому добавим механизм повторных попыток.
import "time" func scheduleSMS(db *gorm.DB, uid uint64, to, message string) { delay := 30 * 24 * time.Hour time.AfterFunc(delay, func() { retryCount := 3 for i := 0; i < retryCount; i++ { if sendSMS(to, message) { log.Printf("SMS отправлено для UID: %d", uid) break } else { log.Printf("Ошибка отправки SMS для UID: %d, попытка %d", uid, i+1) time.Sleep(5 * time.Second) } } }) } func sendSMS(to, message string) bool { // Здесь будет реальная логика отправки SMS return true }
Функция scheduleSMS планирует отправку SMS через месяц, а если попытка отправки не удалась, повторяет её до трёх раз. Если все попытки провалены, система просто зафиксирует ошибку в логе.
Используем webhook для полной автоматизации
Чтобы сделать систему полностью автономной, добавим webhook. Он будет автоматом запускать анализ текста и отправку SMS, когда расшифровка разговора готова. Это избавляет от необходимости вручную запускать проверку для каждого звонка.
import ( "github.com/gin-gonic/gin" "net/http" ) func handleWebhook(db *gorm.DB) func(c *gin.Context) { return func(c *gin.Context) { var payload struct { UID uint64 `json:"uid"` } if err := c.BindJSON(&payload); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "неверный формат данных"}) return } text, err := getTranscription(payload.UID) if err != nil { log.Printf("Ошибка получения транскрибации: %v", err) return } agreed := analyzeConsent(text) if err := saveConsent(db, payload.UID, text, agreed); err != nil { log.Printf("Ошибка сохранения согласия: %v", err) } if agreed { scheduleSMS(db, payload.UID, "+79991112233", "Напоминаем о нашем предложении!") } } } func main() { db, err := initDB() if err != nil { log.Fatalf("Ошибка инициализации базы данных: %v", err) } r := gin.Default() r.POST("/webhook", handleWebhook(db)) r.Run(":8080") }
Webhook позволяет Exolve автоматически уведомлять сервер, когда расшифровка готова.
Заключение
Вот и всё — создали простую автоматическую систему напоминаний, которая берёт на себя процесс от звонка до SMS. Эту систему легко расширить и улучшить: подключить аналитику для отслеживания конверсий, добавить улучшенный NLP для анализа сложных ответов, а также интегрировать дополнительные каналы связи.
Если хотите углубиться в детали API и узнать больше о возможностях МТС Exolve, рекомендую ознакомиться с документацией Exolve.
ссылка на оригинал статьи https://habr.com/ru/articles/861346/
Добавить комментарий