Содержание

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

Модуль проверки представляет собой приложение в виде 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 // значение в этом столбце;
   }[]
}

Подмодуль фильтрации

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

Пример приложения

Ниже указан 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)