realtimex-deeptutor 0.5.0.post7__py3-none-any.whl → 0.5.0.post8__py3-none-any.whl
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.
- {realtimex_deeptutor-0.5.0.post7.dist-info → realtimex_deeptutor-0.5.0.post8.dist-info}/METADATA +1 -1
- {realtimex_deeptutor-0.5.0.post7.dist-info → realtimex_deeptutor-0.5.0.post8.dist-info}/RECORD +7 -7
- scripts/start_web.py +121 -41
- {realtimex_deeptutor-0.5.0.post7.dist-info → realtimex_deeptutor-0.5.0.post8.dist-info}/WHEEL +0 -0
- {realtimex_deeptutor-0.5.0.post7.dist-info → realtimex_deeptutor-0.5.0.post8.dist-info}/entry_points.txt +0 -0
- {realtimex_deeptutor-0.5.0.post7.dist-info → realtimex_deeptutor-0.5.0.post8.dist-info}/licenses/LICENSE +0 -0
- {realtimex_deeptutor-0.5.0.post7.dist-info → realtimex_deeptutor-0.5.0.post8.dist-info}/top_level.txt +0 -0
{realtimex_deeptutor-0.5.0.post7.dist-info → realtimex_deeptutor-0.5.0.post8.dist-info}/RECORD
RENAMED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
realtimex_deeptutor/__init__.py,sha256=sSfuCLjJa6BnayszcU4azNl_sr1OzuKgLP10BAtdoh8,1567
|
|
2
|
-
realtimex_deeptutor-0.5.0.
|
|
2
|
+
realtimex_deeptutor-0.5.0.post8.dist-info/licenses/LICENSE,sha256=hIahDEOTzuHCU5J2nd07LWwkLW7Hko4UFO__ffsvB-8,34523
|
|
3
3
|
scripts/__init__.py,sha256=mxMsCbci-Qon3qWU1JIi93-tYlHAy0NIUbDRmAPVcg0,54
|
|
4
4
|
scripts/audit_prompts.py,sha256=Ltuk7tvsjpKhiobVbYq1volgVFKiVLgSTaE_Is4MGaM,5651
|
|
5
5
|
scripts/check_install.py,sha256=GbApEcDLJ6r0QmYrCVHAFCOK4wolpSLwL3eBRmmD3og,13929
|
|
@@ -7,7 +7,7 @@ scripts/generate_roster.py,sha256=COsJ12bvZ5W9TI-wAvKpknKBgHr9uQTvJ_JCz2gVMVo,12
|
|
|
7
7
|
scripts/install_all.py,sha256=u-A3eLhk1ua_KCjz8WZMkrVNJN6QdYs7NhGOcsm-Mks,23875
|
|
8
8
|
scripts/migrate_kb.py,sha256=uyJgplkJag35rT2RrwSiT37__gpB4TiA0xh5uVcWIa4,19667
|
|
9
9
|
scripts/start.py,sha256=EYbyjryor0DN_WcxQMSkKWCboM9UjMkv61fWhLyv63I,30300
|
|
10
|
-
scripts/start_web.py,sha256=
|
|
10
|
+
scripts/start_web.py,sha256=ZND4cNGYKpd52hygA2HFJFFiB1IGJoFAgP1mBXUNURA,34796
|
|
11
11
|
scripts/sync_prompts_from_en.py,sha256=TkBSFilYSwnwo0a3cgRnJ84i02zByAIW12N3ePzBwE8,4677
|
|
12
12
|
src/__init__.py,sha256=UNw3C20mbskiQF3rK3HhjglrG8snhfuiVthc5UsoHX0,1046
|
|
13
13
|
src/agents/__init__.py,sha256=IPhP4RZnCH2kcUDBkdKHO_ciVdyWnuHUCG2flG5Ydcw,885
|
|
@@ -289,8 +289,8 @@ src/utils/error_utils.py,sha256=ME_9q-DlmxFl-Xvv3ETPZE_iP705x6MXiuAREgWYsjM,2262
|
|
|
289
289
|
src/utils/json_parser.py,sha256=M_KfrsrNvQPSiFvpKHQV79Aj85_MEcLVc6hnKzvTV58,3243
|
|
290
290
|
src/utils/realtimex.py,sha256=vs7fAEnJJ4zpAyyBn-7vUmGWiiQvpTWQCRgax1MLTDw,9769
|
|
291
291
|
src/utils/network/circuit_breaker.py,sha256=BtjogK5R3tG8fuJniS5-PJKZMtwD5P2SkP2JFiQ9sRA,2722
|
|
292
|
-
realtimex_deeptutor-0.5.0.
|
|
293
|
-
realtimex_deeptutor-0.5.0.
|
|
294
|
-
realtimex_deeptutor-0.5.0.
|
|
295
|
-
realtimex_deeptutor-0.5.0.
|
|
296
|
-
realtimex_deeptutor-0.5.0.
|
|
292
|
+
realtimex_deeptutor-0.5.0.post8.dist-info/METADATA,sha256=UZu0J6h0x9m5V-Rn1_dOZYA0FPdgWSm2Na8eKkmeUxQ,58304
|
|
293
|
+
realtimex_deeptutor-0.5.0.post8.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
294
|
+
realtimex_deeptutor-0.5.0.post8.dist-info/entry_points.txt,sha256=slNAzwRLUpqiMtDRZBQIkXbU2vGMHL_om6-o19gYdh8,134
|
|
295
|
+
realtimex_deeptutor-0.5.0.post8.dist-info/top_level.txt,sha256=zUAd6V7jDYhdL7bvg2S38YCM-gVhvd36WqkjxrT-02I,32
|
|
296
|
+
realtimex_deeptutor-0.5.0.post8.dist-info/RECORD,,
|
scripts/start_web.py
CHANGED
|
@@ -143,6 +143,103 @@ else:
|
|
|
143
143
|
return False
|
|
144
144
|
|
|
145
145
|
|
|
146
|
+
def find_pid_by_port(port: int) -> int | None:
|
|
147
|
+
"""
|
|
148
|
+
Find PID using a port with multiple fallback methods.
|
|
149
|
+
Returns PID or None if not found.
|
|
150
|
+
"""
|
|
151
|
+
if os.name == "nt":
|
|
152
|
+
# Windows: use netstat
|
|
153
|
+
try:
|
|
154
|
+
result = subprocess.run(
|
|
155
|
+
["netstat", "-ano"],
|
|
156
|
+
capture_output=True,
|
|
157
|
+
text=True,
|
|
158
|
+
timeout=5,
|
|
159
|
+
)
|
|
160
|
+
for line in result.stdout.splitlines():
|
|
161
|
+
if f":{port}" in line and "LISTENING" in line:
|
|
162
|
+
parts = line.split()
|
|
163
|
+
if parts:
|
|
164
|
+
try:
|
|
165
|
+
return int(parts[-1])
|
|
166
|
+
except ValueError:
|
|
167
|
+
pass
|
|
168
|
+
except Exception:
|
|
169
|
+
pass
|
|
170
|
+
return None
|
|
171
|
+
|
|
172
|
+
# Unix: Try strategies in order: lsof -> ss -> netstat
|
|
173
|
+
|
|
174
|
+
# Strategy 1: lsof (standard)
|
|
175
|
+
try:
|
|
176
|
+
result = subprocess.run(
|
|
177
|
+
["lsof", "-ti", f":{port}"],
|
|
178
|
+
capture_output=True,
|
|
179
|
+
text=True,
|
|
180
|
+
timeout=5,
|
|
181
|
+
)
|
|
182
|
+
if result.returncode == 0 and result.stdout.strip():
|
|
183
|
+
try:
|
|
184
|
+
# May return multiple PIDs, take the first one
|
|
185
|
+
return int(result.stdout.strip().split()[0])
|
|
186
|
+
except (ValueError, IndexError):
|
|
187
|
+
pass
|
|
188
|
+
except FileNotFoundError:
|
|
189
|
+
pass # lsof not installed
|
|
190
|
+
except Exception:
|
|
191
|
+
pass
|
|
192
|
+
|
|
193
|
+
# Strategy 2: ss (modern Linux)
|
|
194
|
+
try:
|
|
195
|
+
# ss -lptn 'sport = :8001'
|
|
196
|
+
result = subprocess.run(
|
|
197
|
+
["ss", "-lptn", f"sport = :{port}"],
|
|
198
|
+
capture_output=True,
|
|
199
|
+
text=True,
|
|
200
|
+
timeout=5,
|
|
201
|
+
)
|
|
202
|
+
if result.returncode == 0:
|
|
203
|
+
# Output format: Users:(("python",pid=1234,fd=3))
|
|
204
|
+
output = result.stdout
|
|
205
|
+
if f":{port}" in output and "pid=" in output:
|
|
206
|
+
import re
|
|
207
|
+
|
|
208
|
+
match = re.search(r"pid=(\d+)", output)
|
|
209
|
+
if match:
|
|
210
|
+
return int(match.group(1))
|
|
211
|
+
except FileNotFoundError:
|
|
212
|
+
pass # ss not installed
|
|
213
|
+
except Exception:
|
|
214
|
+
pass
|
|
215
|
+
|
|
216
|
+
# Strategy 3: netstat (legacy Unix)
|
|
217
|
+
try:
|
|
218
|
+
# netstat -nlp | grep :8001
|
|
219
|
+
p1 = subprocess.Popen(
|
|
220
|
+
["netstat", "-nlp"], stdout=subprocess.PIPE, stderr=subprocess.DEVNULL
|
|
221
|
+
)
|
|
222
|
+
p2 = subprocess.Popen(
|
|
223
|
+
["grep", f":{port}"], stdin=p1.stdout, stdout=subprocess.PIPE, text=True
|
|
224
|
+
)
|
|
225
|
+
if p1.stdout:
|
|
226
|
+
p1.stdout.close()
|
|
227
|
+
output, _ = p2.communicate(timeout=5)
|
|
228
|
+
|
|
229
|
+
if output:
|
|
230
|
+
# Expected: tcp 0 0 0.0.0.0:8001 0.0.0.0:* LISTEN 1234/python
|
|
231
|
+
parts = output.split()
|
|
232
|
+
for part in parts:
|
|
233
|
+
if "/" in part and part.split("/")[0].isdigit():
|
|
234
|
+
return int(part.split("/")[0])
|
|
235
|
+
except FileNotFoundError:
|
|
236
|
+
pass
|
|
237
|
+
except Exception:
|
|
238
|
+
pass
|
|
239
|
+
|
|
240
|
+
return None
|
|
241
|
+
|
|
242
|
+
|
|
146
243
|
def check_port_in_use(port: int) -> tuple[bool, int | None]:
|
|
147
244
|
"""
|
|
148
245
|
Check if a port is in use and return the PID of the process using it.
|
|
@@ -177,42 +274,7 @@ def check_port_in_use(port: int) -> tuple[bool, int | None]:
|
|
|
177
274
|
pass
|
|
178
275
|
|
|
179
276
|
# Port is in use (connection succeeded), try to find the PID
|
|
180
|
-
pid =
|
|
181
|
-
try:
|
|
182
|
-
if os.name == "nt":
|
|
183
|
-
# Windows: use netstat
|
|
184
|
-
result = subprocess.run(
|
|
185
|
-
["netstat", "-ano"],
|
|
186
|
-
capture_output=True,
|
|
187
|
-
text=True,
|
|
188
|
-
timeout=5,
|
|
189
|
-
)
|
|
190
|
-
for line in result.stdout.splitlines():
|
|
191
|
-
if f":{port}" in line and "LISTENING" in line:
|
|
192
|
-
parts = line.split()
|
|
193
|
-
if parts:
|
|
194
|
-
try:
|
|
195
|
-
pid = int(parts[-1])
|
|
196
|
-
break
|
|
197
|
-
except ValueError:
|
|
198
|
-
pass
|
|
199
|
-
else:
|
|
200
|
-
# Unix: use lsof
|
|
201
|
-
result = subprocess.run(
|
|
202
|
-
["lsof", "-ti", f":{port}"],
|
|
203
|
-
capture_output=True,
|
|
204
|
-
text=True,
|
|
205
|
-
timeout=5,
|
|
206
|
-
)
|
|
207
|
-
if result.returncode == 0 and result.stdout.strip():
|
|
208
|
-
# May return multiple PIDs, take the first one
|
|
209
|
-
try:
|
|
210
|
-
pid = int(result.stdout.strip().split()[0])
|
|
211
|
-
except (ValueError, IndexError):
|
|
212
|
-
pass
|
|
213
|
-
except Exception:
|
|
214
|
-
pass
|
|
215
|
-
|
|
277
|
+
pid = find_pid_by_port(port)
|
|
216
278
|
return True, pid
|
|
217
279
|
|
|
218
280
|
|
|
@@ -233,7 +295,11 @@ def kill_process_on_port(port: int, force: bool = False) -> bool:
|
|
|
233
295
|
|
|
234
296
|
if pid is None:
|
|
235
297
|
print_flush(f"⚠️ Port {port} is in use but couldn't identify the process")
|
|
236
|
-
|
|
298
|
+
# Retry detection once with slightly longer delay just in case
|
|
299
|
+
time.sleep(1)
|
|
300
|
+
_, pid = check_port_in_use(port)
|
|
301
|
+
if pid is None:
|
|
302
|
+
return False
|
|
237
303
|
|
|
238
304
|
print_flush(f" Stopping process {pid} on port {port}...")
|
|
239
305
|
|
|
@@ -241,21 +307,35 @@ def kill_process_on_port(port: int, force: bool = False) -> bool:
|
|
|
241
307
|
if os.name == "nt":
|
|
242
308
|
subprocess.run(["taskkill", "/F", "/PID", str(pid)], check=True, capture_output=True)
|
|
243
309
|
else:
|
|
244
|
-
|
|
245
|
-
|
|
310
|
+
# Try to kill the process group first (handles child processes)
|
|
311
|
+
try:
|
|
312
|
+
pgid = os.getpgid(pid)
|
|
313
|
+
sig = signal.SIGKILL if force else signal.SIGTERM
|
|
314
|
+
os.killpg(pgid, sig)
|
|
315
|
+
except (ProcessLookupError, PermissionError):
|
|
316
|
+
# Fallbck to simple kill if PGID fails
|
|
317
|
+
sig = signal.SIGKILL if force else signal.SIGTERM
|
|
318
|
+
os.kill(pid, sig)
|
|
319
|
+
|
|
246
320
|
# Wait a moment for process to terminate
|
|
247
321
|
time.sleep(0.5)
|
|
248
322
|
# Check if still running, force kill if needed
|
|
249
323
|
if not force:
|
|
250
324
|
try:
|
|
251
325
|
os.kill(pid, 0) # Check if process exists
|
|
252
|
-
|
|
326
|
+
# If still alive, Force Kill
|
|
327
|
+
print_flush(f" Process {pid} still alive, force killing...")
|
|
328
|
+
try:
|
|
329
|
+
pgid = os.getpgid(pid)
|
|
330
|
+
os.killpg(pgid, signal.SIGKILL)
|
|
331
|
+
except:
|
|
332
|
+
os.kill(pid, signal.SIGKILL)
|
|
253
333
|
time.sleep(0.3)
|
|
254
334
|
except ProcessLookupError:
|
|
255
335
|
pass # Process already terminated
|
|
256
336
|
|
|
257
337
|
# Verify port is now free
|
|
258
|
-
time.sleep(0.
|
|
338
|
+
time.sleep(0.5)
|
|
259
339
|
in_use, _ = check_port_in_use(port)
|
|
260
340
|
if not in_use:
|
|
261
341
|
print_flush(f"✅ Port {port} is now free")
|
{realtimex_deeptutor-0.5.0.post7.dist-info → realtimex_deeptutor-0.5.0.post8.dist-info}/WHEEL
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|