natural 6.10.5 → 6.11.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/.env ADDED
@@ -0,0 +1,22 @@
1
+ # Storage backend you want to use
2
+ NATURAL_STORAGE=PG
3
+ # Settings for Postgres
4
+ PG_USER=user
5
+ PG_PASSWORD=password
6
+ PG_DATABASE=naturaldb
7
+ PG_HOST=localhost
8
+ PG_PORT=5432
9
+ PG_TABLE=naturaltable
10
+ # Settings for Redis
11
+ REDIS_HOST=localhost
12
+ REDIS_PORT=6379
13
+ # Settings for Memcached
14
+ MEM_HOST=localhost
15
+ MEM_PORT=11211
16
+ MEM_EXPIRES = 3600
17
+ # Settings for MongoDB
18
+ MONGO_HOST=localhost
19
+ MONGO_PORT=27017
20
+ MONGO_DATABASE=naturaldb
21
+ # Path to the folder writing files
22
+ FS_PATH=.
@@ -16,7 +16,7 @@ jobs:
16
16
 
17
17
  strategy:
18
18
  matrix:
19
- node-version: [14.x, 16.x, 18.x]
19
+ node-version: [16.x, 18.x, 20.x]
20
20
  # See supported Node.js release schedule at https://nodejs.org/en/about/releases/
21
21
 
22
22
  steps:
@@ -11,10 +11,10 @@ jobs:
11
11
  build:
12
12
  runs-on: ubuntu-latest
13
13
  steps:
14
- - uses: actions/checkout@v2
14
+ - uses: actions/checkout@v4
15
15
  - uses: actions/setup-node@v4
16
16
  with:
17
- node-version: 12
17
+ node-version: 20
18
18
  - run: npm ci
19
19
  - run: npm test
20
20
 
@@ -22,10 +22,10 @@ jobs:
22
22
  needs: build
23
23
  runs-on: ubuntu-latest
24
24
  steps:
25
- - uses: actions/checkout@v2
25
+ - uses: actions/checkout@v4
26
26
  - uses: actions/setup-node@v4
27
27
  with:
28
- node-version: 14
28
+ node-version: 20
29
29
  registry-url: https://registry.npmjs.org/
30
30
  - run: npm ci
31
31
  - run: git config user.name "$GITHUB_ACTOR"
package/example.txt ADDED
@@ -0,0 +1 @@
1
+ {"attr1":"val1","attr2":"val2"}
@@ -0,0 +1 @@
1
+ {"attr1":"val1","attr2":"val2"}
@@ -23,7 +23,6 @@ THE SOFTWARE.
23
23
  'use strict'
24
24
 
25
25
  const EventEmitter = require('events')
26
-
27
26
  const PorterStemmer = require('../stemmers/porter_stemmer')
28
27
  const parallelTrainer = require('./classifier_train_parallel')
29
28
 
@@ -72,13 +72,12 @@ declare interface ClassifierOptions {
72
72
 
73
73
  declare type ClassifierCallback = (err: NodeJS.ErrnoException | null, classifier?: ClassifierBase) => void
74
74
 
75
- declare class ClassifierBase {
75
+ declare class ClassifierBase extends events.EventEmitter {
76
76
  classifier: ApparatusClassifier
77
77
  docs: ClassifierDoc[]
78
78
  features: { [key: string]: number | undefined }
79
79
  stemmer: Stemmer
80
80
  lastAdded: number
81
- events: events.EventEmitter
82
81
 
83
82
  constructor (classifier: ApparatusClassifier, stemmer?: Stemmer)
84
83
  addDocument (text: string | string[], classification: string): void
@@ -89,7 +88,7 @@ declare class ClassifierBase {
89
88
  getClassifications (observation: string | string[]): ApparatusClassification[]
90
89
  classify (observation: string | string[]): string
91
90
  setOptions (options: ClassifierOptions): void
92
- save (filename: string, callback: ClassifierCallback): void
91
+ save (filename: string, callback?: ClassifierCallback): void
93
92
  }
94
93
 
95
94
  declare type BayesClassifierCallback = (err: NodeJS.ErrnoException | null, classifier?: BayesClassifier) => void
@@ -56,7 +56,7 @@ class LogisticRegressionClassifier extends Classifier {
56
56
  // needs its matricies to have their widths synced, etc.
57
57
  this.lastAdded = 0
58
58
  this.classifier = new ApparatusLogisticRegressionClassifier()
59
- Classifier.prototype.train.call(this)
59
+ super.train()
60
60
  }
61
61
  }
62
62
 
@@ -0,0 +1,21 @@
1
+ require('dotenv').config()
2
+ const { v4: uuidv4 } = require('uuid')
3
+ const fs = require('fs').promises
4
+ const path = process.env.FS_PATH
5
+
6
+ // Class for creating file-based storage
7
+ class FilePlugin {
8
+ async store (object, options) {
9
+ const key = uuidv4()
10
+ const data = JSON.stringify(object)
11
+ await fs.writeFile(path + '/' + key + '.json', data)
12
+ return key
13
+ }
14
+
15
+ async retrieve (key, options) {
16
+ const data = await fs.readFile(path + '/' + key + '.json', 'utf8')
17
+ return JSON.parse(data)
18
+ }
19
+ }
20
+
21
+ module.exports = FilePlugin
@@ -0,0 +1,27 @@
1
+ const { v4: uuidv4 } = require('uuid')
2
+ require('dotenv').config()
3
+ const memjs = require('memjs')
4
+ const memCachedConnectionString = process.env.MEM_HOST + ':' +
5
+ process.env.MEM_PORT
6
+ const memCachedExpiration = process.env.MEM_EXPIRES || 2
7
+
8
+ // Class for creating memcached client including store and retrieve methods
9
+ class MemcachedPlugin {
10
+ constructor () {
11
+ this.client = memjs.Client.create(memCachedConnectionString)
12
+ }
13
+
14
+ async store (object, options) {
15
+ const key = uuidv4()
16
+ const data = JSON.stringify(object)
17
+ const isStored = await this.client.set(key, data, { expires: memCachedExpiration })
18
+ return isStored ? key : null
19
+ }
20
+
21
+ async retrieve (key, options) {
22
+ const result = await this.client.get(key)
23
+ return JSON.parse(result.value.toString())
24
+ }
25
+ }
26
+
27
+ module.exports = MemcachedPlugin
@@ -0,0 +1,27 @@
1
+ require('dotenv').config()
2
+ const mongoose = require('mongoose')
3
+ const mongoDBConnectionString = 'mongodb://' + process.env.MONGO_HOST + ':' +
4
+ process.env.MONGO_PORT + '/' + process.env.MONGO_DATABASE
5
+
6
+ class MongoDBPlugin {
7
+ constructor () {
8
+ mongoose.connect(mongoDBConnectionString, {})
9
+ // We do not enforce a schema with MongoDB
10
+ this.ObjectModel = mongoose.model('ObjectModel', new mongoose.Schema({},
11
+ { strict: false, versionKey: false }))
12
+ }
13
+
14
+ async store (object, options) {
15
+ // To make sure the payload is stored as a whole and nog merged with the id object
16
+ const objectToStore = { naturalObject: object }
17
+ const storedObject = await this.ObjectModel.create(objectToStore)
18
+ return storedObject._id
19
+ }
20
+
21
+ async retrieve (key, options) {
22
+ const retrievedObject = await this.ObjectModel.findById(key)
23
+ return retrievedObject.naturalObject
24
+ }
25
+ }
26
+
27
+ module.exports = MongoDBPlugin
@@ -0,0 +1,89 @@
1
+ const postgres = require('pg')
2
+ require('dotenv').config()
3
+
4
+ class PostgresPlugin {
5
+ constructor () {
6
+ this.configPostgres()
7
+ }
8
+
9
+ async configPostgres () {
10
+ // Initialize connection to Postgres
11
+ const client = new postgres.Client({
12
+ user: process.env.PG_USER,
13
+ host: process.env.PG_HOST,
14
+ database: process.env.PG_DATABASE,
15
+ password: process.env.PG_PASSWORD,
16
+ port: process.env.PG_PORT
17
+ })
18
+ this.postgresClient = client
19
+ this.postgresTableName = process.env.PG_TABLE
20
+ // Connect to the database
21
+ return new Promise((resolve, reject) => {
22
+ client.connect()
23
+ .then(() => {
24
+ // Call the function to create the table
25
+ createTable(this.postgresTableName)
26
+ resolve()
27
+ })
28
+ .catch(err => {
29
+ console.error('Error connecting to the database:', err)
30
+ reject(err)
31
+ })
32
+ })
33
+
34
+ // Function to create the table
35
+ function createTable (tableName) {
36
+ // We use JSONB (binary JSON format of Postgres) to store objects
37
+ const createTableQuery = `
38
+ CREATE TABLE IF NOT EXISTS ${tableName} (
39
+ id SERIAL PRIMARY KEY,
40
+ data JSONB
41
+ );
42
+ `
43
+ return new Promise((resolve, reject) => {
44
+ client.query(createTableQuery)
45
+ .then(() => {
46
+ resolve()
47
+ })
48
+ .catch(error => {
49
+ reject(error)
50
+ })
51
+ })
52
+ }
53
+ }
54
+
55
+ // Function to insert a JavaScript object by key
56
+ // Returns the id generated by the database
57
+ async store (object, options) {
58
+ try {
59
+ const query = `INSERT INTO ${this.postgresTableName} (data) VALUES ($1) RETURNING id;`
60
+ const result = await this.postgresClient.query(query, [object])
61
+ if (result.rowCount > 0) {
62
+ return result.rows[0].id
63
+ } else {
64
+ return null
65
+ }
66
+ } catch (error) {
67
+ console.error('Error inserting object:', error)
68
+ }
69
+ }
70
+
71
+ // Function to retrieve a JavaScript object by key
72
+ async retrieve (key, options) {
73
+ try {
74
+ const query = `SELECT data FROM ${this.postgresTableName} WHERE id = $1`
75
+ const result = await this.postgresClient.query(query, [key])
76
+ if (result.rows.length > 0) {
77
+ return result.rows[0].data
78
+ } else {
79
+ console.log('No object found with the specified key')
80
+ return null
81
+ }
82
+ } catch (error) {
83
+ console.error('Error retrieving object:', error)
84
+ return null
85
+ }
86
+ }
87
+ }
88
+
89
+ module.exports = PostgresPlugin
@@ -0,0 +1,32 @@
1
+ const { v4: uuidv4 } = require('uuid')
2
+ require('dotenv').config()
3
+ const redis = require('redis')
4
+ const redisConnectionString = 'redis://' + process.env.REDIS_HOST + ':' +
5
+ process.env.REDIS_PORT
6
+
7
+ class RedisPlugin {
8
+ constructor () {
9
+ this.configRedis()
10
+ }
11
+
12
+ async configRedis () {
13
+ this.redisClient = await redis.createClient(redisConnectionString)
14
+ this.redisClient
15
+ .on('error', err => console.log('Redis Client Error', err))
16
+ .connect()
17
+ }
18
+
19
+ async store (object, options) {
20
+ const key = uuidv4()
21
+ const data = JSON.stringify(object)
22
+ await this.redisClient.set(key, data)
23
+ return key
24
+ }
25
+
26
+ async retrieve (key, options) {
27
+ const result = await this.redisClient.get(key)
28
+ return JSON.parse(result)
29
+ }
30
+ }
31
+
32
+ module.exports = RedisPlugin
@@ -0,0 +1,77 @@
1
+ const PostgresPlugin = require('./Postgres')
2
+ const MongoDBPlugin = require('./MongoDB')
3
+ const RedisPlugin = require('./Redis')
4
+ const MemcachedPlugin = require('./Memcached')
5
+ const FilePlugin = require('./File')
6
+
7
+ // Enum for different types of storage backends that can be used
8
+ const STORAGE_TYPES = {
9
+ POSTGRES: 'POSTGRES',
10
+ REDIS: 'REDIS',
11
+ MONGODB: 'MONGODB',
12
+ MEMCACHED: 'MEMCACHED',
13
+ FILE: 'FILE'
14
+ }
15
+
16
+ // Standard behaviour of the backend is:
17
+ // - Javascript in and out, so JSON.stringify and JSON.parse is done here.
18
+ // - A key is returned after storing an object.
19
+ // - The key is determined by the storage method, if possible: MongoDB and Postgres can do this.
20
+ // If not, a uuid is created.
21
+ // - File-based storage is no different: a uuid is created and used as filename: uuid.json
22
+ class StorageBackend {
23
+ constructor (storageType, options) {
24
+ if (storageType) {
25
+ this.setStorageType(storageType, options)
26
+ }
27
+ }
28
+
29
+ // Sets the storage type. Valid values are POSTGRES, REDIS, MONGODB, MEMCACHED, FILE
30
+ async setStorageType (storageType) {
31
+ if (!storageType) {
32
+ throw new Error('No storage type specified')
33
+ }
34
+ if (this.storageType) {
35
+ throw new Error('Storage type already set')
36
+ }
37
+ this.storageType = storageType
38
+ switch (storageType) {
39
+ case STORAGE_TYPES.POSTGRES:
40
+ this.client = new PostgresPlugin()
41
+ break
42
+ case STORAGE_TYPES.REDIS:
43
+ this.client = new RedisPlugin()
44
+ break
45
+ case STORAGE_TYPES.MONGODB:
46
+ this.client = new MongoDBPlugin()
47
+ break
48
+ case STORAGE_TYPES.MEMCACHED:
49
+ this.client = new MemcachedPlugin()
50
+ break
51
+ case STORAGE_TYPES.FILE:
52
+ this.client = new FilePlugin()
53
+ break
54
+ default:
55
+ throw new Error('Invalid storage type')
56
+ }
57
+ }
58
+
59
+ // Stores value to the selected storage type.
60
+ async store (object) {
61
+ if (this.storageType && this.client) {
62
+ return await this.client.store(object)
63
+ } else {
64
+ throw new Error('Storage type or client not set')
65
+ }
66
+ }
67
+
68
+ async retrieve (key) {
69
+ if (this.storageType && this.client) {
70
+ return await this.client.retrieve(key)
71
+ } else {
72
+ throw new Error('Storage type or client not set')
73
+ }
74
+ }
75
+ }
76
+
77
+ module.exports = { StorageBackend, STORAGE_TYPES }
@@ -0,0 +1,28 @@
1
+ version: '3'
2
+
3
+ services:
4
+ postgres:
5
+ image: postgres:latest
6
+ environment:
7
+ POSTGRES_DB: naturaldb
8
+ POSTGRES_USER: user
9
+ POSTGRES_PASSWORD: password
10
+ ports:
11
+ - "5432:5432"
12
+
13
+ mongodb:
14
+ image: mongo:latest
15
+ environment:
16
+ MONGO_INITDB_DATABASE: naturaldb
17
+ ports:
18
+ - "27017:27017"
19
+
20
+ redis:
21
+ image: redis:latest
22
+ ports:
23
+ - "6379:6379"
24
+
25
+ memcached:
26
+ image: memcached:latest
27
+ ports:
28
+ - "11211:11211"
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "natural",
3
3
  "description": "General natural language (tokenizing, stemming (English, Russian, Spanish), part-of-speech tagging, sentiment analysis, classification, inflection, phonetics, tfidf, WordNet, jaro-winkler, Levenshtein distance, Dice's Coefficient) facilities for node.",
4
- "version": "6.10.5",
4
+ "version": "6.11.1",
5
5
  "homepage": "https://github.com/NaturalNode/natural",
6
6
  "repository": {
7
7
  "type": "git",
@@ -14,10 +14,16 @@
14
14
  "afinn-165": "^1.0.2",
15
15
  "afinn-165-financialmarketnews": "^3.0.0",
16
16
  "apparatus": "^0.0.10",
17
+ "dotenv": "^16.4.5",
18
+ "memjs": "^1.3.2",
19
+ "mongoose": "^8.2.0",
20
+ "pg": "^8.11.3",
21
+ "redis": "^4.6.13",
17
22
  "safe-stable-stringify": "^2.2.0",
18
23
  "stopwords-iso": "^1.1.0",
19
24
  "sylvester": "^0.0.12",
20
25
  "underscore": "^1.9.1",
26
+ "uuid": "^9.0.1",
21
27
  "wordnet-db": "^3.1.11"
22
28
  },
23
29
  "devDependencies": {