Добавить, заменить и удалить свою грамматику только в текущем сеансе

Учебные задачи

Полный модуль собственного обычного окна: создаём новый уникальный ключ и массив двух реальных учебных фраз, затем заменяем только этот же ключ тремя фразами и удаляем свою запись. Фактические наборы ключей проверяются после каждой стадии; чужие записи не меняются.

Где и как запускать

Полный модуль обычной формы собственной обработки УчебнаяГрамматика85.Пульт; толстый клиент, Обычное приложение, новая база УчебныеГрамматикиРечи85.

Подготовка

  1. Создайте новую отдельную файловую базу и конфигурацию УчебныеГрамматикиРечи85, платформа8.5.1.1343. Не переименовывайте рабочую базу для обхода проверки и не подключайте production-обмены или фоновые задания.

  2. Этот опыт предназначен для толстого клиента в режиме обычного приложения. В свойствах своей конфигурации выберите основной режим запуска Обычное приложение; не переносите код обычной формы в управляемую форму или браузер.

  3. Администратор заранее настраивает реальное подключение именно собственного стенда к сервису речи. Код не регистрирует аккаунт, не содержит URL, паролей или токенов и не угадывает регион. Проверьте права, тариф, ограничения и согласие на передачу трёх несекретных учебных фраз.

  4. В конфигураторе: Обработки → УчебнаяГрамматика85 → Формы → Пульт, тип Обычная. Добавьте реквизиты Согласие типа Булево, КлючОпыта типа Строка неограниченной длины и Итог типа Строка неограниченной длины.

  5. Выведите поля этих реквизитов. Согласие — флажок; КлючОпыта и многострочный Итог сделайте только для просмотра. Не вводите свой ключ вручную: он создаётся настоящим УникальнымИдентификатором и хранится в закрытой переменной модуля.

  6. Добавьте три обычные кнопки ПодготовитьОпыт, ВыполнитьОпыт и ОчиститьОпыт. Их событию Нажатие назначьте одноимённые процедуры без параметров. Это точная сигнатура события Кнопка.Нажатие обычной формы, а не обработчик команды управляемой формы.

  7. Вставьте полный основной код в пустой модуль обычной формы. Назначьте ПриОткрытии событию ПриОткрытии, ПередЗакрытием событию ПередЗакрытием. В обычной форме сигнатуры соответственно без параметров и с двумя параметрами, не как в управляемой.

  8. Нажмите F7 и обновите только учебную базу. Не считайте F7 подтверждением доступа к сервису, содержимого его грамматик или фактического распознавания.

  9. Запустите именно толстый клиент Обычное приложение и откройте свою обработку. Закройте другие окна опыта, не меняйте область данных или подключение во время одного запуска. Согласие каждый раз сбрасывается в Ложь; установите его только после подготовки.

  10. Сначала нажмите ПодготовитьОпыт: эта кнопка только создаёт и показывает ключ, без записи грамматики и без сети. До отдельного нажатия ВыполнитьОпыт сохраните КлючОпыта, если требуется адресная аварийная очистка после падения клиента. Сам урок файлов, резервных копий или архивов не создаёт.

  11. Здесь никакого запуска1С, регистрации, передачи фраз или удаления грамматик не выполнялось: runtimeVerifiedScenarios=0. Ни число чужих ключей, ни успешность ответа заранее не обещаются.

  12. Сеансовая грамматика хранится в данных текущего сеанса. Все вызовы выполняются в одном собственном окне толстого клиента; не переносите часть опыта в фоновое задание или другой сеанс.

Перем СвойКлюч;
Перем ИсходныеКлючи;
Перем СвояПопытка;
Перем СвояГотовность;
Перем СвойПодготовлен;

Процедура ПриОткрытии()
    СвойКлюч = "";
    ИсходныеКлючи = Новый Массив;
    СвояПопытка = Ложь;
    СвояГотовность = Ложь;
    СвойПодготовлен = Ложь;
    Согласие = Ложь;
    КлючОпыта = "";
    Итог = "Разрешите только собственный опыт после подготовки сервиса";
    ПроверитьСвойСтенд();
    СвояГотовность = Истина;
КонецПроцедуры

Процедура ПередЗакрытием(Отказ, СтандартнаяОбработка)
    СтандартнаяОбработка = Истина;
    Если СвояПопытка Тогда
        Отказ = Истина;
        Сообщить("Сначала выполните ОчиститьОпыт для своего ключа: " + СвойКлюч);
        Возврат;
    КонецЕсли;
    СвояГотовность = Ложь;
КонецПроцедуры

Процедура ПроверитьСвойСтенд()
    Если ТранзакцияАктивна() Тогда
        ВызватьИсключение "Не изменяйте настройки сервиса внутри чужой транзакции";
    КонецЕсли;
КонецПроцедуры

Процедура ПроверитьСвоеСогласие()
    ПроверитьСвойСтенд();
    Если Не СвояГотовность Или Не Согласие Тогда
        ВызватьИсключение "Нужны открытое собственное окно и явное согласие на опыт";
    КонецЕсли;
КонецПроцедуры

Процедура ПодготовитьОпыт()
    ПроверитьСвоеСогласие();
    Если СвояПопытка Тогда
        ВызватьИсключение "Не меняйте ключ, пока не подтверждена очистка предыдущего опыта";
    КонецЕсли;
    СвойКлюч = "УчебнаяГрамматика85-" + Строка(Новый УникальныйИдентификатор);
    КлючОпыта = СвойКлюч;
    СвойПодготовлен = Истина;
    Итог = "Ключ подготовлен без записи грамматики. Сохраните его для аварийного случая, затем нажмите ВыполнитьОпыт";
КонецПроцедуры

Процедура ВыполнитьОпыт()
    ПроверитьСвоеСогласие();
    Если СвояПопытка Тогда
        ВызватьИсключение "Сначала очистите предыдущий собственный ключ, новый не создаётся";
    КонецЕсли;
    Если Не СвойПодготовлен Или СвойКлюч = "" Тогда
        ВызватьИсключение "Сначала нажмите ПодготовитьОпыт: каждый запуск требует нового собственного ключа";
    КонецЕсли;
    Итог = "Получение исходных ключей; прошлый успешный результат сброшен";
    ИсходныеКлючи = ПолучитьНастоящиеКлючи();
    Если ИсходныеКлючи.Найти(СвойКлюч) <> Неопределено Тогда
        ВызватьИсключение "Ключ уже существовал: его нельзя заменить или удалить этим опытом";
    КонецЕсли;
    Фразы = Новый Массив;
    Фразы.Добавить("выбрать учебный товар");
    Фразы.Добавить("завершить учебный опыт");
    СвойПодготовлен = Ложь;
    СвояПопытка = Истина;
    Попытка
        РаботаСРечью.УстановитьДополнительнуюГрамматикуСеанса(СвойКлюч, Фразы);
        ПроверитьТолькоСвойКлюч(ПолучитьНастоящиеКлючи(), Истина);
        Фразы.Добавить("отменить учебный опыт");
        РаботаСРечью.УстановитьДополнительнуюГрамматикуСеанса(СвойКлюч, Фразы);
        ПроверитьТолькоСвойКлюч(ПолучитьНастоящиеКлючи(), Истина);
        УдалитьТолькоСвойКлюч();
        Итог = "Свой ключ создан, заменён и удалён; исходный набор ключей сохранился. Тексты грамматики обратно не читались, распознавания не было";
    Исключение
        Если СвояПопытка Тогда
            Итог = "Опыт не завершён. Возможна незавершённая запись только под собственным ключом: "
                + СвойКлюч + ". После восстановления связи вручную нажмите ОчиститьОпыт в этом же окне";
        Иначе
            Итог = "Свой ключ уже отсутствует, но итоговая проверка выявила изменение других ключей. Автоматического восстановления чужих записей нет";
        КонецЕсли;
        ВызватьИсключение;
    КонецПопытки;
КонецПроцедуры

Процедура ОчиститьОпыт()
    ПроверитьСвоеСогласие();
    Если Не СвояПопытка Тогда
        Итог = "Нет собственного незавершённого опыта; никакие ключи не удалялись";
        Возврат;
    КонецЕсли;
    Итог = "Проверка и удаление только своего ключа: " + СвойКлюч;
    Попытка
        УдалитьТолькоСвойКлюч();
        Итог = "Свой ключ отсутствует; исходные ключи сохранились. Закрытие окна разрешено";
    Исключение
        Если СвояПопытка Тогда
            Итог = "Отсутствие своего ключа ещё не подтверждено. Ключ сохранён в поле КлючОпыта: " + СвойКлюч;
        Иначе
            Итог = "Отсутствие своего ключа подтверждено, но чужой набор изменился. Чужие записи не восстанавливались";
        КонецЕсли;
        ВызватьИсключение;
    КонецПопытки;
КонецПроцедуры

Процедура УдалитьТолькоСвойКлюч()
    Если Не СвояПопытка Или СвойКлюч = "" Или ИсходныеКлючи.Найти(СвойКлюч) <> Неопределено Тогда
        ВызватьИсключение "Удаление разрешено только собственному новому ключу этого открытого окна";
    КонецЕсли;
    Текущие = ПолучитьНастоящиеКлючи();
    Если Текущие.Найти(СвойКлюч) <> Неопределено Тогда
        РаботаСРечью.УдалитьДополнительнуюГрамматикуСеанса(СвойКлюч);
    КонецЕсли;
    ПослеУдаления = ПолучитьНастоящиеКлючи();
    Если ПослеУдаления.Найти(СвойКлюч) <> Неопределено Тогда
        ВызватьИсключение "Сервис ещё показывает собственный ключ; очистка не подтверждена";
    КонецЕсли;
    СвояПопытка = Ложь;
    ПроверитьТолькоСвойКлюч(ПослеУдаления, Ложь);
КонецПроцедуры

Функция ПолучитьНастоящиеКлючи()
    Ответ = РаботаСРечью.ПолучитьДополнительныеГрамматикиСеанса();
    Если ТипЗнч(Ответ) <> Тип("Массив") Тогда
        ВызватьИсключение "Нужен настоящий массив строковых ключей, не описания грамматик";
    КонецЕсли;
    Если Ответ.Количество() > 1000 Тогда
        ВызватьИсключение "Для собственного опыта допустимы не более1000исходных ключей";
    КонецЕсли;
    Ключи = Новый Массив;
    Для Каждого Ключ Из Ответ Цикл
        Если ТипЗнч(Ключ) <> Тип("Строка") Тогда
            ВызватьИсключение "Каждый настоящий ключ должен быть строкой";
        КонецЕсли;
        Если Ключи.Найти(Ключ) <> Неопределено Тогда
            ВызватьИсключение "Повторяющийся ключ не подходит для проверки единственной собственной записи";
        КонецЕсли;
        Ключи.Добавить(Ключ);
    КонецЦикла;
    Возврат Ключи;
КонецФункции

Процедура ПроверитьТолькоСвойКлюч(Текущие, ДолженБытьСвой)
    Если (Текущие.Найти(СвойКлюч) <> Неопределено) <> ДолженБытьСвой Тогда
        ВызватьИсключение "Фактическое наличие собственного ключа не соответствует стадии опыта";
    КонецЕсли;
    Для Каждого Исходный Из ИсходныеКлючи Цикл
        Если Текущие.Найти(Исходный) = Неопределено Тогда
            ВызватьИсключение "Один из исходных ключей исчез; чужую грамматику автоматически не восстанавливаем";
        КонецЕсли;
    КонецЦикла;
    Для Каждого Текущий Из Текущие Цикл
        Если Текущий <> СвойКлюч И ИсходныеКлючи.Найти(Текущий) = Неопределено Тогда
            ВызватьИсключение "Появился другой ключ; не удаляем чужую параллельную запись ради совпадения наборов";
        КонецЕсли;
    КонецЦикла;
    Если Текущие.Количество() <> ИсходныеКлючи.Количество() + ?(ДолженБытьСвой, 1, 0) Тогда
        ВызватьИсключение "Количество фактических ключей отличается от ожидаемого";
    КонецЕсли;
КонецПроцедуры

Разбор по шагам

  1. ПодготовитьОпыт проверяет имя собственного стенда, версию, отсутствие транзакции и явное согласие, затем создаёт новый ключ без сети и записи. ВыполнитьОпыт — отдельное нажатие после сохранения этого ключа. Закрытые переменные обычной формы не принимают произвольный ключ из поля.

  2. Первый вызов ПолучитьДополнительныеГрамматики получает настоящий массив строковых ключей. Создаём отдельную копию этого списка в памяти, проверяем тип каждого значения и отсутствие дубликатов. Это не копия содержимого грамматик и не резервный файл.

  3. Подготовленный ключ состоит из учебного префикса и настоящего нового GUID. Перед записью он обязан отсутствовать в только что прочитанном исходном наборе; при совпадении запись и удаление запрещены. КлючОпыта показывает закрытую переменную, но не управляет ею.

  4. Массив строк содержит фразы выбрать учебный товар и завершить учебный опыт. Это обычные строки, не SRGS, XML или ABNF. УстановитьДополнительнуюГрамматику вызывается с настоящим новым ключом; глобальная грамматика модели не редактируется.

  5. После первой записи читаем реальные ключи заново: должен появиться только собственный ключ, каждый исходный сохраниться. Сравниваем наборы по членству, а не порядок возвращённых строк.

  6. Добавляем третью фразу отменить учебный опыт в свой массив и вызываем setter с тем же собственным ключом. По контракту он заменяет грамматику; повторное чтение ключей должно показать одну собственную запись, не две. Сам текст getter обратно не возвращает.

  7. Удаление получает фактический текущий набор и удаляет лишь собственный ключ, если он ещё присутствует. Повторное чтение должно подтвердить его отсутствие. Только после этого СвояПопытка сбрасывается; затем проверяется сохранность чужого набора.

  8. Флаг СвояПопытка ставится перед первой записью: при потере ответа запись могла состояться. Ошибка сохраняет ключ и не запускает автоматически новую запись. ОчиститьОпыт вручную повторяет только адресную очистку своего ключа; событие закрытия сеть не вызывает.

Как проверить результат

  1. Снимите согласие: все три кнопки должны отказаться до сетевых вызовов. Проверки версии, имени стенда и транзакции также должны остановить опыт. ВыполнитьОпыт без отдельной подготовки не создаёт ключ автоматически.

  2. При нормальной доступности сервиса ожидаются три наблюдения набора: исходные плюс один собственный ключ; тот же набор после замены; исходный набор без собственного ключа после удаления.

  3. Вызов ОчиститьОпыт после уже завершённого опыта не удаляет ничего. Второй запуск требует нового нажатия ПодготовитьОпыт и нового GUID, не переиспользует предыдущую запись.

  4. При ошибке ответа используйте только кнопку ОчиститьОпыт в этом же окне. До подтверждения отсутствия своего ключа новый запуск и обычное закрытие отклоняются; сообщение не должно выдавать неподтверждённую очистку за успех.

  5. Если другая запись появилась или исчезла параллельно, строгая проверка должна сообщить различие. Чужие ключи нельзя удалять или восстанавливать ради получения зелёного результата.

  6. Проверка доказывает фактическое наличие ключей, не то, что распознаватель использовал все три фразы. Микрофон, распознавание, синтез и воспроизведение здесь не запускаются.

Ожидаемый результат

В успешном ручном опыте один собственный ключ создан, заменён и удалён; фактический исходный набор ключей сохранился. Тексты обратно не читались и качество распознавания не измерялось.

На что обратить внимание

  1. Getter возвращает массив ключей типа Строка, а не объекты грамматик и не тексты фраз. Учебный вывод не утверждает, что прочитал или сравнил содержимое удалённой записи.

  2. Setter с уже существующим ключом заменяет запись. Единственный разрешённый уже существующий ключ в этом уроке — свой ключ, созданный именно этим открытым окном; произвольные пользовательские строки не принимаются.

  3. Обработчик ошибки намеренно не делает автоматический повтор платного запроса и не скрывает исключение. После потери связи наличие своего ключа неизвестно, пока последующее чтение не подтвердит результат.

  4. Блокировка обычного закрытия не спасает от падения процесса, принудительного завершения ОС или закрытия клиента другим способом. После потери окна нельзя запускать массовую очистку: администратору нужен сохранённый фактический собственный ключ и правильная область.

  5. Наличие своих и чужих ключей сравнивается без учёта порядка. Параллельное изменение может завершить проверку ошибкой даже после успешного удаления своего ключа; чужое состояние автоматически не переписывается.

  6. Предел1000 относится только к этому уроку и проверяется после получения ответа. Он не ограничивает сетевое время, память до получения массива или реальные возможности платформы.

  7. Имя базы — только ограждение учебного опыта, не модель безопасности. Настоящие права, тариф, подключение и разделители должны быть проверены отдельно. Здесь не создаются файлы или резервные копии, runtimeVerifiedScenarios=0.

  8. Сеансовая запись не является настройкой всей базы. После окончания сеанса её жизненный цикл отличается от сохраняемой грамматики информационной базы.

Пример не запускался в вашей базе. Перед применением проверьте его в указанном учебном контексте.

Не хотите разбираться сами?

Адаптируем это решение под вашу базу. Оценка бесплатно.

Оставить задачу

1С, 1С:Предприятие — товарные знаки ООО «1С». Сайт не является официальным представительством фирмы «1С» и не аффилирован с ней.