dynamic-learning-model 1.1__tar.gz → 1.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: 1.1
3
+ Version: 1.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
@@ -264,9 +264,9 @@ class DLM:
264
264
 
265
265
  Parameters:
266
266
  mode (str): The access mode. Options:
267
- 't' for Training mode,
268
- 'c' for Commercial mode,
269
- 'e' for Experimental mode.
267
+ 't' for Training mode (to train the bot with queries),
268
+ 'c' for Commercial mode (to use it in your deployment/production program),
269
+ 'e' for Experimental mode (for arithmetic or conversion queries).
270
270
  db_filename (str): The SQLite database file used to train and retrieve
271
271
  question-answer-category triples.
272
272
 
@@ -308,8 +308,6 @@ class DLM:
308
308
  if password.lower() == "stop":
309
309
  self.__mode = "commercial"
310
310
  print("\n")
311
- self.__loadingAnimation("Logging in as Commercial User", 0.6)
312
- print("\n")
313
311
  break
314
312
  if password == self.__trainingPwd:
315
313
  # trainers must understand these rules as DLM can generate bad responses if these instructions are neglected
@@ -337,12 +335,8 @@ class DLM:
337
335
  print("\n")
338
336
  elif mode.lower() == "c":
339
337
  self.__mode = "commercial"
340
- self.__loadingAnimation("Logging in as Commercial User", 0.6)
341
- print("Ask Non-Computational Queries (switch to experimental for computational queries)")
342
338
  else:
343
339
  self.__mode = "experimental"
344
- self.__loadingAnimation("Logging in as Experimental", 0.6)
345
- print("Ask Computational Problems (Arithmetics or Conversions)")
346
340
 
347
341
  def __create_table_if_missing(self): # no return, void
348
342
  """
@@ -538,12 +532,13 @@ class DLM:
538
532
  else:
539
533
  self.__tone = ""
540
534
 
541
- def __perform_advanced_CoT(self, filtered_query): # no return, void
535
+ def __perform_advanced_CoT(self, filtered_query, display_thought): # no return, void
542
536
  """
543
537
  Perform advanced Chain-of-Thought (CoT) reasoning to solve arithmetic or unit conversion problems.
544
538
 
545
539
  Parameters:
546
540
  filtered_query (str): The cleaned user input, expected to be a math- or logic-based question.
541
+ display_thought (bool): Indicates whether the user wants to have the bot display its thought process or just give the answer
547
542
 
548
543
  Behavior:
549
544
  - Simulates step-by-step reasoning to solve arithmetic word problems without relying on memorized answers.
@@ -551,14 +546,9 @@ class DLM:
551
546
  - Detects arithmetic operations via lexical and semantic matching with predefined keyword sets.
552
547
  - Handles both numeric digits and text-based numbers (e.g., "three", "double").
553
548
  - Supports simple arithmetic expressions and unit conversions (e.g., inches to cm).
554
- - Prints the interpreted steps, logical inferences, and the final computed result with contextual explanations.
549
+ - Prints the interpreted steps, logical inferences (if display_thought is True), and the final computed result with contextual explanations.
555
550
  - Displays fallback messages if the query is incomplete or too ambiguous to solve.
556
551
  """
557
- print(
558
- f"{'\033[33m'}I am presented with a more involved query asking me to do some form of computation{'\033[0m'}")
559
- self.__loadingAnimation("Let me think about this carefully and break it down so that I can solve it", 0.8)
560
- self.__loadingAnimation(
561
- f"I’ve trimmed away any extra words so I’m focusing on \"{filtered_query.title()}\" now", 0.8)
562
552
  persons_mentioned = []
563
553
  items_mentioned = []
564
554
  keywords_mentioned = []
@@ -574,6 +564,13 @@ class DLM:
574
564
  filtered_query = filtered_query.title()
575
565
  doc = self.__nlp(filtered_query)
576
566
 
567
+ if display_thought:
568
+ print(
569
+ f"{'\033[33m'}I am presented with a more involved query asking me to do some form of computation{'\033[0m'}")
570
+ self.__loadingAnimation("Let me think about this carefully and break it down so that I can solve it", 0.8)
571
+ self.__loadingAnimation(f"I’ve trimmed away any extra words so I’m focusing on \"{filtered_query}\" now",
572
+ 0.8)
573
+
577
574
  # Have the bot pick out names mentioned (in order) using SpaCy and NLTK (for maximum coverage)
578
575
  for ent in doc.ents:
579
576
  if ent.label_ == "PERSON":
@@ -755,21 +752,23 @@ class DLM:
755
752
  print(
756
753
  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'}")
757
754
  else: # else, the bot needs to explain what it has tokenized
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", 0.2)
767
- self.__loadingAnimation(
768
- 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",
769
- 0.2)
770
- self.__loadingAnimation("Now I have the parts, so let me put it all together and solve", 0.3)
771
- # Finally compute it and then give the response (if there is any)
755
+ if display_thought:
756
+ self.__loadingAnimation(
757
+ f"1.) I see {', '.join(persons_mentioned) if persons_mentioned.__len__() >= 1 else 'no one'} mentioned as a person name; "
758
+ f"{'they’re likely key to this problem' if persons_mentioned.__len__() >= 1 else 'moving on'}", 0.2)
759
+ self.__loadingAnimation(
760
+ f"2.) Moreover, I see {', '.join(items_mentioned) if items_mentioned.__len__() >= 1 else 'no items'} mentioned as proper nouns; "
761
+ f"{'this might be a key thing to this problem' if items_mentioned.__len__() >= 1 else 'moving on'}",
762
+ 0.2)
763
+ self.__loadingAnimation(
764
+ f"3.) I’ve also identified the numbers {' and '.join(num_mentioned)} that I need to compute with",
765
+ 0.2)
766
+ self.__loadingAnimation(
767
+ 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",
768
+ 0.2)
769
+ self.__loadingAnimation("Now I have the parts, so let me put it all together and solve", 0.3)
772
770
 
771
+ # Finally compute it and then give the response (if there is any)
773
772
  # move "originally" numbers to the front
774
773
  indicators = {"original", "originally", "initial", "initially", "at first", "to begin with", "had",
775
774
  "savings", "saving", "of"}
@@ -873,9 +872,10 @@ class DLM:
873
872
  # 4) Compute only if we have both source_key and target_key
874
873
  if source_key and target_key:
875
874
  result = (num0 * self.__units[source_key]) / self.__units[target_key]
876
- self.__loadingAnimation(
877
- 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",
878
- 0.2)
875
+ if display_thought:
876
+ self.__loadingAnimation(
877
+ 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",
878
+ 0.2)
879
879
  expr = f"{num_mentioned[0]} {source_key}(s) ==> {round(result, 2)} {target_key}(s)"
880
880
  print(f"{'\033[34m'}Conversion Answer: {expr} {'\033[0m'}")
881
881
  else:
@@ -913,8 +913,8 @@ class DLM:
913
913
  print(
914
914
  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'}")
915
915
 
916
- def __generate_thought(self, filtered_query, best_match_question, best_match_answer,
917
- highest_similarity): # no return, void
916
+ def __generate_thought(self, filtered_query, best_match_question, best_match_answer, highest_similarity,
917
+ display_thought): # no return, void
918
918
  """
919
919
  Simulate a Chain-of-Thought (CoT) reasoning process by printing the bot's internal analysis.
920
920
 
@@ -923,6 +923,7 @@ class DLM:
923
923
  best_match_question (str): The closest matching question found in the knowledge base.
924
924
  best_match_answer (str): The corresponding answer to the matched question.
925
925
  highest_similarity (float): The calculated string similarity score (0 to 1) for the match.
926
+ display_thought (bool): "True" if the bot is allowed to print its thought or else "False"
926
927
 
927
928
  Behavior:
928
929
  - Outputs step-by-step reasoning in a conversational format (e.g., interpreting the question's structure and tone).
@@ -931,63 +932,74 @@ class DLM:
931
932
  - Displays confidence based on similarity metrics and sets flags for uncertain answers.
932
933
  - Uses colorized terminal output and a loading animation to simulate reflective thought.
933
934
  """
934
- print("\nThought Process (Yellow):")
935
- if filtered_query is None or filtered_query == "":
936
- print(
937
- 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'}")
938
- else:
939
- sentiment_tone = self.__tone.split()
940
-
941
- if self.__tone != "":
935
+ if display_thought:
936
+ print("\nThought Process (Yellow):")
937
+ if filtered_query is None or filtered_query == "":
942
938
  print(
943
- 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'}")
944
- if self.__mode == "experimental":
945
- self.__perform_advanced_CoT(filtered_query)
939
+ 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'}")
946
940
  else:
947
- interrogative_start = filtered_query.split()[0]
948
- identifier = filtered_query
949
- special_start = ["definition", "explanation", "description", "comparison", "calculation", "translation",
950
- "meaning"] # special word in different form
951
- for word in special_start:
952
- identifier = identifier.replace(word, "")
953
- # collapse any extra spaces
954
- identifier = " ".join(identifier.split())
955
- identifier = identifier.split()
956
-
957
- if " ".join(identifier) == "":
941
+ sentiment_tone = self.__tone.split()
942
+
943
+ if self.__tone != "":
958
944
  print(
959
- 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'}")
945
+ 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'}")
946
+ if self.__mode == "experimental":
947
+ self.__perform_advanced_CoT(filtered_query, display_thought)
960
948
  else:
961
- print(
962
- f"{'\033[33m'}The user starts their query with \"{interrogative_start.title()}\" and they are asking about \"{" ".join(identifier).title()}\".{'\033[0m'}")
963
- self.__loadingAnimation("Let me think about this carefully", 0.8)
964
-
965
- for s in special_start:
966
- for u in filtered_query.split():
967
- s_input = self.__nlp(s)
968
- u_input = self.__nlp(u)
969
- if (s_input.vector_norm != 0 and u_input.vector_norm != 0) and (
970
- s_input.similarity(u_input) > 0.60):
949
+ interrogative_start = filtered_query.split()[0]
950
+ identifier = filtered_query
951
+ special_start = ["definition", "explanation", "description", "comparison", "calculation",
952
+ "translation",
953
+ "meaning"] # special word in different form
954
+ for word in special_start:
955
+ identifier = identifier.replace(word, "")
956
+ # collapse any extra spaces
957
+ identifier = " ".join(identifier.split())
958
+ identifier = identifier.split()
959
+
960
+ if " ".join(identifier) == "":
961
+ print(
962
+ 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'}")
963
+ else:
964
+ print(
965
+ f"{'\033[33m'}The user starts their query with \"{interrogative_start.title()}\" and they are asking about \"{" ".join(identifier).title()}\".{'\033[0m'}")
966
+ self.__loadingAnimation("Let me think about this carefully", 0.8)
967
+
968
+ for s in special_start:
969
+ for u in filtered_query.split():
970
+ s_input = self.__nlp(s)
971
+ u_input = self.__nlp(u)
972
+ if (s_input.vector_norm != 0 and u_input.vector_norm != 0) and (
973
+ s_input.similarity(u_input) > 0.60):
974
+ print(
975
+ f"{'\033[33m'}It seems like they want a {s} of \"{" ".join(identifier).title()}\".{'\033[0m'}")
976
+
977
+ self.__semantic_similarity(self.__special_stripped_query, best_match_question)
978
+ spacy_proceed = self.__nlp_similarity_value is not None
979
+ if (best_match_answer is None) or (
980
+ highest_similarity < 0.65 and (spacy_proceed and self.__nlp_similarity_value < 0.85)):
981
+ print(
982
+ f"{'\033[33m'}The closest match is only {int(highest_similarity * 100)}% similar when I used sequence matching.{'\033[0m'}")
983
+ if spacy_proceed:
971
984
  print(
972
- f"{'\033[33m'}It seems like they want a {s} of \"{" ".join(identifier).title()}\".{'\033[0m'}")
973
-
974
- self.__semantic_similarity(self.__special_stripped_query, best_match_question)
975
- spacy_proceed = self.__nlp_similarity_value is not None
976
- if (best_match_answer is None) or (highest_similarity < 0.65 and (spacy_proceed and self.__nlp_similarity_value < 0.85)):
977
- print(f"{'\033[33m'}The closest match is only {int(highest_similarity * 100)}% similar when I used sequence matching.{'\033[0m'}")
978
- if spacy_proceed:
979
- print(f"{'\033[33m'}Furthermore, an in-depth vector analysis revealed a similarity percentage of {int(self.__nlp_similarity_value * 100)}%.{'\033[0m'}")
980
- 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'}")
981
- self.__unsure_while_thinking = True
982
- else:
983
- self.__unsure_while_thinking = False
984
- DB_identifier = self.__get_specific_question(best_match_answer)
985
- print(f"{'\033[33m'}Yes! I do remember learning about \"{DB_identifier}\" and I might have the right answer!")
986
- 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.")
987
- if spacy_proceed:
988
- 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'}")
989
- self.__loadingAnimation("Let me recall that answer", 0.8)
990
- print("\n")
985
+ f"{'\033[33m'}Furthermore, an in-depth vector analysis revealed a similarity percentage of {int(self.__nlp_similarity_value * 100)}%.{'\033[0m'}")
986
+ print(
987
+ 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'}")
988
+ self.__unsure_while_thinking = True
989
+ else:
990
+ self.__unsure_while_thinking = False
991
+ DB_identifier = self.__get_specific_question(best_match_answer)
992
+ print(
993
+ f"{'\033[33m'}Yes! I do remember learning about \"{DB_identifier}\" and I might have the right answer!")
994
+ print(
995
+ 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.")
996
+ if spacy_proceed:
997
+ print(
998
+ 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'}")
999
+ self.__loadingAnimation("Let me recall that answer", 0.8)
1000
+ print("\n")
1001
+ elif self.__mode == "experimental":
1002
+ self.__perform_advanced_CoT(filtered_query, display_thought)
991
1003
 
992
1004
  def __generate_response(self, best_match_answer, best_match_question): # no return, void
993
1005
  """
@@ -1254,10 +1266,15 @@ class DLM:
1254
1266
  conn.commit()
1255
1267
  conn.close()
1256
1268
 
1257
- def ask(self, query): # no return, void
1269
+ def ask(self, query, display_thought): # no return, void
1258
1270
  """
1259
1271
  Handle a full user interaction loop with the DLM bot.
1260
- NOTICE: To make the bot run continuously, implement a loop in your program
1272
+
1273
+ NOTICE: To make the bot run continuously, implement a loop in your program.
1274
+
1275
+ Parameters:
1276
+ query (str): Question the bot would answer, compute, or learn
1277
+ display_thought (bool): "True" for allowing bot to print its thought and CoT or "False"
1261
1278
 
1262
1279
  Behavior:
1263
1280
  - Prompts the user for input.
@@ -1318,7 +1335,8 @@ class DLM:
1318
1335
  best_match_answer = stored_answer
1319
1336
 
1320
1337
  # "Chain of Thought" (CoT) Feature
1321
- self.__generate_thought(filtered_query, best_match_question, best_match_answer, highest_similarity)
1338
+ self.__generate_thought(filtered_query, best_match_question, best_match_answer, highest_similarity,
1339
+ display_thought)
1322
1340
 
1323
1341
  # accept a match if highest_similarity is 65% or more, or if semantic similarity is recognized
1324
1342
  if self.__mode != "experimental":
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dynamic-learning-model
3
- Version: 1.1
3
+ Version: 1.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='1.1',
8
+ version='1.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.',