sohojoe commited on
Commit
2d6aefc
1 Parent(s): 14a183e

fix: ui_app will start charles_app when not in debug mode

Browse files
Files changed (4) hide show
  1. app_interface_actor.py +25 -2
  2. charles_app.py +2 -0
  3. pid_helper.py +28 -0
  4. ui_app.py +25 -21
app_interface_actor.py CHANGED
@@ -3,7 +3,7 @@ from ray.util.queue import Queue
3
  from ray.actor import ActorHandle
4
  import torch
5
  import numpy as np
6
-
7
 
8
  @ray.remote
9
  class AppInterfaceActor:
@@ -14,6 +14,7 @@ class AppInterfaceActor:
14
  self.video_output_queue = Queue(maxsize=10) # Adjust the size as needed
15
  self.debug_str = ""
16
  self.state = "Initializing"
 
17
 
18
  @staticmethod
19
  def get_singleton():
@@ -77,7 +78,29 @@ class AppInterfaceActor:
77
  shared_tensor = await self.video_input_queue.get_async()
78
  video_frames.append(shared_tensor)
79
  return video_frames
80
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
81
  # debug helpers
82
  async def get_debug_output(self)->str:
83
  return self.debug_str
 
3
  from ray.actor import ActorHandle
4
  import torch
5
  import numpy as np
6
+ import pid_helper
7
 
8
  @ray.remote
9
  class AppInterfaceActor:
 
14
  self.video_output_queue = Queue(maxsize=10) # Adjust the size as needed
15
  self.debug_str = ""
16
  self.state = "Initializing"
17
+ self.charles_app_pids = []
18
 
19
  @staticmethod
20
  def get_singleton():
 
78
  shared_tensor = await self.video_input_queue.get_async()
79
  video_frames.append(shared_tensor)
80
  return video_frames
81
+
82
+ # pid helpers
83
+ async def add_charles_app_pid(self, pid:int):
84
+ self.charles_app_pids.append(pid)
85
+
86
+ async def get_charles_app_pids(self)->[int]:
87
+ # prune dead pids
88
+ running_charles_app_pids = []
89
+ for pid in self.charles_app_pids:
90
+ if pid_helper.is_pid_running(pid):
91
+ running_charles_app_pids.append(pid)
92
+ self.charles_app_pids = running_charles_app_pids
93
+ return self.charles_app_pids
94
+
95
+ async def is_charles_app_running(self)->bool:
96
+ # prune dead pids
97
+ running_charles_app_pids = []
98
+ for pid in self.charles_app_pids:
99
+ if pid_helper.is_pid_running(pid):
100
+ running_charles_app_pids.append(pid)
101
+ self.charles_app_pids = running_charles_app_pids
102
+ return len(self.charles_app_pids) > 0
103
+
104
  # debug helpers
105
  async def get_debug_output(self)->str:
106
  return self.debug_str
charles_app.py CHANGED
@@ -8,6 +8,7 @@ from response_state_manager import ResponseStateManager
8
  from respond_to_prompt_async import RespondToPromptAsync
9
  import asyncio
10
  import subprocess
 
11
 
12
  class CharlesApp:
13
  def __init__(self):
@@ -30,6 +31,7 @@ class CharlesApp:
30
  self.set_state("001 - creating AppInterfaceActor")
31
  from app_interface_actor import AppInterfaceActor
32
  self._app_interface_actor = AppInterfaceActor.get_singleton()
 
33
  self._audio_output_queue = await self._app_interface_actor.get_audio_output_queue.remote()
34
 
35
  self.set_state("002 - creating ResponseStateManager")
 
8
  from respond_to_prompt_async import RespondToPromptAsync
9
  import asyncio
10
  import subprocess
11
+ import pid_helper
12
 
13
  class CharlesApp:
14
  def __init__(self):
 
31
  self.set_state("001 - creating AppInterfaceActor")
32
  from app_interface_actor import AppInterfaceActor
33
  self._app_interface_actor = AppInterfaceActor.get_singleton()
34
+ await self._app_interface_actor.add_charles_app_pid.remote(pid_helper.get_current_pid())
35
  self._audio_output_queue = await self._app_interface_actor.get_audio_output_queue.remote()
36
 
37
  self.set_state("002 - creating ResponseStateManager")
pid_helper.py ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import platform
3
+ import psutil
4
+
5
+ def is_pid_running(pid: int) -> bool:
6
+ system = platform.system()
7
+
8
+ if system == "Linux" or system == "Darwin": # Linux or macOS
9
+ try:
10
+ os.kill(pid, 0)
11
+ return True
12
+ except OSError:
13
+ return False
14
+
15
+ elif system == "Windows":
16
+ try:
17
+ process = psutil.Process(pid)
18
+ return True
19
+ except psutil.NoSuchProcess:
20
+ return False
21
+
22
+ else:
23
+ raise NotImplementedError(f"Unsupported operating system: {system}")
24
+
25
+ def get_current_pid() -> int:
26
+ return os.getpid()
27
+
28
+
ui_app.py CHANGED
@@ -29,6 +29,8 @@ load_dotenv()
29
 
30
  webrtc_ctx = None
31
 
 
 
32
 
33
  @st.cache_resource
34
  def init_ray():
@@ -45,17 +47,6 @@ def init_ray():
45
  else:
46
  ray.init(namespace="project_charles")
47
 
48
- # @st.cache_resource
49
- # def get_charles_actor():
50
- # charles_actor_instance = None
51
- # charles_actor_proc = subprocess.Popen([sys.executable, "charles_actor.py"])
52
- # while charles_actor_instance == None:
53
- # try:
54
- # charles_actor_instance = ray.get_actor("CharlesApp")
55
- # except ValueError as e:
56
- # time.sleep(0.1) # give the subprocess a chance to start
57
- # return charles_actor_instance
58
-
59
  @st.cache_resource
60
  def get_streamlit_av_queue():
61
  from streamlit_av_queue import StreamlitAVQueue
@@ -68,11 +59,16 @@ def get_app_interface_instance():
68
  app_interface_instance = AppInterfaceActor.get_singleton()
69
  return app_interface_instance
70
 
 
 
 
 
 
 
 
71
  async def main():
72
  # Initialize Ray
73
  ray_status = init_ray()
74
- while not ray.is_initialized():
75
- await asyncio.sleep(0.1)
76
  # get ray actors
77
  app_interface_instance = get_app_interface_instance()
78
  await asyncio.sleep(0.1)
@@ -128,17 +124,25 @@ async def main():
128
 
129
  try:
130
  while True:
 
131
  if not webrtc_ctx.state.playing:
132
  system_one_audio_status.write("Camera has stopped.")
133
  await asyncio.sleep(0.1)
134
  continue
135
- # if charles_actor is None:
136
- # system_one_audio_status.write("Looking for Charles actor...")
137
- # charles_actor = get_charles_actor()
138
- # if charles_actor is None:
139
- # await asyncio.sleep(0.1)
140
- # continue
141
- # system_one_audio_status.write("Found Charles actor.")
 
 
 
 
 
 
 
142
  try:
143
  streamlit_av_queue.set_looking_listening(looking, listening)
144
  charles_debug_str = await app_interface_instance.get_debug_output.remote()
@@ -148,7 +152,7 @@ async def main():
148
  except Exception as e:
149
  # assume we disconnected
150
  charles_actor = None
151
- await asyncio.sleep(0.1)
152
 
153
  except Exception as e:
154
  print(f"An error occurred: {e}")
 
29
 
30
  webrtc_ctx = None
31
 
32
+ debug_charles_app = os.getenv('DEBUG_CHARLES_APP', 'false').lower() == 'true'
33
+ charles_app_running = False
34
 
35
  @st.cache_resource
36
  def init_ray():
 
47
  else:
48
  ray.init(namespace="project_charles")
49
 
 
 
 
 
 
 
 
 
 
 
 
50
  @st.cache_resource
51
  def get_streamlit_av_queue():
52
  from streamlit_av_queue import StreamlitAVQueue
 
59
  app_interface_instance = AppInterfaceActor.get_singleton()
60
  return app_interface_instance
61
 
62
+ @st.cache_resource
63
+ def create_charles_app()->int:
64
+ charles_app_proc = subprocess.Popen([sys.executable, "charles_app.py"])
65
+ return charles_app_proc.pid
66
+
67
+
68
+
69
  async def main():
70
  # Initialize Ray
71
  ray_status = init_ray()
 
 
72
  # get ray actors
73
  app_interface_instance = get_app_interface_instance()
74
  await asyncio.sleep(0.1)
 
124
 
125
  try:
126
  while True:
127
+ charles_app_running = await app_interface_instance.is_charles_app_running.remote()
128
  if not webrtc_ctx.state.playing:
129
  system_one_audio_status.write("Camera has stopped.")
130
  await asyncio.sleep(0.1)
131
  continue
132
+ if not charles_app_running and debug_charles_app:
133
+ system_one_audio_status.write("Start Charles app from your debugger...")
134
+ await asyncio.sleep(0.1)
135
+ continue
136
+ if not charles_app_running:
137
+ print("Starting Charles app...")
138
+ system_one_audio_status.write("Starting Charles app...")
139
+ chalres_app_pid = create_charles_app()
140
+ print(f"Started Charles app with PID {chalres_app_pid}")
141
+ await asyncio.sleep(.1)
142
+ pids = await app_interface_instance.get_charles_app_pids.remote()
143
+ assert chalres_app_pid in pids, f"Charles app PID {chalres_app_pid} not found in {pids}"
144
+ assert len(pids) == 1, f"Expected 1 PID, found {len(pids)}"
145
+ continue
146
  try:
147
  streamlit_av_queue.set_looking_listening(looking, listening)
148
  charles_debug_str = await app_interface_instance.get_debug_output.remote()
 
152
  except Exception as e:
153
  # assume we disconnected
154
  charles_actor = None
155
+ await asyncio.sleep(0.01)
156
 
157
  except Exception as e:
158
  print(f"An error occurred: {e}")