@aj-archipelago/cortex 1.3.4 → 1.3.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (99) hide show
  1. package/helper-apps/cortex-autogen/agents.py +90 -20
  2. package/helper-apps/cortex-realtime-voice-server/.env.sample +6 -0
  3. package/helper-apps/cortex-realtime-voice-server/README.md +22 -0
  4. package/helper-apps/cortex-realtime-voice-server/bun.lockb +0 -0
  5. package/helper-apps/cortex-realtime-voice-server/client/bun.lockb +0 -0
  6. package/helper-apps/cortex-realtime-voice-server/client/index.html +12 -0
  7. package/helper-apps/cortex-realtime-voice-server/client/package.json +65 -0
  8. package/helper-apps/cortex-realtime-voice-server/client/postcss.config.js +6 -0
  9. package/helper-apps/cortex-realtime-voice-server/client/public/favicon.ico +0 -0
  10. package/helper-apps/cortex-realtime-voice-server/client/public/index.html +43 -0
  11. package/helper-apps/cortex-realtime-voice-server/client/public/logo192.png +0 -0
  12. package/helper-apps/cortex-realtime-voice-server/client/public/logo512.png +0 -0
  13. package/helper-apps/cortex-realtime-voice-server/client/public/manifest.json +25 -0
  14. package/helper-apps/cortex-realtime-voice-server/client/public/robots.txt +3 -0
  15. package/helper-apps/cortex-realtime-voice-server/client/public/sounds/connect.mp3 +0 -0
  16. package/helper-apps/cortex-realtime-voice-server/client/public/sounds/disconnect.mp3 +0 -0
  17. package/helper-apps/cortex-realtime-voice-server/client/src/App.test.tsx +9 -0
  18. package/helper-apps/cortex-realtime-voice-server/client/src/App.tsx +126 -0
  19. package/helper-apps/cortex-realtime-voice-server/client/src/SettingsModal.tsx +207 -0
  20. package/helper-apps/cortex-realtime-voice-server/client/src/chat/Chat.tsx +553 -0
  21. package/helper-apps/cortex-realtime-voice-server/client/src/chat/ChatBubble.tsx +22 -0
  22. package/helper-apps/cortex-realtime-voice-server/client/src/chat/ChatBubbleLeft.tsx +22 -0
  23. package/helper-apps/cortex-realtime-voice-server/client/src/chat/ChatBubbleRight.tsx +21 -0
  24. package/helper-apps/cortex-realtime-voice-server/client/src/chat/ChatMessage.tsx +27 -0
  25. package/helper-apps/cortex-realtime-voice-server/client/src/chat/ChatMessageInput.tsx +74 -0
  26. package/helper-apps/cortex-realtime-voice-server/client/src/chat/ChatTile.tsx +211 -0
  27. package/helper-apps/cortex-realtime-voice-server/client/src/chat/audio/SoundEffects.ts +56 -0
  28. package/helper-apps/cortex-realtime-voice-server/client/src/chat/audio/WavPacker.ts +112 -0
  29. package/helper-apps/cortex-realtime-voice-server/client/src/chat/audio/WavRecorder.ts +571 -0
  30. package/helper-apps/cortex-realtime-voice-server/client/src/chat/audio/WavStreamPlayer.ts +290 -0
  31. package/helper-apps/cortex-realtime-voice-server/client/src/chat/audio/analysis/AudioAnalysis.ts +186 -0
  32. package/helper-apps/cortex-realtime-voice-server/client/src/chat/audio/analysis/constants.ts +59 -0
  33. package/helper-apps/cortex-realtime-voice-server/client/src/chat/audio/worklets/AudioProcessor.ts +214 -0
  34. package/helper-apps/cortex-realtime-voice-server/client/src/chat/audio/worklets/StreamProcessor.ts +183 -0
  35. package/helper-apps/cortex-realtime-voice-server/client/src/chat/components/AudioVisualizer.tsx +151 -0
  36. package/helper-apps/cortex-realtime-voice-server/client/src/chat/components/CopyButton.tsx +32 -0
  37. package/helper-apps/cortex-realtime-voice-server/client/src/chat/components/ImageOverlay.tsx +166 -0
  38. package/helper-apps/cortex-realtime-voice-server/client/src/chat/components/MicrophoneVisualizer.tsx +95 -0
  39. package/helper-apps/cortex-realtime-voice-server/client/src/chat/components/ScreenshotCapture.tsx +116 -0
  40. package/helper-apps/cortex-realtime-voice-server/client/src/chat/hooks/useWindowResize.ts +27 -0
  41. package/helper-apps/cortex-realtime-voice-server/client/src/chat/utils/audio.ts +33 -0
  42. package/helper-apps/cortex-realtime-voice-server/client/src/index.css +20 -0
  43. package/helper-apps/cortex-realtime-voice-server/client/src/index.tsx +19 -0
  44. package/helper-apps/cortex-realtime-voice-server/client/src/logo.svg +1 -0
  45. package/helper-apps/cortex-realtime-voice-server/client/src/react-app-env.d.ts +1 -0
  46. package/helper-apps/cortex-realtime-voice-server/client/src/reportWebVitals.ts +15 -0
  47. package/helper-apps/cortex-realtime-voice-server/client/src/setupTests.ts +5 -0
  48. package/helper-apps/cortex-realtime-voice-server/client/src/utils/logger.ts +45 -0
  49. package/helper-apps/cortex-realtime-voice-server/client/tailwind.config.js +14 -0
  50. package/helper-apps/cortex-realtime-voice-server/client/tsconfig.json +30 -0
  51. package/helper-apps/cortex-realtime-voice-server/client/vite.config.ts +22 -0
  52. package/helper-apps/cortex-realtime-voice-server/index.ts +19 -0
  53. package/helper-apps/cortex-realtime-voice-server/package.json +28 -0
  54. package/helper-apps/cortex-realtime-voice-server/src/ApiServer.ts +35 -0
  55. package/helper-apps/cortex-realtime-voice-server/src/SocketServer.ts +769 -0
  56. package/helper-apps/cortex-realtime-voice-server/src/Tools.ts +546 -0
  57. package/helper-apps/cortex-realtime-voice-server/src/cortex/expert.ts +29 -0
  58. package/helper-apps/cortex-realtime-voice-server/src/cortex/image.ts +29 -0
  59. package/helper-apps/cortex-realtime-voice-server/src/cortex/memory.ts +89 -0
  60. package/helper-apps/cortex-realtime-voice-server/src/cortex/reason.ts +29 -0
  61. package/helper-apps/cortex-realtime-voice-server/src/cortex/search.ts +30 -0
  62. package/helper-apps/cortex-realtime-voice-server/src/cortex/style.ts +31 -0
  63. package/helper-apps/cortex-realtime-voice-server/src/cortex/utils.ts +94 -0
  64. package/helper-apps/cortex-realtime-voice-server/src/cortex/vision.ts +34 -0
  65. package/helper-apps/cortex-realtime-voice-server/src/realtime/client.ts +484 -0
  66. package/helper-apps/cortex-realtime-voice-server/src/realtime/realtimeTypes.ts +279 -0
  67. package/helper-apps/cortex-realtime-voice-server/src/realtime/socket.ts +27 -0
  68. package/helper-apps/cortex-realtime-voice-server/src/realtime/transcription.ts +75 -0
  69. package/helper-apps/cortex-realtime-voice-server/src/realtime/utils.ts +33 -0
  70. package/helper-apps/cortex-realtime-voice-server/src/utils/logger.ts +45 -0
  71. package/helper-apps/cortex-realtime-voice-server/src/utils/prompt.ts +81 -0
  72. package/helper-apps/cortex-realtime-voice-server/tsconfig.json +28 -0
  73. package/package.json +1 -1
  74. package/pathways/basePathway.js +3 -1
  75. package/pathways/system/entity/memory/sys_memory_manager.js +3 -0
  76. package/pathways/system/entity/memory/sys_memory_update.js +43 -45
  77. package/pathways/system/entity/memory/sys_read_memory.js +86 -6
  78. package/pathways/system/entity/memory/sys_search_memory.js +66 -0
  79. package/pathways/system/entity/shared/sys_entity_constants.js +1 -1
  80. package/pathways/system/entity/sys_entity_continue.js +2 -1
  81. package/pathways/system/entity/sys_entity_start.js +13 -2
  82. package/pathways/system/entity/sys_generator_ack.js +2 -2
  83. package/pathways/system/entity/sys_generator_expert.js +0 -2
  84. package/pathways/system/entity/sys_generator_memory.js +31 -0
  85. package/pathways/system/entity/sys_generator_quick.js +22 -7
  86. package/pathways/system/entity/sys_generator_reasoning.js +1 -1
  87. package/pathways/system/entity/sys_generator_results.js +20 -16
  88. package/pathways/system/entity/sys_generator_voice_filler.js +1 -1
  89. package/pathways/system/entity/sys_generator_voice_sample.js +36 -0
  90. package/pathways/system/entity/sys_router_tool.js +13 -10
  91. package/pathways/system/sys_parse_numbered_object_list.js +1 -1
  92. package/server/pathwayResolver.js +41 -31
  93. package/server/plugins/azureVideoTranslatePlugin.js +28 -16
  94. package/server/plugins/claude3VertexPlugin.js +0 -9
  95. package/server/plugins/gemini15ChatPlugin.js +18 -5
  96. package/server/plugins/modelPlugin.js +27 -6
  97. package/server/plugins/openAiChatPlugin.js +10 -8
  98. package/server/plugins/openAiVisionPlugin.js +56 -0
  99. package/tests/memoryfunction.test.js +73 -1
@@ -19,6 +19,8 @@ import threading
19
19
  import shutil
20
20
 
21
21
  human_input_queues = {}
22
+ human_input_text_queues = {}
23
+ request_stored_message_queues = {}
22
24
  def background_human_input_check(request_id):
23
25
  while True:
24
26
  human_input = check_for_human_input(request_id)
@@ -26,8 +28,20 @@ def background_human_input_check(request_id):
26
28
  human_input_queues[request_id].put(human_input)
27
29
  if human_input in ["TERMINATE", "PAUSE"]:
28
30
  break
31
+ else:
32
+ if not human_input_text_queues.get(request_id):
33
+ human_input_text_queues[request_id] = queue.Queue()
34
+ human_input_text_queues[request_id].put(human_input)
29
35
  time.sleep(1)
30
36
 
37
+
38
+ def get_message_with_user_input(message, request_id):
39
+ human_input_text = ""
40
+ if human_input_text_queues.get(request_id):
41
+ while not human_input_text_queues[request_id].empty():
42
+ human_input_text += " " + human_input_text_queues[request_id].get()
43
+ return message + human_input_text
44
+
31
45
  def get_request_temp_dir(request_id):
32
46
  if not request_id:
33
47
  logging.warning("No request_id provided!")
@@ -100,6 +114,7 @@ def chat_with_agents(**kwargs):
100
114
  original_request_message = kwargs.pop("original_request_message", None)
101
115
  original_request_message_data = kwargs.pop("original_request_message_data", None)
102
116
 
117
+
103
118
  llm_config = kwargs.pop("llm_config", None)
104
119
  request_id = kwargs.pop("request_id", None)
105
120
  chat_publish_progress = kwargs.pop("chat_publish_progress", None)
@@ -137,13 +152,14 @@ def chat_with_agents(**kwargs):
137
152
  assistant.send = create_send_function(assistant)
138
153
  user_proxy.send = create_send_function(user_proxy)
139
154
 
155
+ message_with_possible_human_input = get_message_with_user_input(message, request_id)
156
+
140
157
  chat_result = user_proxy.initiate_chat(
141
158
  assistant,
142
- message=message,
159
+ message=message_with_possible_human_input,
143
160
  )
144
161
 
145
162
 
146
-
147
163
  code_msg = find_code_message(all_messages)
148
164
  if code_msg:
149
165
  try:
@@ -155,12 +171,20 @@ def chat_with_agents(**kwargs):
155
171
  index_message({
156
172
  "requestId": request_id,
157
173
  "content":corrector_result, #code_msg,
158
- "task": original_request_message,
174
+ "task": get_message_with_user_input(original_request_message,request_id),
159
175
  "contextId": original_request_message_data.get("contextId"),
160
176
  })
161
177
  except Exception as e:
162
178
  logging.error(f"Error extracting code corrector result: {e}")
163
179
 
180
+ try:
181
+ request_stored_message_queues[request_id].put(all_messages[-2]["message"] or all_messages[-2]["content"])
182
+ request_stored_message_queues[request_id].put(all_messages[-1]["message"] or all_messages[-1]["content"])
183
+ except Exception as e:
184
+ logging.error(f"Error storing messages in queue: {e}")
185
+
186
+
187
+
164
188
  if return_type == "chat_history":
165
189
  return chat_result.chat_history
166
190
  if return_type == "chat_result":
@@ -175,7 +199,6 @@ def chat_with_agents(**kwargs):
175
199
  return chat_result
176
200
 
177
201
 
178
-
179
202
  def logged_send(sender, original_send, message, recipient, request_reply=None, silent=True, request_id=None, chat_publish_progress=None, all_messages=None):
180
203
  if not message:
181
204
  logging.info("Empty message, skipping!")
@@ -214,15 +237,19 @@ def logged_send(sender, original_send, message, recipient, request_reply=None, s
214
237
  return logged_send(sender, original_send, new_input, recipient, request_reply, silent)
215
238
  logging.info("Pause timeout, ending conversation")
216
239
  raise Exception("Conversation ended due to pause timeout")
240
+
241
+ #if not terminate or pause, then it's text input from human
217
242
  logging.info(f"Human input to {recipient.name}: {human_input}")
218
- return original_send(human_input, recipient, request_reply, silent)
243
+ #need to update original message with human input
244
+ new_input = message + human_input
245
+ return original_send(new_input, recipient, request_reply, silent)
219
246
 
220
247
  logging.info(f"Message from {sender.name} to {recipient.name}: {message}")
221
248
 
222
249
  return original_send(message, recipient, request_reply, silent)
223
250
 
224
251
 
225
- def process_message(original_request_message_data, original_request_message_data_obj):
252
+ def process_message(original_request_message_data, original_request_message_data_obj, first_run=True):
226
253
  try:
227
254
  all_messages = []
228
255
  started_at = datetime.now()
@@ -230,9 +257,15 @@ def process_message(original_request_message_data, original_request_message_data
230
257
  original_request_message = original_request_message_data['message']
231
258
 
232
259
  human_input_queues[request_id] = queue.Queue()
233
- thread = threading.Thread(target=background_human_input_check, args=(request_id,))
234
- thread.daemon = True
235
- thread.start()
260
+ human_input_text_queues[request_id] = queue.Queue()
261
+ if not request_stored_message_queues.get(request_id):
262
+ request_stored_message_queues[request_id] = queue.Queue()
263
+ request_stored_message_queues[request_id].put(original_request_message)
264
+
265
+ if first_run:
266
+ thread = threading.Thread(target=background_human_input_check, args=(request_id,))
267
+ thread.daemon = True
268
+ thread.start()
236
269
 
237
270
  final_msg = process_message_safe(original_request_message_data, original_request_message_data_obj, original_request_message, all_messages, request_id, started_at)
238
271
 
@@ -252,6 +285,44 @@ def process_message(original_request_message_data, original_request_message_data
252
285
  publish_request_progress(finalData)
253
286
  store_in_mongo(finalData)
254
287
 
288
+ #wait for any human input before terminating
289
+ #if you receive human input start the conversation again
290
+ for i in range(31*6): # 30+1 minutes
291
+ if human_input_queues[request_id].empty():
292
+ time.sleep(1)
293
+ else:
294
+ human_input = human_input_queues[request_id].get()
295
+ if human_input:
296
+ logging.info(f"Human input to assistant: {human_input}")
297
+ #update request with human input
298
+ new_message_data = original_request_message_data.copy()
299
+
300
+ old_task = original_request_message_data.get("message")
301
+
302
+ #get request_stored_message_queues
303
+ old_messages = []
304
+ if request_stored_message_queues.get(request_id):
305
+ while not request_stored_message_queues[request_id].empty():
306
+ old_messages.append(request_stored_message_queues[request_id].get())
307
+
308
+
309
+ #convert to text, limit to max 2000 characters, keep most recent
310
+ old_messages_text = "\n".join(old_messages)
311
+ old_messages_text = old_messages_text[-2000:]
312
+
313
+
314
+ new_message_data['message'] = f"NEW TASK: {human_input}\n\nPREV TASK: {old_task} STUFF DONE IN PREV TASK: {old_messages_text}\n\n{final_msg}\n\n"
315
+ new_message_data['keywords'] = ''
316
+ # new_message_data_obj = original_request_message_data_obj.copy()
317
+ # new_message_data_obj['message'] = new_message_data['message']
318
+
319
+
320
+
321
+ process_message(new_message_data, original_request_message_data_obj, first_run=False)
322
+ return
323
+
324
+ logging.info(f"Task completed, task:\n{get_message_with_user_input(original_request_message,request_id)},\nresult: {final_msg}")
325
+
255
326
 
256
327
  except Exception as e:
257
328
  logging.error(f"Error processing message: {str(e)}")
@@ -292,7 +363,6 @@ def process_message(original_request_message_data, original_request_message_data
292
363
  logging.error(f"Error cleaning up: {str(e)}")
293
364
 
294
365
 
295
-
296
366
  def process_message_safe(original_request_message_data, original_request_message_data_obj, original_request_message, all_messages, request_id, started_at):
297
367
  config_list = config_list_from_json(env_or_file="OAI_CONFIG_LIST")
298
368
  llm_config = {
@@ -342,10 +412,10 @@ def process_message_safe(original_request_message_data, original_request_message
342
412
 
343
413
 
344
414
  preparer = AssistantAgent("preparer", llm_config=llm_config, system_message=prompts.get("PLANNER_SYSTEM_MESSAGE"))
345
- prepared_plan = preparer.generate_reply(messages=[{"content": original_request_message, "role":"user"}])
415
+ prepared_plan = preparer.generate_reply(messages=[{"content": get_message_with_user_input(original_request_message,request_id), "role":"user"}])
346
416
 
347
417
  helper_decider = AssistantAgent("helper_decider", llm_config=llm_config, system_message=prompts.get("HELPER_DECIDER_SYSTEM_MESSAGE"))
348
- helper_decider_result = helper_decider.generate_reply(messages=[{"content": original_request_message, "role":"user"}])
418
+ helper_decider_result = helper_decider.generate_reply(messages=[{"content": get_message_with_user_input(original_request_message,request_id), "role":"user"}])
349
419
 
350
420
  try:
351
421
  helper_decider_result = json.loads(helper_decider_result)
@@ -361,17 +431,17 @@ def process_message_safe(original_request_message_data, original_request_message
361
431
  context += f"\n#SECTION_OF_OLD_TASK_CODE_INFO_START:\nHere's code/info from old-tasks that might help:\n{search_index(code_keywords)}\n#SECTION_OF_OLD_TASK_CODE_INFO_END\n"
362
432
 
363
433
  if helper_decider_result.get("bing_search"):
364
- bing_search_message = f"Search Bing for more information on the task: {original_request_message}, prepared draft plan to solve task: {prepared_plan}"
434
+ bing_search_message = f"Search Bing for more information on the task: {get_message_with_user_input(original_request_message,request_id)}, prepared draft plan to solve task: {prepared_plan}"
365
435
  result = chat(prompts.get("BING_SEARCH_PROMPT"), bing_search_message)
366
436
  context += f"\n\nBing search results: {result}"
367
437
 
368
438
  if helper_decider_result.get("cognitive_search"):
369
- cognitive_search_message = f"Search cognitive index for more information on the task: {original_request_message}."
439
+ cognitive_search_message = f"Search cognitive index for more information on the task: {get_message_with_user_input(original_request_message,request_id)}."
370
440
  result = chat(prompts.get("COGNITIVE_SEARCH_PROMPT"), cognitive_search_message)
371
441
  context += f"\n\nCognitive search results: {result}"
372
442
 
373
443
 
374
- context = process_helper_results(helper_decider_result, original_request_message, context, chat)
444
+ context = process_helper_results(helper_decider_result, get_message_with_user_input(original_request_message,request_id), context, chat)
375
445
 
376
446
  context_message = ""
377
447
  if context:
@@ -379,7 +449,7 @@ def process_message_safe(original_request_message_data, original_request_message
379
449
 
380
450
 
381
451
  check_message = f"""
382
- Task: \n{original_request_message}\n\n
452
+ Task: \n{get_message_with_user_input(original_request_message,request_id)}\n\n
383
453
  Context to check if task can be considered completed: {context_message}\n\n
384
454
  """
385
455
 
@@ -389,7 +459,7 @@ Context to check if task can be considered completed: {context_message}\n\n
389
459
  chat_result = None
390
460
  if check_result != "DONE":
391
461
  message = f"""
392
- Your task is to complete the following: \n{original_request_message}\n\n"
462
+ Your task is to complete the following: \n{get_message_with_user_input(original_request_message,request_id)}\n\n"
393
463
  Here is a draft plan to solve the task: \n{prepared_plan}\n\n
394
464
  {context_message}
395
465
  You don't have to follow the plan, it's just a suggestion.
@@ -404,7 +474,7 @@ Do your best to complete the task, user expects you to continue original task re
404
474
  presenter_messages_context = context_message
405
475
  presenter_message = f"""
406
476
  Here is everything done in order to complete the task: {presenter_messages_context}\n\n
407
- Original task was: {original_request_message}\n\n
477
+ Original task was: {get_message_with_user_input(original_request_message,request_id)}\n\n
408
478
  Reply to it with task result, do not forget that user expects you continue original task request conversation:\n\n
409
479
  """
410
480
 
@@ -418,6 +488,6 @@ Reply to it with task result, do not forget that user expects you continue origi
418
488
  final_msg += f"\n\n[Download all files of this task]({zip_url})"
419
489
 
420
490
 
421
- print(f"Task completed, task:\n{original_request_message},\nresult: {final_msg}")
422
- logging.info(f"Task completed, task:\n{original_request_message},\nresult: {final_msg}")
491
+ print(f"Task completed, task:\n{get_message_with_user_input(original_request_message,request_id)},\nresult: {final_msg}")
492
+ logging.info(f"Task completed, task:\n{get_message_with_user_input(original_request_message,request_id)},\nresult: {final_msg}")
423
493
  return final_msg
@@ -0,0 +1,6 @@
1
+ CORTEX_API_KEY=...
2
+ CORTEX_DEV_API_KEY=...
3
+ OPENAI_API_KEY=...
4
+ CORS_HOSTS='["http://localhost:3000"]'
5
+ PORT=8081
6
+ VOICE_LIB_DEBUG=false
@@ -0,0 +1,22 @@
1
+ # cortex-realtime-voice
2
+
3
+ To install dependencies:
4
+
5
+ ```bash
6
+ bun install
7
+ ```
8
+
9
+ To run:
10
+
11
+ ```bash
12
+ cd client
13
+ bun run build
14
+ cd ..
15
+ bun run start
16
+ ```
17
+
18
+ To run in production:
19
+
20
+ ```bash
21
+ bun run start:prod
22
+ ```
@@ -0,0 +1,12 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>Cortex Realtime Voice</title>
7
+ </head>
8
+ <body>
9
+ <div id="root"></div>
10
+ <script type="module" src="/src/index.tsx"></script>
11
+ </body>
12
+ </html>
@@ -0,0 +1,65 @@
1
+ {
2
+ "name": "client",
3
+ "version": "0.1.0",
4
+ "private": true,
5
+ "dependencies": {
6
+ "@emotion/react": "^11.14.0",
7
+ "@emotion/styled": "^11.14.0",
8
+ "@mui/icons-material": "^6.2.0",
9
+ "@mui/material": "^6.2.0",
10
+ "@tailwindcss/typography": "^0.5.15",
11
+ "katex": "^0.16.15",
12
+ "react": "^19.0.0",
13
+ "react-dom": "^19.0.0",
14
+ "react-markdown": "^9.0.1",
15
+ "react-spinners": "0.15.0",
16
+ "react-syntax-highlighter": "^15.6.1",
17
+ "rehype-katex": "^7.0.1",
18
+ "rehype-raw": "^7.0.0",
19
+ "remark-gfm": "^4.0.0",
20
+ "remark-math": "^6.0.0",
21
+ "socket.io-client": "4.8.1",
22
+ "typescript": "^4.4.2",
23
+ "web-vitals": "^2.1.0"
24
+ },
25
+ "devDependencies": {
26
+ "@babel/plugin-proposal-private-property-in-object": "7.21.11",
27
+ "@testing-library/jest-dom": "^5.14.1",
28
+ "@testing-library/react": "^13.0.0",
29
+ "@testing-library/user-event": "^13.2.1",
30
+ "@types/jest": "^27.0.1",
31
+ "@types/node": "^16.7.13",
32
+ "@types/react": "^18.0.0",
33
+ "@types/react-dom": "^18.0.0",
34
+ "@types/react-syntax-highlighter": "^15.5.13",
35
+ "@vitejs/plugin-react": "^4.3.4",
36
+ "autoprefixer": "^10.4.20",
37
+ "postcss": "^8.4.49",
38
+ "tailwindcss": "^3.4.17",
39
+ "vite": "^6.0.5"
40
+ },
41
+ "scripts": {
42
+ "start": "vite",
43
+ "dev": "vite",
44
+ "build": "vite build",
45
+ "preview": "vite preview"
46
+ },
47
+ "eslintConfig": {
48
+ "extends": [
49
+ "react-app",
50
+ "react-app/jest"
51
+ ]
52
+ },
53
+ "browserslist": {
54
+ "production": [
55
+ ">0.2%",
56
+ "not dead",
57
+ "not op_mini all"
58
+ ],
59
+ "development": [
60
+ "last 1 chrome version",
61
+ "last 1 firefox version",
62
+ "last 1 safari version"
63
+ ]
64
+ }
65
+ }
@@ -0,0 +1,6 @@
1
+ module.exports = {
2
+ plugins: {
3
+ tailwindcss: {},
4
+ autoprefixer: {},
5
+ },
6
+ }
@@ -0,0 +1,43 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
6
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
7
+ <meta name="theme-color" content="#000000" />
8
+ <meta
9
+ name="description"
10
+ content="Chat with the Cortex Realtime Voice Server"
11
+ />
12
+ <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
13
+ <!--
14
+ manifest.json provides metadata used when your web app is installed on a
15
+ user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
16
+ -->
17
+ <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
18
+ <!--
19
+ Notice the use of %PUBLIC_URL% in the tags above.
20
+ It will be replaced with the URL of the `public` folder during the build.
21
+ Only files inside the `public` folder can be referenced from the HTML.
22
+
23
+ Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
24
+ work correctly both with client-side routing and a non-root public URL.
25
+ Learn how to configure a non-root public URL by running `npm run build`.
26
+ -->
27
+ <title>Cortex Realtime Voice</title>
28
+ </head>
29
+ <body>
30
+ <noscript>You need to enable JavaScript to run this app.</noscript>
31
+ <div id="root"></div>
32
+ <!--
33
+ This HTML file is a template.
34
+ If you open it directly in the browser, you will see an empty page.
35
+
36
+ You can add webfonts, meta tags, or analytics to this file.
37
+ The build step will place the bundled scripts into the <body> tag.
38
+
39
+ To begin the development, run `npm start` or `yarn start`.
40
+ To create a production bundle, use `npm run build` or `yarn build`.
41
+ -->
42
+ </body>
43
+ </html>
@@ -0,0 +1,25 @@
1
+ {
2
+ "short_name": "React App",
3
+ "name": "Create React App Sample",
4
+ "icons": [
5
+ {
6
+ "src": "favicon.ico",
7
+ "sizes": "64x64 32x32 24x24 16x16",
8
+ "type": "image/x-icon"
9
+ },
10
+ {
11
+ "src": "logo192.png",
12
+ "type": "image/png",
13
+ "sizes": "192x192"
14
+ },
15
+ {
16
+ "src": "logo512.png",
17
+ "type": "image/png",
18
+ "sizes": "512x512"
19
+ }
20
+ ],
21
+ "start_url": ".",
22
+ "display": "standalone",
23
+ "theme_color": "#000000",
24
+ "background_color": "#ffffff"
25
+ }
@@ -0,0 +1,3 @@
1
+ # https://www.robotstxt.org/robotstxt.html
2
+ User-agent: *
3
+ Disallow:
@@ -0,0 +1,9 @@
1
+ import React from 'react';
2
+ import { render, screen } from '@testing-library/react';
3
+ import App from './App';
4
+
5
+ test('renders learn react link', () => {
6
+ render(<App />);
7
+ const linkElement = screen.getByText(/learn react/i);
8
+ expect(linkElement).toBeInTheDocument();
9
+ });
@@ -0,0 +1,126 @@
1
+ import {useEffect, useState} from 'react';
2
+ import ClipLoader from "react-spinners/ClipLoader";
3
+ import Chat from "./chat/Chat";
4
+ import {SettingsModal} from "./SettingsModal";
5
+ import { SettingsData } from "./SettingsModal";
6
+ import type { Voice } from '../../src/realtime/realtimeTypes';
7
+
8
+ function App() {
9
+ const [loading, setLoading] = useState(true);
10
+ const [userName, setUserName] = useState('');
11
+ const [userId, setUserId] = useState('');
12
+ const [aiName, setAiName] = useState('Jarvis');
13
+ const [settingsOpen, setSettingsOpen] = useState(false);
14
+ const [language, setLanguage] = useState('en');
15
+ const [aiMemorySelfModify, setAiMemorySelfModify] = useState(false);
16
+ const [aiStyle, setAiStyle] = useState('Anthropic');
17
+ const [voice, setVoice] = useState('alloy' as Voice);
18
+
19
+ const onCloseSettings = () => setSettingsOpen(false);
20
+ const onSaveSettings = (settings: SettingsData) => {
21
+ console.log('Saving settings', settings);
22
+ setUserName(settings.userName);
23
+ localStorage.setItem('userName', settings.userName);
24
+
25
+ let newUserId = settings.userId;
26
+ if (!newUserId || newUserId.length === 0) {
27
+ newUserId = Math.random().toString(36).substring(7);
28
+ }
29
+ setUserId(newUserId);
30
+ localStorage.setItem('userId', newUserId);
31
+
32
+ setAiName(settings.aiName);
33
+ localStorage.setItem('aiName', settings.aiName);
34
+
35
+ setLanguage(settings.language);
36
+ localStorage.setItem('language', settings.language);
37
+
38
+ setAiMemorySelfModify(settings.aiMemorySelfModify);
39
+ localStorage.setItem('aiMemorySelfModify', String(settings.aiMemorySelfModify));
40
+
41
+ setAiStyle(settings.aiStyle);
42
+ localStorage.setItem('aiStyle', settings.aiStyle);
43
+
44
+ setVoice(settings.voice as Voice);
45
+ localStorage.setItem('voice', settings.voice);
46
+ };
47
+
48
+ useEffect(() => {
49
+ const name = localStorage.getItem('userName');
50
+ if (name) {
51
+ setUserName(localStorage.getItem('userName') as string);
52
+ } else {
53
+ setSettingsOpen(true);
54
+ }
55
+ const id = localStorage.getItem('userId');
56
+ if (id) {
57
+ setUserId(localStorage.getItem('userId') as string);
58
+ } else {
59
+ setSettingsOpen(true);
60
+ }
61
+ const ai = localStorage.getItem('aiName');
62
+ if (ai) {
63
+ setAiName(localStorage.getItem('aiName') as string);
64
+ } else {
65
+ setSettingsOpen(true);
66
+ }
67
+ const savedLanguage = localStorage.getItem('language');
68
+ if (savedLanguage) setLanguage(savedLanguage);
69
+
70
+ const savedAiMemorySelfModify = localStorage.getItem('aiMemorySelfModify');
71
+ if (savedAiMemorySelfModify) setAiMemorySelfModify(savedAiMemorySelfModify === 'true');
72
+
73
+ const savedAiStyle = localStorage.getItem('aiStyle');
74
+ if (savedAiStyle) setAiStyle(savedAiStyle);
75
+
76
+ const savedVoice = localStorage.getItem('voice');
77
+ if (savedVoice) setVoice(savedVoice as Voice);
78
+
79
+ setLoading(false);
80
+ }, []);
81
+
82
+ if (loading) {
83
+ return (
84
+ <div className="min-h-screen bg-gradient-to-b from-gray-900 via-gray-800 to-gray-900 flex justify-center items-center">
85
+ <ClipLoader color={'#0EA5E9'} loading={true} size={150}/>
86
+ </div>
87
+ );
88
+ }
89
+
90
+ return (
91
+ <div className="h-screen overflow-hidden bg-gradient-to-b from-gray-900 via-gray-800 to-gray-900">
92
+ <button
93
+ className="fixed top-4 right-4 z-10 p-2 text-gray-400 hover:text-cyan-400 transition-colors duration-200"
94
+ onClick={() => setSettingsOpen(true)}
95
+ aria-label="Settings"
96
+ >
97
+ ⚙️
98
+ </button>
99
+
100
+ {userName && userName.length > 0 && (
101
+ <Chat
102
+ userId={userId}
103
+ userName={userName}
104
+ aiName={aiName}
105
+ language={language}
106
+ aiMemorySelfModify={aiMemorySelfModify}
107
+ aiStyle={aiStyle}
108
+ voice={voice}
109
+ />
110
+ )}
111
+ <SettingsModal
112
+ aiName={aiName}
113
+ userName={userName}
114
+ userId={userId}
115
+ voice={voice}
116
+ aiStyle={aiStyle}
117
+ language={language}
118
+ isOpen={settingsOpen}
119
+ onClose={onCloseSettings}
120
+ onSave={onSaveSettings}
121
+ />
122
+ </div>
123
+ );
124
+ }
125
+
126
+ export default App;