dynamic-learning-model 1.2.5__tar.gz → 1.3__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: 1.2.5
3
+ Version: 1.3
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
@@ -32,22 +32,64 @@ Dynamic: summary
32
32
  ![SQLite](https://img.shields.io/badge/SQLite-003B57?style=flat-square&logo=SQLite&logoColor=white)
33
33
 
34
34
  # Dynamic Learning Model
35
- The Dynamic Learning Model (DLM) is a hybrid AI system designed to learn, adapt, and intelligently respond to user queries. It combines natural language understanding with structured reasoning to improve over time as it interacts with users.
35
+ **ABOUT**:
36
+
37
+ The Dynamic Learning Model (DLM) is a hybrid AI system designed to learn, adapt, and intelligently respond to user queries. It combines natural language understanding with structured reasoning, continually improving as it is trained.
36
38
 
37
39
  Key capabilities include:
38
40
 
39
41
  * FAQ Handling: Learns and responds to frequently asked questions based on the knowledge it has been trained on.
40
42
 
41
- * Chain-of-Thought (CoT) Reasoning: Performs clear, step by step logic to solve non-ambiguous arithmetic and unit conversion problems.
43
+ * Chain-of-Thought (CoT) Reasoning: Performs clear, step-by-step logic to solve non-ambiguous arithmetic and unit conversion problems.
44
+
45
+ * Custom Knowledge Integration: DLM is fully extensible. You can initialize it with an empty SQL database and train it with your domain-specific knowledge.
46
+
47
+ Whether you're building a student support bot, a domain-specific assistant, or a computation system, DLM offers a flexible foundation to power your intelligent applications
48
+
49
+ **REQUIRED PARAMETERS**:
50
+ * The constructor requires passing in two parameters:
51
+ - Bot Mode: 't' = training, 'c' = commercial, 'e' = experimental
52
+ - Empty SQL Database for training the bot with queries
53
+ * The ask() method also requires passing in two parameters:
54
+ - Query: "What is the definition of FAFSA" (as an example)
55
+ - Display Thought: "True" to allow the bot's Chain of Thought to be displayed, or else "False"
56
+
57
+ **GET STARTED**:
58
+ * To install, run:
59
+ ```bash
60
+ pip install dynamic-learning-model
61
+ ```
62
+ * ***Python 3.12 or higher is required to use this bot in your program***
63
+
64
+ (Experimental 'e' mode [computation queries])
65
+ ```python
66
+ from dlm import DLM
67
+
68
+ computation_bot = DLM("e", "college_knowledge.db")
69
+
70
+ computation_bot.ask("Compute the following: 5 * 5 * 5 + 5 / 5", True)
71
+ ```
72
+
73
+ (Training 't' mode [training queries])
74
+ * You can find the training password in the ```__trainingPwd``` variable defined within the DLM.py file
75
+ ```python
76
+ from dlm import DLM
77
+
78
+ training_bot = DLM("t", "college_knowledge.db")
42
79
 
43
- * Custom Knowledge Integration: DLM is fully extensible. You can initialize it with an empty SQL database and train it with your own domain-specific knowledge.
80
+ training_bot.ask("What is FAFSA in college?", True)
81
+ ```
44
82
 
45
- Whether you're building a student support bot, a domain-specific assistant, or an adaptive Q&A system, DLM offers a flexible foundation to power your intelligent applications
83
+ (Commercial 'c' mode [deployment/production use after training])
84
+ ```python
85
+ from dlm import DLM
46
86
 
47
- * This model uses SpaCy, SQLite, & NLTK for many of its functions
87
+ commercial_bot = DLM("c", "college_knowledge.db")
48
88
 
49
- NOTICE: This is a public package, to install it, run: **pip install dynamic-learning-model**
89
+ commercial_bot.ask("What is the difference between FAFSA and CADAA in California?", False)
90
+ ```
50
91
 
92
+ **HIGH-LEVEL PIPELINE VISUALS**:
51
93
 
52
94
  ![image](https://github.com/user-attachments/assets/340dc69a-8374-45df-ac1e-82431c5111f2)
53
95
 
@@ -0,0 +1,67 @@
1
+ ![Python](https://img.shields.io/badge/python-3670A0?style=for-the-badge&logo=python&logoColor=ffdd54)
2
+ ![SQLite](https://img.shields.io/badge/SQLite-003B57?style=flat-square&logo=SQLite&logoColor=white)
3
+
4
+ # Dynamic Learning Model
5
+ **ABOUT**:
6
+
7
+ The Dynamic Learning Model (DLM) is a hybrid AI system designed to learn, adapt, and intelligently respond to user queries. It combines natural language understanding with structured reasoning, continually improving as it is trained.
8
+
9
+ Key capabilities include:
10
+
11
+ * FAQ Handling: Learns and responds to frequently asked questions based on the knowledge it has been trained on.
12
+
13
+ * Chain-of-Thought (CoT) Reasoning: Performs clear, step-by-step logic to solve non-ambiguous arithmetic and unit conversion problems.
14
+
15
+ * Custom Knowledge Integration: DLM is fully extensible. You can initialize it with an empty SQL database and train it with your domain-specific knowledge.
16
+
17
+ Whether you're building a student support bot, a domain-specific assistant, or a computation system, DLM offers a flexible foundation to power your intelligent applications
18
+
19
+ **REQUIRED PARAMETERS**:
20
+ * The constructor requires passing in two parameters:
21
+ - Bot Mode: 't' = training, 'c' = commercial, 'e' = experimental
22
+ - Empty SQL Database for training the bot with queries
23
+ * The ask() method also requires passing in two parameters:
24
+ - Query: "What is the definition of FAFSA" (as an example)
25
+ - Display Thought: "True" to allow the bot's Chain of Thought to be displayed, or else "False"
26
+
27
+ **GET STARTED**:
28
+ * To install, run:
29
+ ```bash
30
+ pip install dynamic-learning-model
31
+ ```
32
+ * ***Python 3.12 or higher is required to use this bot in your program***
33
+
34
+ (Experimental 'e' mode [computation queries])
35
+ ```python
36
+ from dlm import DLM
37
+
38
+ computation_bot = DLM("e", "college_knowledge.db")
39
+
40
+ computation_bot.ask("Compute the following: 5 * 5 * 5 + 5 / 5", True)
41
+ ```
42
+
43
+ (Training 't' mode [training queries])
44
+ * You can find the training password in the ```__trainingPwd``` variable defined within the DLM.py file
45
+ ```python
46
+ from dlm import DLM
47
+
48
+ training_bot = DLM("t", "college_knowledge.db")
49
+
50
+ training_bot.ask("What is FAFSA in college?", True)
51
+ ```
52
+
53
+ (Commercial 'c' mode [deployment/production use after training])
54
+ ```python
55
+ from dlm import DLM
56
+
57
+ commercial_bot = DLM("c", "college_knowledge.db")
58
+
59
+ commercial_bot.ask("What is the difference between FAFSA and CADAA in California?", False)
60
+ ```
61
+
62
+ **HIGH-LEVEL PIPELINE VISUALS**:
63
+
64
+ ![image](https://github.com/user-attachments/assets/340dc69a-8374-45df-ac1e-82431c5111f2)
65
+
66
+
67
+ ![image](https://github.com/user-attachments/assets/422f1045-07bc-4ddf-ae28-9f5731324b93)
@@ -7,6 +7,7 @@ import time
7
7
  import sqlite3
8
8
  import re
9
9
  import nltk
10
+ import math
10
11
  from better_profanity import profanity
11
12
  from nltk.corpus import names
12
13
  from word2number import w2n
@@ -213,6 +214,40 @@ class DLM:
213
214
  ]
214
215
  }
215
216
 
217
+ # to solve geometric problems (advanced CoT)
218
+ __geometric_calculation_identifiers = {
219
+ "triangle": {
220
+ "keywords": ["area", "triangle"], # keyword that will be mentioned while in CoT
221
+ "params": ["base", "height"], # helps with formula
222
+ "formula": lambda d: 0.5 * d["base"] * d["height"] # formula to solve geometric problem
223
+ },
224
+ "rectangle": {
225
+ "keywords": ["area", "rectangle"],
226
+ "params": ["length", "width"],
227
+ "formula": lambda d: d["length"] * d["width"]
228
+ },
229
+ "parallelogram": {
230
+ "keywords": ["area", "parallelogram"],
231
+ "params": ["base", "height"],
232
+ "formula": lambda d: d["base"] * d["height"]
233
+ },
234
+ "square": {
235
+ "keywords": ["area", "square"],
236
+ "params": ["side"],
237
+ "formula": lambda d: math.pow(d["side"], 2)
238
+ },
239
+ "trapezoid": {
240
+ "keywords": ["area", "trapezoid"],
241
+ "params": ["other", "height"],
242
+ "formula": lambda d: 0.5 * (d["other"][0] + d["other"][1]) * d["height"]
243
+ },
244
+ "circle": {
245
+ "keywords": ["area", "circle"],
246
+ "params": ["radius"],
247
+ "formula": lambda d: (math.pow(d["radius"], 2)) * math.pi
248
+ }
249
+ }
250
+
216
251
  # for SI conversion and CoT
217
252
  __units = {
218
253
  # distance units (base = meters)
@@ -534,6 +569,131 @@ class DLM:
534
569
  else:
535
570
  self.__tone = ""
536
571
 
572
+ def __geometric_calculation(self, filtered_query, display_thought):
573
+ """
574
+ Perform formula-related math and geometric problems that will be called inside perform_advanced_CoT
575
+
576
+ Parameters:
577
+ filtered_query (str): user query that has been filtered to have mostly computational details
578
+ display_thought (bool): Indicates whether the user wants to have the bot display its thought process or just give the answer
579
+
580
+ Returns:
581
+ float: The result after computing the formula calculation
582
+
583
+ Behavior:
584
+ - Search through query to find specific keywords like 'area' or 'volume'
585
+ - Then, search to find shape or object to perform math on like 'triangle' or 'square'
586
+ - Find numbers associated with object details and store in appropriate list
587
+ - Finally, find appropriate formula with identifiers and plug in and return answer
588
+
589
+ """
590
+ height_value = None
591
+ height_value_index = None
592
+ other_values = []
593
+ object_intel = []
594
+ common_endings = ["ular", "ish", "al"] # some people might say "squarish" or "rectangular" etc
595
+
596
+ tokens = filtered_query.split()
597
+ lower_tokens = [t.lower() for t in tokens]
598
+
599
+ # set height value number (if exists) to height_value and also its corresponding index
600
+ for idx, token in enumerate(lower_tokens):
601
+ is_similar = difflib.get_close_matches(token, ["height"], n=1, cutoff=0.7)
602
+ if is_similar and is_similar[0] == "height":
603
+ # try token before
604
+ if idx > 0:
605
+ candidate = lower_tokens[idx - 1]
606
+ try:
607
+ height_value = w2n.word_to_num(candidate)
608
+ height_value_index = idx - 1
609
+ except ValueError:
610
+ if candidate.replace('.', '', 1).isdigit():
611
+ height_value = float(candidate)
612
+ height_value_index = idx - 1
613
+ break
614
+ pass
615
+
616
+ # try token after
617
+ if idx < len(tokens) - 1:
618
+ candidate = lower_tokens[idx + 1]
619
+ try:
620
+ height_value = w2n.word_to_num(candidate)
621
+ height_value_index = idx + 1
622
+ except ValueError:
623
+ if candidate.replace('.', '', 1).isdigit():
624
+ height_value = float(candidate)
625
+ height_value_index = idx + 1
626
+ break
627
+ pass
628
+
629
+ # append all other numbers to "other_value" list
630
+ for i, token in enumerate(tokens):
631
+ if i == height_value_index:
632
+ continue # skip the height value itself
633
+ try:
634
+ num = w2n.word_to_num(token)
635
+ other_values.append(num)
636
+ except ValueError:
637
+ if token.replace('.', '', 1).isdigit():
638
+ other_values.append(float(token))
639
+
640
+ # find the object name and what to compute about the object
641
+ for token in lower_tokens:
642
+ for obj in self.__geometric_calculation_identifiers:
643
+ # remove common endings for better matching
644
+ for ending in common_endings:
645
+ if token.endswith(ending):
646
+ token = token[: -len(ending)] # Remove the ending
647
+ break
648
+ is_similar = difflib.get_close_matches(token, [obj], n=1, cutoff=0.80)
649
+ if is_similar and is_similar[0] == obj:
650
+ object_intel.extend(self.__geometric_calculation_identifiers[obj]["keywords"])
651
+
652
+ obj_name = object_intel[1]
653
+ if display_thought:
654
+ self.__loadingAnimation(f"It seems that the user wants to compute the {' of a '.join(object_intel)}", 0.5)
655
+ if height_value is not None:
656
+ self.__loadingAnimation(f"* The user has mentioned that the height of the {obj_name} object is {height_value}", 0.4)
657
+ else:
658
+ self.__loadingAnimation(f"* The {object_intel[1]} object has no height associated with it, so moving on", 0.4)
659
+ if len(other_values) > 0:
660
+ self.__loadingAnimation(f"* Additional numerical values associated with the dimensions of the {obj_name} object is {' and '.join(str(v) for v in other_values)}", 0.4)
661
+ else:
662
+ self.__loadingAnimation(f"* No additional numerical values associated with the dimensions of the {obj_name} were given",0.4)
663
+
664
+ # Now iterate through the geometric identifier list, find the correct object, and then find its formula, then plug compute
665
+ formula = self.__geometric_calculation_identifiers[obj_name]["formula"]
666
+ params = self.__geometric_calculation_identifiers[obj_name]["params"]
667
+
668
+ formula_inputs = {} # all data gathered to compute geometry
669
+
670
+ try:
671
+ if "height" in params:
672
+ formula_inputs["height"] = height_value
673
+
674
+ value_idx = 0 # count how many values to be added in formula_inputs
675
+ for param in params:
676
+ if param == "height":
677
+ continue # already added
678
+ elif param == "other": # two consecutive numbers to append
679
+ formula_inputs["other"] = other_values[value_idx:value_idx + 2]
680
+ value_idx += 2
681
+ else: # only one number to append
682
+ formula_inputs[param] = other_values[value_idx]
683
+ value_idx += 1
684
+
685
+ # Try calculating the result and return
686
+ result = round(formula(formula_inputs), 4)
687
+ return result
688
+
689
+ except Exception as e:
690
+ if display_thought:
691
+ print(f"{'\033[33m'}Unable to compute the {object_intel[0]} of the {obj_name} due to missing or mismatched values{'\033[0m'}")
692
+ else:
693
+ print(f"{'\033[34m'}Unable to compute the {object_intel[0]} of the {obj_name} due to missing or mismatched values{'\033[0m'}")
694
+ return None
695
+
696
+
537
697
  def __perform_advanced_CoT(self, filtered_query, display_thought): # no return, void
538
698
  """
539
699
  Perform advanced Chain-of-Thought (CoT) reasoning to solve arithmetic or unit conversion problems.
@@ -570,8 +730,7 @@ class DLM:
570
730
  print(
571
731
  f"{'\033[33m'}I am presented with a more involved query asking me to do some form of computation{'\033[0m'}")
572
732
  self.__loadingAnimation("Let me think about this carefully and break it down so that I can solve it", 0.8)
573
- self.__loadingAnimation(f"I’ve trimmed away any extra words so I’m focusing on \"{filtered_query}\" now",
574
- 0.8)
733
+ self.__loadingAnimation(f"I’ve trimmed away any extra words so I’m focusing on \"{filtered_query}\" now", 0.8)
575
734
 
576
735
  # Have the bot pick out names mentioned (in order) using SpaCy and NLTK (for maximum coverage)
577
736
  for ent in doc.ents:
@@ -599,176 +758,189 @@ class DLM:
599
758
  tokens_lower = filtered_query.lower().split()
600
759
  last_two = set(tokens_lower[-2:]) # only the final 2 words from filtered input
601
760
 
602
- # Then have it find all operand indicating keywords
603
- found_operand = False
604
- for fq in filtered_query.split():
605
- fq_l = fq.lower()
606
- # If this word is one of the ending phrases and sits among the last five, skip it
607
- if fq_l in arithmetic_ending_phrases and fq_l in last_two:
608
- continue
609
- if fq_l in {"+", "-", "*", "/"}:
610
- operands_mentioned.append(fq_l)
611
- keywords_mentioned.append(fq_l)
612
- continue # move on to the next token
613
- for operand, keywords in self.__computation_identifiers.items():
614
- for kw in keywords:
615
- p1 = self.__nlp(kw)
616
- p2 = self.__nlp(fq_l)
617
- word_num_surrounded = re.search(rf'\d+\s*{fq.lower()}\s*\d+', filtered_query.lower())
618
-
619
- # Direct match or lemma match
620
- if (kw.lower() == fq.lower()) or p1[0].lemma_ == p2[0].lemma_:
621
- keywords_mentioned.append(kw.title())
622
- if kw.lower() == "average":
623
- operands_mentioned.append("+")
624
- elif kw.lower() == "out of":
625
- if word_num_surrounded:
761
+ # First see if the problem is a geometric problem
762
+ words = filtered_query.lower().split()
763
+ geometric_ans = None
764
+ # checks if the query contains shapes or object to perform possibly formula calculation
765
+ geometric_calc = any(difflib.get_close_matches(word, self.__geometric_calculation_identifiers.keys(), n=1, cutoff=0.70) for word in words)
766
+ is_geometric_query = False
767
+
768
+ geo_types = set() # currently supported types of geometric calculations
769
+
770
+ for t in self.__geometric_calculation_identifiers:
771
+ shape = self.__geometric_calculation_identifiers[t]["keywords"]
772
+ geo_types.add(shape[0])
773
+ if any(difflib.get_close_matches(word, geo_types, n=1, cutoff=0.70) for word in words) and geometric_calc:
774
+ geometric_ans = self.__geometric_calculation(filtered_query, display_thought)
775
+ if geometric_ans is not None:
776
+ is_geometric_query = True
777
+ else: # Not geometric, so have the bot find all operand indicating keywords
778
+ found_operand = False
779
+ for fq in filtered_query.split():
780
+ fq_l = fq.lower()
781
+ # If this word is one of the ending phrases and sits among the last five, skip it
782
+ if fq_l in arithmetic_ending_phrases and fq_l in last_two:
783
+ continue
784
+ if fq_l in {"+", "-", "*", "/"}:
785
+ operands_mentioned.append(fq_l)
786
+ keywords_mentioned.append(fq_l)
787
+ continue # move on to the next token
788
+ for operand, keywords in self.__computation_identifiers.items():
789
+ for kw in keywords:
790
+ p1 = self.__nlp(kw)
791
+ p2 = self.__nlp(fq_l)
792
+ word_num_surrounded = re.search(rf'\d+\s*{fq.lower()}\s*\d+', filtered_query.lower())
793
+
794
+ # Direct match or lemma match
795
+ if (kw.lower() == fq.lower()) or p1[0].lemma_ == p2[0].lemma_:
796
+ keywords_mentioned.append(kw.title())
797
+ if kw.lower() == "average":
798
+ operands_mentioned.append("+")
799
+ elif kw.lower() == "out of":
800
+ if word_num_surrounded:
801
+ operands_mentioned.append(operand)
802
+ found_operand = True
803
+ break # only break if 'out of' condition is satisfied
804
+ continue # skip adding 'out of' if not surrounded by numbers
805
+ else:
626
806
  operands_mentioned.append(operand)
627
807
  found_operand = True
628
- break # only break if 'out of' condition is satisfied
629
- continue # skip adding 'out of' if not surrounded by numbers
630
- else:
631
- operands_mentioned.append(operand)
632
- found_operand = True
633
- break
808
+ break
634
809
 
635
- # Vector + string similarity
636
- if p1.vector_norm != 0 and p2.vector_norm != 0 and (
637
- p1.similarity(p2) > 0.80 and difflib.SequenceMatcher(None, kw, fq_l).ratio() > 0.40):
638
- keywords_mentioned.append(kw.title())
639
- if kw.lower() == "average":
640
- operands_mentioned.append("+")
641
- elif kw.lower() == "out of":
642
- if word_num_surrounded:
810
+ # Vector + string similarity
811
+ if p1.vector_norm != 0 and p2.vector_norm != 0 and (
812
+ p1.similarity(p2) > 0.80 and difflib.SequenceMatcher(None, kw, fq_l).ratio() > 0.40):
813
+ keywords_mentioned.append(kw.title())
814
+ if kw.lower() == "average":
815
+ operands_mentioned.append("+")
816
+ elif kw.lower() == "out of":
817
+ if word_num_surrounded:
818
+ operands_mentioned.append(operand)
819
+ found_operand = True
820
+ break
821
+ continue
822
+ else:
643
823
  operands_mentioned.append(operand)
644
824
  found_operand = True
645
825
  break
646
- continue
647
- else:
648
- operands_mentioned.append(operand)
649
- found_operand = True
650
- break
651
826
 
652
- # Fallback: high string similarity
653
- elif difflib.SequenceMatcher(None, kw, fq_l).ratio() > 0.80:
654
- keywords_mentioned.append(kw.title())
655
- if kw.lower() == "average":
656
- operands_mentioned.append("+")
657
- elif kw.lower() == "out of":
658
- if word_num_surrounded:
827
+ # Fallback: high string similarity
828
+ elif difflib.SequenceMatcher(None, kw, fq_l).ratio() > 0.80:
829
+ keywords_mentioned.append(kw.title())
830
+ if kw.lower() == "average":
831
+ operands_mentioned.append("+")
832
+ elif kw.lower() == "out of":
833
+ if word_num_surrounded:
834
+ operands_mentioned.append(operand)
835
+ found_operand = True
836
+ break
837
+ continue
838
+ else:
659
839
  operands_mentioned.append(operand)
660
840
  found_operand = True
661
841
  break
662
- continue
663
- else:
664
- operands_mentioned.append(operand)
665
- found_operand = True
666
- break
667
-
668
- if found_operand:
669
- found_operand = False
670
- break
671
842
 
672
- # If no operands were found in the main pass, check ending phrases as a last resort
673
- if not operands_mentioned:
674
- for fq in filtered_query.split():
675
- p_fq = self.__nlp(fq)
676
-
677
- # Replace exact matching with a spaCy similarity check against ending_phrases
678
- matched_ep = None
679
- for ep in arithmetic_ending_phrases:
680
- p_ep = self.__nlp(ep)
681
- if p_ep.vector_norm != 0 and p_fq.vector_norm != 0 and p_ep.similarity(p_fq) > 0.50:
682
- matched_ep = ep
843
+ if found_operand:
844
+ found_operand = False
683
845
  break
684
846
 
685
- if not matched_ep:
686
- continue
847
+ # If no operands were found in the main pass, check ending phrases as a last resort
848
+ if not operands_mentioned:
849
+ for fq in filtered_query.split():
850
+ p_fq = self.__nlp(fq)
851
+
852
+ # Replace exact matching with a spaCy similarity check against ending_phrases
853
+ matched_ep = None
854
+ for ep in arithmetic_ending_phrases:
855
+ p_ep = self.__nlp(ep)
856
+ if p_ep.vector_norm != 0 and p_fq.vector_norm != 0 and p_ep.similarity(p_fq) > 0.50:
857
+ matched_ep = ep
858
+ break
687
859
 
688
- # Now matched_ep roughly corresponds to an ending phrase; find its operand via spaCy
689
- for operand, keywords in self.__computation_identifiers.items():
690
- for kw in keywords:
691
- p_kw = self.__nlp(kw)
692
- if p_kw.vector_norm != 0 and p_fq.vector_norm != 0 and p_kw.similarity(p_fq) > 0.70:
693
- keywords_mentioned.append(kw.title())
694
- operands_mentioned.append(operand)
860
+ if not matched_ep:
861
+ continue
862
+
863
+ # Now matched_ep roughly corresponds to an ending phrase; find its operand via spaCy
864
+ for operand, keywords in self.__computation_identifiers.items():
865
+ for kw in keywords:
866
+ p_kw = self.__nlp(kw)
867
+ if p_kw.vector_norm != 0 and p_fq.vector_norm != 0 and p_kw.similarity(p_fq) > 0.70:
868
+ keywords_mentioned.append(kw.title())
869
+ operands_mentioned.append(operand)
870
+ break
871
+ if operands_mentioned:
695
872
  break
696
873
  if operands_mentioned:
697
874
  break
698
- if operands_mentioned:
699
- break
700
- keywords_mentioned = list(dict.fromkeys(keywords_mentioned))
701
-
702
- # Now have the bot pick out numbers (in order)
703
- # additionally, "double", "triple", "quadruple", "half", "an" and "a" also count as numbers, in addition to text numbers (e.g. "three")
704
- text_nums = ["a", "an", "half", "double", "triple", "quadruple"]
705
- a_an_detected = False
706
-
707
- # Combined regex and word match pass
708
- tokens = filtered_query.lower().split()
709
- for token in tokens:
710
- # Check if it's a digit-based number (e.g. 600, 20.5)
711
- if re.fullmatch(r"\d+(\.\d+)?", token):
712
- num_mentioned.append(str(float(token)))
713
- continue
714
-
715
- # Check if it's a word-based number (e.g. 'three', 'double', 'a')
716
- try:
717
- num = w2n.word_to_num(token)
718
- num_mentioned.append(str(float(num)))
719
- continue
720
- except ValueError:
721
- pass # not a word2num-recognized word
722
-
723
- # Check if it's in our custom list (a, an, half, double, etc.)
724
- for t in text_nums:
725
- p1 = self.__nlp(token)
726
- p2 = self.__nlp(t)
727
- if p1[0].lemma_ == p2[0].lemma_:
728
- if t == "double":
729
- num_mentioned.append(float(2).__str__())
730
- elif t == "triple":
731
- num_mentioned.append(float(3).__str__())
732
- elif t == "half":
733
- num_mentioned.append(float(0.5).__str__())
734
- elif ("=" in operands_mentioned) and (t == "a" or t == "an"):
735
- a_an_detected = True
736
- num_mentioned.append(float(1.0).__str__())
737
- elif t == "quadruple":
738
- num_mentioned.append(float(4).__str__())
739
-
740
- # Remove "1.0" if 'a'/'an' was used in an invalid context (like not following "=")
741
- if a_an_detected and (num_mentioned.count("1.0") > 1 or len(num_mentioned) > 1):
742
- num_mentioned.remove("1.0")
743
-
744
- if ('=' in operands_mentioned) and (len(num_mentioned) < 2):
745
- operands_mentioned.clear()
746
- operands_mentioned.append('=')
747
- else:
748
- if '=' in operands_mentioned:
749
- operands_mentioned = [op for op in operands_mentioned if op != '=']
875
+ keywords_mentioned = list(dict.fromkeys(keywords_mentioned))
876
+
877
+ # Now have the bot pick out numbers (in order)
878
+ # additionally, "double", "triple", "quadruple", "half", "an" and "a" also count as numbers, in addition to text numbers (e.g. "three")
879
+ text_nums = ["a", "an", "half", "double", "triple", "quadruple"]
880
+ a_an_detected = False
881
+
882
+ # Combined regex and word match pass
883
+ tokens = filtered_query.lower().split()
884
+ for token in tokens:
885
+ # Check if it's a digit-based number (e.g. 600, 20.5)
886
+ if re.fullmatch(r"\d+(\.\d+)?", token):
887
+ num_mentioned.append(str(float(token)))
888
+ continue
750
889
 
751
- print("\n")
752
- if any(not lst for lst in (num_mentioned, operands_mentioned)) or (
753
- '=' not in operands_mentioned and num_mentioned.__len__() < 2): # don't compute if parts are missing
754
- print(
755
- f"{self.__loadingAnimation('Hmm', 0.8) or ''}{'\033[34m'}It looks like some essential details are missing, so I can’t complete this calculation right now.{'\033[0m'}")
890
+ # Check if it's a word-based number (e.g. 'three', 'double', 'a')
891
+ try:
892
+ num = w2n.word_to_num(token)
893
+ num_mentioned.append(str(float(num)))
894
+ continue
895
+ except ValueError:
896
+ pass # not a word2num-recognized word
897
+
898
+ # Check if it's in our custom list (a, an, half, double, etc.)
899
+ for t in text_nums:
900
+ p1 = self.__nlp(token)
901
+ p2 = self.__nlp(t)
902
+ if p1[0].lemma_ == p2[0].lemma_:
903
+ if t == "double":
904
+ num_mentioned.append(float(2).__str__())
905
+ elif t == "triple":
906
+ num_mentioned.append(float(3).__str__())
907
+ elif t == "half":
908
+ num_mentioned.append(float(0.5).__str__())
909
+ elif ("=" in operands_mentioned) and (t == "a" or t == "an"):
910
+ a_an_detected = True
911
+ num_mentioned.append(float(1.0).__str__())
912
+ elif t == "quadruple":
913
+ num_mentioned.append(float(4).__str__())
914
+
915
+ # Remove "1.0" if 'a'/'an' was used in an invalid context (like not following "=")
916
+ if a_an_detected and (num_mentioned.count("1.0") > 1 or len(num_mentioned) > 1):
917
+ num_mentioned.remove("1.0")
918
+
919
+ if ('=' in operands_mentioned) and (len(num_mentioned) < 2):
920
+ operands_mentioned.clear()
921
+ operands_mentioned.append('=')
922
+ else:
923
+ if '=' in operands_mentioned:
924
+ operands_mentioned = [op for op in operands_mentioned if op != '=']
925
+
926
+ # verify and possibly print thoughts
927
+ if (not is_geometric_query) and (any(not lst for lst in (num_mentioned, operands_mentioned)) or ('=' not in operands_mentioned and num_mentioned.__len__() < 2)): # don't compute if parts are missing
928
+ print(f"{self.__loadingAnimation('Hmm', 0.8) or '' if display_thought else ''}{'\033[34m'}It looks like some essential details are missing, so I can’t complete this calculation right now.{'\033[0m'}")
929
+ print(f"\033[34mIf you are asking a geometric query, try including geometric identifiers like \"{'\", \"'.join(geo_types)}\" in your query.\033[0m")
930
+ print(f"\033[34mCurrently, I can only compute those identifiers aforementioned, but more geometric features are coming soon!\033[0m")
756
931
  else: # else, the bot needs to explain what it has tokenized
757
932
  if display_thought:
758
- self.__loadingAnimation(
759
- f"1.) I see {', '.join(persons_mentioned) if persons_mentioned.__len__() >= 1 else 'no one'} mentioned as a person name; "
933
+ self.__loadingAnimation(f"1.) I see {', '.join(persons_mentioned) if persons_mentioned.__len__() >= 1 else 'no one'} mentioned as a person name; "
760
934
  f"{'they’re likely key to this problem' if persons_mentioned.__len__() >= 1 else 'moving on'}", 0.2)
761
- self.__loadingAnimation(
762
- f"2.) Moreover, I see {', '.join(items_mentioned) if items_mentioned.__len__() >= 1 else 'no items'} mentioned as proper nouns; "
935
+ self.__loadingAnimation(f"2.) Moreover, I see {', '.join(items_mentioned) if items_mentioned.__len__() >= 1 else 'no items'} mentioned as proper nouns; "
763
936
  f"{'this might be a key thing to this problem' if items_mentioned.__len__() >= 1 else 'moving on'}",
764
937
  0.2)
765
- self.__loadingAnimation(
766
- f"3.) I’ve also identified the numbers {' and '.join(num_mentioned)} that I need to compute with",
767
- 0.2)
768
- self.__loadingAnimation(
769
- f"4.) I see the keywords \"{'\" and \"'.join(keywords_mentioned)}\", meaning I need to perform a \"{'\" and \"'.join(operands_mentioned)}\" operation for this query; I’ll use that to guide my calculation",
770
- 0.2)
771
- self.__loadingAnimation("Now I have the parts, so let me put it all together and solve", 0.3)
938
+ if is_geometric_query:
939
+ self.__loadingAnimation(f"3.) This is a geometric problem and I have already computed the answer", 0.2)
940
+ else:
941
+ self.__loadingAnimation(f"3.) I’ve also identified the numbers {' and '.join(num_mentioned)} that I need to compute with", 0.2)
942
+ self.__loadingAnimation(f"4.) I see the keywords \"{'\" and \"'.join(keywords_mentioned)}\", meaning I need to perform a \"{'\" and \"'.join(operands_mentioned)}\" operation for this query; I’ll use that to guide my calculation", 0.2)
943
+ self.__loadingAnimation("Now I have the parts, so let me put it all together and solve", 0.3)
772
944
 
773
945
  # Finally compute it and then give the response (if there is any)
774
946
  # move "originally" numbers to the front
@@ -801,8 +973,11 @@ class DLM:
801
973
  num_mentioned.remove(str(float(temp)))
802
974
  num_mentioned.insert(0, str(float(temp)))
803
975
 
976
+ # geometric problem
977
+ if is_geometric_query:
978
+ print(f"{'\033[34m'}Geometric Answer: {geometric_ans}{'\033[0m'}")
804
979
  # conversion problem
805
- if len(num_mentioned) == 1 and len(operands_mentioned) == 1:
980
+ elif len(num_mentioned) == 1 and len(operands_mentioned) == 1:
806
981
  try:
807
982
  tokens = filtered_query.lower().split()
808
983
  num0 = float(num_mentioned[0])
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dynamic-learning-model
3
- Version: 1.2.5
3
+ Version: 1.3
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
@@ -32,22 +32,64 @@ Dynamic: summary
32
32
  ![SQLite](https://img.shields.io/badge/SQLite-003B57?style=flat-square&logo=SQLite&logoColor=white)
33
33
 
34
34
  # Dynamic Learning Model
35
- The Dynamic Learning Model (DLM) is a hybrid AI system designed to learn, adapt, and intelligently respond to user queries. It combines natural language understanding with structured reasoning to improve over time as it interacts with users.
35
+ **ABOUT**:
36
+
37
+ The Dynamic Learning Model (DLM) is a hybrid AI system designed to learn, adapt, and intelligently respond to user queries. It combines natural language understanding with structured reasoning, continually improving as it is trained.
36
38
 
37
39
  Key capabilities include:
38
40
 
39
41
  * FAQ Handling: Learns and responds to frequently asked questions based on the knowledge it has been trained on.
40
42
 
41
- * Chain-of-Thought (CoT) Reasoning: Performs clear, step by step logic to solve non-ambiguous arithmetic and unit conversion problems.
43
+ * Chain-of-Thought (CoT) Reasoning: Performs clear, step-by-step logic to solve non-ambiguous arithmetic and unit conversion problems.
44
+
45
+ * Custom Knowledge Integration: DLM is fully extensible. You can initialize it with an empty SQL database and train it with your domain-specific knowledge.
46
+
47
+ Whether you're building a student support bot, a domain-specific assistant, or a computation system, DLM offers a flexible foundation to power your intelligent applications
48
+
49
+ **REQUIRED PARAMETERS**:
50
+ * The constructor requires passing in two parameters:
51
+ - Bot Mode: 't' = training, 'c' = commercial, 'e' = experimental
52
+ - Empty SQL Database for training the bot with queries
53
+ * The ask() method also requires passing in two parameters:
54
+ - Query: "What is the definition of FAFSA" (as an example)
55
+ - Display Thought: "True" to allow the bot's Chain of Thought to be displayed, or else "False"
56
+
57
+ **GET STARTED**:
58
+ * To install, run:
59
+ ```bash
60
+ pip install dynamic-learning-model
61
+ ```
62
+ * ***Python 3.12 or higher is required to use this bot in your program***
63
+
64
+ (Experimental 'e' mode [computation queries])
65
+ ```python
66
+ from dlm import DLM
67
+
68
+ computation_bot = DLM("e", "college_knowledge.db")
69
+
70
+ computation_bot.ask("Compute the following: 5 * 5 * 5 + 5 / 5", True)
71
+ ```
72
+
73
+ (Training 't' mode [training queries])
74
+ * You can find the training password in the ```__trainingPwd``` variable defined within the DLM.py file
75
+ ```python
76
+ from dlm import DLM
77
+
78
+ training_bot = DLM("t", "college_knowledge.db")
42
79
 
43
- * Custom Knowledge Integration: DLM is fully extensible. You can initialize it with an empty SQL database and train it with your own domain-specific knowledge.
80
+ training_bot.ask("What is FAFSA in college?", True)
81
+ ```
44
82
 
45
- Whether you're building a student support bot, a domain-specific assistant, or an adaptive Q&A system, DLM offers a flexible foundation to power your intelligent applications
83
+ (Commercial 'c' mode [deployment/production use after training])
84
+ ```python
85
+ from dlm import DLM
46
86
 
47
- * This model uses SpaCy, SQLite, & NLTK for many of its functions
87
+ commercial_bot = DLM("c", "college_knowledge.db")
48
88
 
49
- NOTICE: This is a public package, to install it, run: **pip install dynamic-learning-model**
89
+ commercial_bot.ask("What is the difference between FAFSA and CADAA in California?", False)
90
+ ```
50
91
 
92
+ **HIGH-LEVEL PIPELINE VISUALS**:
51
93
 
52
94
  ![image](https://github.com/user-attachments/assets/340dc69a-8374-45df-ac1e-82431c5111f2)
53
95
 
@@ -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='1.2.5',
8
+ version='1.3',
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.',
@@ -1,25 +0,0 @@
1
- ![Python](https://img.shields.io/badge/python-3670A0?style=for-the-badge&logo=python&logoColor=ffdd54)
2
- ![SQLite](https://img.shields.io/badge/SQLite-003B57?style=flat-square&logo=SQLite&logoColor=white)
3
-
4
- # Dynamic Learning Model
5
- The Dynamic Learning Model (DLM) is a hybrid AI system designed to learn, adapt, and intelligently respond to user queries. It combines natural language understanding with structured reasoning to improve over time as it interacts with users.
6
-
7
- Key capabilities include:
8
-
9
- * FAQ Handling: Learns and responds to frequently asked questions based on the knowledge it has been trained on.
10
-
11
- * Chain-of-Thought (CoT) Reasoning: Performs clear, step by step logic to solve non-ambiguous arithmetic and unit conversion problems.
12
-
13
- * Custom Knowledge Integration: DLM is fully extensible. You can initialize it with an empty SQL database and train it with your own domain-specific knowledge.
14
-
15
- Whether you're building a student support bot, a domain-specific assistant, or an adaptive Q&A system, DLM offers a flexible foundation to power your intelligent applications
16
-
17
- * This model uses SpaCy, SQLite, & NLTK for many of its functions
18
-
19
- NOTICE: This is a public package, to install it, run: **pip install dynamic-learning-model**
20
-
21
-
22
- ![image](https://github.com/user-attachments/assets/340dc69a-8374-45df-ac1e-82431c5111f2)
23
-
24
-
25
- ![image](https://github.com/user-attachments/assets/422f1045-07bc-4ddf-ae28-9f5731324b93)