dlflannery commited on
Commit
d04ae31
·
verified ·
1 Parent(s): 4eeb806

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +323 -0
app.py ADDED
@@ -0,0 +1,323 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from operator import indexOf
2
+ import os
3
+ import gradio as gr
4
+ import asyncio
5
+ from dotenv import load_dotenv
6
+ from pathlib import Path
7
+ from time import sleep
8
+ from glob import glob
9
+ import copy
10
+ import base64
11
+ import json
12
+ from PIL import Image
13
+ from io import BytesIO
14
+ import math
15
+ import requests
16
+ from urllib.parse import quote
17
+ from multiprocessing import context
18
+ from agents.tool import WebSearchTool
19
+ from typing_extensions import TypedDict, Any
20
+ from agents import Agent, FunctionTool, ImageGenerationTool, RunContextWrapper, Runner, function_tool, SQLiteSession
21
+ from markdown_pdf import MarkdownPdf
22
+ from markdown_pdf import Section
23
+ import brave
24
+ import geo_distance
25
+
26
+ load_dotenv(override=True)
27
+ # key = os.getenv('OPENAI_API_KEY')
28
+ users = os.getenv('LOGNAME')
29
+ unames = users.split(',')
30
+ pwds = os.getenv('PASSWORD')
31
+ pwd_list = pwds.split(',')
32
+ # DEEPSEEK_KEY=os.getenv('DEEPSEEK_KEY')
33
+ # GROQ_KEY=os.getenv('GROQ_KEY')
34
+ BRAVE_KEY=os.getenv('BRAVE_KEY')
35
+ # BRAVE_SEARCH_KEY=os.getenv('BRAVE_SEARCH_KEY')
36
+ LOCATIONID_KEY=os.getenv('LOCATIONID_KEY')
37
+
38
+ # site = os.getenv('SITE')
39
+ # if site == 'local':
40
+ # dp = Path('./data')
41
+ # dp.mkdir(exist_ok=True)
42
+ # dataDir = './data/'
43
+ # else:
44
+ # dp = Path('/data')
45
+ # dp.mkdir(exist_ok=True)
46
+ # dataDir = '/data/'
47
+
48
+ @function_tool
49
+ async def make_pdf(text: str, title: str)->str:
50
+ '''Creates a pdf document based on input markdown text and title string.
51
+
52
+ Args:
53
+ text: The markdown text to be processed to create the pdf document.
54
+ title: A title that will be used as part of a filename in a file path.
55
+
56
+ Returns:
57
+ The file path to the PDF that was created and saved.
58
+ '''
59
+ for file in glob('./document.pdf'):
60
+ os.remove(file)
61
+ pdf = MarkdownPdf()
62
+ pdf.add_section(Section(text))
63
+ outpath = os.path.join('./','document.pdf')
64
+ pdf.save(outpath)
65
+ return outpath
66
+
67
+ @function_tool
68
+ async def get_news(query: str, window: str)->str:
69
+ '''Searches the internet news sources for news related to the query, within
70
+ a time window defined by argument window.
71
+
72
+ Args:
73
+ query: The topic about which news is desired.
74
+ window: a string indicating the time window over which news occurs, must be either 'day', 'week', 'month' or 'year'.
75
+ '''
76
+ periods = {"day":"pd","week":"pw","month":"pm","year":"py"}
77
+ window = window.casefold()
78
+ period = 'pw'
79
+ if window in periods.keys():
80
+ period = periods[window]
81
+ news = brave.get_brave_news(query, BRAVE_KEY, period)
82
+ return news
83
+
84
+ @function_tool
85
+ async def search_web(query: str)->str:
86
+ '''Searches the internet for information related to the query.
87
+
88
+ Args:
89
+ query: The topics to be searched on.
90
+ '''
91
+
92
+ result = brave.get_brave_search_results(query, BRAVE_KEY)
93
+ return result
94
+
95
+ @function_tool
96
+ async def get_distance(addr1: str, addr2: str)->float:
97
+ '''Compute the great-circle distance in miles between two addresses or other location specifiers.
98
+
99
+ Args:
100
+ addr1: The first address or location specifier.
101
+ addr2: The second address or location specifier.
102
+
103
+ Returns:
104
+ Distance in miles
105
+ '''
106
+
107
+ (lat1, lon1) = geo_distance.get_geo_coords(addr1, LOCATIONID_KEY)
108
+ (lat2, lon2) = geo_distance.get_geo_coords(addr2, LOCATIONID_KEY)
109
+ distance = geo_distance.great_circle_distance_miles(lat1, lon1, lat2, lon2)
110
+ return distance
111
+
112
+
113
+ def md(txt):
114
+ return str(txt).replace('```', ' ').replace(' ', '&nbsp;&nbsp;').replace(' ', '&nbsp;&nbsp;').replace(' ', '&nbsp;&nbsp;').replace('\n','<br>').replace('~~','~')
115
+
116
+ # def clean_history(db_path: str):
117
+ # connection = sqlite3.connect(db_path)
118
+ # cursor = connection.cursor()
119
+
120
+ # # Query to fetch all table names
121
+ # cursor.execute("SELECT name FROM sqlite_master WHERE type='table';")
122
+ # tables = cursor.fetchall()
123
+
124
+ # # Drop each table
125
+ # for table_name in tables:
126
+ # if table_name != 'sqlite_sequence':
127
+ # cursor.execute(f"DELETE FROM {table_name[0]};")
128
+
129
+ # # Commit changes and close the connection
130
+ # connection.commit()
131
+ # connection.close()
132
+
133
+ def updatePassword(pwd, user):
134
+ password = 'none'
135
+ if user in unames:
136
+ pwd = pwd.lower().strip()
137
+ if pwd == pwd_list[unames.index(user)]:
138
+ password = pwd
139
+ return [password, "*********"]
140
+ else:
141
+ return [password, "invalid password"]
142
+ else:
143
+ return [password, "invalid user"]
144
+
145
+ def update_user(user_win):
146
+ user_win = user_win.lower().strip()
147
+ user = 'unknown'
148
+ for s in unames:
149
+ if user_win == s:
150
+ user = s
151
+ break
152
+ return [user, user]
153
+
154
+ def credentials_ok(user, pwd):
155
+ return user in unames and pwd in pwd_list
156
+
157
+ def clean_up_files():
158
+ for file in glob('./document.pdf'):
159
+ try:
160
+ os.remove(file)
161
+ except:
162
+ pass
163
+ for file in glob('./*.png'):
164
+ try:
165
+ os.remove(file)
166
+ except:
167
+ pass
168
+
169
+ def load_image(image, user):
170
+ status = 'OK, image is ready! Enter prompt and tap submit button'
171
+ try:
172
+ with open(image, 'rb') as image_file:
173
+ base64_image = base64.b64encode(image_file.read()).decode('utf-8')
174
+ fpath = user + '_image.b64'
175
+ with open(fpath, 'wt') as fp:
176
+ fp.write(base64_image)
177
+ except:
178
+ status = 'Unable to upload image'
179
+ return [fpath, status]
180
+
181
+ def upload_image(user, password):
182
+ if not credentials_ok(user, password):
183
+ return [gr.Image(visible=False, interactive=True), "Incorrect user name and/or password"]
184
+ return [gr.Image(visible=True, interactive=True), '']
185
+
186
+ async def chat(prompt_window, user_window, password, history, output_window,
187
+ uploaded_image_file):
188
+ file_download = gr.DownloadButton(label='Download File', visible=False, value=None)
189
+ image_window = gr.Image(visible=False, value=None)
190
+
191
+ if not credentials_ok(user_window, password):
192
+ return ['Invalid Credentials', prompt_window, uploaded_image_file,
193
+ image_window, file_download, history]
194
+ instructions = '''
195
+ You are a helpful assistant.
196
+ You can call tools to compute straight-line distances and to search the web for
197
+ either information or news. When you search for news you need to specify a period
198
+ of either 'day', 'week', 'month' or 'year'. You also have a tool to create PDF
199
+ documents and it requires markdown text as input. If a distance is requested use
200
+ straight-line distance by default, and when possible use street addresses for locations.
201
+ '''
202
+
203
+ agent = Agent(name="Assistant",
204
+ instructions=instructions,
205
+ tools=[get_distance, search_web, get_news, make_pdf,
206
+ ImageGenerationTool(tool_config={"type": "image_generation", "quality": "low"},)],)
207
+
208
+ response = output_window
209
+ if not response:
210
+ response = ''
211
+ prompt = prompt_window
212
+ history.append({"role":"user", "content":prompt})
213
+ inputs = history
214
+ image_input = ''
215
+ if uploaded_image_file != '':
216
+ with open(uploaded_image_file, 'rt') as fp:
217
+ b64data = fp.read()
218
+ os.remove(uploaded_image_file)
219
+ uploaded_image_file = ''
220
+ image_input = (
221
+ {
222
+ "role": "user",
223
+ "content": [
224
+ {
225
+ "type": "input_image",
226
+ "image_url": f'data:image/jpeg;base64, {b64data}',
227
+ }
228
+ ]
229
+ }
230
+ )
231
+ inputs.append(image_input)
232
+ result = await Runner.run(agent, max_turns=20,
233
+ input=inputs)
234
+ for item in result.new_items:
235
+ if (
236
+ item.type == "tool_call_item"
237
+ and item.raw_item.type == "image_generation_call"
238
+ and (img_result := item.raw_item.result)
239
+ ):
240
+ # with tempfile.NamedTemporaryFile(suffix=".png", delete=False) as tmp:
241
+ image_out_path = f'{user_window}_out.png'
242
+ with open(image_out_path,'wb') as fp:
243
+ fp.write(base64.b64decode(img_result))
244
+ image_window = gr.Image(visible=True, value=image_out_path)
245
+
246
+ history.append({"role":"assistant", "content":result.final_output})
247
+
248
+ reply = md(result.final_output)
249
+ response += "\n\n***YOU***: " + prompt + "\n\n***GPT***: " + reply.replace('```','\n\n```\n\n')
250
+ usage = result.context_wrapper.usage
251
+ response += f"\nTotal tokens: = {usage.total_tokens}"
252
+ pdf_list = glob('./document.pdf')
253
+ if len(pdf_list):
254
+ file_download = gr.DownloadButton(label='Download PDF Doc',
255
+ visible=True, value='./document.pdf')
256
+ return [response, '', uploaded_image_file, image_window, file_download, history]
257
+
258
+ # outputs=[history, output_window, prompt_window, uploaded_image_file,
259
+ # image_window, file_download])
260
+
261
+ def new_session(user_window, history):
262
+ history = []
263
+ return [prompt_window, history, 'Session cleared',
264
+ gr.Image(visible=False, value=None),
265
+ gr.Image(visible=False, value=None), '',
266
+ gr.DownloadButton(label='Download File', visible=False, value=None),
267
+ gr.File(visible=False, label='Upload File', type='filepath')]
268
+
269
+
270
+ with gr.Blocks(theme=gr.themes.Soft()) as demo:
271
+ password = gr.State("")
272
+ user = gr.State("unknown")
273
+ uploaded_image_file = gr.State('')
274
+ uploaded_file_path = gr.State('')
275
+ history = gr.State([])
276
+
277
+ gr.Markdown('# GPT Agent')
278
+ gr.Markdown('Enter user name & password. Tap "Help & Hints" button for more instructions.')
279
+ with gr.Row():
280
+ user_window = gr.Textbox(label = "User Name")
281
+ user_window.blur(fn=update_user, inputs=user_window, outputs=[user, user_window])
282
+ pwd_window = gr.Textbox(label = "Password")
283
+ help_button = gr.Button(value='Help & Hints')
284
+ with gr.Row():
285
+ clear_button = gr.Button(value="Start New Session")
286
+ button_do_image = gr.Button(value='Make Image')
287
+ button_upload_file = gr.Button(value='Upload Input File')
288
+ button_get_image = gr.Button(value='Upload Image to Analyze')
289
+ submit_button = gr.Button(value="Submit Prompt/Question")
290
+ with gr.Row():
291
+ prompt_window = gr.Textbox(label = "Prompt or Question", scale=7)
292
+ gr.Markdown('### **Dialog:**')
293
+ #output_window = gr.Text(container=True, label='Dialog')
294
+ output_window = gr.Markdown(container=True)
295
+ file_download = gr.DownloadButton(label='Download File', visible=False, value=None)
296
+ with gr.Row():
297
+ with gr.Column():
298
+ image_window2 = gr.Image(visible=False, interactive=True, label='Image to Analyze', type='filepath')
299
+ with gr.Column():
300
+ image_window = gr.Image(visible=False, label='Generated Image')
301
+ with gr.Row():
302
+ file_uploader = gr.File(visible=False, label='Upload File', type='filepath')
303
+ submit_button.click(chat,
304
+ inputs=[prompt_window, user_window, password, history, output_window,
305
+ uploaded_image_file],
306
+ outputs=[output_window, prompt_window, uploaded_image_file,
307
+ image_window, file_download, history])
308
+ clear_button.click(fn=new_session, inputs=[user_window, history],
309
+ outputs=[prompt_window, history, output_window, image_window, image_window2,
310
+ uploaded_image_file, file_download, file_uploader])
311
+ # image_window.change(fn=delete_image, inputs=[user])
312
+ # help_button.click(fn=show_help, outputs=output_window)
313
+ button_get_image.click(fn=upload_image,inputs = [user, password],
314
+ outputs = [image_window2, output_window])
315
+ image_window2.upload(fn=load_image, inputs=[image_window2, user], outputs=[uploaded_image_file, output_window])
316
+ pwd_window.blur(updatePassword, inputs = [pwd_window, user], outputs = [password, pwd_window])
317
+ # button_upload_file.click(fn=upload_file, inputs=[user, password],
318
+ # outputs=[file_uploader, output_window])
319
+ # file_uploader.upload(fn=load_file, inputs=[file_uploader, user], outputs=[uploaded_file_path, output_window])
320
+ # demo.launch(share=True, allowed_paths=[dataDir], ssr_mode=False)
321
+ # demo.load(delete_db_files)
322
+ demo.unload(clean_up_files)
323
+ demo.launch(share=True, ssr_mode=False)