ai_chatbot 0.1.6.3 → 0.1.6.5

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: 4a93ff88f75370288533bd606e7705f2ad7223b56974a81fe6967c72756b8e21
4
- data.tar.gz: 5966c1c3aaec715819780a3ea285ac489346007bf234e759b46824c70d846fa6
3
+ metadata.gz: 65a8e9d42a6f0a36cff9a13f7428975232912b4a2decd9509772b38d849f6340
4
+ data.tar.gz: f54c3642f29fb1f12f49af978f4ae34bd9dcdb85c7d22b48d07b195384354832
5
5
  SHA512:
6
- metadata.gz: 817bac75b5fe2949efbc8b5a4baf96fd45b85051ca2be69755c618ed4c72effc8e17174073068912651188181595e25d76f0d9b342479cb92977715a8d2c3881
7
- data.tar.gz: e097a21eeb6f95098bf25c1159b00d6a1a05ad8a5e5379f9fceb25d5fe6d1baf02704b541aa109502d4aeb8147f7985c15ca781774ede5a1dd9c522440921b5b
6
+ metadata.gz: 6a7d4c388b24487a16a51dac935eb54d6dfc384f8d478dd80667f5de9a3dc2d8140e2785a0721db5d93f79b29285ad5deb3462042238536925c5b8e66b481939
7
+ data.tar.gz: e691cb235c3cae3c9b754c30a20cec05ca17bc684e0e7c727528ccf0b8f06e4a100e4473d050793a62029bf3352425f1b1c00540e709f04f868366bb2a0f5559
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module AiChatbot
4
- VERSION = "0.1.6.3"
4
+ VERSION = "0.1.6.5"
5
5
  end
data/lib/ml_model.py CHANGED
@@ -1,142 +1,119 @@
1
1
  import sys
2
+ import psycopg2
3
+ import os
4
+ from dotenv import load_dotenv
2
5
  from sklearn.feature_extraction.text import TfidfVectorizer
3
6
  from sklearn.naive_bayes import MultinomialNB
4
7
  from sklearn.pipeline import make_pipeline
5
8
  from sklearn.metrics.pairwise import cosine_similarity
6
- import pickle
7
- import os
8
9
 
9
- # Load or initialize the dataset
10
- if os.path.exists("qa_model.pkl"):
11
- with open("qa_model.pkl", "rb") as f:
12
- model_data = pickle.load(f)
13
- questions = model_data.get(['questions'],[])
14
- answers = model_data.get(['answers'],[])
15
- else:
16
- questions = [
17
- "How to create a new model in Rails?",
18
- "What is migration?",
19
- "How to add a route?"
20
- ]
21
- answers = [
22
- "You can create a model using 'rails generate model'.",
23
- "Migration is a database schema change.",
24
- "You can add a route in the config/routes.rb file."
25
- ]
26
-
27
- # Create a pipeline (TF-IDF + MultinomialNB)
28
- model = make_pipeline(TfidfVectorizer(), MultinomialNB())
29
- model.fit(questions, answers)
30
-
31
- # Function to predict or retrain the model
32
- def main(action, query=None, new_answer=None):
33
- if action == "predict":
34
- return get_prediction(query)
35
- elif action == "train_model":
36
- return train_model(query, new_answer)
37
- elif action == "update_answer":
38
- return update_answer(query, new_answer)
39
- elif action == "update_or_delete_question":
40
- return update_or_delete_question(query, new_answer) # Corrected here, calling the right function
41
- elif action == "list_questions":
42
- return list_questions()
43
- elif action == "list_answers":
44
- return list_answers()
45
-
10
+ # Connect to PostgreSQL
11
+ conn = psycopg2.connect(
12
+ dbname= os.getenv("DB_NAME"),
13
+ user=os.getenv("DB_USERNAME"),
14
+ password=os.getenv("DB_PASSWORD"),
15
+ host=os.getenv("DB_HOST"),
16
+ port=os.getenv("DB_PORT"),
17
+ )
18
+ cursor = conn.cursor()
19
+
20
+ db_name = os.getenv("DB_NAME")
21
+
22
+ cursor.execute("SELECT question, answer FROM qa_data")
23
+ rows = cursor.fetchall()
24
+ questions = [row[0] for row in rows]
25
+ answers = [row[1] for row in rows]
26
+
27
+ vectorizer = TfidfVectorizer()
28
+ question_vecs = vectorizer.fit_transform(questions) if questions else None
29
+
46
30
 
47
- # Function to predict the response with confidence check
48
31
  def get_prediction(query):
49
- query_vec = model.named_steps['tfidfvectorizer'].transform([query])
50
- question_vecs = model.named_steps['tfidfvectorizer'].transform(questions)
32
+ if not questions:
33
+ return "No questions available in the database."
34
+
35
+ query_vec = vectorizer.transform([query])
36
+ similarities = cosine_similarity(query_vec, question_vecs).flatten()
51
37
 
52
- # Calculate cosine similarity between query and known questions
53
- similarities = cosine_similarity(query_vec, question_vecs)
54
- max_similarity = similarities.max()
38
+ max_sim_index = similarities.argmax()
39
+ max_similarity = similarities[max_sim_index]
55
40
 
56
41
  threshold = 0.65
57
42
  if max_similarity < threshold:
58
43
  return "No good match found. Please provide the correct answer."
59
44
  else:
60
- prediction = model.predict([query])
61
- return prediction[0]
45
+ return answers[max_sim_index]
62
46
 
63
- # Function to train the model with a new question and answer
47
+ # Function to train the model with new data
64
48
  def train_model(new_question, new_answer):
65
49
  global questions, answers
66
50
 
67
- # Append new question-answer pair to the dataset
51
+ # Store in database
52
+
53
+ cursor.execute("INSERT INTO qa_data (question, answer, created_at,updated_at) VALUES (%s, %s, NOW(),NOW()) ON CONFLICT (question) DO NOTHING",
54
+ (new_question, new_answer))
55
+ conn.commit()
56
+
57
+ # Update lists and retrain model
68
58
  questions.append(new_question)
69
59
  answers.append(new_answer)
70
-
71
- # Retrain the model with updated data
72
60
  model.fit(questions, answers)
73
61
 
74
- # Save the updated model and data
75
- with open("qa_model.pkl", "wb") as f:
76
- pickle.dump({"questions": questions, "answers": answers}, f)
77
-
78
- return f"Model retrained with the new question: '{new_question}' and answer: '{new_answer}'"
62
+ return f"Added: '{new_question}' -> '{new_answer}'"
79
63
 
64
+ # Function to update an answer
80
65
  def update_answer(existing_question, new_answer):
81
- global questions, answers
66
+ cursor.execute("UPDATE qa_data SET answer = %s WHERE question = %s", (new_answer, existing_question))
67
+ conn.commit()
68
+
69
+ # Update lists and retrain model
70
+ index = questions.index(existing_question)
71
+ answers[index] = new_answer
72
+ model.fit(questions, answers)
73
+
74
+ return f"Updated: '{existing_question}' -> '{new_answer}'"
75
+
76
+ # Function to delete a question
77
+ def delete_question(existing_question):
78
+ cursor.execute("DELETE FROM qa_data WHERE question = %s", (existing_question,))
79
+ conn.commit()
82
80
 
83
81
  if existing_question in questions:
84
- # Find the index of the existing question
85
82
  index = questions.index(existing_question)
86
- # Update the answer
87
- answers[index] = new_answer
88
- # Retrain the model with updated data
83
+ del questions[index]
84
+ del answers[index]
89
85
  model.fit(questions, answers)
90
- # Save the updated model and data
91
- with open("qa_model.pkl", "wb") as f:
92
- pickle.dump({"questions": questions, "answers": answers}, f)
93
- return f"Answer updated for the question: '{existing_question}'"
94
- else:
95
- return "Question not found. Please provide a valid question."
96
-
97
- def update_or_delete_question(existing_question, new_question):
98
- global questions # Only 'questions' is global, not 'new_question'
99
- if new_question=="None":
100
- new_question = None
101
-
102
- if existing_question in questions:
103
- if new_question:
104
- # Find the index of the existing question
105
- index = questions.index(existing_question)
106
- # Update the question
107
- questions[index] = new_question
108
- # Retrain the model with updated data
109
- model.fit(questions, answers)
110
- # Save the updated model and data
111
- with open("qa_model.pkl", "wb") as f:
112
- pickle.dump({"questions": questions, "answers": answers}, f)
113
- return f"Question updated from '{existing_question}' to '{new_question}'"
114
- else:
115
- # Remove the question if no new question is provided
116
- index = questions.index(existing_question)
117
- del questions[index]
118
- del answers[index] # Ensure you also delete the corresponding answer
119
- # Retrain the model with updated data
120
- model.fit(questions, answers)
121
- # Save the updated model and data
122
- with open("qa_model.pkl", "wb") as f:
123
- pickle.dump({"questions": questions, "answers": answers}, f)
124
- return f"Question '{existing_question}' deleted successfully."
125
- else:
126
- return "Question not found. Please provide a valid question."
127
86
 
87
+ return f"Deleted: '{existing_question}'"
128
88
 
89
+ # Function to list questions
129
90
  def list_questions():
130
- global questions
131
- return questions
91
+ cursor.execute("SELECT question FROM qa_data")
92
+ return [row[0] for row in cursor.fetchall()]
132
93
 
94
+ # Function to list answers
133
95
  def list_answers():
134
- global answers
135
- return answers
96
+ cursor.execute("SELECT answer FROM qa_data")
97
+ return [row[0] for row in cursor.fetchall()]
136
98
 
137
99
  if __name__ == "__main__":
138
- # Expecting action (predict/train), question, and answer (if training)
139
100
  action = sys.argv[1]
140
101
  question = sys.argv[2] if len(sys.argv) > 2 else None
141
102
  answer = sys.argv[3] if len(sys.argv) > 3 else None
142
- print(main(action, question, answer))
103
+
104
+ if action == "predict":
105
+ print(get_prediction(question))
106
+ elif action == "train_model":
107
+ print(train_model(question, answer))
108
+ elif action == "update_answer":
109
+ print(update_answer(question, answer))
110
+ elif action == "delete_question":
111
+ print(delete_question(question))
112
+ elif action == "list_questions":
113
+ print(list_questions())
114
+ elif action == "list_answers":
115
+ print(list_answers())
116
+
117
+ # Close DB connection
118
+ cursor.close()
119
+ conn.close()
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.3
4
+ version: 0.1.6.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sanket
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-02-24 00:00:00.000000000 Z
11
+ date: 2025-03-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: open3
@@ -24,8 +24,8 @@ dependencies:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
- description: Integrates a chatbot using Python for predictions and training in a Rails
28
- application.
27
+ description: Added caching to avoid redundant DB queries, improving chatbot response
28
+ time. Also updated unanswered question logging.
29
29
  email:
30
30
  - sanket.tikhande@gmail.com
31
31
  executables: []
@@ -58,5 +58,5 @@ requirements: []
58
58
  rubygems_version: 3.3.7
59
59
  signing_key:
60
60
  specification_version: 4
61
- summary: A chatbot for Rails integration with AI model using Python
61
+ summary: 'Fix: Added postgres integration'
62
62
  test_files: []