Импорт данных в телефонную книгу
Поддерживается 2 основных источника данных для телефонной книги:
Источник: AddressBook (GraphQL)
Используется как основной корпоративный справочник.
Clerk обращается к GraphQL‑API AddressBook с запросом contactsFind, получая постранично (по 1000 записей) контакты.
Для каждого контакта запрашиваются поля:
id— UID;firstName,middleName,lastName— Имя, Отчество, Фамилия (маппинг:lastName→SecondName,firstName→FirstName,middleName→ThirdName);org— Department (используется, если не удалось определить по иерархии);parents— список родительских групп (kind и position) для определения Department, Group, SubGroup по маппингу уровней;phones— массив номеров; приоритет у номера с типомwork, иначе берётся первый непустой.
Авторизация выполняется через Keycloak (JWT) или по API‑ключу (зависит от AUTH_TYPE).
Источник: VCF (vCard)
Используется как альтернативный или дополнительный источник (задаётся через PB_URL);
Поддерживается версия VERSION:4.0;
Обязательные поля для каждой карточки:
FN— полное имя. Разбивается по пробелам на слова (см. шаблоны выше). Если количество слов не равно 1, 2 или 3 – контакт пропускается.TEL— номер телефона (берётся первое встреченное значение, нормализуется — удаляются все нецифровые символы).UID— уникальный идентификатор. При отсутствии UID контакт обрабатывается, но не участвует в механизме диффа, и для него не сохраняются пользовательские настройки (например, множитель).
Необязательное поле:
CATEGORIES— содержит от 0 до 3 наименований, разделённых точкой с запятой (;). Первое → Department, второе → Group, третье → SubGroup. Если значений меньше, недостающие поля остаются пустыми. Использование запятой (,) в качестве разделителя не поддерживается — значения «слипнутся».
Все остальные поля vCard (N, EMAIL, ORG, TITLE, REV и др.) игнорируются.
Пример контакта VCF
Телефонная книга в приложении заполняется из заранее подготовленной адресной книги с контактами в формате vcard.
Пример контакта в vcard:
BEGIN:VCARD VERSION:4.0 UID:2368919030008402998 CATEGORIES:Отдел разработки;Космические аппараты;Микропроцессоры FN:Петрова Маргарита Дмитриевна REV:2023-09-12 09:06:38 TEL;TYPE=WORK:112 TITLE:Инженер-программист END:VCARD
Внутренняя структура телефонной книги
Формирование контактов из vcard во внутреннее представление автосекретаря происходит следующим образом:
- Поле UID берется без изменений.
- Поле TEL записывается в поле Number.
- Поле FN разбивается по пробелам и обрабатывается одним из способов, в зависимости от полученных слов:
- Получено одно слово: оно записывается в поле FirstName. SecondName и ThirdName заполняются пустыми строками;
- Получено два слова: первое записывается в поле SecondName, второе — в поле FirstName, и ThirdName заполняется пустой строкой;
- Получено три слова: первое записывается в поле SecondName, второе записывается в поле FirstName, третье — в поле ThirdName.
- Поле CATEGORIES разбивается на значения (разделенные «;»), и полученные значения заполняются в следующем порядке:
- Первое в Department;
- Второе в Group;
- Третье в SubGroup.
Если полученных значений получается меньше трех, то недостающие поля заполняются пустой строкой.
Пример сформированного контакта в телефонной книге секретаря:
{
"UID": "2368919030008402998",
"FirstName": "маргарита",
"SecondName": "петрова",
"ThirdName": "дмитриевна",
"Department": "отдел разработки",
"Group": "космические аппараты",
"SubGroup": "микропроцессоры",
"Number": "112",
}
Для организации логики поиска с использованием уточнений создается словарь на основе телефонной книги, содержащий слова и фразы из телефонной книги со специальными тегами.
Специальные теги могут принимать следующие значения:
- firstname — имя;
- secondname — фамилия;
- thirdname — отчество;
- department — отдел;
- group — группа;
- subgroup — подгруппа;
- notag — слова, не относящиеся к остальным тегам (необходимо для собирания фраз, например, слова [«отдел», «коммерции»] по отдельности имеют тег notag, но фраза «отдел коммерции», уже будет иметь тег department).
Обработка некорректных контактов
Контакты, не прошедшие валидацию (например, с повреждёнными словами, невалидным номером, неправильным форматом ФИО), не попадают в основную телефонную книгу и недоступны для поиска.
Такие записи помещаются в отдельный список повреждённых контактов, который можно просмотреть через эндпоинт /pb_corrupted (и в web‑интерфейсе). Это позволяет администратору вручную исправить данные и повторно загрузить книгу.
В логах Clerk фиксируются предупреждения о пропущенных контактах с указанием причины (например, «mixed alphabets in word», «invalid phone number», «invalid FN format»).
Настройка множителей для «проблемных» контактов
Некоторые контакты могут плохо распознаваться системой, в силу особенностей работы модели:
- Редкие и иностранные: Фамилии со сложной фонетикой для конкретного языка (например, Джгамадзе, Кшиштоф, Нгуен, Купп);
- С созвучными согласными: Имена, отличающиеся одной согласной (Мила — Мира, Коля — Толя, Аня — Аля);
- Похожие на нарицательные слова: Имена и фамилии, совпадающие со смысловыми словами (Лилия, Вера, Мороз, Король), так как модель пытается заменить их по контексту;
- Из одного слога: Короткие имена и фамилии из двух–трех букв (Ян, Ли, Ким) часто теряются в потоке речи или принимаются за предлоги и союзы.
Такие контакты в дальнейшем будут называться «проблемными».
Механизм множителей улучшает распознавание таких контактов. Множитель корректирует вес в языковой модели. На примере фамилии Купп — увеличение множителя позволяет системе ASR при обработке созвучных фонем отдавать приоритет гипотезе «купп», снижая вероятность ошибочного распознавания слова «куб».
Для каждого контакта можно задать числовой множитель (по умолчанию 1), который влияет на вероятность выбора этого контакта при распознавании.
Множитель не улучшает качество распознавания речи, а только изменяет относительный вес контакта в модели: контакт с множителем 10 будет представлен в тренировочном словаре в 10 раз чаще, чем с множителем 1.
Оптимальный диапазон — от 1 до 30; значения выше 100 не рекомендуются, так как могут привести к перекосу модели в пользу одного контакта.
Изменение множителя вступает в силу только после инициации обновления телефонной книги и успешной перекомпиляции модели. Изменения сохраняются в резервной копии (backup.pb) в volume Clerk и переживают перезапуск.
Для настройки множителей для проблемных контактов (рисунок 1):
- Откройте web‑интерфейс ASR и перейдите в раздел «Телефонная книга»;
- Найдите проблемный контакт (по ФИО или номеру);
- В строке контакта найдите поле «Множитель»:
- по умолчанию оно, как правило, равно 1 (или другому небольшому значению).
- Увеличьте множитель для этого контакта, например, до 10.
- Сохраните изменения (кнопка в поле редактирования).
- Запустите обновление телефонной книги:
- нажмите кнопку «Обновить телефонную книгу» в правом верхнем углу окна;
- убедитесь, что слева внизу по индикатору статуса модель сейчас не компилируется (если идёт компиляция, дождитесь её окончания и только потом запускайте новое обновление).
- Дождитесь завершения обновления и перекомпиляции модели (индикатор статуса должен перейти в «готово/ok»).
- Повторно протестируйте звонки на этого абонента и оцените качество распознавания.
Рисунок 1
Если после первого повышения множителя проблема осталась:
- Ещё раз увеличьте множитель для этого же контакта на 10 (с 10 до 20).
- Повторите действия:
- Сохранить изменённый множитель;
- Нажать «Обновить телефонную книгу»;
- Дождаться окончания компиляции модели;
- Проверить распознавание на реальных или тестовых звонках.
При необходимости можно повышать множитель ещё, но:
- не стоит сразу ставить слишком большие значения (100 и более) — это может привести к перекосу модели в пользу одного контакта;
- оптимальный диапазон обычно находится в пределах 10–30, для единичных особо сложных контактных записей — чуть выше.
Множитель влияет только на вероятность выбора конкретного контакта, а не на базовое качество распознавания речи.
После изменения множителей обязательно нужно инициировать обновление телефонной книги и дождаться завершения компиляции — без этого изменения не попадут в модель.
Алгоритм поиска
На входе поиск получает текст с ASR в виде строки, и осуществляется поиск, который содержит следующие шаги:
- Препроцессинг строки и NER (распознавание сущностей);
- Поиск с использованием полученных сущностей;
- Если в результате поиска приложение нашло несколько подходящих контактов, то запрашивается уточнение (фамилия, департамент, отдел или группа). Полученные уточнения (сущности) сохраняются в контекст.
Далее разберем шаги подробнее.
Препроцессинг строки и NER
На данном этапе полученный от ASR текст очищается от лишних слов (которых нет в словаре), и к оставшимся словам добавляются соответствующие теги.
Полученный от ASR текст: иванова оля возьмите потом
Результат препроцесcинга: {слово:"иванова", тег:"secondname"}, {слово:"оля", тег:"firstname"}
Полученный от ASR текст: направление разработки медиа цэпэе
Результат препроцесcинга: {слово:"направление", тег:"notag"}, {слово:"разработки", тег:"notag"}, {слово:"медиа", тег:"notag"}, {слово:"цэпэе", тег:"notag"}
Поиск с использованием полученных сущностей
Поиск разделен на следующие этапы:
- Раскрытие псевдонимов (alias). Например, «оля» → «ольга»; «цэпэе» → «cpe», «медиа» → «media»;
- Составление комбинаций строк с полученными псевдонимами: «иванова оля», «иванова ольга»; «направление разработки медиа цэпэе», «направление разработки медиа cpe», «направление разработки media цэпэе», «направление разработки медиа cpe»;
- Объединение слов с тегом notag, и подстановка тега для фразы {слово:"направление", тег:"notag"}, {слово:"разработки", тег:"notag"}, {слово:"media", тег:"notag"}, {слово:"cpe", тег:"notag"} → {слово:"направление разработки media cpe", тег:"department"};
- Поиск по полученным строкам.
Уточнения
Если в результате поиска обнаружено несколько абонентов, то запрашиваются уточнения.
Ниже представлена вводная информация о контексте.
Контекст содержит следующие поля:
- CallRef — выступает «идентификатором» сессии диалога, задается на стороне Softswitch;
- OldResult — список контактов, полученный при прошлой итерации поиска. При первой итерации он пустой, в последующих заменяет телефонную книгу (то есть поиск происходит по нему, а не по всей книге);
- NextTag — тег для поиска по подстроке, изначально соответствует FirstName, далее меняет свое значение в зависимости от содержимого OldResult.
Если результат поиска содержит больше одного контакта, то полученный результат записывается в OldResult.
Для составления, уточнения и изменения NextTag происходит сравнение полей полученных контактов в следующем порядке:
- FirstName
- SecondName
- Department
- Group
- SubGroup
- ThirdName
Сравнение полей происходит до того момента, пока все значения полей не станут равны.
Первое «неравное поле» записывается в NextTag, и все уникальные значения для текущего поля используются в строке для уточнения (если их меньше 6).
Требования к телефонной книге
Телефонная книга, используемая в приложении, должна удовлетворять ряду обязательных условий, чтобы обеспечивать корректный поиск, распознавание и обновление данных. Эти требования едины для всех источников (Address Book и VCF) и делятся на несколько категорий.
Каждый контакт в телефонной книге должен содержать:
Уникальный идентификатор (UID) — строка, однозначно идентифицирующая запись. Используется для отслеживания изменений (добавление, обновление, удаление) при синхронизации.
ФИО — минимум одно слово (имя), максимум три (фамилия, имя, отчество). Допустимые шаблоны:
<фамилия> <имя> <отчество><фамилия> <имя><имя>
Номер телефона — строка, содержащая только цифры (0–9). Все прочие символы (скобки, тире, буквы) при загрузке игнорируются и удаляются.
Структурные поля (необязательные):
Department— подразделение (отдел, департамент).Group— группа внутри подразделения.SubGroup— подгруппа (если требуется более глубокая иерархия).
Все текстовые поля (ФИО, Department, Group, SubGroup) после загрузки проходят нормализацию:
приводятся к нижнему регистру;
буква
ёзаменяется нае;удаляются все символы, кроме букв латиницы (
a–z) и кириллицы (а–я), пробела и дефиса (-);множественные пробелы схлопываются в один;
строка обрезается по краям.
Важно: в пределах одного слова запрещено смешивать кириллицу и латиницу.
Например, «Pеtрова» — третяя буква латинская, остальные кириллические). Такие слова считаются «повреждёнными», а весь контакт исключается из основной книги и помещается в список повреждённых (/pb_corrupted) для ручной правки.
Процесс обновления и компиляции
Телефонная книга загружается при старте Clerk и далее обновляется автоматически каждые 12 часов (по расписанию) или вручную через кнопку «Обновить телефонную книгу» в web‑интерфейсе (или POST /pb_update).
При обновлении:
Полученные контакты валидируются (проверка структуры ФИО, номера, допустимых символов);
Валидные записи проходят нормализацию и маппинг во внутренний формат;
Вычисляется хэш (
Hash) каждого контакта для сравнения с текущей книгой;Применяется дифф — добавляются новые, обновляются изменённые (по UID и Hash), удаляются отсутствующие;
Пользовательские настройки (множители) сохраняются по UID и переносятся на обновлённые записи.
После обновления книги автоматически запускается перекомпиляция голосовой модели ASR:
Clerk отправляет подготовленный словарь (с учётом множителей) в asr-server;
asr-server транслитерирует и фонетизирует контакты, пересобирает граф распознавания и перезапускает Vosk.
Компиляция может занимать от нескольких минут до 30 минут (в зависимости от размера книги и мощности хоста).
Во время компиляции модель недоступна для новых запросов (возвращается статус «компиляция»). После успешного завершения статус меняется на «готово».
В случае ошибки на любом этапе статус становится «ошибка», а предыдущая рабочая модель остаётся активной до устранения проблемы.
