Spaces:
PhilSpiel
/
Sleeping

PhilSpiel commited on
Commit
6dc0aaa
·
verified ·
1 Parent(s): 5eca574

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +369 -41
app.py CHANGED
@@ -1,14 +1,19 @@
1
  import gradio as gr
2
  import os
3
  from openai import OpenAI
4
- import os.path
5
  from datetime import datetime
 
 
 
6
 
7
  ################# Start PERSONA-SPECIFIC VALUES ######################
8
  coach_code = os.getenv("COACH_CODE")
9
  coach_name_short = os.getenv("COACH_NAME_SHORT")
10
  coach_name_upper = os.getenv("COACH_NAME_UPPER")
 
11
  sys_prompt_new = os.getenv("PROMPT_NEW")
 
 
12
  theme=os.getenv("THEME")
13
  ################# End PERSONA-SPECIFIC VALUES ######################
14
 
@@ -19,70 +24,393 @@ client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
19
  openai_model = os.getenv("OPENAI_MODEL")
20
  ################# End OpenAI-SPECIFIC VALUES ######################
21
 
22
- tx = os.getenv("TX")
23
  prefix = os.getenv("PREFIX") # "/data/" if in HF or "data/" if local
24
- file_name = os.getenv("FILE_NAME")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
25
 
26
- ############### CHAT ###################
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
27
  def predict(user_input, history):
28
- max_length = 3000
29
- transcript_file_path = f"{prefix}{coach_code}-{file_name}"
30
- transcript = "" # Initialize the transcript variable
31
 
32
- if user_input == tx + coach_code:
33
  try:
34
- # Prepare the transcript for the Textbox output
35
- if os.path.exists(transcript_file_path):
36
- with open(transcript_file_path, "r", encoding="UTF-8") as file:
37
- transcript = file.read()
38
- return transcript
 
 
39
  except FileNotFoundError:
40
- return "File '" + file_name + "' not found."
 
41
  elif len(user_input) > max_length:
42
- user_input = ""
43
- # raise gr.Error(f"Input is TOO LONG. Max length is {max_length} characters. Try again.")
 
 
 
 
 
 
 
 
44
 
45
- history_openai_format = [
46
- {"role": "system", "content": "IDENTITY: " + sys_prompt_new}
47
- ]
 
 
 
 
 
 
 
 
 
 
 
 
 
48
  for human, assistant in history:
49
- history_openai_format.append({"role": "user", "content": human})
50
- history_openai_format.append({"role": "assistant", "content": assistant})
51
  history_openai_format.append({"role": "user", "content": user_input})
52
 
53
  completion = client.chat.completions.create(
54
  model=openai_model,
55
- messages=history_openai_format,
56
- temperature=0.8,
57
  frequency_penalty=0.4,
58
  presence_penalty=0.1,
59
  stream=True
60
  )
61
 
62
  output_stream = ""
63
- try:
64
- for chunk in completion:
65
- if chunk.choices[0].delta.content is not None:
66
- output_stream = output_stream + (chunk.choices[0].delta.content)
67
- message_content = output_stream
68
- except StopAsyncIteration:
69
- pass
 
 
 
 
 
 
70
 
71
  # Append latest user and assistant messages to the transcript
72
- transcript += "Date/Time: " + datetime.now().strftime("%Y-%m-%d %H:%M:%S") + "\n"
73
- transcript += f"YOU: {user_input}\n\n"
74
- transcript += f"{coach_name_upper}: {message_content}\n\n\n"
75
  # Write the updated transcript to the file
76
- with open(transcript_file_path, "a", encoding="UTF-8") as file:
77
  file.write(transcript)
78
 
79
- return message_content
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
80
 
81
  #GUI
82
- #GUI
83
- with gr.Blocks(theme, css="""
84
- footer {visibility: hidden}
85
- #share-btn-container {display: none !important}
86
- """) as demo:
87
- gr.ChatInterface(predict, submit_btn="Chat with "+ coach_name_short, retry_btn=None, undo_btn=None, clear_btn=None, autofocus=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
88
  demo.launch(show_api=False)
 
1
  import gradio as gr
2
  import os
3
  from openai import OpenAI
 
4
  from datetime import datetime
5
+ import threading
6
+ import time
7
+ import os.path
8
 
9
  ################# Start PERSONA-SPECIFIC VALUES ######################
10
  coach_code = os.getenv("COACH_CODE")
11
  coach_name_short = os.getenv("COACH_NAME_SHORT")
12
  coach_name_upper = os.getenv("COACH_NAME_UPPER")
13
+ coach_name_long = os.getenv("COACH_NAME_LONG")
14
  sys_prompt_new = os.getenv("PROMPT_NEW")
15
+ sys_prompt_hist = os.getenv("PROMPT_HIST")
16
+ pics_prompt = os.getenv("PROMPT_PICS")
17
  theme=os.getenv("THEME")
18
  ################# End PERSONA-SPECIFIC VALUES ######################
19
 
 
24
  openai_model = os.getenv("OPENAI_MODEL")
25
  ################# End OpenAI-SPECIFIC VALUES ######################
26
 
27
+ # define file name prefix
28
  prefix = os.getenv("PREFIX") # "/data/" if in HF or "data/" if local
29
+ tx = os.getenv("TX")
30
+
31
+ # Assistants API prompts
32
+ bullet_instructions = os.getenv("PROMPT_BULLET")
33
+ summary_instructions = os.getenv("PROMPT_SUMM")
34
+
35
+ # Get dateTime string to build a filename reflecting the UserID + Timestamp
36
+ dt = datetime.now()
37
+ dt_string = str(dt)
38
+
39
+ # User inactivity check interval in seconds
40
+ CHECK_INTERVAL = 10
41
+
42
+ # User inactivity timeout in seconds (initially set to 1 minute)
43
+ USER_TIMEOUT = 1 * 60
44
+
45
+ # Keep track of the last interaction time, current user_id, and the last file modification time
46
+ last_interaction_time = time.time()
47
+ user_id = "NOTLOGGEDIN"
48
+ last_file_mod_time = None
49
+
50
+ # Function to determine whether user is new or returning, and generate the appropriate SYSTEM PROMPT
51
+ def get_system_prompt(user_id):
52
+ past_summary_bullet = ""
53
+ past_summary_summ = ""
54
+ pics_file = ""
55
+ user_summ_file_bullet = f"{prefix}{coach_code}-{user_id.upper().replace(' ', '')}-bullet.txt"
56
+ user_summ_file_summ = f"{prefix}{coach_code}-{user_id.upper().replace(' ', '')}-summ.txt"
57
+ pics_file_path = f"{prefix}{coach_code}-{user_id.upper().replace(' ', '')}-pics.txt"
58
+
59
+ # Create pics file if not exist
60
+ if not os.path.exists(pics_file_path):
61
+ pics_file = "The user has not shared any images."
62
+ with open(pics_file_path, "w", encoding="UTF-8") as file:
63
+ file.write(pics_file)
64
+
65
+ if os.path.exists(pics_file_path):
66
+ with open(pics_file_path, "r", encoding="UTF-8") as file:
67
+ user_pics_content = file.read().strip()
68
+
69
+ # Check if the bullet summary file exists and read from it
70
+ if os.path.exists(user_summ_file_bullet):
71
+ with open(user_summ_file_bullet, "r", encoding="UTF-8") as file:
72
+ past_summary_bullet = file.read().strip() # Read the contents of the summary file
73
+
74
+ # Check if the summary file exists and read from it
75
+ if os.path.exists(user_summ_file_summ):
76
+ with open(user_summ_file_summ, "r", encoding="UTF-8") as file:
77
+ past_summary_summ = file.read().strip() # Read the contents of the summary file
78
+
79
+ # past_summary = past_summary_bullet + "\n" + past_summary_summ
80
+ past_summary = past_summary_bullet
81
+
82
+ # System prompt for returning users includes past summary
83
+ return [
84
+ {"role": "system", "content": sys_prompt_hist + past_summary +
85
+ "If the user asks how to share or upload pictures, refer them to the 'DatingFinesse.com' website for instructions. The user may have shared pictures with you. Each picture will be separated by 'IMAGE - Date/Time:'. If the user has shared images, most recently shared will be listed last and they would be summarized here: " +
86
+ user_pics_content + pics_prompt}
87
+ ]
88
+ else:
89
+ # System prompt for new users
90
+ return [
91
+ {"role": "system", "content": "IDENTITY: " + sys_prompt_new + " If the user asks about sharing or uploading pictures, refer them to the 'DatingFinesse.com' website for instructions."}
92
+ ]
93
+
94
+ # Function that returns the modification time of the user's history file or None if it does not exist
95
+ def get_user_hist_file_mod_time(user_id):
96
+ user_hist_file = f"{prefix}{coach_code}-{user_id.upper().replace(' ', '')}.txt"
97
+ if os.path.exists(user_hist_file):
98
+ return os.path.getmtime(user_hist_file)
99
+ else:
100
+ return None
101
+
102
+ # Function to be run in the case of user timeout
103
+ ############################## LAUNCH DUAL SUMMARIZER ASSISTANT
104
+ def on_timeout(user_id):
105
+ global last_file_mod_time
106
+ current_mod_time = get_user_hist_file_mod_time(user_id)
107
+ if current_mod_time is not None and (last_file_mod_time is None or current_mod_time > last_file_mod_time):
108
+ #print(f"User with ID {user_id} has been inactive, but the history file was updated. Running timeout script.")
109
+ last_file_mod_time = current_mod_time
110
+ # Insert your timeout script here
111
+ # Construct the filename for the user's summary file & user's history file
112
+ user_bullet_file = prefix + coach_code + "-" + user_id + "-bullet.txt" # Filename where the user history summary will be stored.
113
+ user_summ_file = prefix + coach_code + "-" + user_id + "-summ.txt" # Filename where the user history summary will be stored.
114
+ user_hist_file = prefix + coach_code + "-" + user_id + ".txt" # Filename where the user history is stored.
115
+ # Construct the filename for the user's bullet file
116
+ user_summ_file_bullet = f"{prefix}{coach_code}-{user_id.upper().replace(' ', '')}-bullet.txt"
117
+
118
+ # Construct the filename for the user's transcript file
119
+ transcript_file_path = f"{prefix}{coach_code}-{user_id}-transcript.txt"
120
+
121
+ if os.path.exists(transcript_file_path):
122
+ with open(transcript_file_path, "r", encoding="UTF-8") as file:
123
+ transcript = file.read().strip()
124
+ else:
125
+ transcript = ""
126
+
127
+ assistant = client.beta.assistants.create(
128
+ name="Summarizer_Bullet",
129
+ instructions=bullet_instructions + transcript,
130
+ model="gpt-4o"
131
+ )
132
+
133
+ assistant_id = assistant.id
134
+
135
+ # Create a conversation thread with the assistant
136
+ thread = client.beta.threads.create(
137
+ messages=[
138
+ {
139
+ "role": "user",
140
+ "content": " ", # Start the thread with a greeting message. CANNOT BE EMPTY ""
141
+ }
142
+ ]
143
+ )
144
+
145
+ # Start a run to get the assistant's reply
146
+ run = client.beta.threads.runs.create(
147
+ thread_id=thread.id,
148
+ assistant_id=assistant.id
149
+ # The 'instructions' parameter is commented out, but indicates what kind of responses are expected from the assistant.
150
+ )
151
+
152
+ # Function to wait for the run to complete before fetching the response
153
+ def wait_on_run(run, thread):
154
+ while run.status == "queued" or run.status == "in_progress":
155
+ # Poll for the run's completion status
156
+ run = client.beta.threads.runs.retrieve(
157
+ thread_id=thread.id,
158
+ run_id=run.id,
159
+ )
160
+ time.sleep(0.5) # Sleep for 0.5 second between each poll to avoid hammering the API
161
+ return run
162
 
163
+ # Call the function to wait for the run to complete
164
+ run = wait_on_run(run, thread)
165
+
166
+ # Get the messages from the thread
167
+ messages = client.beta.threads.messages.list(
168
+ thread_id=thread.id
169
+ )
170
+
171
+ # Print out all messages in reverse order (to show the conversation flow correctly)
172
+ for message in reversed(messages.data):
173
+ try:
174
+ print(message.content[0].text.value)
175
+ except (IndexError, AttributeError) as e:
176
+ print(f"An error occurred while accessing message content: {e}")
177
+
178
+ # Open the file for appending messages
179
+ with open(user_summ_file_bullet, "a", encoding="UTF-8") as file:
180
+ # Add a separator between previous and new bullet points
181
+ file.write("\n--- New Conversation ---")
182
+
183
+ # Loop through each message and append its contents
184
+ for message in reversed(messages.data):
185
+ try:
186
+ # Attempt to write message content
187
+ file.write(message.content[0].text.value + "\n")
188
+ except IndexError:
189
+ # Handle cases where message.content list is not as expected
190
+ file.write("\n")
191
+ except AttributeError:
192
+ # Handle cases where .text or .value attributes are not present
193
+ file.write("An error occurred while accessing message text attributes.\n")
194
+
195
+ client.beta.assistants.delete(assistant_id)
196
+
197
+ # Delete the TRANSCRIPT file
198
+ if os.path.exists(f"{prefix}{coach_code}-{user_id}-transcript.txt"):
199
+ os.remove(f"{prefix}{coach_code}-{user_id}-transcript.txt")
200
+
201
+ user_id = "NOTLOGGEDIN"
202
+ ############################## END OF SUMMARIZER ASSISTANT
203
+
204
+
205
+ ############################## USER INACTIVITY CHECK
206
+ # Function to keep checking for user inactivity
207
+ def check_for_inactivity():
208
+ global last_interaction_time, user_id, USER_TIMEOUT
209
+ while True:
210
+ time.sleep(CHECK_INTERVAL)
211
+ current_time = time.time()
212
+ if current_time - last_interaction_time > USER_TIMEOUT and os.path.exists(f"{prefix}{coach_code}-{user_id}-transcript.txt") and user_id is not None:
213
+ on_timeout(user_id)
214
+ # Reset the last interaction time (WHY???)
215
+ # last_interaction_time = current_time
216
+
217
+ # Initialize and start the inactivity check thread
218
+ inactivity_thread = threading.Thread(target=check_for_inactivity)
219
+ inactivity_thread.daemon = True
220
+ inactivity_thread.start()
221
+
222
+ ############### CHAT ###################
223
  def predict(user_input, history):
224
+ max_length = 2000
225
+ if len(user_input) > max_length:
226
+ user_input = ""
227
 
228
+ if user_input == tx:
229
  try:
230
+ # Read the contents of the user_hist_file
231
+ with open(user_hist_file, "r", encoding="UTF-8") as file:
232
+ file_contents = file.read()
233
+
234
+ # Yield the file contents as chat output
235
+ yield file_contents
236
+ return
237
  except FileNotFoundError:
238
+ yield "File '" + user_hist_file + "' not found."
239
+ return
240
  elif len(user_input) > max_length:
241
+ raise gr.Error(f"Input is TOO LONG. Max length is {max_length} characters. Try again.")
242
+
243
+ global last_interaction_time, user_id, last_file_mod_time
244
+ # ... [other global variables that are used]
245
+
246
+ # Update the last interaction time
247
+ last_interaction_time = time.time()
248
+
249
+ user_hist_file = f"{prefix}{coach_code}-{user_id}.txt"
250
+ pics_file_path = f"{prefix}{coach_code}-{user_id}-pics.txt"
251
 
252
+ if user_id == "NOTLOGGEDIN":
253
+ raise gr.Error(f"You must be LOGGED IN to Chat. Refresh the page and try again.")
254
+ if user_id == "":
255
+ raise gr.Error(f"You must be LOGGED IN to Chat. Refresh the page and try again.")
256
+ if user_id == None:
257
+ raise gr.Error(f"You must be LOGGED IN to Chat. Refresh the page and try again.")
258
+ if user_hist_file == prefix + coach_code + "-None.txt":
259
+ raise gr.Error(f"You must be LOGGED IN to Chat. Refresh the page and try again.")
260
+ if user_hist_file == prefix + coach_code + "-.txt":
261
+ raise gr.Error(f"You must be LOGGED IN to Chat. Refresh the page and try again.")
262
+
263
+ # Determine appropriate system prompt based on new or returning user
264
+ # This is a placeholder line, replace it with your actual function logic that creates the prompt message
265
+ system_prompt = get_system_prompt(user_id)
266
+
267
+ history_openai_format = system_prompt
268
  for human, assistant in history:
269
+ history_openai_format.append({"role": "user", "content": human })
270
+ history_openai_format.append({"role": "assistant", "content":assistant})
271
  history_openai_format.append({"role": "user", "content": user_input})
272
 
273
  completion = client.chat.completions.create(
274
  model=openai_model,
275
+ messages= history_openai_format,
276
+ temperature=1.0,
277
  frequency_penalty=0.4,
278
  presence_penalty=0.1,
279
  stream=True
280
  )
281
 
282
  output_stream = ""
283
+ for chunk in completion:
284
+ if chunk.choices[0].delta.content is not None:
285
+ output_stream = output_stream + (chunk.choices[0].delta.content)
286
+ yield output_stream
287
+ message_content = output_stream
288
+
289
+ # Prepare the transcript for the Textbox output
290
+ transcript_file_path = f"{prefix}{coach_code}-{user_id}-transcript.txt"
291
+ if os.path.exists(transcript_file_path):
292
+ with open(transcript_file_path, "r", encoding="UTF-8") as file:
293
+ transcript = file.read()
294
+ else:
295
+ transcript = "START OF CONVERSATION - Date/Time: " + datetime.now().strftime("%Y-%m-%d %H:%M:%S") + "\n\n"
296
 
297
  # Append latest user and assistant messages to the transcript
298
+ transcript += f"YOU: {user_input}\n"
299
+ transcript += f"{coach_name_upper}: {message_content}\n\n"
300
+
301
  # Write the updated transcript to the file
302
+ with open(transcript_file_path, "w", encoding="UTF-8") as file:
303
  file.write(transcript)
304
 
305
+ # Get the last exchange (the user input and the assistant's message)
306
+ last_exchange = f"User: {user_input}\nAssistant: {message_content}\n\n"
307
+
308
+ # Write the last exchange to the history file
309
+ with open(user_hist_file, "a+", encoding="UTF-8") as file:
310
+ file.write(last_exchange)
311
+ return message_content, transcript
312
+
313
+ # Function to update transcript
314
+ def update_transcript(transcript_update, user_id):
315
+ transcript_file_path = f"{prefix}{coach_code}-{user_id}-transcript.txt"
316
+ if os.path.exists(transcript_file_path):
317
+ with open(transcript_file_path, "r", encoding="UTF-8") as file:
318
+ transcript = file.read()
319
+ else:
320
+ transcript = "START OF CONVERSATION - Date/Time: " + datetime.now().strftime("%Y-%m-%d %H:%M:%S") + "\n\n"
321
+ transcript += transcript_update
322
+ with open(transcript_file_path, "w", encoding="UTF-8") as file:
323
+ file.write(transcript)
324
+ return transcript
325
+
326
+ def get_user_summary(name):
327
+ global user_id
328
+ name_cap = str(name)
329
+ user_id = name.strip().upper().replace(" ", "")
330
+ name_cap = name_cap.title()
331
+ summary = "Welcome! Please proceed to the '" + coach_name_long + "' tab (at top of chatbot) to chat."
332
+ user_summ_file = f"{prefix}{coach_code}-{user_id}-summ.txt"
333
+ if os.path.exists(user_summ_file):
334
+ with open(user_summ_file, "r", encoding="UTF-8") as file:
335
+ summary = file.read().strip()
336
+ summary = summary.replace("User", "Client")
337
+ summary = summary.replace("user", "Client")
338
+ summary = summary.replace("the assistant", coach_name_short)
339
+ summary = summary.replace("The assistant", coach_name_short)
340
+ summary = summary.replace("- Assistant", "- Coach")
341
+ summary = f"COACH: {coach_name_short}\n\nLAST ENCOUNTER: {summary}"
342
+ return "Welcome! Please proceed to the '" + coach_name_long + "' tab (at top of chatbot) to chat", summary, admin()
343
+
344
+ def admin():
345
+ if user_id == "POIPOIPOI":
346
+ # Set the directory path
347
+ directory_path = "data" # different on huggingface
348
+
349
+ # Get a list of all files in the directory
350
+ file_list = os.listdir(directory_path)
351
+
352
+ # Print the list of files
353
+ for file_name in file_list:
354
+ print(file_name)
355
 
356
  #GUI
357
+ with gr.Blocks(theme) as demo:
358
+ output_choice = gr.State('Text') # Set 'Text' as the default state value
359
+
360
+ with gr.Tabs() as tabs:
361
+ with gr.TabItem("Log In"):
362
+ username_input = gr.Textbox(label="Username (REQUIRED):", placeholder="Enter your USERNAME", type="text")
363
+ password_input = gr.Textbox(label="Emailed Code (REQUIRED):", placeholder="Enter CODE from your email", type="password")
364
+
365
+ # The submit_name function will expect two inputs
366
+ name = ""
367
+ password = ""
368
+
369
+ def submit_name(name, password):
370
+ name = name + "7777"
371
+ pwd = password
372
+ if name != pwd:
373
+ name = "NOTLOGGEDIN"
374
+ raise gr.Error(f"You must be LOGGED IN to Chat. Refresh the page, log in, and try again.")
375
+ if name == "":
376
+ name = "NOTLOGGEDIN"
377
+ raise gr.Error(f"You must be LOGGED IN to Chat. Refresh the page, log in, and try again.")
378
+ else:
379
+ name = name[:-4]
380
+ user_summary = get_user_summary(name)
381
+ return user_summary[0] if isinstance(user_summary, tuple) else user_summary
382
+
383
+ submit_name_button = gr.Button("Log in")
384
+ status_text = gr.Label(label="", container=False)
385
+
386
+ submit_name_button.click(
387
+ fn=submit_name,
388
+ inputs=[username_input, password_input],
389
+ outputs=[status_text]
390
+ )
391
+
392
+ # Attach submit event to both the username and password fields
393
+ username_input.submit(
394
+ fn=submit_name,
395
+ inputs=[username_input, password_input],
396
+ outputs=[status_text]
397
+ )
398
+
399
+ # Make sure this is done for the password field as well
400
+ password_input.submit(
401
+ fn=submit_name,
402
+ inputs=[username_input, password_input],
403
+ outputs=[status_text]
404
+ )
405
+
406
+ with gr.TabItem(coach_name_long):
407
+ gr.ChatInterface(
408
+ predict,
409
+ submit_btn="Chat with " + coach_name_short,
410
+ retry_btn=None,
411
+ undo_btn=None,
412
+ clear_btn=None,
413
+ css=".gradio-container {height: 1600px !important;}" # Add custom CSS
414
+ )
415
+
416
  demo.launch(show_api=False)