Это старая версия документа!


Инструкция по установке Модуля проверки

Создано тестовое приложение в виде server.js-файла, который запускается на Node.js как веб-сервер. Исходный код находится в репозитории: https://git.hitsoft-it.com/e-dictation/rsv

Пользователь: ecopsy
Пароль: экопси_пароль

Сервер, собранный в docker-образ, имеет следующий идентификатор reg.hitsoft-it.com/e-dictation/rsv/server:latest

Чтобы получить доступ к репозиторию, необходимо авторизоваться в хранилище образов reg.hitsoft-it.com

Для этого нужно использовать команду:

docker login reg.hitsoft-it.com

Далее, ввести пароль и логин пользователя, указанные выше.

Для этого пользователя сгенерирован токен ecopsy_token, с ключом токен_ключ, поэтому авторизоваться также можно через команду:

docker login reg.hitsoft-it.com -u ecopsy_token -p токен_ключ

Для запуска можно использовать docker compose, например, такой файл docker-compose.yml

version: '2.0'
 
services:
 
  server:
    image: reg.hitsoft-it.com/e-dictation/rsv/server:latest
    restart: always
    volumes:
      - ./logs:/server/logs
    ports:
      - "8980:8080" 
    networks:
      - rsv-network
 
networks:
  rsv-network:

Вместо 8980 можно указать любой предпочтительный порт, который будет пробрасыватьcя в докер, а вместо ./logs любой относительный (относительно файла docker-compose.yml) или абсолютный путь к директории, которая будет заменять директорию с логами в докере.

После создания файла, докер контейнер можно запустить командой:

docker compose up -d

Либо можно запускать docker-контейнер обычным докером при помощи команды:

docker run -v ./logs:/server/logs -p 8980:8080 -d reg.hitsoft-it.com/e-dictation/rsv/server:latest

Затем сервер будет доступен по адресу http://localhost:8980/calcResult на сервере, где запущен docker (либо на на другом порту, на который будет заменён 8980).

Note: Полный цикл установки проверен на чистой системе Ubuntu 22.04.2 LTS, в которую был установлен только docker и его компоненты.

Адрес порта задаётся в конфигурации модуля при установке. Модуль проверки имеет точку входа через вызов функции calcResult.

POST http://localhost:8980/calcResult
Content-type: application/json

Тело запроса JSON:

{ 
  dictId: string, //идентификатор диктанта для выбора соответствующего скрипта проверки; 
  dictSubId: string, //идентификатор подверсии диктанта для выбора соответствующего скрипта проверки; 
  userId: string, //идентификатор пользователя, написавшего текст (для логирования);
  text: string, //текст диктанта, который написал пользователь;
  returnStats: boolean //флаг возврата аналитических данных;
}

Ответ:

{
  userId: string, //внешний идентификатор пользователя;
  skipped: boolean, // флаг пропуска проверки;
  skipDetails: {
            reason: string, //причина пропуска, приоритет по порядку: textSizePercent, obsceneWords, penaltyErrors
textSizePercent: float, // процент объёма входного текста от текста диктанта;
obsceneWords: string[], //список найденных слов из словаря;
penaltyErrors: int //число штрафных ошибок;
          },
  errors: {
  orfo: int, // число орфографических ошибок;
  punct: int, //число пунктуационных ошибок;
  typo: int //число опечаток;
}
  stats: // массив с аналитической статистикой, передаётся, если в вызове returnStats был true;
  {
    name: string, // имя столбца, например var_id или word1_orph1_rule33;
    value: string // значение в этом столбце;
   }[]
}

Подмодуль фильтрации текстов включает в себя следующие функции:

  • Фильтрация текстов по признаку объема (текст отличается от текста в задании, меньше/больше/другой) не более чем на 20% слов. Причина фильтрации и процент логируется. Текстовое задание, прошедшее фильтрацию, передаётся далее подмодулю проверки текстовых заданий.
  • Предобработка текста на аберрантное поведение (в тексте нет обсценной лексики, частей HTML разметки). Предобработка проверки текстового задания осуществляется функциями на поиск слов из заранее заданного словаря обсценной лексики. Если одно или несколько слов найдены, то выставляется соответствующий флаг пропуска проверки с причиной obsceneWords. Текстовое задание далее не проверяется на ошибки, проверка останавливается.
  • После проверки каждого текстового задания на выходе выдаётся файл в формате JSON, содержащий следующие данные:
    • флаг пропуска проверки (параметр skipped),
    • причина пропуска, параметр reason принимает одно из значений причины фильтрации: textSizePercent, obsceneWords, penaltyErrors,
    • процент соответствия объёма текста, написанного респондентом, от текста задания (параметр textSizePercent),
    • список найденных стоп-слов из словаря обсценной лексики (параметр obsceneWord), предоставленного Заказчиком, число штрафных ошибок в текстовом задании (параметр penaltyErrors).

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

const path = require('path'); // Модуль для работы с путями файловой системы
const fs = require('fs'); // Модуль для работы с файловой системой
const request = require('request'); // Библиотека для HTTP-запросов
const process = require('process'); // Модуль для взаимодействия с процессом Node.js
 
// URL для POST-запроса
const url = 'http://127.0.0.1:8979/calcResult';
 
// Путь к директории с текстовыми файлами
const dirpath = path.join(__dirname, '/texts')
 
// Константа для перевода секунд в наносекунды (используется с process.hrtime)
const NS_PER_SEC = 1e9;
 
// Чтение всех файлов в директории
fs.readdir(dirpath, function(err, files) {
  // Отмечаем время начала обработки всех файлов
  const allStart = process.hrtime();
 
  // Фильтруем только .txt файлы
  const txtFiles = files.filter(el => path.extname(el) === '.txt')
 
  // Рекурсивная функция для последовательной отправки POST-запросов
  function run(idx) {
    if (idx < txtFiles.length) {
      // Время начала обработки конкретного файла
      const start = process.hrtime();
 
      // POST-запрос на сервер с содержимым файла и параметрами
      request.post(
          url,
          { 
            json: { 
              returnStats: true, 
              dictId: 'v1', 
              dictSubId: 'v1_1', 
              userId: idx.toString(), 
              text: fs.readFileSync(dirpath + '/' + txtFiles[idx], {encoding:'utf8', flag:'r'}) // читаем файл
            }
          },
          function (error, response, body) {
            if (!error && response.statusCode == 200) {
              console.log(body); // выводим ответ сервера
            }
 
            // Логируем время обработки конкретного файла
            console.log('text '  + idx + ' take ' + process.hrtime(start));
 
            // Рекурсивно вызываем следующую итерацию для следующего файла
            run(idx + 1);
          }
      );
    } else {
      // Когда все файлы обработаны, выводим общее время
      const time = process.hrtime(allStart);
      const nanoTime = time[0] * NS_PER_SEC + time[1]
      console.log('All time is ' + time + ' for ' + txtFiles.length);
 
      // Выводим среднее время обработки одного файла
      if (txtFiles.length > 0) {
        console.log('Average time is ' + ((nanoTime / txtFiles.length)/NS_PER_SEC).toFixed(4));
      }
    }
  }
 
  // Запускаем рекурсивную обработку с первого файла
  run(0)
});
 
console.log(global.txtFiles)
  • /opt/bitnami/dokuwiki/data/attic/tech/customer/rsv/install.1763721488.txt.gz
  • Последнее изменение: 2025/11/21 10:38
  • dmitry_kalashnikov