bat-6 commited on
Commit
8463318
Β·
1 Parent(s): 5e95de5

feat: implement chatbot engine and prompt builder modules for graduation project recommendation and validation

Browse files
src/recommendation_engine/__pycache__/chatbot_engine.cpython-313.pyc CHANGED
Binary files a/src/recommendation_engine/__pycache__/chatbot_engine.cpython-313.pyc and b/src/recommendation_engine/__pycache__/chatbot_engine.cpython-313.pyc differ
 
src/recommendation_engine/__pycache__/prompt_builder.cpython-313.pyc CHANGED
Binary files a/src/recommendation_engine/__pycache__/prompt_builder.cpython-313.pyc and b/src/recommendation_engine/__pycache__/prompt_builder.cpython-313.pyc differ
 
src/recommendation_engine/chatbot_engine.py CHANGED
@@ -119,31 +119,32 @@ Do not include any other text or punctuation.
119
  except Exception as e:
120
  return "general_chat"
121
 
122
- def is_valid_graduation_project_domain(domain: str) -> bool:
123
  # 1. Quick local validation for standard domains
124
  extracted = extract_domain(domain)
125
  if extracted and extracted.lower() != "others":
126
- return True
127
 
128
  # 2. Fall back to LLM validation
129
  prompt = f"""
130
  Determine if the following domain/field is a valid academic, engineering, scientific, or technology domain suitable for a university graduation project (e.g., Computer Science, Engineering, Medicine, Business, Agriculture, Biology, etc.).
 
131
 
132
  Domain to evaluate: "{domain}"
133
 
134
  Rules:
135
- - If it is a valid field of study, technology, or academic discipline (e.g., "artificial intelligence", "robotics", "bioinformatics", "educational games") -> Return YES
136
- - If it is unrelated to academic/technology graduation projects, or contains names of celebrities, sports teams, food, pop culture, or random questions (e.g., "messi", "fc barcelona", "pizza", "what is this") -> Return NO
137
 
138
- Return ONLY "YES" or "NO".
139
  """
140
  try:
141
- res = generate_text(prompt, task="intent").strip().upper()
142
- if not res:
143
- return True
144
- return "YES" in res
145
  except Exception:
146
- return True
147
 
148
  def is_weak_project_title(title: str) -> bool:
149
 
@@ -532,10 +533,16 @@ def chatbot(user_id: str, user_input: str):
532
  "ideas"
533
  ]
534
 
535
- if any(x in text for x in explicit_idea_requests) or text in ["change domain", "new domain", "reset domain", "reset", "restart"]:
536
- memory = get_user_memory(user_id)
537
- current_state = memory.get("state") or default_state()
538
-
 
 
 
 
 
 
539
  if not current_state.get("waiting_for_niche_domain"):
540
  state = default_state()
541
  state["waiting_for_domain"] = True
@@ -715,6 +722,11 @@ def chatbot(user_id: str, user_input: str):
715
  state["waiting_for_project_idea_confirm"] = False
716
 
717
  if is_yes:
 
 
 
 
 
718
  title = state.get("project_title", "")
719
  abstract = state.get("abstract", "")
720
 
@@ -734,11 +746,9 @@ def chatbot(user_id: str, user_input: str):
734
  f"πŸ“Œ Title: {title}\n"
735
  f"{domain_line}\n\n"
736
  f"What would you like to do next?\n"
737
- f"1️⃣ Generate features\n"
738
- f"2️⃣ Talk with chatbot about the idea\n\n"
739
  f"πŸ‘‰ You can also say:\n"
740
- f"- generate features\n"
741
- f"- discuss project"
742
  )
743
  else:
744
  reason = validation.get("reason", "")
@@ -814,11 +824,9 @@ def chatbot(user_id: str, user_input: str):
814
  f"{project_title}\n\n"
815
  "Choose what you want next:\n"
816
  "1️⃣ Generate features\n"
817
- "2️⃣ Talk with chatbot about the idea\n"
818
- "3️⃣ Generate full project\n\n"
819
  "πŸ‘‰ You can also say:\n"
820
  "- generate features\n"
821
- "- discuss project\n"
822
  "- generate full project"
823
  )
824
 
@@ -947,6 +955,7 @@ def chatbot(user_id: str, user_input: str):
947
  state["category"] = state.get("domain")
948
 
949
  state["waiting_for_project_idea_confirm"] = True
 
950
 
951
  response = f"""
952
  πŸ“¦ Full Project Generated
@@ -1098,7 +1107,6 @@ Reply **yes** to validate & categorize it, or **no** to explore other ideas.
1098
  ]
1099
 
1100
  chat_words = [
1101
- "2",
1102
  "chat",
1103
  "talk",
1104
  "discussion",
@@ -1109,7 +1117,7 @@ Reply **yes** to validate & categorize it, or **no** to explore other ideas.
1109
  ]
1110
 
1111
  full_project_words = [
1112
- "3",
1113
  "full project",
1114
  "generate full project",
1115
  "complete project",
@@ -1235,6 +1243,7 @@ Reply **yes** to validate & categorize it, or **no** to explore other ideas.
1235
  state["category"] = state.get("domain")
1236
 
1237
  state["waiting_for_project_idea_confirm"] = True
 
1238
 
1239
  response = f"""
1240
  πŸ“¦ Full Project Generated
@@ -1546,12 +1555,10 @@ Reply **yes** to validate & categorize it, or **no** to explore other ideas.
1546
  Choose what you want:
1547
 
1548
  1️⃣ Generate Features
1549
- 2️⃣ Discuss Project
1550
- 3️⃣ Generate Full Project
1551
 
1552
  πŸ‘‰ You can also type:
1553
  - features
1554
- - discuss
1555
  - full project
1556
  """,
1557
 
@@ -1575,11 +1582,9 @@ Choose what you want:
1575
  f"πŸ“Œ Project selected:\n"
1576
  f"{idea}\n\n"
1577
  "Choose what you want next:\n"
1578
- "1️⃣ Generate features\n"
1579
- "2️⃣ Talk with chatbot about the idea\n\n"
1580
  "πŸ‘‰ You can also say:\n"
1581
- "- generate features\n"
1582
- "- discuss project"
1583
  )
1584
 
1585
 
@@ -1631,14 +1636,15 @@ Choose what you want:
1631
  return finalize_response(user_input, response, history, state, user_id)
1632
  else:
1633
  domain = user_input.strip()
1634
- if not is_valid_graduation_project_domain(domain):
 
1635
  return (
1636
  "⚠️ That does not seem to be a valid technology or academic domain.\n\n"
1637
  "Please enter a valid domain (e.g. AI, Healthcare, Fintech, or 'Others')."
1638
  )
1639
  state["waiting_for_niche_domain"] = False
1640
  state["suggested_domains"] = []
1641
- analysis["domain"] = domain
1642
  analysis["intent"] = "idea"
1643
  if "project_title" in analysis:
1644
  del analysis["project_title"]
@@ -1680,10 +1686,18 @@ Choose what you want:
1680
  if "project_title" in analysis:
1681
  del analysis["project_title"]
1682
  else:
1683
- return (
1684
- "⚠️ Please enter a valid domain "
1685
- "(AI, healthcare, fintech...)"
1686
- )
 
 
 
 
 
 
 
 
1687
 
1688
  intent = analysis.get("intent", "chat")
1689
 
@@ -1691,6 +1705,12 @@ Choose what you want:
1691
 
1692
  user_project = analysis.get("project_title")
1693
 
 
 
 
 
 
 
1694
  # Override intent using the LLM-derived semantic context when no project is active yet
1695
  if not state.get("project_title") and not is_in_domain_or_selection_state:
1696
  if context == "idea_request":
@@ -1894,11 +1914,9 @@ Choose what you want:
1894
  f"{user_project}\n\n"
1895
  "Choose what you want next:\n"
1896
  "1️⃣ Generate features\n"
1897
- "2️⃣ Talk with chatbot about the idea\n"
1898
- "3️⃣ Generate full project\n\n"
1899
  "πŸ‘‰ You can also say:\n"
1900
  "- generate features\n"
1901
- "- discuss project\n"
1902
  "- generate full project"
1903
  )
1904
 
@@ -2106,6 +2124,7 @@ Choose what you want:
2106
  state["category"] = state.get("domain")
2107
 
2108
  state["waiting_for_project_idea_confirm"] = True
 
2109
 
2110
  response = f"""
2111
  πŸ“¦ Project Specification Ready!
@@ -2206,7 +2225,7 @@ User:
2206
 
2207
 
2208
 
2209
- if not is_project_related(text):
2210
 
2211
  return (
2212
  "I'm designed specifically for graduation projects πŸŽ“\n\n"
 
119
  except Exception as e:
120
  return "general_chat"
121
 
122
+ def validate_and_format_domain(domain: str) -> str:
123
  # 1. Quick local validation for standard domains
124
  extracted = extract_domain(domain)
125
  if extracted and extracted.lower() != "others":
126
+ return extracted
127
 
128
  # 2. Fall back to LLM validation
129
  prompt = f"""
130
  Determine if the following domain/field is a valid academic, engineering, scientific, or technology domain suitable for a university graduation project (e.g., Computer Science, Engineering, Medicine, Business, Agriculture, Biology, etc.).
131
+ Also, correct any typos and format it cleanly (e.g., Title Case).
132
 
133
  Domain to evaluate: "{domain}"
134
 
135
  Rules:
136
+ - If it is a valid field of study, technology, or academic discipline (e.g., "artificial intelligence", "robotics", "bioinformatics", "educational games"), return ONLY the corrected and formatted domain name (e.g., "Artificial Intelligence").
137
+ - If it is unrelated to academic/technology graduation projects, or contains names of celebrities, sports teams, food, pop culture, or random questions (e.g., "messi", "fc barcelona", "pizza", "what is this"), return exactly "INVALID".
138
 
139
+ Return ONLY the formatted domain name or "INVALID". Do not include any other text.
140
  """
141
  try:
142
+ res = generate_text(prompt, task="intent").strip()
143
+ if not res or res.upper() == "INVALID":
144
+ return ""
145
+ return res.strip('"').strip("'")
146
  except Exception:
147
+ return ""
148
 
149
  def is_weak_project_title(title: str) -> bool:
150
 
 
533
  "ideas"
534
  ]
535
 
536
+ memory = get_user_memory(user_id)
537
+ current_state = memory.get("state") or default_state()
538
+
539
+ is_explicit_idea = False
540
+ if text in explicit_idea_requests or text in ["change domain", "new domain", "reset domain", "reset", "restart"]:
541
+ is_explicit_idea = True
542
+ elif any(x in text for x in explicit_idea_requests) and len(text.split()) <= 3 and not current_state.get("project_chat_mode"):
543
+ is_explicit_idea = True
544
+
545
+ if is_explicit_idea:
546
  if not current_state.get("waiting_for_niche_domain"):
547
  state = default_state()
548
  state["waiting_for_domain"] = True
 
722
  state["waiting_for_project_idea_confirm"] = False
723
 
724
  if is_yes:
725
+ if state.get("from_full_project_generation"):
726
+ state["from_full_project_generation"] = False
727
+ save_user_memory(user_id, {"history": history, "state": state})
728
+ return "Do you want to add this to Submission?"
729
+
730
  title = state.get("project_title", "")
731
  abstract = state.get("abstract", "")
732
 
 
746
  f"πŸ“Œ Title: {title}\n"
747
  f"{domain_line}\n\n"
748
  f"What would you like to do next?\n"
749
+ f"1️⃣ Generate features\n\n"
 
750
  f"πŸ‘‰ You can also say:\n"
751
+ f"- generate features"
 
752
  )
753
  else:
754
  reason = validation.get("reason", "")
 
824
  f"{project_title}\n\n"
825
  "Choose what you want next:\n"
826
  "1️⃣ Generate features\n"
827
+ "2️⃣ Generate full project\n\n"
 
828
  "πŸ‘‰ You can also say:\n"
829
  "- generate features\n"
 
830
  "- generate full project"
831
  )
832
 
 
955
  state["category"] = state.get("domain")
956
 
957
  state["waiting_for_project_idea_confirm"] = True
958
+ state["from_full_project_generation"] = True
959
 
960
  response = f"""
961
  πŸ“¦ Full Project Generated
 
1107
  ]
1108
 
1109
  chat_words = [
 
1110
  "chat",
1111
  "talk",
1112
  "discussion",
 
1117
  ]
1118
 
1119
  full_project_words = [
1120
+ "2",
1121
  "full project",
1122
  "generate full project",
1123
  "complete project",
 
1243
  state["category"] = state.get("domain")
1244
 
1245
  state["waiting_for_project_idea_confirm"] = True
1246
+ state["from_full_project_generation"] = True
1247
 
1248
  response = f"""
1249
  πŸ“¦ Full Project Generated
 
1555
  Choose what you want:
1556
 
1557
  1️⃣ Generate Features
1558
+ 2️⃣ Generate Full Project
 
1559
 
1560
  πŸ‘‰ You can also type:
1561
  - features
 
1562
  - full project
1563
  """,
1564
 
 
1582
  f"πŸ“Œ Project selected:\n"
1583
  f"{idea}\n\n"
1584
  "Choose what you want next:\n"
1585
+ "1️⃣ Generate features\n\n"
 
1586
  "πŸ‘‰ You can also say:\n"
1587
+ "- generate features"
 
1588
  )
1589
 
1590
 
 
1636
  return finalize_response(user_input, response, history, state, user_id)
1637
  else:
1638
  domain = user_input.strip()
1639
+ validated_domain = validate_and_format_domain(domain)
1640
+ if not validated_domain:
1641
  return (
1642
  "⚠️ That does not seem to be a valid technology or academic domain.\n\n"
1643
  "Please enter a valid domain (e.g. AI, Healthcare, Fintech, or 'Others')."
1644
  )
1645
  state["waiting_for_niche_domain"] = False
1646
  state["suggested_domains"] = []
1647
+ analysis["domain"] = validated_domain
1648
  analysis["intent"] = "idea"
1649
  if "project_title" in analysis:
1650
  del analysis["project_title"]
 
1686
  if "project_title" in analysis:
1687
  del analysis["project_title"]
1688
  else:
1689
+ validated_domain = validate_and_format_domain(user_input.strip())
1690
+ if validated_domain:
1691
+ state["waiting_for_domain"] = False
1692
+ analysis["domain"] = validated_domain
1693
+ analysis["intent"] = "idea"
1694
+ if "project_title" in analysis:
1695
+ del analysis["project_title"]
1696
+ else:
1697
+ return (
1698
+ "⚠️ Please enter a valid domain "
1699
+ "(AI, healthcare, fintech...)"
1700
+ )
1701
 
1702
  intent = analysis.get("intent", "chat")
1703
 
 
1705
 
1706
  user_project = analysis.get("project_title")
1707
 
1708
+ if state.get("project_chat_mode"):
1709
+ user_project = None
1710
+ exact_cmds = {"idea", "ideas", "menu", "exit", "quit", "generate features", "features", "generate full project"}
1711
+ if user_input.strip().lower() not in exact_cmds:
1712
+ intent = "chat"
1713
+
1714
  # Override intent using the LLM-derived semantic context when no project is active yet
1715
  if not state.get("project_title") and not is_in_domain_or_selection_state:
1716
  if context == "idea_request":
 
1914
  f"{user_project}\n\n"
1915
  "Choose what you want next:\n"
1916
  "1️⃣ Generate features\n"
1917
+ "2️⃣ Generate full project\n\n"
 
1918
  "πŸ‘‰ You can also say:\n"
1919
  "- generate features\n"
 
1920
  "- generate full project"
1921
  )
1922
 
 
2124
  state["category"] = state.get("domain")
2125
 
2126
  state["waiting_for_project_idea_confirm"] = True
2127
+ state["from_full_project_generation"] = True
2128
 
2129
  response = f"""
2130
  πŸ“¦ Project Specification Ready!
 
2225
 
2226
 
2227
 
2228
+ if not is_project_related(text) and not state.get("project_title"):
2229
 
2230
  return (
2231
  "I'm designed specifically for graduation projects πŸŽ“\n\n"
src/recommendation_engine/prompt_builder.py CHANGED
@@ -243,6 +243,7 @@ RULES:
243
  - Be realistic
244
  - Be technically accurate
245
  - Keep all answers related to the current project
 
246
  """.strip()
247
 
248
  def build_full_project_prompt(context):
 
243
  - Be realistic
244
  - Be technically accurate
245
  - Keep all answers related to the current project
246
+ - STRICTLY REFUSE to discuss any illegal, inappropriate, explicit (e.g., sexual content), or unethical topics. If the user mentions such topics, reply immediately with a professional warning that you can only discuss academic graduation projects.
247
  """.strip()
248
 
249
  def build_full_project_prompt(context):