golang

Как создать систему страшных звонков на Хэллоуин на Go и Exolve Voice API

  • вторник, 29 октября 2024 г. в 00:00:06
https://habr.com/ru/companies/exolve/articles/853952/

Хэллоуин — это время костюмов, конфет и, конечно же, легких розыгрышей. И что может быть лучше, чем отправить друзьям и знакомым жуткие автоматические звонки со страшными аудиосообщениями? В этой статье рассмотрим, как с помощью Exolve Voice API и Go можно создать систему для отправки пугающих звонков.

Что нам потребуется

  • API-ключ Exolve API (зарегистрируйтесь на Exolve).

  • Go.

  • Аудиофайлы для создания звонков (например, звук дыхания, шепот или страшные голоса). Скачать их можно здесь и дополнить своим голосом

  • Список номеров телефонов, на которые мы будем отправлять звонки.

Подготовка проекта

Создаем новый проект Go, инициализируем его и устанавливаем зависимости. Для начала определим структуру файлов проекта:

spooky_calls/
├── audio.go          # Логика работы с аудиофайлами
├── voice_message.go  # Работа с Exolve Voice API
├── worker.go         # Логика многопоточной обработки звонков
├── main.go           # Основной файл программы
├── .env              # Файл с переменными окружения

Инициализируем проект и устанавливаем зависимости:

mkdir spooky_calls
cd spooky_calls
go mod init spooky_calls
go get github.com/joho/godotenv

Создаем файл .env для хранения переменных окружения:

touch .env

Добавляем в файл .env следующие строки:

EXOLVE_API_KEY="api_key"
SENDER="номер_выданный_exolve"

Загрузка аудиофайлов

Прежде чем двигаться дальше, загрузите свои жуткие аудиофайлы в личный кабинет Exolve. При загрузке аудио в библиотеку на выходе клиент получает resource_id. Этот resource_id и будем использовать при создании голосового сообщения — передавать значение в параметре media_id Эти идентификаторы мы будем использовать для выбора случайных аудиофайлов при отправке звонков.

Логика выбора аудиофайла

Теперь создаем файл audio.go, где реализуем логику случайного выбора аудиофайла из списка загруженных:

package main

import (
    "math/rand"
    "time"
)

// Структура для хранения информации об аудиофайле
type AudioFile struct {
    ID   string
    Name string
}

// Функция для случайного выбора аудиофайла
func randomAudioClip() AudioFile {
    rand.Seed(time.Now().UnixNano())
    audioFiles := []AudioFile{
        {ID: "1967", Name: "Шепот призрака"},
        {ID: "1968", Name: "Крик из бездны"},
        {ID: "1969", Name: "Скрежет костей"},
    }
    return audioFiles[rand.Intn(len(audioFiles))]
}

Задаем несколько аудиофайлов и случайным образом выбираем один из них для каждого звонка. Файл содержит идентификатор media_id, который мы получили при загрузке аудиофайлов.

Работа с Voice API

Создадим файл voice_message.go, в котором опишем отправку голосового сообщения через Exolve Voice API:

package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "net/http"
    "os"
)

// Структура для запроса к Voice API
type VoiceRequest struct {
    Source      string `json:"source"`
    Destination string `json:"destination"`
    ServiceID   string `json:"service_id"`
}

// Функция отправки голосового сообщения
func sendVoiceCall(apiKey, source, destination, serviceID string) error {
    client := &http.Client{}
    voiceURL := "https://api.exolve.ru/call/v1/MakeVoiceMessage"

    voiceData := VoiceRequest{
        Source:      source,
        Destination: destination,
        ServiceID:   serviceID,
    }

    jsonData, err := json.Marshal(voiceData)
    if err != nil {
        return fmt.Errorf("Ошибка сериализации данных: %w", err)
    }

    req, err := http.NewRequest("POST", voiceURL, bytes.NewBuffer(jsonData))
    if err != nil {
        return fmt.Errorf("Ошибка создания запроса: %w", err)
    }

    req.Header.Set("Authorization", "Bearer "+apiKey)
    req.Header.Set("Content-Type", "application/json")

    resp, err := client.Do(req)
    if err != nil {
        return fmt.Errorf("Ошибка отправки запроса: %w", err)
    }
    defer resp.Body.Close()

    if resp.StatusCode == http.StatusOK {
        fmt.Println("Звонок успешно отправлен")
    } else {
        return fmt.Errorf("Неожиданный код ответа: %d", resp.StatusCode)
    }
    return nil
}

Код создает HTTP-запрос к API, отправляя данные о номере отправителя, получателя и идентификаторе аудиофайла.

Многопоточная отправка звонков

Для работы с большим количеством номеров воспользуемся многопоточностью. Создаем файл worker.go, где опишем логику обработки очереди номеров:

package main

import (
    "log"
)

func sendWithQueue(apiKey string, recipients []string, sender string) {
    maxWorkers := 3 // Количество одновременных потоков
    jobs := make(chan string, len(recipients))
    results := make(chan error, len(recipients))

    // Запуск воркеров
    for w := 1; w <= maxWorkers; w++ {
        go worker(apiKey, sender, jobs, results)
    }

    // Передача номеров в очередь
    for _, recipient := range recipients {
        jobs <- recipient
    }
    close(jobs)

    // Обработка результатов
    for r := 1; r <= len(recipients); r++ {
        err := <-results
        if err != nil {
            log.Println("Ошибка:", err)
        } else {
            log.Println("Звонок успешно отправлен")
        }
    }
}

// Логика воркеров для параллельной обработки
func worker(apiKey string, sender string, jobs <-chan string, results chan <- error) {
    for recipient := range jobs {
        audioFile := randomAudioClip() // Случайный выбор аудиофайла
        err := sendVoiceCall(apiKey, sender, recipient, audioFile.ID)
        results <- err
    }
}

В этом модуле используем систему очередей и запускаем несколько потоков для одновременной обработки запросов. Таким образом, можно параллельно отправлять звонки.

Основная функция

Теперь, когда все части готовы, объединяем их в основной функции программы:

package main

import (
    "log"
    "os"
    "github.com/joho/godotenv"
)

func init() {
    // Загружаем переменные окружения
    err := godotenv.Load(".env")
    if err != nil {
        log.Fatal("Ошибка загрузки файла .env")
    }
    log.Println("Переменные окружения загружены")
}

func main() {
    apiKey := os.Getenv("EXOLVE_API_KEY")
    sender := os.Getenv("SENDER")

    recipients := []string{
        "79991112233",
        "79992223344",
        "79993334455",
    }

    // Запуск массовой рассылки
    sendWithQueue(apiKey, recipients, sender)
}

Здесь загружаем переменные окружения и запускаем рассылку звонков с помощью функции sendWithQueue.


Заключение

Вот и всё! Теперь ваши друзья точно не забудут этот Хэллоуин.

А самое классное — этот проект легко модифицируется. Хотите вместо жутких криков отправлять рассылки с напоминаниями? Или продвигать акции, а может, отправлять персонализированные поздравления на Новый год? Пожалуйста! Просто замените аудиофайлы и немного адаптируйте логику с помощью API — всё в ваших руках.

Удачи в разработке, и не забывайте — шутки должны быть добрыми!