Хэллоуин — это время костюмов, конфет и, конечно же, легких розыгрышей. И что может быть лучше, чем отправить друзьям и знакомым жуткие автоматические звонки со страшными аудиосообщениями? В этой статье рассмотрим, как с помощью 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 — всё в ваших руках.
Удачи в разработке, и не забывайте — шутки должны быть добрыми!