- 📚 Оглавление
- Описание
- Объяснение работы
- Триггеры
- Инициализация Russian Text Tagger
- Анализ текста
- Примеры использования
Эта маленькая библиотека призвана помочь в поиске словосочетаний и последовательностей русских слов в тексте.
Она не использует нейросети, работает на обыкновенных алгоритмах и на русском словаре.
Для чего её можно использовать? Если коротко - для классификации. Ты задаёшь триггер - а она возвращает его, если он был найден в тексте.
Демка тут! 👀
Используется в боте @MyPocketLawyerBot
Мы сделали массив с одним триггером, который срабатывает на наличие первичных форм слов сколько(norm:сколько), стоит (norm:стоить), машина (norm:машина) и тачка (norm:тачка).
let triggers = [
{
name: "Вопрос про стоимость машина",
words: [
{normalized: ["сколько"]},
{normalized: ["стоить"]},
{normalized: ["машина", "тачка"]},
],
markers: ['car_price']
},
]В этом случае Russian Text Tagger сработает на все следующие варианты:
Сколько стоит машина
Сколько стоит ваша машина
Сколько стоит эта тачка
Меня интересует сколько может стоить эта тачка
машина сколько стоит?
await Analysis("Меня интересует сколько может стоить эта тачка");Рассмотрим, как RTT разбирает текст на примере последнего варианта.
// Разделение текста на предложения (в нашем случае оно одно)
Меня интересует сколько может стоить эта тачка
-> ["Меня интересует сколько может стоить эта тачка"]
// Нормализация всех слов каждого предложения с помощью Az.js
Меня интересует сколько может стоить эта тачка
я интересовать сколько мочь стоить этот тачка
// Разделение на морфемы и получение их данных
я интересовать сколько мочь стоить этот тачка
NPRO VERB CONJ VERB INFN ADJF NOUN
+ 15 параметров по каждой, их можно использовать в триггерах.
// Перебор тригеров и поиск совпадений
Триггер triggers[0] ( сколько, стоить, тачка )
я интересовать сколько мочь стоить этот тачка
¯¯¯¯¯¯¯ ¯¯¯¯¯¯ ¯¯¯¯¯
// Триггер найден, возвращаются его маркеры
-> ["car_price"]
Результат работы RTT выглядит следующим образом:
{
"sentence": "Меня интересует сколько может стоить эта тачка",
"sentences": ["Меня интересует сколько может стоить эта тачка"],
"markers": ["car_price"],
"triggered": [
{
"strict_word_direction": false,
"strict_word_sequence": false,
"name": "Вопрос про стоимость машина",
"words": [
{"normalized": ["сколько"]},
{"normalized": ["стоить"]},
{"normalized": ["машина","тачка"]}
],
"markers": ["car_price"]
}
],
"morphs": [
[
{
"source": "Меня интересует сколько может стоить эта тачка",
"st": 0,
"length": 4,
"index": 0,
"firstUpper": true,
"allUpper": false,
"type": "WORD",
"subType": "CYRIL",
"_str": "Меня",
"POST": "NPRO",
"text": "меня",
"text_non_yo": "меня",
"normalized": ["я","я"],
"is_drugs": false,
"is_god": false,
"is_swear": false,
"is_dangerous_people": false,
"is_racism": false
},
{
"source": "Меня интересует сколько может стоить эта тачка",
"st": 4,
"length": 1,
"index": 1,
"firstUpper": false,
"allUpper": false,
"type": "SPACE"
},
...
]
]
}Именно по маркерам можно определять какие совпадения были найдены в тексте.
Триггеры - это объекты, содержащие в себе правила для поиска сочитаний.
{ // (object) Триггер
name, // (string) Название триггера
words: [ // (array) Массив слов используемых триггером
{ // (object) Слово
text //* (string||array) Слово для поиска
normalized //* (string||array) Нормализованное слово для поиска
}
],
markers, // (array) массив маркеров, которые добавляются в итоговы результат
check_scope, // (string) границы поиска сочитаний:
// весь текст - undefined,
// предложение - "sentences"
strict_word_sequence, // (bool) Маркер поиска строгой последовательности слов (буквально как указано в words)
strict_word_direction, // (bool) Маркер поиска строгого направления слов (буквально как указано в words)
}Объясняю strict_word_sequence и strict_word_direction.
При strict_word_sequence важно, чтобы слова стояли ровно в том же самом направлении и в тех же самых местах, как указано в words.
При words: я, читаю, книги.
✔ я читаю книги
✔ знаешь, я читаю книги, а ты?
✕ я читаю умные книги
✕ я книги читаю
✕ умные книги я читаю
При strict_word_direction важно, чтобы слова стояли ровно в том же самом направлении, как указано в words.
При words: я, читаю, книги.
✔ я читаю книги
✔ знаешь, я читаю книги, а ты?
✔ я читаю умные книги
✕ я книги читаю
✕ умные книги я читаю
Если оба параметра не указаны или являются false, то...
При words: я, читаю, книги.
✔ я читаю книги
✔ знаешь, я читаю книги, а ты?
✔ я читаю умные книги
✔ я книги читаю
✔ умные книги я читаю
Как ты понимаешь, здесь не важны ни последовательность, ни направление.
Вот так может выглядеть массив триггеров:
let triggers = [
{
// (привет|хелоу|здарова|хай|прив)
name: "Приветсвие",
words: [{text: ["привет", "хелоу", "здарова", "хай", "прив"]}],
markers: [1],
check_scope: 'sentences'
},
{
// в (какое|какие) (время|часы) вы (работаете)
name: "Вопрос о времени работы",
words: [
{normalized: ["какой"]},
{normalized: ["время", "час"]},
{normalized: ["работать"]},
],
markers: [2],
check_scope: 'sentences'
},
];Чтобы создать новый объект Russian Text Tagger'а, достаточно выполнить функцию:
let Analysis = require("russian-text-tagger")({
triggers, // (array) Массив триггеров
loadedAz, //* (object) Экземпляр инициализированной библиотеки Az.js
uniq_markers // (bool) Возвращать без дубликатов маркеров
});Просто даешь анализатору текст.
let results = await Analysis("Как-то в зоопарке петух сказал петуху: Привет, петух!");В браузере RTT нужно передать эксземпляр инициализированного Az.js.
<script src="./az.min.js"></script>
<script src="./RTT/index.js"></script>
<script>
Az.Morph.init('./dicts', function(){
let rtt = RussianTextTagger({triggers, loadedAz: Az});
let result = rtt("привет, друг!");
console.log('result:', result);
})
</script>Устанавливаем зависимость в проект
npm i @powerdot/russian-text-taggerЮзаем!
let Analysis = require("russian-text-tagger")({triggers});
(async ()=>{
let results = await Analysis("в какое время вы работаете?");
console.log(results);
})();