dwipper commited on
Commit
289132f
·
1 Parent(s): 34fbabd

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +390 -0
app.py ADDED
@@ -0,0 +1,390 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import openai
3
+ import datetime
4
+ import gradio as gr
5
+ import json
6
+ from jinja2 import Template
7
+ import requests
8
+ from dotenv import load_dotenv
9
+
10
+ load_dotenv()
11
+
12
+ # Initialize OpenAI
13
+ openai.api_key = os.environ.get('OPENAI_API_KEY')
14
+
15
+ # Configuration variables
16
+ airtable_api_key = os.environ.get('AIRTABLE_API_KEY')
17
+
18
+ # Airtable table names
19
+ policies_table_name = 'tbla6PC65qZfqdJhE'
20
+ prompts_table_name = 'tblYIZEB8m6JkGDEP'
21
+ qalog_table_name = 'tbl4oNgFPWM5xH1XO'
22
+ examples_table_name = 'tblu7sraOEmRgEGkp'
23
+ users_table_name = 'tblLNe5ZL47SvrAEk'
24
+ user_log_table_name = 'tblrlTsRrkl6BqMAJ'
25
+
26
+ # Define the style and content for the response field
27
+ label_text = "NILI Response"
28
+ color = "#6562F4"
29
+ background_color = "white"
30
+ border_radius = "10px"
31
+ response_label = f'<h3 style="color: {color}; background-color: {background_color}; border-radius: {border_radius}; padding: 10px;display: inline-block;">{label_text}</h3>'
32
+
33
+ #Airtable Base ID
34
+ base_id = 'appcUK3hUWC7GM2Kb'
35
+
36
+ #Name of the prompt temlate record
37
+ prompt_name = "NILI_v1"
38
+
39
+ #Header for the Airtable requests
40
+ headers = {
41
+ "Authorization": f"Bearer {airtable_api_key}",
42
+ "Content-Type": "application/json",
43
+ "Accept": "application/json",
44
+ }
45
+
46
+ #Function to trim prompts....not used
47
+ def prompt_trim(prompt: str) -> str:
48
+ lines = prompt.split('\n')
49
+ trimmed = '\n'.join([l.strip() for l in lines])
50
+ return trimmed
51
+
52
+ #Get the policies for the selected schools and concatenate them.
53
+ def get_policies(school_selection):
54
+
55
+ airtable_endpoint = f'https://api.airtable.com/v0/{base_id}/{policies_table_name}'
56
+
57
+ # Parameters for the API request to filter by 'school' field and retrieve 'policy_text'
58
+ params = {
59
+ 'filterByFormula': "OR({})".format(','.join(["school='{}'".format(school) for school in school_selection])),
60
+ 'fields[]': 'policy_text', # Replace with the name of your field
61
+ }
62
+
63
+ # Initialize an empty string to store concatenated policies
64
+ concatenated_policies = ''
65
+
66
+ #print(params)
67
+
68
+ try:
69
+ # Send a GET request to the Airtable API
70
+ response = requests.get(airtable_endpoint, headers=headers, params=params)
71
+
72
+ # Check if the request was successful (status code 200)
73
+ if response.status_code == 200:
74
+ # Parse the JSON response
75
+ data = response.json()
76
+
77
+ # Check if there are records in the response
78
+ if data.get('records'):
79
+
80
+ # Extract the 'policy_text' values from each record and concatenate them
81
+ for record in data['records']:
82
+ policy_text = record['fields']['policy_text']
83
+ if concatenated_policies:
84
+ concatenated_policies += "\n----------\n"
85
+ concatenated_policies += policy_text
86
+
87
+ else:
88
+ print("No records found in the 'policies' table for the selected schools.")
89
+ else:
90
+ print(f"Failed to retrieve data. Status code: {response.status_code}")
91
+ except Exception as e:
92
+ print(f"An error occurred: {str(e)}")
93
+
94
+ #print(concatenated_policies)
95
+
96
+ return concatenated_policies
97
+
98
+ #Get a list of School Name from the policies for the UI dropdown
99
+ def get_schools():
100
+
101
+ airtable_endpoint = f'https://api.airtable.com/v0/{base_id}/{policies_table_name}'
102
+
103
+ # Parameters for the API request to select only the 'school' field
104
+ params = {
105
+ 'fields[]': 'school', # Replace with the name of your field
106
+ 'sort[0][field]': 'school', # Sort by the 'school' field
107
+ 'sort[0][direction]': 'asc', # Sort in ascending order
108
+ }
109
+
110
+ schools = ''
111
+
112
+ try:
113
+ # Send a GET request to the Airtable API
114
+ response = requests.get(airtable_endpoint, headers=headers, params=params)
115
+
116
+ # Check if the request was successful (status code 200)
117
+ if response.status_code == 200:
118
+ # Parse the JSON response
119
+ data = response.json()
120
+
121
+ # Check if there are records in the response
122
+ if data.get('records'):
123
+ # Extract the 'school' values from each record
124
+ schools = [record['fields']['school'] for record in data['records']]
125
+
126
+ else:
127
+ print("No records found in the 'policies' table.")
128
+ else:
129
+ print(f"Failed to retrieve data. Status code: {response.status_code}")
130
+ except Exception as e:
131
+ print(f"An error occurred: {str(e)}")
132
+
133
+ return schools
134
+
135
+ #Get the designated prompt template record
136
+ def get_prompt(header, template_content):
137
+
138
+ airtable_endpoint = f'https://api.airtable.com/v0/{base_id}/{prompts_table_name}'
139
+
140
+ params = {
141
+ 'filterByFormula': "prompt_name='NILI_v1'"
142
+ }
143
+
144
+ response = requests.get(airtable_endpoint, headers=headers, params=params)
145
+
146
+ # Check for errors
147
+ response.raise_for_status()
148
+
149
+ data = response.json()
150
+
151
+ # Check if there is at least one record matching the condition
152
+ if data.get('records'):
153
+ # Get the first record (there should be only one)
154
+ record = data['records'][0]['fields']
155
+
156
+ # Assign system_prompt and user_prompt to variables
157
+ header = record.get('system_prompt', '')
158
+ template_content = record.get('user_prompt', '')
159
+
160
+ return header, template_content
161
+
162
+
163
+ def get_examples():
164
+
165
+ airtable_endpoint = f'https://api.airtable.com/v0/{base_id}/{examples_table_name}'
166
+
167
+ # Send your request and parse the response
168
+ response = requests.get(airtable_endpoint, headers=headers)
169
+ data = json.loads(response.text)
170
+
171
+ # Check for errors
172
+ response.raise_for_status()
173
+
174
+ for record in data['records']:
175
+ nil_question = record['fields']['nil_question']
176
+ ui_examples.append([None, None, None, nil_question])
177
+
178
+ #print(ui_examples)
179
+
180
+
181
+ def append_to_at_qalog(your_role, school_selection, output_format, input_text, gpt_response,response_time,question_cost,prompt_tokens,completion_tokens):
182
+
183
+ airtable_endpoint = f'https://api.airtable.com/v0/{base_id}/{qalog_table_name}'
184
+
185
+ # Organize data for Airtable
186
+ new_fields = {
187
+ 'your_role': str(your_role),
188
+ 'school_selection': str(school_selection),
189
+ 'output_format': str(output_format),
190
+ 'input_text': str(input_text),
191
+ 'gpt_response': str(gpt_response),
192
+ 'response_time': str(response_time),
193
+ 'question_cost': question_cost,
194
+ 'user_name': str(logged_in_user),
195
+ 'prompt_tokens': prompt_tokens,
196
+ 'completion_tokens': completion_tokens
197
+ }
198
+
199
+ data = {
200
+ 'fields': new_fields
201
+ }
202
+ try:
203
+ # Post data to Airtable
204
+ response = requests.post(airtable_endpoint, headers=headers, json=data)
205
+
206
+ # Check for errors
207
+ response.raise_for_status()
208
+
209
+ except requests.exceptions.HTTPError as http_error:
210
+ # Handle the HTTP error (e.g., log it or display an error message)
211
+ print(f"HTTP error occurred: {http_error}")
212
+
213
+ except Exception as e:
214
+ # Handle exceptions, log errors, or raise them as needed
215
+ print(f"An error occurred: {str(e)}")
216
+
217
+
218
+ #Chatbot Function
219
+ def chatbot(your_role,school_selection,output_format,input_text):
220
+
221
+ start_time = datetime.datetime.now()
222
+
223
+ # school_selection holds an array of one or more schools
224
+ #print(school_selection)
225
+
226
+ # Read the Hydrated policies
227
+
228
+ policies = get_policies(school_selection)
229
+
230
+ template_content = ''
231
+ header = ''
232
+
233
+ header, template_content = get_prompt(header, template_content)
234
+
235
+ #print(header)
236
+ #print(template_content)
237
+
238
+ header_template = Template(header)
239
+ merged_header = header_template.render(your_role=your_role)
240
+
241
+ # Create a Jinja2 template from the content
242
+ template = Template(template_content)
243
+
244
+ # Render the template with the policy JSON
245
+ analysis_input = template.render(policies=policies, question=input_text,format=output_format,your_role=your_role)
246
+
247
+ trimmed_input = prompt_trim(analysis_input)
248
+
249
+ with open('analysis_input.txt', 'w', encoding='utf-8') as out_file:
250
+ out_file.write(trimmed_input)
251
+
252
+ response = openai.ChatCompletion.create(
253
+ model="gpt-4",
254
+ #model="gpt-3.5-turbo",
255
+ temperature=0,
256
+ messages=[
257
+ {
258
+ "role": "system",
259
+ "content": merged_header
260
+ },
261
+ {
262
+ "role": "user",
263
+ "content": analysis_input
264
+ }
265
+ ]
266
+ )
267
+
268
+ gpt_response = response.choices[0].message["content"]
269
+
270
+ tokens_used = response.usage
271
+
272
+ question_cost = (tokens_used.get('total_tokens', 0) / 1000) * .03
273
+ prompt_tokens = tokens_used.get('prompt_tokens',)
274
+ completion_tokens = tokens_used.get('completion_tokens', 0)
275
+
276
+ """
277
+ with open('response.txt', 'w', encoding='utf-8') as out_file:
278
+ out_file.write(gpt_response)
279
+ """
280
+ end_time = datetime.datetime.now()
281
+ response_time = end_time - start_time
282
+
283
+ append_to_at_qalog(your_role, school_selection, output_format, input_text, gpt_response,response_time,question_cost,prompt_tokens,completion_tokens)
284
+
285
+ return response_label,gpt_response
286
+
287
+ def log_login(username):
288
+
289
+ airtable_endpoint = f'https://api.airtable.com/v0/{base_id}/{user_log_table_name}'
290
+
291
+ # Organize data for Airtable
292
+ new_fields = {
293
+ 'user_name': str(username),
294
+ }
295
+
296
+ data = {
297
+ 'fields': new_fields
298
+ }
299
+
300
+ try:
301
+ # Post data to Airtable
302
+ response = requests.post(airtable_endpoint, headers=headers, json=data)
303
+
304
+ # Check for errors
305
+ response.raise_for_status()
306
+
307
+ except requests.exceptions.HTTPError as http_error:
308
+ # Handle the HTTP error (e.g., log it or display an error message)
309
+ print(f"HTTP error occurred: {http_error}")
310
+
311
+ except Exception as e:
312
+ # Handle exceptions, log errors, or raise them as needed
313
+ print(f"An error occurred: {str(e)}")
314
+
315
+
316
+ def login_auth(username, password):
317
+
318
+ airtable_endpoint = f'https://api.airtable.com/v0/{base_id}/{users_table_name}'
319
+
320
+ # Query the 'users' table to check for a match with the provided username and password
321
+ params = {
322
+ 'filterByFormula': f'AND(user_name = "{username}", password = "{password}")'
323
+ }
324
+
325
+ response = requests.get(airtable_endpoint, headers=headers, params=params)
326
+
327
+ if response.status_code == 200:
328
+ data = response.json()
329
+ #If the matching user/password record is found:
330
+ if data.get('records'):
331
+
332
+ #Log that the user logged in
333
+ log_login(username)
334
+
335
+ #Set the global logged_in_user variable. This used in the append_to_at_qalog function to track what user asked the question
336
+ global logged_in_user
337
+ logged_in_user = username
338
+
339
+ return True
340
+
341
+ print(f"Invalid user/password combination")
342
+
343
+ return False
344
+
345
+ #Gradio UI
346
+ CIMStheme = gr.themes.Soft().set(button_primary_background_fill='#6562F4')
347
+
348
+ # Initialize an empty list to store the examples
349
+ ui_examples = []
350
+ school_selection = []
351
+
352
+ schools = get_schools()
353
+
354
+ get_examples()
355
+
356
+ logged_in_user = 'admin'
357
+
358
+ with gr.Blocks(CIMStheme) as iface:
359
+ with gr.Row():
360
+ with gr.Column(scale=2):
361
+ gr.Image(label="Logo",value="CIMS Logo Purple.png",width=10,show_download_button=False,interactive=False,show_label=False,elem_id="logo",container=False)
362
+ with gr.Column(scale=2):
363
+ #gr.Textbox(value="# NILI - Powered by CIMS.AI",show_label=False,interactive=False,text_align="center",elem_id="CIMSTitle")
364
+ gr.Markdown(value="# NILI - Powered by CIMS.AI")
365
+ with gr.Column(scale=2):
366
+ gr.Markdown("")
367
+ with gr.Row():
368
+ with gr.Column():
369
+ gr.Interface(fn=chatbot,
370
+ inputs=[
371
+ gr.components.Dropdown(["Student Athlete","Parent","Athletic Director"],multiselect=False,info="Select a role.",label="User Role", ),
372
+ gr.components.Dropdown(schools,multiselect=True,info="Select one or more schools. This will help set the context of your question.",label="School Context"),
373
+ gr.components.Dropdown(["Summary","Detailed Analysis","Table"],multiselect=False,info="Select the desired output format.",label="Output Format"),
374
+ gr.components.Textbox(lines=5, placeholder="Enter your question here", label="NIL Question")],
375
+ outputs=[
376
+ gr.components.Markdown(response_label),
377
+ gr.components.HTML(label="NILI Response")
378
+ ],
379
+ description="Ask any question about Name, Image, Likeness (NIL)",
380
+ allow_flagging="manual",
381
+ examples=ui_examples,
382
+ cache_examples=False,
383
+ flagging_options=["The response is incorrect","The response is inappropriate","The response doesn't make sense"]
384
+ )
385
+ with gr.Row():
386
+ with gr.Column():
387
+ gr.HTML('<center><i>CIMS.AI Confidential 2023</i></center>')
388
+
389
+ iface.launch(auth=login_auth, auth_message= "Enter your username and password that you received from CIMS.AI. To request a login, please email 'info@cims.ai'")
390
+ #iface.launch(share=True)