dynamic-learning-model 3.5.0__tar.gz → 3.5.2__tar.gz

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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dynamic-learning-model
3
- Version: 3.5.0
3
+ Version: 3.5.2
4
4
  Summary: A Dynamic Learning Model for processing NLP queries using hybrid AI and reasoning.
5
5
  Home-page: https://github.com/VigneshT24/Dynamic_Learning_Model
6
6
  Author: Vignesh Thondikulam
@@ -14,6 +14,11 @@ from better_profanity import profanity
14
14
  from nltk.corpus import names
15
15
 
16
16
  class DLM:
17
+ # for one-time, shared model loaders so that each object won't load a new model (> 2GB)
18
+ _shared_nlp = None
19
+ _shared_hf = None
20
+ _shared_profanity_loaded = False
21
+
17
22
  __filename = None # knowledge-base (SQL)
18
23
  __query = None # user-inputted query
19
24
  __expectation = None # trainer-inputted expected answer to query
@@ -376,14 +381,49 @@ class DLM:
376
381
  - Verify login information based on mode.
377
382
  - Ensures the required table structure exists (creates if missing).
378
383
  """
379
- self.__nlp = spacy.load("en_core_web_lg")
380
- self.__hf_classifier = pipeline("zero-shot-classification", model="facebook/bart-large-mnli")
381
- profanity.load_censor_words()
384
+ # lazy load SpaCy
385
+ if DLM._shared_nlp is None:
386
+ print("Loading Spacy NLP model... (one-time)")
387
+ DLM._shared_nlp = spacy.load("en_core_web_lg")
388
+
389
+ # lazy Load HuggingFace
390
+ if DLM._shared_hf is None:
391
+ print("Loading HuggingFace Classifier... (one-time)")
392
+ DLM._shared_hf = pipeline("zero-shot-classification", model="facebook/bart-large-mnli")
393
+
394
+ # load profanity filter
395
+ if not DLM._shared_profanity_loaded:
396
+ profanity.load_censor_words()
397
+ DLM._shared_profanity_loaded = True
398
+
399
+ self.__nlp = DLM._shared_nlp
400
+ self.__hf_classifier = DLM._shared_hf
401
+
382
402
  self.__filename = db_filename
383
403
  self.__mode = mode
404
+
405
+ try:
406
+ self.__conn = sqlite3.connect(self.__filename, check_same_thread=False)
407
+ self.__cursor = self.__conn.cursor()
408
+ except sqlite3.Error as e:
409
+ print(f"System: Error connecting to database: {e}")
410
+ self.__conn = None
411
+ self.__cursor = None
412
+
384
413
  self.__login_verification(self.__mode)
385
414
  self.__create_table_if_missing()
386
415
 
416
+ def __del__(self):
417
+ """
418
+ Destructor: safely closes the database connection when the object is destroyed.
419
+ """
420
+ try:
421
+ # We check if the connection attribute exists and is not None
422
+ if hasattr(self, '_DLM__conn') and self.__conn:
423
+ self.__conn.close()
424
+ except Exception:
425
+ pass # Suppress errors during destruction to prevent noisy exit
426
+
387
427
  def __login_verification(self, mode): # no return, void
388
428
  """
389
429
  Verify and initialize the selected access mode (Learn or Apply).
@@ -436,27 +476,28 @@ class DLM:
436
476
  - If the table already exists but is missing the 'category' column, the method adds it with a default empty string.
437
477
  - Used exclusively within the class constructor to ensure the database schema is properly initialized.
438
478
  """
439
- conn = sqlite3.connect(self.__filename)
440
- c = conn.cursor()
441
- # Create table with identifier column if it doesn't exist
442
- c.execute("""
443
- CREATE TABLE IF NOT EXISTS knowledge_base (
444
- id INTEGER PRIMARY KEY AUTOINCREMENT,
445
- question TEXT NOT NULL UNIQUE,
446
- answer TEXT NOT NULL,
447
- category TEXT NOT NULL
448
- )
449
- """)
450
- # If the table existed already without identifier, add it now
451
- c.execute("PRAGMA table_info(knowledge_base)")
452
- cols = [row[1] for row in c.fetchall()]
479
+ if not self.__conn:
480
+ return
481
+
482
+ self.__cursor.execute("""
483
+ CREATE TABLE IF NOT EXISTS knowledge_base (
484
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
485
+ question TEXT NOT NULL UNIQUE,
486
+ answer TEXT NOT NULL,
487
+ category TEXT NOT NULL
488
+ )
489
+ """)
490
+
491
+ self.__cursor.execute("PRAGMA table_info(knowledge_base)")
492
+ cols = [row[1] for row in self.__cursor.fetchall()]
493
+
453
494
  if 'category' not in cols:
454
- c.execute("""
455
- ALTER TABLE knowledge_base
456
- ADD COLUMN category TEXT NOT NULL DEFAULT ''
457
- """)
458
- conn.commit()
459
- conn.close()
495
+ self.__cursor.execute("""
496
+ ALTER TABLE knowledge_base
497
+ ADD COLUMN category TEXT NOT NULL DEFAULT ''
498
+ """)
499
+
500
+ self.__conn.commit()
460
501
 
461
502
  @staticmethod
462
503
  # ANSI escape for moving the cursor up N lines
@@ -953,11 +994,11 @@ class DLM:
953
994
  # collapse any extra spaces
954
995
  self.__special_stripped_query = " ".join(self.__special_stripped_query.split())
955
996
 
956
- conn = sqlite3.connect(self.__filename)
957
- cursor = conn.cursor()
958
- cursor.execute("SELECT question, answer FROM knowledge_base")
959
- rows = cursor.fetchall()
960
- conn.close()
997
+ if self.__cursor:
998
+ self.__cursor.execute("SELECT question, answer FROM knowledge_base")
999
+ rows = self.__cursor.fetchall()
1000
+ else:
1001
+ rows = []
961
1002
 
962
1003
  highest_similarity = 0.0
963
1004
  best_match_question = None
@@ -15,18 +15,23 @@ def get_category(self, exact_question): # returns category as a string or None
15
15
  - Performs a lookup for the given question.
16
16
  - Returns the corresponding category tag if a match exists.
17
17
  """
18
- conn = sqlite3.connect(self._DLM__filename)
19
- cursor = conn.cursor()
20
- cursor.execute(
21
- "SELECT category FROM knowledge_base WHERE question = ?",
22
- (exact_question,)
23
- )
24
- row = cursor.fetchone()
25
- conn.close()
26
- if row:
27
- return row[0] # this is the category/question_type
28
- else:
29
- return None # question not found
18
+ if not hasattr(self, '_DLM__cursor') or not self._DLM__cursor:
19
+ return None
20
+ try:
21
+ self._DLM__cursor.execute(
22
+ "SELECT category FROM knowledge_base WHERE question = ?",
23
+ (exact_question,)
24
+ )
25
+ row = self._DLM__cursor.fetchone()
26
+
27
+ if row:
28
+ return row[0] # this is the category/question_type
29
+ else:
30
+ return None # question not found
31
+
32
+ except Exception as e:
33
+ print(f"System: Database Read Error in get_category: {e}")
34
+ return None
30
35
 
31
36
 
32
37
  def get_specific_question(self, exact_answer): # returns question as a string or None
@@ -44,18 +49,24 @@ def get_specific_question(self, exact_answer): # returns question as a string o
44
49
  - Searches for a question where the answer matches exactly.
45
50
  - Returns the first matching question, or None if no match exists.
46
51
  """
47
- conn = sqlite3.connect(self._DLM__filename)
48
- cursor = conn.cursor()
49
- cursor.execute(
50
- "SELECT question FROM knowledge_base WHERE answer = ?",
51
- (exact_answer,)
52
- )
53
- row = cursor.fetchone()
54
- conn.close()
55
- if row:
56
- return row[0] # this is the category/question_type
57
- else:
58
- return None # question not found
52
+ if not hasattr(self, '_DLM__cursor') or not self._DLM__cursor:
53
+ return None
54
+
55
+ try:
56
+ self._DLM__cursor.execute(
57
+ "SELECT question FROM knowledge_base WHERE answer = ?",
58
+ (exact_answer,)
59
+ )
60
+ row = self._DLM__cursor.fetchone()
61
+
62
+ if row:
63
+ return row[0]
64
+ else:
65
+ return None
66
+
67
+ except Exception as e:
68
+ print(f"System: Database Read Error in get_specific_question: {e}")
69
+ return None
59
70
 
60
71
  def learn(self, expectation, category): # no return, void
61
72
  """
@@ -70,11 +81,18 @@ def learn(self, expectation, category): # no return, void
70
81
  into the SQLite database.
71
82
  - Uses 'INSERT OR IGNORE' to prevent duplicate entries.
72
83
  """
73
- conn = sqlite3.connect(self._DLM__filename)
74
- c = conn.cursor()
75
- c.execute(
76
- "INSERT OR IGNORE INTO knowledge_base (question, answer, category) VALUES (?, ?, ?)",
77
- (self._DLM__special_stripped_query, expectation, category)
78
- )
79
- conn.commit()
80
- conn.close()
84
+ # we need to both run cursor and connection
85
+ if not hasattr(self, '_DLM__cursor') or not self._DLM__conn:
86
+ print("System: Error - Cannot learn, database connection lost.")
87
+ return
88
+
89
+ try:
90
+ self._DLM__cursor.execute(
91
+ "INSERT OR IGNORE INTO knowledge_base (question, answer, category) VALUES (?, ?, ?)",
92
+ (self._DLM__special_stripped_query, expectation, category)
93
+ )
94
+
95
+ self._DLM__conn.commit()
96
+
97
+ except Exception as e:
98
+ print(f"System: Database Write Error in learn: {e}")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dynamic-learning-model
3
- Version: 3.5.0
3
+ Version: 3.5.2
4
4
  Summary: A Dynamic Learning Model for processing NLP queries using hybrid AI and reasoning.
5
5
  Home-page: https://github.com/VigneshT24/Dynamic_Learning_Model
6
6
  Author: Vignesh Thondikulam
@@ -5,7 +5,7 @@ with open('README.md', 'r', encoding='utf-8') as f:
5
5
 
6
6
  setup(
7
7
  name='dynamic-learning-model',
8
- version='3.5.0',
8
+ version='3.5.2',
9
9
  author='Vignesh Thondikulam',
10
10
  author_email='vignesh.tho2006@gmail.com',
11
11
  description='A Dynamic Learning Model for processing NLP queries using hybrid AI and reasoning.',