ai_chatbot 0.1.6.5.1 → 0.1.6.5.2

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fee6347bdac6070db1bfbc1711f039103c1237c149f42a7f0b848b85eba98314
4
- data.tar.gz: c54c29b235f159921d4b33ac36bc56d505983eb03a25500829d72e9741628983
3
+ metadata.gz: 751a6f2a9c762af2c03f9f14842ccafaefee38e2d0d2e9fb7f6595cfd1fc9a6c
4
+ data.tar.gz: 5030f83ae39a359a498bbbb2956bb5cffb79e7071b9b22c9f87c3bf67775a2dd
5
5
  SHA512:
6
- metadata.gz: f80cec458575b77b6be9879007e3f60830886b88bcfbde28974e9fe1e68b59d61424956a0aea0db62e69e5705e2c8d2b2b97d3e6700ee3b9cdd141530816325f
7
- data.tar.gz: d2ac4f47ef9ce02255a60e84a6bff019c9036be5368f79e43748ca945a459c4459c5b53ee7a57a8345114018e03d0f5a1eeab70895ac78bafefed6980223dc59
6
+ metadata.gz: ba1346f5b15c8c08af48bfcd72490c060c34acb07112a63f6c2cc5589574195bc5dcf0b83c5471ef8d149a26b42a3ffbf7e6838aa3b28a42a12684bf4946fe5f
7
+ data.tar.gz: e652e1c7aa1cc2d80550832892b62a3d7018a13684f9c734f75b9ef73947c56e711569e3c99176dd71f3d65965ff10cd801d92b5c62010dfc8547279987b58b8
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module AiChatbot
4
- VERSION = "0.1.6.5.1"
4
+ VERSION = "0.1.6.5.2"
5
5
  end
data/lib/ml_model.py CHANGED
@@ -1,142 +1,125 @@
1
1
  import sys
2
- import psycopg2
2
+ import pickle
3
3
  import os
4
- from dotenv import load_dotenv
5
4
  from sklearn.feature_extraction.text import TfidfVectorizer
6
5
  from sklearn.naive_bayes import MultinomialNB
7
6
  from sklearn.pipeline import make_pipeline
8
7
  from sklearn.metrics.pairwise import cosine_similarity
9
8
 
10
- # Load environment variables
11
- load_dotenv()
12
-
13
- # Connect to PostgreSQL
14
- conn = psycopg2.connect(
15
- dbname=os.getenv("DB_NAME"),
16
- user=os.getenv("DB_USERNAME"),
17
- password=os.getenv("DB_PASSWORD"),
18
- host=os.getenv("DB_HOST"),
19
- port=os.getenv("DB_PORT"),
20
- )
21
- cursor = conn.cursor()
22
-
23
- # Fetch data from DB
24
- cursor.execute("SELECT question, answer FROM qa_data")
25
- rows = cursor.fetchall()
26
- questions = [row[0] for row in rows]
27
- answers = [row[1] for row in rows]
28
-
29
- # Define the vectorizer and Naive Bayes model
30
- vectorizer = TfidfVectorizer()
31
- model = MultinomialNB()
32
- pipeline = make_pipeline(vectorizer, model)
33
-
34
- # Train model if there is data
35
- if questions:
36
- pipeline.fit(questions, answers)
9
+ DATA_FILE = "qa_model.pkl"
37
10
 
11
+ # Globals
12
+ questions = []
13
+ answers = []
14
+ model = make_pipeline(TfidfVectorizer(), MultinomialNB())
38
15
 
16
+ # ------------------- Load or Initialize ------------------- #
17
+ def load_data():
18
+ global questions, answers
19
+ if os.path.exists(DATA_FILE):
20
+ with open(DATA_FILE, "rb") as f:
21
+ model_data = pickle.load(f)
22
+ questions = model_data.get('questions', [])
23
+ answers = model_data.get('answers', [])
24
+ print(f"Loaded {len(questions)} Q&A pairs.")
25
+ else:
26
+ # Default seed data
27
+ questions.extend([
28
+ "How to create a new model in Rails?",
29
+ "What is migration?",
30
+ "How to add a route?"
31
+ ])
32
+ answers.extend([
33
+ "You can create a model using 'rails generate model'.",
34
+ "Migration is a database schema change.",
35
+ "You can add a route in the config/routes.rb file."
36
+ ])
37
+ print("No existing model found, using default seed data.")
38
+
39
+ retrain_model()
40
+
41
+ def save_data():
42
+ with open(DATA_FILE, "wb") as f:
43
+ pickle.dump({'questions': questions, 'answers': answers}, f)
44
+
45
+ def retrain_model():
46
+ if questions and answers:
47
+ model.fit(questions, answers)
48
+
49
+ # ------------------- Core Actions ------------------- #
39
50
  def get_prediction(query):
40
- if not questions:
41
- return "No questions available in the database."
42
-
43
- query_vec = vectorizer.transform([query])
44
- similarities = cosine_similarity(query_vec, vectorizer.transform(questions)).flatten()
51
+ query_vec = model.named_steps['tfidfvectorizer'].transform([query])
52
+ question_vecs = model.named_steps['tfidfvectorizer'].transform(questions)
53
+ similarities = cosine_similarity(query_vec, question_vecs)
54
+ max_similarity = similarities.max()
45
55
 
46
- max_sim_index = similarities.argmax()
47
- max_similarity = similarities[max_sim_index]
56
+ print(f"🔍 Similarity Score: {max_similarity:.2f}")
48
57
 
49
58
  threshold = 0.65
50
59
  if max_similarity < threshold:
51
- return "No good match found. Please provide the correct answer."
60
+ return "No good match found. You may need to train the model with this question."
52
61
  else:
53
- return answers[max_sim_index]
62
+ prediction = model.predict([query])
63
+ return prediction[0]
54
64
 
55
-
56
- # Function to train the model with new data
57
65
  def train_model(new_question, new_answer):
58
- global questions, answers
59
-
60
- # Store in database
61
- cursor.execute(
62
- "INSERT INTO qa_data (question, answer, created_at, updated_at) VALUES (%s, %s, NOW(), NOW()) ON CONFLICT (question) DO NOTHING",
63
- (new_question, new_answer),
64
- )
65
- conn.commit()
66
-
67
- # Update lists and retrain model
68
66
  questions.append(new_question)
69
67
  answers.append(new_answer)
70
- pipeline.fit(questions, answers) # Retrain model
71
-
72
- return f"Added: '{new_question}' -> '{new_answer}'"
73
-
68
+ retrain_model()
69
+ save_data()
70
+ return f"Model updated with: '{new_question}'"
74
71
 
75
- # Function to update an answer
76
72
  def update_answer(existing_question, new_answer):
77
- if existing_question not in questions:
78
- return f"Question '{existing_question}' not found."
79
-
80
- cursor.execute(
81
- "UPDATE qa_data SET answer = %s WHERE question = %s", (new_answer, existing_question)
82
- )
83
- conn.commit()
84
-
85
- # Update lists and retrain model
86
- index = questions.index(existing_question)
87
- answers[index] = new_answer
88
- pipeline.fit(questions, answers)
89
-
90
- return f"Updated: '{existing_question}' -> '{new_answer}'"
73
+ if existing_question in questions:
74
+ idx = questions.index(existing_question)
75
+ answers[idx] = new_answer
76
+ retrain_model()
77
+ save_data()
78
+ return f"Answer updated for: '{existing_question}'"
79
+ return "Question not found."
80
+
81
+ def update_or_delete_question(existing_question, new_question=None):
82
+ if existing_question in questions:
83
+ idx = questions.index(existing_question)
84
+ if new_question:
85
+ questions[idx] = new_question
86
+ action = f"Question updated to: '{new_question}'"
87
+ else:
88
+ questions.pop(idx)
89
+ answers.pop(idx)
90
+ action = f"🗑️ Question '{existing_question}' deleted."
91
+ retrain_model()
92
+ save_data()
93
+ return action
94
+ return "Question not found."
91
95
 
92
-
93
- # Function to delete a question
94
- def delete_question(existing_question):
95
- if existing_question not in questions:
96
- return f"Question '{existing_question}' not found."
97
-
98
- cursor.execute("DELETE FROM qa_data WHERE question = %s", (existing_question,))
99
- conn.commit()
100
-
101
- index = questions.index(existing_question)
102
- del questions[index]
103
- del answers[index]
104
- pipeline.fit(questions, answers)
105
-
106
- return f"Deleted: '{existing_question}'"
107
-
108
-
109
- # Function to list questions
110
96
  def list_questions():
111
- cursor.execute("SELECT question FROM qa_data")
112
- return [row[0] for row in cursor.fetchall()]
97
+ return "\n".join([f"{i+1}. {q}" for i, q in enumerate(questions)])
113
98
 
114
-
115
- # Function to list answers
116
99
  def list_answers():
117
- cursor.execute("SELECT answer FROM qa_data")
118
- return [row[0] for row in cursor.fetchall()]
100
+ return "\n".join([f"{i+1}. {a}" for i, a in enumerate(answers)])
119
101
 
120
-
121
- # Command-line execution
122
- if __name__ == "__main__":
123
- action = sys.argv[1]
124
- question = sys.argv[2] if len(sys.argv) > 2 else None
125
- answer = sys.argv[3] if len(sys.argv) > 3 else None
102
+ # ------------------- CLI Entry ------------------- #
103
+ def main(action, query=None, answer=None):
104
+ load_data()
126
105
 
127
106
  if action == "predict":
128
- print(get_prediction(question))
107
+ return get_prediction(query)
129
108
  elif action == "train_model":
130
- print(train_model(question, answer))
109
+ return train_model(query, answer)
131
110
  elif action == "update_answer":
132
- print(update_answer(question, answer))
133
- elif action == "delete_question":
134
- print(delete_question(question))
111
+ return update_answer(query, answer)
112
+ elif action == "update_or_delete_question":
113
+ return update_or_delete_question(query, answer)
135
114
  elif action == "list_questions":
136
- print(list_questions())
115
+ return list_questions()
137
116
  elif action == "list_answers":
138
- print(list_answers())
117
+ return list_answers()
118
+ else:
119
+ return "Unknown action. Try: predict, train_model, update_answer, list_questions, list_answers"
139
120
 
140
- # Close DB connection
141
- cursor.close()
142
- conn.close()
121
+ if __name__ == "__main__":
122
+ action = sys.argv[1] if len(sys.argv) > 1 else None
123
+ question = sys.argv[2] if len(sys.argv) > 2 else None
124
+ answer = sys.argv[3] if len(sys.argv) > 3 else None
125
+ print(main(action, question, answer))
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ai_chatbot
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.6.5.1
4
+ version: 0.1.6.5.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sanket
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-03-05 00:00:00.000000000 Z
11
+ date: 2025-06-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: open3
@@ -24,8 +24,7 @@ dependencies:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
- description: Added PostgreSQL support, fixed model error. Version 0.1.6.5.1 Details
28
- on Git.
27
+ description: fixed model error. Version 0.1.6.5.1 Details on Git.
29
28
  email:
30
29
  - sanket.tikhande@gmail.com
31
30
  executables: []
@@ -58,5 +57,5 @@ requirements: []
58
57
  rubygems_version: 3.3.7
59
58
  signing_key:
60
59
  specification_version: 4
61
- summary: 'Fix: Added postgres integration'
60
+ summary: 'Fix: Added high accuracy'
62
61
  test_files: []