Реалізація AI Voice Cloning (клонування голосу) в мобільному додатку
Voice cloning в мобільному додатку — це запис образцу голосу на пристрої, відправка на API провайдера, створення клона та подальший синтез нових фраз цим голосом. Технічно задача не складна, але упирається в вимоги до якості запису, юридичні обмеження та UX управління голосовими профілями.
Провайдери та їхні API
ElevenLabs — де-факто стандарт для voice cloning. Instant Voice Cloning вимагає мінімум 1 хвилину аудіо. Professional — 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 тижні.







