Jasper Sands commited on
Commit
42d7a9a
·
1 Parent(s): 268c02d
Clean Missouri Data.csv ADDED
The diff for this file is too large to render. See raw diff
 
app.py ADDED
@@ -0,0 +1,220 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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 = '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,
111
+ add_generation_prompt=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()
fostercare-449201-75a303a8c238.json ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "type": "service_account",
3
+ "project_id": "fostercare-449201",
4
+ "private_key_id": "75a303a8c2386704d3ef7db035e1179716b2f4dd",
5
+ "private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDFZTdiG4aOG9q+\nk1HLTSC852O0gnhcxcVXBmlqIvT7adll39i9xMpoirsUbzCqoeT1kNFrYTcCO7u7\n50za3rZzwkq6DGK1D7i911EHJrUHAt5jDZXJmYO8IGx/piPILF58otAJuKrFVOJh\nOF3Ig6roPFD9aEGmfbORBwF8DLXvFZPs/7SboVjSN6baiYYEdeE2rasq9FUmMrbk\ngJOuBFUwlDQn0/JDGXtmrLfjoRH7ff2rrMKYpIboWedjHT99gnBhshRKYuWzRium\ny4hn3z/iG4OLvyglFrY7RhpZYiSAX6d7OdTyy6D3hUYJ8wjC7s/79QwgLwd2ZJ+r\n4dFO8EWZAgMBAAECggEAFavOD8RL2nAubLvJwBMgo/yXUqr8QdsolixLCG78DFoL\nlwajSfo/6ohIj67BXgpWE6upgitzGZirPK7hHipTR5QuFgzkDVLDinwIFkvmlfV3\nqtJD/pUPBGle4AjCZuiQGwjY5ChU/0MZc2j3ytrBuatdjOSUSI4GV8a4IAFZO/0m\nFGSqapleHHyxSLPPvCmD2QZ8+Qq316aPwxLm1JaV4U9gxLOA1p1zpx+QWuBetE3Y\n03Q3GZpSBO98eiZSwipPirEgc1We3oAg46iB2EN8SAFWEZN6Nnof8vCTjh175fUT\n0WHXzA64KUnH48HBtRPVgLZowTj6QO3hqgoIPCCeAQKBgQDoZhkt7ngzcOtfXGFr\nL8f/aslNih0Fh3EKz7aSfU0oPgFjdOs7QeMHhUt5bhFRCdxE07aKQZ4k6pN09XDO\ntEZHj7t5lFEIDkIqhQqxTmLW81A9syl27DRVfwzjExKgcTs+VXhVtHL4r9EkLagy\nPs2KZY0seUwZUvCF3K7+/Q4RwQKBgQDZcRlOTs8+t+hFc19Ya9C2+WMjZm3kDEIa\nLfTPpSep6L6BR+jWhk7jAz6bfGcZsVGOGdrf7fEDMkYPB7UpN37rH7fM08/2wowe\n4nEfXwicwXp3qVmtBn2ZcqkQCmRdi6yMf3c8ElCt+QCNZojERPSrSsPnNUCq0u46\nDEPa0V952QKBgD3XBTY6sZOGpasvauDZyw9FPCG88bIJ82OcGAns+74MmdP8Raf0\nBVR3/LhoOIVm6U0LRRSPF2TdYrWJpiXqxJTAQ3O7qsBJAwRLeKfrotNt1VlFtm/l\ntJtXfndiGN/GoawZlDbCGKHiLvXAjHQqUAlWsnU2JbDLaCNGsO47KiZBAoGAEgQS\n6rAQ78thDVAP2E2mj2J+WlKETF7Po0enfwTaEnPcRO3mVs/t/VUpfMyD5lcQwMtX\nnTIjw/YIY/ppgi6871JDck8ibfmUjoKIiObg2cwWD5AShAmDopEjfNa/lhiahVGS\nWYHS+XcmGpEiR9DGzOJ29NMutnifkGOvw5ORa5ECgYB1OXutTWeyL84xcQ8ZykDB\nUqlGwcfEXxn0LoRSpf4UUExV+6J6Xhukm1hvw0peIlX90WEn4CRkNj2Sd/bDhrhx\nd8cZkm0hOLQjTA1d6DSS0a6gmEynkqqvhA3oZSXkOeL6rPfAqSzP6td0oVPpyqKc\npHK7ghqJ2RUUhuvzoFa+Ug==\n-----END PRIVATE KEY-----\n",
6
+ "client_email": "fostercare-editor@fostercare-449201.iam.gserviceaccount.com",
7
+ "client_id": "114238156298993075680",
8
+ "auth_uri": "https://accounts.google.com/o/oauth2/auth",
9
+ "token_uri": "https://oauth2.googleapis.com/token",
10
+ "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
11
+ "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/fostercare-editor%40fostercare-449201.iam.gserviceaccount.com",
12
+ "universe_domain": "googleapis.com"
13
+ }
requirements.txt ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ torch
2
+ torchvision
3
+ unsloth
4
+ scikit-learn
5
+ pandas
6
+ nltk
7
+ sentence-transformers
8
+ gradio
9
+ peft