imravi commited on
Commit
0c4f650
·
verified ·
1 Parent(s): 47da386

Update main.py

Browse files
Files changed (1) hide show
  1. main.py +87 -31
main.py CHANGED
@@ -1,4 +1,3 @@
1
- from flask import Flask, request, jsonify
2
  import torch
3
  import numpy as np
4
  import pandas as pd
@@ -6,20 +5,21 @@ from sentence_transformers import SentenceTransformer, util
6
  from transformers import AutoTokenizer, AutoModelForCausalLM
7
  import json
8
 
9
- app = Flask(__name__)
10
-
11
  class PlantChatbot:
12
  def __init__(self, preprocessed_data_path: str):
13
  self.device = "cuda" if torch.cuda.is_available() else "cpu"
14
- print(f"Using device: {self.device}")
15
 
 
16
  self.embedding_model = SentenceTransformer(
17
  model_name_or_path="all-mpnet-base-v2",
18
  device=self.device
19
  )
20
 
 
21
  self.load_data(preprocessed_data_path)
22
 
 
23
  self.tokenizer = AutoTokenizer.from_pretrained(
24
  "Qwen/Qwen2.5-1.5B-Instruct",
25
  trust_remote_code=True
@@ -28,12 +28,18 @@ class PlantChatbot:
28
  "Qwen/Qwen2.5-1.5B-Instruct",
29
  device_map="auto",
30
  trust_remote_code=True,
31
- torch_dtype=torch.float16
32
  )
 
 
 
 
33
 
34
  def load_data(self, preprocessed_data_path: str):
 
35
  df = pd.read_csv(preprocessed_data_path)
36
 
 
37
  def parse_embedding(embedding_str):
38
  try:
39
  embedding_str = embedding_str.strip()
@@ -46,13 +52,23 @@ class PlantChatbot:
46
 
47
  df["embedding"] = df["embedding"].apply(parse_embedding)
48
  df = df.dropna(subset=['embedding'])
 
49
  self.chunks_data = df.to_dict(orient="records")
50
 
 
51
  embeddings_array = np.stack(df["embedding"].values)
52
- self.embeddings = torch.tensor(embeddings_array, dtype=torch.float32).to(self.device)
 
 
 
53
 
54
  def retrieve_relevant_chunks(self, query: str, n_chunks: int = 5) -> list[dict]:
55
- query_embedding = self.embedding_model.encode(query, convert_to_tensor=True).to(self.device)
 
 
 
 
 
56
 
57
  if len(query_embedding.shape) == 1:
58
  query_embedding = query_embedding.unsqueeze(0)
@@ -69,22 +85,51 @@ class PlantChatbot:
69
  for i in indices
70
  ]
71
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
72
  def generate_response(self, query: str):
 
73
  try:
 
74
  context_chunks = self.retrieve_relevant_chunks(query)
 
 
75
  prompt = self.format_prompt(query, context_chunks)
76
- inputs = self.tokenizer(prompt, return_tensors="pt", padding=True)
77
- inputs = {k: v.to(self.device) for k, v in inputs.items()}
78
 
79
- generated_text = ""
80
- max_new_tokens = 4096
81
- chunk_size = 50
 
 
 
82
 
83
  with torch.no_grad():
84
- for _ in range(0, max_new_tokens, chunk_size):
85
- outputs = self.model.generate(
86
- **inputs,
87
- max_new_tokens=chunk_size,
 
 
 
88
  do_sample=True,
89
  temperature=0.7,
90
  top_p=0.8,
@@ -92,28 +137,39 @@ class PlantChatbot:
92
  pad_token_id=self.tokenizer.pad_token_id,
93
  eos_token_id=self.tokenizer.eos_token_id,
94
  )
95
- new_tokens = outputs[0][inputs['input_ids'].shape[1]:]
96
- new_text = self.tokenizer.decode(new_tokens, skip_special_tokens=True)
97
- generated_text += new_text
98
- yield new_text
99
 
100
- inputs['input_ids'] = outputs
 
101
 
102
- if outputs[0][-1] == self.tokenizer.eos_token_id:
 
103
  break
 
 
 
 
 
 
 
104
 
 
105
  context_info = json.dumps({"context_items": context_chunks})
106
  yield f"\n<context>{context_info}</context>"
 
107
  except Exception as e:
108
  print(f"Error generating response: {str(e)}")
109
- yield "Error in processing your query."
110
-
111
- @app.route("/chat", methods=["POST"])
112
- def chat():
113
- query = request.json.get('query')
114
- chatbot = PlantChatbot("plant_data_chunks_and_embeddings.csv")
115
- response = chatbot.generate_response(query)
116
- return jsonify({"response": next(response)})
117
 
 
118
  if __name__ == "__main__":
119
- app.run(host='0.0.0.0', port=5000)
 
 
 
 
 
 
 
 
 
 
 
 
1
  import torch
2
  import numpy as np
3
  import pandas as pd
 
5
  from transformers import AutoTokenizer, AutoModelForCausalLM
6
  import json
7
 
 
 
8
  class PlantChatbot:
9
  def __init__(self, preprocessed_data_path: str):
10
  self.device = "cuda" if torch.cuda.is_available() else "cpu"
11
+ #print(f"Using device: {self.device}")
12
 
13
+ # Initialize embedding model
14
  self.embedding_model = SentenceTransformer(
15
  model_name_or_path="all-mpnet-base-v2",
16
  device=self.device
17
  )
18
 
19
+ # Load preprocessed data
20
  self.load_data(preprocessed_data_path)
21
 
22
+ # Initialize local Qwen model and tokenizer
23
  self.tokenizer = AutoTokenizer.from_pretrained(
24
  "Qwen/Qwen2.5-1.5B-Instruct",
25
  trust_remote_code=True
 
28
  "Qwen/Qwen2.5-1.5B-Instruct",
29
  device_map="auto",
30
  trust_remote_code=True,
31
+ torch_dtype=torch.float16 # Use fp16 for memory efficiency
32
  )
33
+
34
+ # Set pad token if not set
35
+ if self.tokenizer.pad_token is None:
36
+ self.tokenizer.pad_token = self.tokenizer.eos_token
37
 
38
  def load_data(self, preprocessed_data_path: str):
39
+ """Load preprocessed data and prepare embeddings"""
40
  df = pd.read_csv(preprocessed_data_path)
41
 
42
+ # Convert embedding strings back to numpy arrays
43
  def parse_embedding(embedding_str):
44
  try:
45
  embedding_str = embedding_str.strip()
 
52
 
53
  df["embedding"] = df["embedding"].apply(parse_embedding)
54
  df = df.dropna(subset=['embedding'])
55
+
56
  self.chunks_data = df.to_dict(orient="records")
57
 
58
+ # Stack embeddings into a single tensor
59
  embeddings_array = np.stack(df["embedding"].values)
60
+ self.embeddings = torch.tensor(
61
+ embeddings_array,
62
+ dtype=torch.float32
63
+ ).to(self.device)
64
 
65
  def retrieve_relevant_chunks(self, query: str, n_chunks: int = 5) -> list[dict]:
66
+ """Retrieve relevant text chunks for the query"""
67
+ query_embedding = self.embedding_model.encode(
68
+ query,
69
+ convert_to_tensor=True,
70
+ show_progress_bar=False
71
+ ).to(self.device)
72
 
73
  if len(query_embedding.shape) == 1:
74
  query_embedding = query_embedding.unsqueeze(0)
 
85
  for i in indices
86
  ]
87
 
88
+ def format_prompt(self, query: str, context_chunks: list[dict]) -> str:
89
+ """Format the prompt with context"""
90
+ context = "- " + "\n- ".join([chunk["sentence_chunk"] for chunk in context_chunks])
91
+
92
+ prompt = f"""<|im_start|>system
93
+ You are a knowledgeable plant expert. Provide helpful and accurate information about plants based on the given context.
94
+ <|im_end|>
95
+ <|im_start|>user
96
+ Based on the following context about plants, please answer the query.
97
+ Please be specific and detailed in your response, using only the information provided in the context.
98
+ If you cannot answer the question based on the provided context, please say so.
99
+
100
+ Context:
101
+ {context}
102
+
103
+ User query: {query}
104
+ <|im_end|>
105
+ <|im_start|>assistant
106
+ """
107
+ return prompt
108
+
109
  def generate_response(self, query: str):
110
+ """Generate a response for the user query"""
111
  try:
112
+ # Get relevant chunks
113
  context_chunks = self.retrieve_relevant_chunks(query)
114
+
115
+ # Format prompt
116
  prompt = self.format_prompt(query, context_chunks)
 
 
117
 
118
+ # Tokenize input
119
+ input_ids = self.tokenizer.encode(prompt, return_tensors="pt").to(self.device)
120
+
121
+ # Generate in smaller chunks
122
+ response = ""
123
+ max_length = input_ids.shape[1] + 512 # Limit total length
124
 
125
  with torch.no_grad():
126
+ generated = input_ids
127
+
128
+ while generated.shape[1] < max_length:
129
+ # Generate next chunk
130
+ outputs = self.model.forward(
131
+ input_ids=generated,
132
+ max_new_tokens=64, # Generate smaller chunks at a time
133
  do_sample=True,
134
  temperature=0.7,
135
  top_p=0.8,
 
137
  pad_token_id=self.tokenizer.pad_token_id,
138
  eos_token_id=self.tokenizer.eos_token_id,
139
  )
 
 
 
 
140
 
141
+ # Get next token probabilities
142
+ next_token = torch.argmax(outputs.logits[:, -1, :], dim=-1).unsqueeze(0)
143
 
144
+ # Check for EOS token
145
+ if next_token[0, 0].item() == self.tokenizer.eos_token_id:
146
  break
147
+
148
+ # Append new token and get its text
149
+ generated = torch.cat([generated, next_token.T], dim=1)
150
+ new_text = self.tokenizer.decode(next_token[0], skip_special_tokens=True)
151
+
152
+ if new_text:
153
+ yield new_text
154
 
155
+ # Add context information at the end
156
  context_info = json.dumps({"context_items": context_chunks})
157
  yield f"\n<context>{context_info}</context>"
158
+
159
  except Exception as e:
160
  print(f"Error generating response: {str(e)}")
161
+ yield "I apologize, but I encountered an error while processing your query. Please try again."
 
 
 
 
 
 
 
162
 
163
+ # Example usage
164
  if __name__ == "__main__":
165
+ filepath = r"/home/avinashhn/bheri_bot/ravi/new/plant_data_chunks_and_embeddings.csv"
166
+ chatbot = PlantChatbot(filepath)
167
+
168
+ # Example query
169
+ query = "Tell me about the Abidjan plant's care requirements"
170
+
171
+ # Generate and print response
172
+ print("User:", query)
173
+ print("\nChatbot:")
174
+ for response_chunk in chatbot.generate_response(query):
175
+ print(response_chunk, end="", flush=True)