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 +4 -4
- data/lib/ai_chatbot/version.rb +1 -1
- data/lib/ml_model.py +81 -104
- metadata +5 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 65a8e9d42a6f0a36cff9a13f7428975232912b4a2decd9509772b38d849f6340
|
4
|
+
data.tar.gz: f54c3642f29fb1f12f49af978f4ae34bd9dcdb85c7d22b48d07b195384354832
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6a7d4c388b24487a16a51dac935eb54d6dfc384f8d478dd80667f5de9a3dc2d8140e2785a0721db5d93f79b29285ad5deb3462042238536925c5b8e66b481939
|
7
|
+
data.tar.gz: e691cb235c3cae3c9b754c30a20cec05ca17bc684e0e7c727528ccf0b8f06e4a100e4473d050793a62029bf3352425f1b1c00540e709f04f868366bb2a0f5559
|
data/lib/ai_chatbot/version.rb
CHANGED
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
|
-
#
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
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
|
-
|
50
|
-
|
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
|
-
|
53
|
-
|
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
|
-
|
61
|
-
return prediction[0]
|
45
|
+
return answers[max_sim_index]
|
62
46
|
|
63
|
-
# Function to train the model with
|
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
|
-
#
|
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
|
-
|
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
|
-
|
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
|
-
|
87
|
-
answers[index]
|
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
|
-
|
131
|
-
return
|
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
|
-
|
135
|
-
return
|
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
|
-
|
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.
|
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-
|
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:
|
28
|
-
|
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:
|
61
|
+
summary: 'Fix: Added postgres integration'
|
62
62
|
test_files: []
|