SHA256
Обновить сервис агента-кодера
This commit is contained in:
@@ -181,6 +181,7 @@ class ShinePyBotService:
|
||||
self.stop_current_job = False
|
||||
self.lock_fd = None
|
||||
self.last_heartbeat_at: float = 0.0
|
||||
self.restart_requested = False
|
||||
|
||||
def run(self) -> None:
|
||||
self._ensure_dirs()
|
||||
@@ -449,6 +450,19 @@ class ShinePyBotService:
|
||||
archived = self._rotate_history("command_new", username)
|
||||
self._safe_send(chat_id, f"История очищена. Новый диалог начат.\nАрхив: {archived.name}", reply_to=message_id)
|
||||
return
|
||||
if lower in ("/restart_service", "/restart"):
|
||||
self._append_history_event("restart_service_requested", {
|
||||
"chatId": chat_id,
|
||||
"messageId": message_id,
|
||||
"username": username,
|
||||
})
|
||||
self._safe_send(
|
||||
chat_id,
|
||||
"Перезапускаю сервис. Если задача была активна, после старта она вернётся в очередь и продолжится.",
|
||||
reply_to=message_id,
|
||||
)
|
||||
self._schedule_self_restart()
|
||||
return
|
||||
if lower == "/stop":
|
||||
stopped = self._cancel_active_job("stopped_by_user")
|
||||
if stopped:
|
||||
@@ -483,6 +497,7 @@ class ShinePyBotService:
|
||||
"/stop — остановить текущую задачу\n"
|
||||
"/cancel <id|all> — удалить задачу по id (префикс) или все\n"
|
||||
"/new — архивировать историю и начать новую\n"
|
||||
"/restart_service — перезапустить сервис через systemd\n"
|
||||
"/help — эта справка"
|
||||
)
|
||||
|
||||
@@ -654,9 +669,11 @@ class ShinePyBotService:
|
||||
self.last_heartbeat_at = 0.0
|
||||
last_user_note = ""
|
||||
last_user_note_at = 0.0
|
||||
codex_started_at = time.time()
|
||||
last_job_message_at = codex_started_at
|
||||
|
||||
def on_line(line: str) -> None:
|
||||
nonlocal last_user_note, last_user_note_at
|
||||
nonlocal last_user_note, last_user_note_at, last_job_message_at
|
||||
output_lines.append(line)
|
||||
note = self._extract_codex_user_note(line)
|
||||
now = time.time()
|
||||
@@ -664,9 +681,7 @@ class ShinePyBotService:
|
||||
self._safe_send(chat_id, f"#{job_num}: {note}", reply_to=message_id)
|
||||
last_user_note = note
|
||||
last_user_note_at = now
|
||||
if now - self.last_heartbeat_at > 60:
|
||||
self._safe_send(chat_id, f"#{job_num}: всё ещё выполняется...", reply_to=message_id)
|
||||
self.last_heartbeat_at = now
|
||||
last_job_message_at = now
|
||||
|
||||
reader_done = threading.Event()
|
||||
|
||||
@@ -682,11 +697,27 @@ class ShinePyBotService:
|
||||
t.start()
|
||||
|
||||
try:
|
||||
return_code = process.wait(timeout=self.cfg.codex_timeout_seconds)
|
||||
except subprocess.TimeoutExpired:
|
||||
process.kill()
|
||||
t.join(timeout=2)
|
||||
raise RuntimeError(f"Codex timeout after {self.cfg.codex_timeout_seconds}s")
|
||||
deadline = time.time() + self.cfg.codex_timeout_seconds
|
||||
return_code = None
|
||||
while return_code is None:
|
||||
return_code = process.poll()
|
||||
now = time.time()
|
||||
if return_code is not None:
|
||||
break
|
||||
if now >= deadline:
|
||||
process.kill()
|
||||
t.join(timeout=2)
|
||||
raise RuntimeError(f"Codex timeout after {self.cfg.codex_timeout_seconds}s")
|
||||
if now - codex_started_at >= 120 and now - last_job_message_at >= 120:
|
||||
elapsed = self._format_duration(int(now - codex_started_at))
|
||||
self._safe_send(
|
||||
chat_id,
|
||||
f"#{job_num}: задача ещё выполняется, работает уже {elapsed}. От Codex давно нет сообщений.",
|
||||
reply_to=message_id,
|
||||
)
|
||||
last_job_message_at = now
|
||||
self.last_heartbeat_at = now
|
||||
time.sleep(1)
|
||||
finally:
|
||||
with self.active_process_lock:
|
||||
self.active_process = None
|
||||
@@ -777,6 +808,18 @@ class ShinePyBotService:
|
||||
except Exception as e:
|
||||
print(f"[py-bot] sendMessage error: {e}", flush=True)
|
||||
|
||||
def _schedule_self_restart(self) -> None:
|
||||
if self.restart_requested:
|
||||
return
|
||||
self.restart_requested = True
|
||||
|
||||
def restart() -> None:
|
||||
time.sleep(1.5)
|
||||
print("[py-bot] restart requested by Telegram command", flush=True)
|
||||
os._exit(0)
|
||||
|
||||
threading.Thread(target=restart, name="shine-py-bot-self-restart", daemon=True).start()
|
||||
|
||||
def _transcribe_voice_job(self, job: dict[str, Any]) -> str:
|
||||
if not self.cfg.openai_api_key:
|
||||
raise RuntimeError("Не задан OPENAI_API_KEY для распознавания voice")
|
||||
@@ -878,6 +921,17 @@ class ShinePyBotService:
|
||||
return line
|
||||
return ""
|
||||
|
||||
@staticmethod
|
||||
def _format_duration(seconds: int) -> str:
|
||||
seconds = max(0, seconds)
|
||||
minutes, sec = divmod(seconds, 60)
|
||||
hours, minutes = divmod(minutes, 60)
|
||||
if hours:
|
||||
return f"{hours}ч {minutes}м {sec}с"
|
||||
if minutes:
|
||||
return f"{minutes}м {sec}с"
|
||||
return f"{sec}с"
|
||||
|
||||
|
||||
def run_selftest(config: BotConfig, prompt: str) -> int:
|
||||
cmd = [
|
||||
|
||||
Reference in New Issue
Block a user