dynamic-learning-model 1.1.1__tar.gz → 1.2.5__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.1.1
3
+ Version: 1.2.5
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
@@ -491,7 +491,9 @@ class DLM:
491
491
  float(word) # Try to treat as number
492
492
  unique_words.append(word) # Keep numeric strings (duplicates allowed)
493
493
  except ValueError:
494
- if word not in seen:
494
+ if any(word in keywords for keywords in self.__computation_identifiers.values()):
495
+ unique_words.append(word) # Keep identifier words (duplicates allowed)
496
+ elif word not in seen:
495
497
  seen.add(word)
496
498
  unique_words.append(word)
497
499
 
@@ -532,12 +534,13 @@ class DLM:
532
534
  else:
533
535
  self.__tone = ""
534
536
 
535
- def __perform_advanced_CoT(self, filtered_query): # no return, void
537
+ def __perform_advanced_CoT(self, filtered_query, display_thought): # no return, void
536
538
  """
537
539
  Perform advanced Chain-of-Thought (CoT) reasoning to solve arithmetic or unit conversion problems.
538
540
 
539
541
  Parameters:
540
542
  filtered_query (str): The cleaned user input, expected to be a math- or logic-based question.
543
+ display_thought (bool): Indicates whether the user wants to have the bot display its thought process or just give the answer
541
544
 
542
545
  Behavior:
543
546
  - Simulates step-by-step reasoning to solve arithmetic word problems without relying on memorized answers.
@@ -545,14 +548,9 @@ class DLM:
545
548
  - Detects arithmetic operations via lexical and semantic matching with predefined keyword sets.
546
549
  - Handles both numeric digits and text-based numbers (e.g., "three", "double").
547
550
  - Supports simple arithmetic expressions and unit conversions (e.g., inches to cm).
548
- - Prints the interpreted steps, logical inferences, and the final computed result with contextual explanations.
551
+ - Prints the interpreted steps, logical inferences (if display_thought is True), and the final computed result with contextual explanations.
549
552
  - Displays fallback messages if the query is incomplete or too ambiguous to solve.
550
553
  """
551
- print(
552
- f"{'\033[33m'}I am presented with a more involved query asking me to do some form of computation{'\033[0m'}")
553
- self.__loadingAnimation("Let me think about this carefully and break it down so that I can solve it", 0.8)
554
- self.__loadingAnimation(
555
- f"I’ve trimmed away any extra words so I’m focusing on \"{filtered_query.title()}\" now", 0.8)
556
554
  persons_mentioned = []
557
555
  items_mentioned = []
558
556
  keywords_mentioned = []
@@ -568,6 +566,13 @@ class DLM:
568
566
  filtered_query = filtered_query.title()
569
567
  doc = self.__nlp(filtered_query)
570
568
 
569
+ if display_thought:
570
+ print(
571
+ f"{'\033[33m'}I am presented with a more involved query asking me to do some form of computation{'\033[0m'}")
572
+ 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)
575
+
571
576
  # Have the bot pick out names mentioned (in order) using SpaCy and NLTK (for maximum coverage)
572
577
  for ent in doc.ents:
573
578
  if ent.label_ == "PERSON":
@@ -603,6 +608,7 @@ class DLM:
603
608
  continue
604
609
  if fq_l in {"+", "-", "*", "/"}:
605
610
  operands_mentioned.append(fq_l)
611
+ keywords_mentioned.append(fq_l)
606
612
  continue # move on to the next token
607
613
  for operand, keywords in self.__computation_identifiers.items():
608
614
  for kw in keywords:
@@ -741,7 +747,6 @@ class DLM:
741
747
  else:
742
748
  if '=' in operands_mentioned:
743
749
  operands_mentioned = [op for op in operands_mentioned if op != '=']
744
- operands_mentioned = list(dict.fromkeys(operands_mentioned))
745
750
 
746
751
  print("\n")
747
752
  if any(not lst for lst in (num_mentioned, operands_mentioned)) or (
@@ -749,21 +754,23 @@ class DLM:
749
754
  print(
750
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'}")
751
756
  else: # else, the bot needs to explain what it has tokenized
752
- self.__loadingAnimation(
753
- f"1.) I see {', '.join(persons_mentioned) if persons_mentioned.__len__() >= 1 else 'no one'} mentioned as a person name; "
754
- f"{'they’re likely key to this problem' if persons_mentioned.__len__() >= 1 else 'moving on'}", 0.2)
755
- self.__loadingAnimation(
756
- f"2.) Moreover, I see {', '.join(items_mentioned) if items_mentioned.__len__() >= 1 else 'no items'} mentioned as proper nouns; "
757
- f"{'this might be a key thing to this problem' if items_mentioned.__len__() >= 1 else 'moving on'}",
758
- 0.2)
759
- self.__loadingAnimation(
760
- f"3.) I’ve also identified the numbers {' and '.join(num_mentioned)} that I need to compute with", 0.2)
761
- self.__loadingAnimation(
762
- 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",
763
- 0.2)
764
- self.__loadingAnimation("Now I have the parts, so let me put it all together and solve", 0.3)
765
- # Finally compute it and then give the response (if there is any)
757
+ 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; "
760
+ 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; "
763
+ f"{'this might be a key thing to this problem' if items_mentioned.__len__() >= 1 else 'moving on'}",
764
+ 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)
766
772
 
773
+ # Finally compute it and then give the response (if there is any)
767
774
  # move "originally" numbers to the front
768
775
  indicators = {"original", "originally", "initial", "initially", "at first", "to begin with", "had",
769
776
  "savings", "saving", "of"}
@@ -867,9 +874,10 @@ class DLM:
867
874
  # 4) Compute only if we have both source_key and target_key
868
875
  if source_key and target_key:
869
876
  result = (num0 * self.__units[source_key]) / self.__units[target_key]
870
- self.__loadingAnimation(
871
- f"I need to take {num0} and multiply it by {self.__units[source_key]}. Finally, I divide by {self.__units[target_key]} and I got my answer",
872
- 0.2)
877
+ if display_thought:
878
+ self.__loadingAnimation(
879
+ f"I need to take {num0} and multiply it by {self.__units[source_key]}. Finally, I divide by {self.__units[target_key]} and I got my answer",
880
+ 0.2)
873
881
  expr = f"{num_mentioned[0]} {source_key}(s) ==> {round(result, 2)} {target_key}(s)"
874
882
  print(f"{'\033[34m'}Conversion Answer: {expr} {'\033[0m'}")
875
883
  else:
@@ -907,8 +915,8 @@ class DLM:
907
915
  print(
908
916
  f"{'\033[34m'}That might've confused me a bit, maybe try leaving one of those out or rephrase it to make it clearer?{'\033[0m'}")
909
917
 
910
- def __generate_thought(self, filtered_query, best_match_question, best_match_answer,
911
- highest_similarity): # no return, void
918
+ def __generate_thought(self, filtered_query, best_match_question, best_match_answer, highest_similarity,
919
+ display_thought): # no return, void
912
920
  """
913
921
  Simulate a Chain-of-Thought (CoT) reasoning process by printing the bot's internal analysis.
914
922
 
@@ -917,6 +925,7 @@ class DLM:
917
925
  best_match_question (str): The closest matching question found in the knowledge base.
918
926
  best_match_answer (str): The corresponding answer to the matched question.
919
927
  highest_similarity (float): The calculated string similarity score (0 to 1) for the match.
928
+ display_thought (bool): "True" if the bot is allowed to print its thought or else "False"
920
929
 
921
930
  Behavior:
922
931
  - Outputs step-by-step reasoning in a conversational format (e.g., interpreting the question's structure and tone).
@@ -925,63 +934,74 @@ class DLM:
925
934
  - Displays confidence based on similarity metrics and sets flags for uncertain answers.
926
935
  - Uses colorized terminal output and a loading animation to simulate reflective thought.
927
936
  """
928
- print("\nThought Process (Yellow):")
929
- if filtered_query is None or filtered_query == "":
930
- print(
931
- f"{'\033[33m'}I couldn't pick out any context or clear topic. If I see a match in my database I will respond with that, or else I have no clue!{'\033[0m'}")
932
- else:
933
- sentiment_tone = self.__tone.split()
934
-
935
- if self.__tone != "":
937
+ if display_thought:
938
+ print("\nThought Process (Yellow):")
939
+ if filtered_query is None or filtered_query == "":
936
940
  print(
937
- f"{'\033[33m'}Right off the bat, the user seems quite {sentiment_tone[0]} or {sentiment_tone[1]} by their query tone. Hopefully I won't disappoint!{'\033[0m'}")
938
- if self.__mode == "experimental":
939
- self.__perform_advanced_CoT(filtered_query)
941
+ f"{'\033[33m'}I couldn't pick out any context or clear topic. If I see a match in my database I will respond with that, or else I have no clue!{'\033[0m'}")
940
942
  else:
941
- interrogative_start = filtered_query.split()[0]
942
- identifier = filtered_query
943
- special_start = ["definition", "explanation", "description", "comparison", "calculation", "translation",
944
- "meaning"] # special word in different form
945
- for word in special_start:
946
- identifier = identifier.replace(word, "")
947
- # collapse any extra spaces
948
- identifier = " ".join(identifier.split())
949
- identifier = identifier.split()
950
-
951
- if " ".join(identifier) == "":
943
+ sentiment_tone = self.__tone.split()
944
+
945
+ if self.__tone != "":
952
946
  print(
953
- f"{'\033[33m'}The user starts their query with \"{interrogative_start.title()}\", but I couldn't pick out a clear topic or context.{'\033[0m'}")
947
+ f"{'\033[33m'}Right off the bat, the user seems quite {sentiment_tone[0]} or {sentiment_tone[1]} by their query tone. Hopefully I won't disappoint!{'\033[0m'}")
948
+ if self.__mode == "experimental":
949
+ self.__perform_advanced_CoT(filtered_query, display_thought)
954
950
  else:
955
- print(
956
- f"{'\033[33m'}The user starts their query with \"{interrogative_start.title()}\" and they are asking about \"{" ".join(identifier).title()}\".{'\033[0m'}")
957
- self.__loadingAnimation("Let me think about this carefully", 0.8)
958
-
959
- for s in special_start:
960
- for u in filtered_query.split():
961
- s_input = self.__nlp(s)
962
- u_input = self.__nlp(u)
963
- if (s_input.vector_norm != 0 and u_input.vector_norm != 0) and (
964
- s_input.similarity(u_input) > 0.60):
951
+ interrogative_start = filtered_query.split()[0]
952
+ identifier = filtered_query
953
+ special_start = ["definition", "explanation", "description", "comparison", "calculation",
954
+ "translation",
955
+ "meaning"] # special word in different form
956
+ for word in special_start:
957
+ identifier = identifier.replace(word, "")
958
+ # collapse any extra spaces
959
+ identifier = " ".join(identifier.split())
960
+ identifier = identifier.split()
961
+
962
+ if " ".join(identifier) == "":
963
+ print(
964
+ f"{'\033[33m'}The user starts their query with \"{interrogative_start.title()}\", but I couldn't pick out a clear topic or context.{'\033[0m'}")
965
+ else:
966
+ print(
967
+ f"{'\033[33m'}The user starts their query with \"{interrogative_start.title()}\" and they are asking about \"{" ".join(identifier).title()}\".{'\033[0m'}")
968
+ self.__loadingAnimation("Let me think about this carefully", 0.8)
969
+
970
+ for s in special_start:
971
+ for u in filtered_query.split():
972
+ s_input = self.__nlp(s)
973
+ u_input = self.__nlp(u)
974
+ if (s_input.vector_norm != 0 and u_input.vector_norm != 0) and (
975
+ s_input.similarity(u_input) > 0.60):
976
+ print(
977
+ f"{'\033[33m'}It seems like they want a {s} of \"{" ".join(identifier).title()}\".{'\033[0m'}")
978
+
979
+ self.__semantic_similarity(self.__special_stripped_query, best_match_question)
980
+ spacy_proceed = self.__nlp_similarity_value is not None
981
+ if (best_match_answer is None) or (
982
+ highest_similarity < 0.65 and (spacy_proceed and self.__nlp_similarity_value < 0.85)):
983
+ print(
984
+ f"{'\033[33m'}The closest match is only {int(highest_similarity * 100)}% similar when I used sequence matching.{'\033[0m'}")
985
+ if spacy_proceed:
965
986
  print(
966
- f"{'\033[33m'}It seems like they want a {s} of \"{" ".join(identifier).title()}\".{'\033[0m'}")
967
-
968
- self.__semantic_similarity(self.__special_stripped_query, best_match_question)
969
- spacy_proceed = self.__nlp_similarity_value is not None
970
- if (best_match_answer is None) or (highest_similarity < 0.65 and (spacy_proceed and self.__nlp_similarity_value < 0.85)):
971
- print(f"{'\033[33m'}The closest match is only {int(highest_similarity * 100)}% similar when I used sequence matching.{'\033[0m'}")
972
- if spacy_proceed:
973
- print(f"{'\033[33m'}Furthermore, an in-depth vector analysis revealed a similarity percentage of {int(self.__nlp_similarity_value * 100)}%.{'\033[0m'}")
974
- print(f"{self.__loadingAnimation("Hmm", 0.8) or ''}{'\033[33m'}I don't think I know the answer, so I am going to let the user know that.{'\033[0m'}")
975
- self.__unsure_while_thinking = True
976
- else:
977
- self.__unsure_while_thinking = False
978
- DB_identifier = self.__get_specific_question(best_match_answer)
979
- print(f"{'\033[33m'}Yes! I do remember learning about \"{DB_identifier}\" and I might have the right answer!")
980
- print(f"This is because when I did a sequence similarity calculation to one of the closest match in my database, I found it to be {int(highest_similarity * 100)}% similar.")
981
- if spacy_proceed:
982
- print(f"Additionally, doing a more in-depth vector NLP analysis resulted in {int(self.__nlp_similarity_value * 100)}% similarity. Although there are room for error, we will see.{'\033[0m'}")
983
- self.__loadingAnimation("Let me recall that answer", 0.8)
984
- print("\n")
987
+ f"{'\033[33m'}Furthermore, an in-depth vector analysis revealed a similarity percentage of {int(self.__nlp_similarity_value * 100)}%.{'\033[0m'}")
988
+ print(
989
+ f"{self.__loadingAnimation("Hmm", 0.8) or ''}{'\033[33m'}I don't think I know the answer, so I am going to let the user know that.{'\033[0m'}")
990
+ self.__unsure_while_thinking = True
991
+ else:
992
+ self.__unsure_while_thinking = False
993
+ DB_identifier = self.__get_specific_question(best_match_answer)
994
+ print(
995
+ f"{'\033[33m'}Yes! I do remember learning about \"{DB_identifier}\" and I might have the right answer!")
996
+ print(
997
+ f"This is because when I did a sequence similarity calculation to one of the closest match in my database, I found it to be {int(highest_similarity * 100)}% similar.")
998
+ if spacy_proceed:
999
+ print(
1000
+ f"Additionally, doing a more in-depth vector NLP analysis resulted in {int(self.__nlp_similarity_value * 100)}% similarity. Although there are room for error, we will see.{'\033[0m'}")
1001
+ self.__loadingAnimation("Let me recall that answer", 0.8)
1002
+ print("\n")
1003
+ elif self.__mode == "experimental":
1004
+ self.__perform_advanced_CoT(filtered_query, display_thought)
985
1005
 
986
1006
  def __generate_response(self, best_match_answer, best_match_question): # no return, void
987
1007
  """
@@ -1248,10 +1268,15 @@ class DLM:
1248
1268
  conn.commit()
1249
1269
  conn.close()
1250
1270
 
1251
- def ask(self, query): # no return, void
1271
+ def ask(self, query, display_thought): # no return, void
1252
1272
  """
1253
1273
  Handle a full user interaction loop with the DLM bot.
1254
- NOTICE: To make the bot run continuously, implement a loop in your program
1274
+
1275
+ NOTICE: To make the bot run continuously, implement a loop in your program.
1276
+
1277
+ Parameters:
1278
+ query (str): Question the bot would answer, compute, or learn
1279
+ display_thought (bool): "True" for allowing bot to print its thought and CoT or "False"
1255
1280
 
1256
1281
  Behavior:
1257
1282
  - Prompts the user for input.
@@ -1312,7 +1337,8 @@ class DLM:
1312
1337
  best_match_answer = stored_answer
1313
1338
 
1314
1339
  # "Chain of Thought" (CoT) Feature
1315
- self.__generate_thought(filtered_query, best_match_question, best_match_answer, highest_similarity)
1340
+ self.__generate_thought(filtered_query, best_match_question, best_match_answer, highest_similarity,
1341
+ display_thought)
1316
1342
 
1317
1343
  # accept a match if highest_similarity is 65% or more, or if semantic similarity is recognized
1318
1344
  if self.__mode != "experimental":
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dynamic-learning-model
3
- Version: 1.1.1
3
+ Version: 1.2.5
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='1.1.1',
8
+ version='1.2.5',
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.',