Jasper Sands commited on
Commit
2fcfcbd
·
1 Parent(s): e72bb6f
Files changed (2) hide show
  1. app.py +165 -65
  2. requirements.txt +5 -4
app.py CHANGED
@@ -1,76 +1,110 @@
1
- import gradio as gr
2
- import pandas as pd
3
- import nltk
4
- from nltk.corpus import stopwords
5
- from sentence_transformers import SentenceTransformer, util
6
- from sklearn.feature_extraction.text import TfidfVectorizer
7
- from sklearn.metrics.pairwise import cosine_similarity
8
-
9
  from unsloth import FastLanguageModel
10
  from peft import PeftModel
11
- from unsloth.chat_templates import get_chat_template
12
 
13
- # Download NLTK stopwords if not already downloaded
14
- nltk.download("stopwords")
15
-
16
- # 1. Load model + tokenizer
17
- base_model_name = "unsloth/Llama-3.2-3B-Instruct"
18
  model, tokenizer = FastLanguageModel.from_pretrained(
19
- model_name=base_model_name,
20
  max_seq_length=2048,
21
  dtype=None,
22
  load_in_4bit=True
23
  )
24
 
25
- # 2. Load the LoRA adapter
26
- adapter_path = "jaspersands/model" # Adjust if needed
 
27
  model = PeftModel.from_pretrained(model, adapter_path)
28
 
29
- # 3. Load data
30
- file_path = "Clean Missouri Data.csv" # Ensure this CSV is in your repo
31
- df = pd.read_csv(file_path, encoding="MacRoman")
 
 
 
 
 
 
 
 
 
 
 
 
32
 
33
- # 4. Define helper functions
34
- def search_relevant_policies(query, df, top_n=10):
 
35
  tfidf = TfidfVectorizer(stop_words='english')
36
  tfidf_matrix = tfidf.fit_transform(df['Content'])
 
 
37
  query_vector = tfidf.transform([query])
 
 
38
  cosine_sim = cosine_similarity(query_vector, tfidf_matrix).flatten()
 
 
 
 
 
39
  top_indices = cosine_sim.argsort()[-top_n:][::-1]
40
- return df.iloc[top_indices]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
41
 
42
  def get_content_after_query(response_text, query):
 
43
  query_position = response_text.lower().find(query.lower())
44
  if query_position != -1:
 
45
  res = response_text[query_position + len(query):].strip()
46
  return res[11:]
47
  else:
 
48
  return response_text.strip()
49
 
50
- def process_query(query, tokenizer):
51
- # 1. Get relevant policies
 
52
  relevant_policies = search_relevant_policies(query, df)
53
 
54
- # 2. Format relevant policies
55
  formatted_policies = []
56
  for index, row in relevant_policies.iterrows():
57
- formatted_policy = (
58
- f"Title: {row['Title']}\nTerritory: {row['Territory']}\n"
59
- f"Type: {row['Type']}\nYear: {row['Year']}\nCategory: {row['Category']}\n"
60
- f"From: {row['From']}\nTo: {row['To']}\nContent: {row['Content']}\n"
61
- f"Link: {row['Link to Content']}\n"
62
- )
63
- formatted_policies.append(formatted_policy)
64
  relevant_policy_text = "\n\n".join(formatted_policies)
65
 
66
- # 3. Create messages for model
67
  messages_with_relevant_policies = [
68
  {"role": "system", "content": relevant_policy_text},
69
  {"role": "user", "content": query},
70
  ]
71
 
72
- # 4. Tokenize with chat template
73
- tokenizer = get_chat_template(tokenizer, chat_template="llama-3.1")
 
 
 
74
  inputs = tokenizer.apply_chat_template(
75
  messages_with_relevant_policies,
76
  tokenize=True,
@@ -78,43 +112,109 @@ def process_query(query, tokenizer):
78
  return_tensors="pt"
79
  ).to("cuda")
80
 
81
- # 5. Generate output
82
  FastLanguageModel.for_inference(model)
83
- outputs = model.generate(
84
- input_ids=inputs,
85
- max_new_tokens=256,
86
- use_cache=True,
87
- temperature=1.5,
88
- min_p=0.1
89
- )
90
  generated_response = tokenizer.batch_decode(outputs, skip_special_tokens=True)[0]
91
  response = get_content_after_query(generated_response, query)
92
 
93
- # 6. Rank the top 10 policies using SBERT
94
- model_sbert = SentenceTransformer("all-MiniLM-L6-v2")
 
 
 
95
  response_embedding = model_sbert.encode(generated_response, convert_to_tensor=True)
 
 
96
  policy_embeddings = model_sbert.encode(relevant_policies['Content'].tolist(), convert_to_tensor=True)
 
 
97
  cosine_similarities = util.cos_sim(response_embedding, policy_embeddings).flatten()
 
 
98
  most_relevant_index = cosine_similarities.argmax().item()
99
  most_relevant_link = relevant_policies.iloc[most_relevant_index]['Link to Content']
100
 
101
- return {"response": response, "most_relevant_link": most_relevant_link}
102
-
103
- # 5. Gradio interface
104
- def answer_query(u_query):
105
- result = process_query(u_query, tokenizer)
106
- return result["response"], result["most_relevant_link"]
107
-
108
- demo = gr.Interface(
109
- fn=answer_query,
110
- inputs="text",
111
- outputs=[
112
- gr.Textbox(label="System Response"),
113
- gr.Textbox(label="Relevant Link")
114
- ],
115
- title="Foster Questions",
116
- description="Enter your question about the US foster system"
117
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
118
 
119
- if __name__ == "__main__":
120
- demo.launch()
 
 
 
 
 
 
 
 
 
1
  from unsloth import FastLanguageModel
2
  from peft import PeftModel
 
3
 
4
+ # Load the base model with FastLanguageModel
 
 
 
 
5
  model, tokenizer = FastLanguageModel.from_pretrained(
6
+ model_name="unsloth/Llama-3.2-3B-Instruct",
7
  max_seq_length=2048,
8
  dtype=None,
9
  load_in_4bit=True
10
  )
11
 
12
+ base_model_name = "unsloth/Llama-3.2-3B-Instruct"
13
+ adapter_path = "jaspersands/model" # Path to LoRA adapter on Hugging Face
14
+
15
  model = PeftModel.from_pretrained(model, adapter_path)
16
 
17
+ # Code for processing a query
18
+ import pandas as pd
19
+ from unsloth.chat_templates import get_chat_template
20
+ from sklearn.feature_extraction.text import TfidfVectorizer
21
+ from sklearn.metrics.pairwise import cosine_similarity
22
+ from sentence_transformers import SentenceTransformer, util
23
+ import nltk
24
+
25
+ # Ensure you have NLTK stopwords downloaded
26
+ nltk.download("stopwords")
27
+ from nltk.corpus import stopwords
28
+
29
+ # Step 1: Load the CSV file
30
+ file_path = '/content/Clean Missouri Data.csv'
31
+ df = pd.read_csv(file_path, encoding='MacRoman')
32
 
33
+ # Step 2: Define a function to search relevant policies based on the user's query using cosine similarity
34
+ def search_relevant_policies(query, df, top_n=10, max_chars = 40000):
35
+ # Convert policies into a TF-IDF matrix
36
  tfidf = TfidfVectorizer(stop_words='english')
37
  tfidf_matrix = tfidf.fit_transform(df['Content'])
38
+
39
+ # Get the query as a TF-IDF vector
40
  query_vector = tfidf.transform([query])
41
+
42
+ # Calculate cosine similarity between query and policies
43
  cosine_sim = cosine_similarity(query_vector, tfidf_matrix).flatten()
44
+
45
+ # Get the top N relevant policies
46
+ top_indices = cosine_sim.argsort()[-top_n:][::-1]
47
+ relevant_policies = df.iloc[top_indices]
48
+
49
  top_indices = cosine_sim.argsort()[-top_n:][::-1]
50
+ relevant_policies = df.iloc[top_indices].copy()
51
+
52
+ # Ensure total text is capped at max_chars
53
+ char_count = 0
54
+ valid_indices = []
55
+
56
+ for idx, row in relevant_policies.iterrows():
57
+ content_length = len(row["Content"])
58
+
59
+ # If adding this content exceeds max_chars, stop adding any further policies
60
+ if char_count + content_length > max_chars:
61
+ break
62
+
63
+ # Otherwise, keep this policy
64
+ char_count += content_length
65
+ valid_indices.append(idx)
66
+
67
+ # Filter the dataframe to only include valid rows
68
+ truncated_policies = relevant_policies.loc[valid_indices]
69
+
70
+ return truncated_policies
71
+
72
 
73
  def get_content_after_query(response_text, query):
74
+ # Find the position of the query within the response text
75
  query_position = response_text.lower().find(query.lower())
76
  if query_position != -1:
77
+ # Return the content after the query position
78
  res = response_text[query_position + len(query):].strip()
79
  return res[11:]
80
  else:
81
+ # If the query is not found, return the full response text as a fallback
82
  return response_text.strip()
83
 
84
+
85
+ def process_query(query,tokenizer):
86
+
87
  relevant_policies = search_relevant_policies(query, df)
88
 
89
+ # Step 5: Combine the relevant policies with the user's query for the model
90
  formatted_policies = []
91
  for index, row in relevant_policies.iterrows():
92
+ # formatted_policy = f"Title: {row['Title']}\nTerritory: {row['Territory']}\nType: {row['Type']}\nYear: {row['Year']}\nCategory: {row['Category']}\nFrom: {row['From']}\nTo: {row['To']}\nContent: {row['Content']}\nLink: {row['Link to Content']}\n"
93
+ # formatted_policies.append(formatted_policy)
94
+ formatted_policies.append(row['Content'])
 
 
 
 
95
  relevant_policy_text = "\n\n".join(formatted_policies)
96
 
97
+ # Messages with relevant policies for the model
98
  messages_with_relevant_policies = [
99
  {"role": "system", "content": relevant_policy_text},
100
  {"role": "user", "content": query},
101
  ]
102
 
103
+ # Step 6: Apply chat template and tokenize
104
+ tokenizer = get_chat_template(
105
+ tokenizer,
106
+ chat_template="llama-3.1",
107
+ )
108
  inputs = tokenizer.apply_chat_template(
109
  messages_with_relevant_policies,
110
  tokenize=True,
 
112
  return_tensors="pt"
113
  ).to("cuda")
114
 
 
115
  FastLanguageModel.for_inference(model)
116
+ outputs = model.generate(input_ids=inputs, max_new_tokens=512, use_cache=True, temperature=0.7, min_p=0.1)
117
+
118
+ # Step 7: Decode the output
 
 
 
 
119
  generated_response = tokenizer.batch_decode(outputs, skip_special_tokens=True)[0]
120
  response = get_content_after_query(generated_response, query)
121
 
122
+ # Step 8: Rank the top 10 policies using SBERT for the final link
123
+ # Load SBERT model
124
+ model_sbert = SentenceTransformer('all-MiniLM-L6-v2') # You can choose another SBERT model if desired
125
+
126
+ # Encode the generated response using SBERT
127
  response_embedding = model_sbert.encode(generated_response, convert_to_tensor=True)
128
+
129
+ # Encode each policy in the top 10 list
130
  policy_embeddings = model_sbert.encode(relevant_policies['Content'].tolist(), convert_to_tensor=True)
131
+
132
+ # Calculate cosine similarities between the generated response and each policy embedding
133
  cosine_similarities = util.cos_sim(response_embedding, policy_embeddings).flatten()
134
+
135
+ # Identify the policy with the highest SBERT cosine similarity score
136
  most_relevant_index = cosine_similarities.argmax().item()
137
  most_relevant_link = relevant_policies.iloc[most_relevant_index]['Link to Content']
138
 
139
+ # Print the link to the most relevant source
140
+ return {
141
+ "response": response,
142
+ "most_relevant_link": most_relevant_link
143
+ }
144
+
145
+
146
+ # Load Google Sheets to store results
147
+ import json
148
+ from google.oauth2.service_account import Credentials
149
+ import gspread
150
+ import pandas as pd
151
+
152
+ # Load the service account JSON
153
+ json_file_path = "fostercare-449201-75a303a8c238.json" # Load the credentials for the service account
154
+ with open(json_file_path, 'r') as file:
155
+ service_account_data = json.load(file)
156
+
157
+ # Authenticate using the loaded service account data
158
+ scopes = ["https://www.googleapis.com/auth/spreadsheets", "https://www.googleapis.com/auth/drive"]
159
+ creds = Credentials.from_service_account_info(service_account_data, scopes=scopes)
160
+ client = gspread.authorize(creds)
161
+
162
+ # Open the shared Google Sheet by name
163
+ spreadsheet = client.open("Foster Care RA Responses").sheet1
164
+
165
+ # Link to Google Sheet
166
+ # https://docs.google.com/spreadsheets/d/15iEcxmTgkgfcxzDGnq3i_nP1hiAXgb3RplHgqAMEyHA/edit?usp=sharing
167
+
168
+
169
+ # Code to set up Gradio GUI
170
+ import gradio as gr
171
+
172
+ def greet(query):
173
+ result_1 = process_query(query, tokenizer)
174
+ content_after_query_1 = result_1["response"]
175
+
176
+ result_2 = process_query(query, tokenizer)
177
+ content_after_query_2 = result_2["response"]
178
+
179
+ return [content_after_query_1, content_after_query_2]
180
+
181
+ def choose_preference(name, output1, output2, preference, query):
182
+ if not name:
183
+ return "Please enter your name before submitting."
184
+
185
+ if preference == "Output 1":
186
+ new_row = [query, output1, output2, name]
187
+ spreadsheet.append_row(new_row)
188
+ return f"You preferred: Output 1 - {output1}"
189
+ elif preference == "Output 2":
190
+ new_row = [query, output2, output1, name]
191
+ spreadsheet.append_row(new_row)
192
+ return f"You preferred: Output 2 - {output2}"
193
+ else:
194
+ return "No preference selected."
195
+
196
+ # Define the interface
197
+ with gr.Blocks() as demo:
198
+ # Name input
199
+ name_input = gr.Textbox(label="Enter your name")
200
+
201
+ # Input for query
202
+ query_input = gr.Textbox(label="Enter your query")
203
+
204
+ # Outputs
205
+ output_1 = gr.Textbox(label="Output 1", interactive=False)
206
+ output_2 = gr.Textbox(label="Output 2", interactive=False)
207
+
208
+ # Preference selection
209
+ preference = gr.Radio(["Output 1", "Output 2"], label="Choose your preferred output")
210
+ preference_result = gr.Textbox(label="Your Preference", interactive=False)
211
+
212
+ # Buttons
213
+ generate_button = gr.Button("Generate Outputs")
214
+ submit_button = gr.Button("Submit Preference")
215
+
216
+ # Link actions to buttons
217
+ generate_button.click(greet, inputs=query_input, outputs=[output_1, output_2])
218
+ submit_button.click(choose_preference, inputs=[name_input, output_1, output_2, preference, query_input], outputs=preference_result)
219
 
220
+ demo.launch()
 
requirements.txt CHANGED
@@ -1,8 +1,9 @@
1
- # requirements.txt
 
2
  unsloth
3
- peft
4
- gradio
5
  scikit-learn
6
  pandas
7
  nltk
8
- sentence-transformers
 
 
 
1
+ torch
2
+ torchvision
3
  unsloth
 
 
4
  scikit-learn
5
  pandas
6
  nltk
7
+ sentence-transformers
8
+ gradio
9
+ peft