Dryanvfi commited on
Commit
8e28b37
·
1 Parent(s): 1ae9683

Create app.py

Browse files

Initial version of the user facing application

Files changed (1) hide show
  1. app.py +309 -0
app.py ADDED
@@ -0,0 +1,309 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import requests
3
+ import json
4
+ import pandas as pd
5
+ import getpass # Can be removed if using secrets
6
+ import snowflake.connector
7
+ from snowflake.connector.pandas_tools import write_pandas
8
+ import numpy as np
9
+ import datetime
10
+ import io
11
+ import lxml
12
+ import matplotlib.pyplot as plt
13
+ import openai
14
+ import plotly
15
+ import gradio as gr
16
+
17
+ # Data Retrieval
18
+
19
+
20
+ def getData(tlspc_api_key, openai_api_key):
21
+ try:
22
+ # Store OpenAI API Key
23
+ openai.api_key = openai_api_key
24
+ # Get Certificate Data
25
+ cert_url = "https://api.venafi.cloud/outagedetection/v1/certificates?ownershipTree=false&excludeSupersededInstances=false&limit=10000"
26
+
27
+ headers = {
28
+ "accept": "application/json",
29
+ "tppl-api-key": tlspc_api_key
30
+ }
31
+
32
+ cert_response = requests.get(cert_url, headers=headers)
33
+
34
+ certs_df = pd.json_normalize(cert_response.json()['certificates']).convert_dtypes()
35
+ certs_df.rename(columns = {'id':'certificateId'}, inplace = True)
36
+ certs_df.drop(['companyId'],axis=1,inplace=True)
37
+
38
+ certs_df['validityStart'] = pd.to_datetime(certs_df['validityStart']).dt.date
39
+ certs_df['validityEnd'] = pd.to_datetime(certs_df['validityEnd']).dt.date
40
+
41
+ # Application Data and Formatting
42
+ application_url = "https://api.venafi.cloud/outagedetection/v1/applications"
43
+
44
+ headers = {
45
+ "accept": "application/json",
46
+ "tppl-api-key": tlspc_api_key
47
+ }
48
+
49
+ application_response = requests.get(application_url, headers=headers)
50
+
51
+ application_df = pd.json_normalize(application_response.json()['applications']).convert_dtypes()
52
+
53
+ application_df_2 = application_df[['id',
54
+ 'name',
55
+ 'description',
56
+ 'fullyQualifiedDomainNames',
57
+ 'ipRanges',
58
+ 'ports',
59
+ 'modificationDate',
60
+ 'creationDate','ownership.owningUsers',
61
+ 'ownership.owningTeams']]
62
+
63
+ # Flatten application owners and re-merge
64
+ application_owners = pd.json_normalize(application_response.json()['applications'],
65
+ record_path = ['ownerIdsAndTypes'],
66
+ meta = ['id']).convert_dtypes()
67
+
68
+ application_df = pd.merge(application_df_2, application_owners, left_on = 'id', right_on = 'id')
69
+ application_df.rename(columns = {'id':'application_id',
70
+ 'creationDate':'application_creationDate',
71
+ 'modificationDate':'application_modificationDate'}, inplace = True)
72
+
73
+ # User Data
74
+ users_url = "https://api.venafi.cloud/v1/users"
75
+
76
+ headers = {
77
+ "accept": "application/json",
78
+ "tppl-api-key": tlspc_api_key
79
+ }
80
+
81
+ users_response = requests.get(users_url, headers=headers)
82
+
83
+ users_df = pd.json_normalize(users_response.json()['users']).convert_dtypes()
84
+
85
+ users_df.rename(columns = {'id':'user_id'}, inplace = True)
86
+
87
+ users_df.drop(['companyId'],axis=1,inplace=True)
88
+
89
+ # Teams Data
90
+ teams_url = "https://api.venafi.cloud/v1/teams"
91
+
92
+ headers = {
93
+ "accept": "application/json",
94
+ "tppl-api-key": tlspc_api_key
95
+ }
96
+
97
+ teams_response = requests.get(teams_url, headers=headers)
98
+
99
+ teams_df = pd.json_normalize(teams_response.json()['teams']).convert_dtypes()
100
+ teams_df.rename(columns = {'id':'team_id',
101
+ 'modificationDate':'teams_modificationDate'}, inplace = True)
102
+
103
+ teams_df.drop(['companyId'],axis=1,inplace=True)
104
+
105
+ # Machines Data
106
+ machines_url = "https://api.venafi.cloud/v1/machines"
107
+
108
+ headers = {
109
+ "accept": "application/json",
110
+ "tppl-api-key": tlspc_api_key
111
+ }
112
+
113
+ machines_response = requests.get(machines_url, headers=headers)
114
+
115
+ machines_df = pd.json_normalize(machines_response.json()['machines']).convert_dtypes()
116
+ machines_df.rename(columns = {'id':'machine_id',
117
+ 'creationDate':'machine_creationDate',
118
+ 'modificationDate':'machine_modificationDate'}, inplace = True)
119
+
120
+ machines_df.drop(['companyId'],axis=1,inplace=True)
121
+
122
+ # Machine Identities Data
123
+ machine_identities_url = "https://api.venafi.cloud/v1/machineidentities"
124
+
125
+ headers = {
126
+ "accept": "application/json",
127
+ "tppl-api-key": tlspc_api_key
128
+ }
129
+
130
+ machine_identities_response = requests.get(machine_identities_url, headers=headers)
131
+
132
+ machine_identities_df = pd.json_normalize(machine_identities_response.json()['machineIdentities']).convert_dtypes().iloc[:,:7]
133
+ machine_identities_df.rename(columns = {'machineId':'machine_id',
134
+ 'id':'machine_identity_id',
135
+ 'creationDate':'machine_identity_creationDate',
136
+ 'modificationDate':'machine_identities_modificationDate'}, inplace = True)
137
+
138
+ machine_identities_df.drop(['companyId'],axis=1,inplace=True)
139
+
140
+ # Certificate Requests
141
+ def getCertRequests():
142
+ currentPage = 0
143
+ cert_requests_url = "https://api.venafi.cloud/outagedetection/v1/certificaterequestssearch"
144
+ headers = {
145
+ "accept": "application/json",
146
+ "tppl-api-key": tlspc_api_key}
147
+ payload = { "paging": {
148
+ "pageNumber": 1,
149
+ "pageSize": 1000}}
150
+ response = requests.post(url=cert_requests_url, headers=headers,json=payload)
151
+ if(response.status_code != 200):
152
+ raise Exception('Error retrieving certificate requests:' + "\n" + response.text + "\n=============\n")
153
+ data = response.json()
154
+ cert_requests = data['certificateRequests']
155
+ while data['numFound'] > (currentPage * 1000):
156
+ currentPage+=1
157
+ print('Getting page ' + str(currentPage) + ': Number remaining - ' + str(data['numFound'] - currentPage*1000))
158
+ payload['paging']['pageNumber'] = currentPage
159
+ response = requests.post(url=cert_requests_url, headers=headers,json=payload)
160
+ data = response.json()
161
+ cert_requests += data['certificateRequests']
162
+ return cert_requests
163
+
164
+ cert_requests_json = getCertRequests()
165
+ cert_requests_df = pd.json_normalize(cert_requests_json).convert_dtypes()
166
+ cert_requests_df.rename(columns = {'id':'cert_request_id', 'creationDate':'cert_request_creationDate'}, inplace = True)
167
+ cert_requests_df.drop(['companyId'],axis=1,inplace=True)
168
+
169
+ # Issuing Templates
170
+ issuing_template_url = "https://api.venafi.cloud/v1/certificateissuingtemplates"
171
+
172
+ headers = {
173
+ "accept": "application/json",
174
+ "tppl-api-key": tlspc_api_key
175
+ }
176
+
177
+ issuing_template_response = requests.get(issuing_template_url, headers=headers)
178
+
179
+ issuing_templates_df = pd.json_normalize(issuing_template_response.json()['certificateIssuingTemplates']).convert_dtypes()
180
+ issuing_templates_df.rename(columns = {'id':'issuing_template_id',
181
+ 'creationDate':'issuing_template_creationDate'}, inplace = True)
182
+
183
+ issuing_templates_df.drop(['companyId'],axis=1,inplace=True)
184
+
185
+ # Prompt Engineering
186
+
187
+ # Get data structure for each dataframe to be passed in initial prompt
188
+ users_data_description = users_df.dtypes.apply(lambda x: x.name).to_dict()
189
+ application_data_description = application_df.dtypes.apply(lambda x: x.name).to_dict()
190
+ certificate_data_description = certs_df.dtypes.apply(lambda x: x.name).to_dict()
191
+ teams_data_description = teams_df.dtypes.apply(lambda x: x.name).to_dict()
192
+ machines_data_description = machines_df.dtypes.apply(lambda x: x.name).to_dict()
193
+ machine_identities_data_description = machine_identities_df.dtypes.apply(lambda x: x.name).to_dict()
194
+ cert_requests_data_description = cert_requests_df.dtypes.apply(lambda x: x.name).to_dict()
195
+ issuing_templates_data_description = issuing_templates_df.dtypes.apply(lambda x: x.name).to_dict()
196
+
197
+ data_structure_overview = f"""I have multiple python pandas dataframes.
198
+ One is named application_df which contains data on applications and has the following structure: {application_data_description}.
199
+ Another python pandas dataframe is named users_df and contains user information and has the following structure: {users_data_description}.
200
+ Another python pandas dataframe is named certs_df and contains certificate information and has the following structure: {certificate_data_description}.
201
+ Another python pandas dataframe is named teams_df and contains teams information and has the following structure: {teams_data_description}.
202
+ Another python pandas dataframe is named machines_df and contains machine information and has the following structure: {machines_data_description}.
203
+ Another python pandas dataframe is named machine_identities_df and contains machine identity information and has the following structure: {machine_identities_data_description}.
204
+ Another python pandas dataframe is named cert_requests_df and contains certificate request information and has the following structure: {cert_requests_data_description}
205
+ Another python pandas dataframe is named issuing_templates_df and contains issuing template information and has the following structure: {issuing_templates_data_description}
206
+ """
207
+
208
+ data_relationships_overview = """The dataframes relate to eachother in the following manner.
209
+ The column values in the 'user_id' column in users_df match the column values in the 'ownerId' column in application_df.
210
+ The column values in the 'team_id' column in teams_df match the column values in the 'owningTeamId' column in machines_df.
211
+ The column values in the 'certificateOwnerUserId' column in cert_requests_df match the column values in the 'user_id' column in users_df.
212
+ The column values in the 'certificateIssuingTemplateId' column in cert_requests_df match the column values in the 'issuing_template_id' column in issuing_templates_df.
213
+ The column values in the 'certificateOwnerUserId' column in cert_requests_df match the column values in the 'user_id' column in users_df.
214
+ The column values in the 'certificateIssuingTemplateId' column in certs_request_df match the column values in the 'issuing_template_id' column in issuing_templates_df.
215
+ """
216
+
217
+ def prompt_analyze_reporting(prompt):
218
+ output = openai.ChatCompletion.create(model="gpt-3.5-turbo",temperature = 0.0, messages=[{"role": "user", "content":
219
+ data_structure_overview},
220
+ {"role": "user", "content":
221
+ data_relationships_overview},{"role": "user", "content":
222
+ f"""Do not attempt to use .csv files in your code."""},
223
+ {"role": "user", "content":
224
+ f"""Only use plotly to output charts, graphs, or figures. Do not use matplotlib or other charting libraries. Name the chart object as 'fig'"""},
225
+ {"role": "user", "content":
226
+ f"""Create a python script to: {prompt}"""}
227
+ ])
228
+ global parsed_response
229
+ parsed_response = output.choices[0].message.content.strip().split('```python')[len(output.choices[0].message.content.strip().split('```python')) -1 ].split('```')[0]
230
+ parsed_response_global = f"""global fig
231
+ global string
232
+ {parsed_response}"""
233
+ exec(parsed_response_global)
234
+ return fig
235
+
236
+ def prompt_analyze_questions(prompt):
237
+ output = openai.ChatCompletion.create(model="gpt-3.5-turbo",temperature = 0.0, messages=[{"role": "user", "content":
238
+ data_structure_overview},
239
+ {"role": "user", "content":
240
+ data_relationships_overview},{"role": "user", "content":
241
+ f"""Do not attempt to use .csv files in your code."""},
242
+ {"role": "user", "content":
243
+ f"""Do not attempt to create charts or visualize the question with graphics. Only provide string responses."""},
244
+ {"role": "user", "content":
245
+ f"""If you are asked to create visualizations or graphs, create a python script to store a string variable named output_string with the text 'Sorry, I cannot create reporting, select 'Add Reporting' to create reports."""},
246
+ {"role": "user", "content":
247
+ f"""Create a python script to: {prompt}"""},
248
+ {"role": "user", "content":
249
+ f"""Store the final response as a string variable named output_string"""}
250
+ ])
251
+
252
+ global parsed_response
253
+ parsed_response = output.choices[0].message.content.strip().split('```python')[len(output.choices[0].message.content.strip().split('```python')) -1 ].split('```')[0]
254
+ parsed_response_global = f"""global fig
255
+ global string
256
+ {parsed_response}
257
+ globals().update(locals())"""
258
+ exec(parsed_response_global)
259
+ return output_string
260
+
261
+ # Store variables for use in other portions of the application
262
+ globals().update(locals())
263
+
264
+ return 'Data successfully loaded!'
265
+
266
+ except:
267
+
268
+ return 'Error in loading data. Please try again.'
269
+
270
+ # User facing application
271
+ with gr.Blocks() as demo:
272
+ gr.Image('https://design.venafi.com/dist/svg/logos/venafi/logo-venafi-combo.svg', height = 100, width = 300,
273
+ show_share_button = False, show_download_button = False, show_label = False)
274
+ gr.Markdown("Get Answers to questions from your TLS Protect Cloud data or Generate Reporting with this Generative AI application from Venafi.")
275
+ with gr.Tab('Read Me'):
276
+ gr.Markdown("""
277
+ # Welcome to Venafi Explorer!
278
+
279
+ This is an experimental generative AI application for the Venafi Control Plane. \
280
+
281
+
282
+ It leverages Venafi's proprietary data capture technology in combination with the OpenAI API to use natural language to provide answers and insights surrounding your Venafi Control Plane environment.\
283
+
284
+
285
+ Please note to use Venafi Explorer you will need to have both a TLS Protect Cloud API key (Try it for free at venafi.com/signup/) as well as an OpenAI API Key. \
286
+
287
+
288
+ To get started, navigate to the 'API Keys' tab to input your API keys and ingest data from your TLS Protect Cloud environment.
289
+ """)
290
+ with gr.Tab("API Keys"):
291
+ tlspc_api_key = gr.Textbox(label = 'Please provide your TLS Protect Cloud API Key:', type = 'password')
292
+ openai_api_key = gr.Textbox(label = 'Please provide your OpenAI API Key:', type = 'password', placeholder = 'Note: To use the OpenAI API, you need a paid account')
293
+ api_key_output = gr.Textbox(label = 'Result')
294
+ load_button = gr.Button('Load TLS Protect Cloud Data')
295
+ with gr.Tab("Answer Questions"):
296
+ #prompt_tlspc_key = gr.Textbox(label = 'Please provide your TLS Protect Cloud API Key:')
297
+ prompt_questions = gr.Textbox(label = 'Input prompt here:', placeholder = "Try something like 'What is the name of the issuing template that has been used to request the most certificates?'")
298
+ text_output = gr.Textbox(label = 'Response:')
299
+ text_button = gr.Button("Submit")
300
+ with gr.Tab("Create Graphs"):
301
+ prompt_reporting = gr.Textbox(label = 'Input prompt here:', placeholder = "Try something like 'Plot a line chart of certificate issuances over time'")
302
+ chart_output = gr.Plot(label = 'Output:')
303
+ chart_button = gr.Button("Submit")
304
+
305
+ text_button.click(prompt_analyze_questions, inputs=prompt_questions, outputs=text_output)
306
+ chart_button.click(prompt_analyze_reporting, inputs=prompt_reporting, outputs=chart_output)
307
+ load_button.click(getData, inputs = [tlspc_api_key, openai_api_key], outputs = api_key_output)
308
+
309
+ demo.launch()