Реализация AI Voice Cloning (клонирование голоса) в мобильном приложении
Voice cloning в мобильном приложении — это запись образца голоса на устройстве, отправка на API провайдера, создание клона и последующий синтез новых фраз этим голосом. Технически задача не сложная, но она упирается в требования к качеству записи, юридические ограничения и UX управления голосовыми профилями.
Провайдеры и их API
ElevenLabs — де-факто стандарт для voice cloning. Instant Voice Cloning требует минимум 1 минуту аудио, Professional Voice Cloning — 30+ минут для высокого качества. API простой: POST /v1/voices/add с multipart аудиофайлами, в ответ — voice_id, который используешь в TTS-запросах.
Resemble AI — чуть хуже по качеству, но дешевле. Поддерживает streaming synthesis.
PlayHT — поддерживает клонирование из 5–10 секунд аудио (с заметно худшим качеством).
Для русского языка ElevenLabs работает хорошо с записью 2–5 минут чистой речи.
Требования к записи на устройстве
Качество клона напрямую зависит от качества образца. Минимальные требования:
- Частота дискретизации: 44100 Гц или 48000 Гц
- Формат: WAV (несжатый) или FLAC. MP3 с артефактами сжатия ухудшает клон
- Шум: SNR > 20 дБ. Тихая комната, не кухня с холодильником
- Длительность: 60+ секунд для Instant Cloning, лучше — 3–5 минут
На iOS записываем через AVAudioEngine с форматом AVAudioFormat(commonFormat: .pcmFormatFloat32, sampleRate: 44100, channels: 1, interleaved: false), затем конвертируем в WAV через AVAudioFile:
func exportToWAV(pcmBuffer: AVAudioPCMBuffer, destinationURL: URL) throws {
let settings: [String: Any] = [
AVFormatIDKey: kAudioFormatLinearPCM,
AVSampleRateKey: 44100.0,
AVNumberOfChannelsKey: 1,
AVLinearPCMBitDepthKey: 16,
AVLinearPCMIsFloatKey: false,
AVLinearPCMIsBigEndianKey: false
]
let file = try AVAudioFile(forWriting: destinationURL, settings: settings)
try file.write(from: pcmBuffer)
}
На Android — AudioRecord с ENCODING_PCM_16BIT, 44100 Гц, запись в WAV через добавление 44-байтного заголовка перед PCM-данными.
Загрузка голоса в ElevenLabs
func uploadVoice(audioURLs: [URL], name: String) async throws -> String {
var request = URLRequest(url: URL(string: "https://api.elevenlabs.io/v1/voices/add")!)
request.httpMethod = "POST"
request.setValue(apiKey, forHTTPHeaderField: "xi-api-key")
let boundary = UUID().uuidString
request.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
var body = Data()
// Name field
body.append("--\(boundary)\r\nContent-Disposition: form-data; name=\"name\"\r\n\r\n\(name)\r\n".data(using: .utf8)!)
// Audio files
for (i, url) in audioURLs.enumerated() {
let audioData = try Data(contentsOf: url)
body.append("--\(boundary)\r\nContent-Disposition: form-data; name=\"files\"; filename=\"sample_\(i).wav\"\r\nContent-Type: audio/wav\r\n\r\n".data(using: .utf8)!)
body.append(audioData)
body.append("\r\n".data(using: .utf8)!)
}
body.append("--\(boundary)--\r\n".data(using: .utf8)!)
request.httpBody = body
let (data, _) = try await URLSession.shared.data(for: request)
let response = try JSONDecoder().decode(VoiceResponse.self, from: data)
return response.voice_id
}
voice_id сохраняем локально (Keychain / SharedPreferences) — он нужен для всех последующих TTS-запросов этим голосом.
Управление голосовыми профилями
Приложение должно позволять:
- Создавать несколько голосовых профилей (свой голос, голос персонажа, голос диктора)
- Переименовывать и удалять (
DELETE /v1/voices/{voice_id}) - Проверять качество клона — воспроизвести тестовую фразу сразу после создания
Хранение: voice_id + метаданные в локальной БД. Аудиообразцы после успешной загрузки можно удалить с устройства — они хранятся у провайдера.
Этические и правовые ограничения
ElevenLabs требует подтверждения, что пользователь клонирует собственный голос или имеет явное согласие владельца голоса. В ToS — запрет на клонирование без согласия. Реализуй обязательный чекбокс согласия и сохраняй timestamp в базе.
В ряде юрисдикций (EU, некоторые штаты США) использование биометрических данных без согласия влечёт регуляторные риски. Это нужно учитывать при проектировании политики хранения данных.
Типичные ошибки
Запись через AVAudioSession.sharedInstance().setCategory(.record) без установки preferredSampleRate: 44100 — на некоторых устройствах система выберет 16000 Гц, что даёт заметно худший клон.
Отправка несжатого WAV на весь экран записи — на 3-минутной записи это ~30 МБ. Нужна фоновая загрузка через URLSession.background.
Сроки
Экран записи + загрузка в ElevenLabs + TTS клонированным голосом — 5–8 дней. Полный флоу с управлением профилями, качественным recorder UI (waveform, громкость, шум), тестовым воспроизведением клона — 2–3 недели.







