From 59047a8d0e6626e5fe2e456c974c376a2dac4c0e3ae713322aed1f0c32a34ca7 Mon Sep 17 00:00:00 2001 From: AidarKC Date: Mon, 20 Jul 2026 18:49:28 +0400 Subject: [PATCH] =?UTF-8?q?=D0=92=D1=8B=D0=BD=D0=B5=D1=81=D1=82=D0=B8=20?= =?UTF-8?q?=D0=BF=D1=80=D0=BE=D0=B4=D1=83=D0=BA=D1=82=D0=BE=D0=B2=D1=8B?= =?UTF-8?q?=D0=B9=20=D1=80=D0=B5=D0=BF=D0=BE=D0=B7=D0=B8=D1=82=D0=BE=D1=80?= =?UTF-8?q?=D0=B8=D0=B9=20=D0=B8=D0=B7=20=D0=BB=D0=BE=D0=BA=D0=B0=D0=BB?= =?UTF-8?q?=D1=8C=D0=BD=D0=BE=D0=B9=20=D0=BE=D0=B1=D0=B2=D1=8F=D0=B7=D0=BA?= =?UTF-8?q?=D0=B8=20=D0=B0=D0=B3=D0=B5=D0=BD=D1=82=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AGENTS.md | 9 +- CLAUDE.md | 2 +- Players/blackbyrd1/files/.gitkeep | 1 - Players/blackbyrd1/history/.gitkeep | 1 - Players/dimasol1/files/.gitkeep | 1 - ...-05-30_agent_instructions_approval_task.md | 71 - Players/dimasol1/history/.gitkeep | 1 - Players/malvviiina/files/.gitkeep | 1 - Players/malvviiina/history/.gitkeep | 1 - .../channels-list.png | Bin 31852 -> 0 bytes .../chat-view_u1.png | Bin 3153 -> 0 bytes .../contact-search-view.png | Bin 107433 -> 0 bytes .../shine-staging-screenshots/login.png | Bin 19475 -> 0 bytes .../messages-list.png | Bin 28201 -> 0 bytes .../network-view.png | Bin 95575 -> 0 bytes .../notifications-view.png | Bin 28201 -> 0 bytes .../shine-staging-screenshots/register.png | Bin 71148 -> 0 bytes .../settings-view.png | Bin 28201 -> 0 bytes .../shine-staging-screenshots/start.png | Bin 50017 -> 0 bytes .../shine-staging-screenshots/wallet-view.png | Bin 28201 -> 0 bytes Players/oidasyda/files/.gitkeep | 1 - Players/oidasyda/history/.gitkeep | 1 - Players/zodiaktechnika32/files/.gitkeep | 1 - Players/zodiaktechnika32/history/.gitkeep | 1 - SHiNE-agent-bot-coder/.env.example | 19 - SHiNE-agent-bot-coder/.gitignore | 5 - SHiNE-agent-bot-coder/AGENT.md | 80 - SHiNE-agent-bot-coder/AGENTS.md | 25 - SHiNE-agent-bot-coder/CLAUDE.md | 2 - .../Players/PROMPTS_REVIEW.md | 26 - SHiNE-agent-bot-coder/README.md | 100 - SHiNE-agent-bot-coder/py_bot_service.py | 2976 ----------------- .../scripts/systemd/install-local-systemd.sh | 28 - .../systemd/shine-agent-bot-coder.service | 19 - VERSION.properties | 4 +- codex-agent-VPS/.env.example | 31 - codex-agent-VPS/.gitignore | 5 - codex-agent-VPS/AGENTS.md | 86 - .../Agent-server-package/.env.example | 31 - codex-agent-VPS/Agent-server-package/AGENT.md | 51 - .../Agent-server-package/py_bot_service.py | 2960 ---------------- .../systemd/shine-agent-bot-coder.service | 23 - codex-agent-VPS/README.md | 32 - deploy/AGENT_BOT_CODER_LOCAL_SYSTEMD.md | 14 +- 44 files changed, 18 insertions(+), 6591 deletions(-) delete mode 100644 Players/blackbyrd1/files/.gitkeep delete mode 100644 Players/blackbyrd1/history/.gitkeep delete mode 100644 Players/dimasol1/files/.gitkeep delete mode 100644 Players/dimasol1/files/2026-05-30_agent_instructions_approval_task.md delete mode 100644 Players/dimasol1/history/.gitkeep delete mode 100644 Players/malvviiina/files/.gitkeep delete mode 100644 Players/malvviiina/history/.gitkeep delete mode 100644 Players/malvviiina/shine-staging-screenshots/channels-list.png delete mode 100644 Players/malvviiina/shine-staging-screenshots/chat-view_u1.png delete mode 100644 Players/malvviiina/shine-staging-screenshots/contact-search-view.png delete mode 100644 Players/malvviiina/shine-staging-screenshots/login.png delete mode 100644 Players/malvviiina/shine-staging-screenshots/messages-list.png delete mode 100644 Players/malvviiina/shine-staging-screenshots/network-view.png delete mode 100644 Players/malvviiina/shine-staging-screenshots/notifications-view.png delete mode 100644 Players/malvviiina/shine-staging-screenshots/register.png delete mode 100644 Players/malvviiina/shine-staging-screenshots/settings-view.png delete mode 100644 Players/malvviiina/shine-staging-screenshots/start.png delete mode 100644 Players/malvviiina/shine-staging-screenshots/wallet-view.png delete mode 100644 Players/oidasyda/files/.gitkeep delete mode 100644 Players/oidasyda/history/.gitkeep delete mode 100644 Players/zodiaktechnika32/files/.gitkeep delete mode 100644 Players/zodiaktechnika32/history/.gitkeep delete mode 100644 SHiNE-agent-bot-coder/.env.example delete mode 100644 SHiNE-agent-bot-coder/.gitignore delete mode 100644 SHiNE-agent-bot-coder/AGENT.md delete mode 100644 SHiNE-agent-bot-coder/AGENTS.md delete mode 100644 SHiNE-agent-bot-coder/CLAUDE.md delete mode 100644 SHiNE-agent-bot-coder/Players/PROMPTS_REVIEW.md delete mode 100644 SHiNE-agent-bot-coder/README.md delete mode 100644 SHiNE-agent-bot-coder/py_bot_service.py delete mode 100755 SHiNE-agent-bot-coder/scripts/systemd/install-local-systemd.sh delete mode 100644 SHiNE-agent-bot-coder/scripts/systemd/shine-agent-bot-coder.service delete mode 100644 codex-agent-VPS/.env.example delete mode 100644 codex-agent-VPS/.gitignore delete mode 100644 codex-agent-VPS/AGENTS.md delete mode 100644 codex-agent-VPS/Agent-server-package/.env.example delete mode 100644 codex-agent-VPS/Agent-server-package/AGENT.md delete mode 100644 codex-agent-VPS/Agent-server-package/py_bot_service.py delete mode 100644 codex-agent-VPS/Agent-server-package/scripts/systemd/shine-agent-bot-coder.service delete mode 100644 codex-agent-VPS/README.md diff --git a/AGENTS.md b/AGENTS.md index 21aa62f4..c1629e40 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -14,14 +14,15 @@ - Веб-панель администратора сервера (управление Solana PDA сервера) находится в `shine-UI/`: - точка входа `shine-UI/server-ui.html`; - остальные файлы серверного UI — в `shine-UI/server-ui/`. -- Локальный Telegram-бот агента-кодера находится в папке `SHiNE-agent-bot-coder/` и не является кодом основного серверного приложения. +- Локальный Telegram-бот агента-кодера живёт рядом с репозиторием продукта, обычно в `../SHiNE-agent-bot-coder/`, и не входит в публичный код основного приложения. - Solana/Anchor-модуль находится в папке `shine-solana/shine/` и ведётся отдельно от основного server/UI деплоя. ## Сервис агента-кодера -- В проекте есть локальный Telegram-бот-сервис агента-кодера в папке `SHiNE-agent-bot-coder/`. +- Локальный Telegram-бот-сервис агента-кодера находится вне этого git-репозитория, обычно в `../SHiNE-agent-bot-coder/`. - Сервис принимает сообщения из Telegram, ведёт историю диалога, ставит задачи в очередь и вызывает Codex CLI для обработки запросов по проекту. -- Автоматически читаемые инструкции для Codex внутри сервиса держать в `SHiNE-agent-bot-coder/AGENTS.md`. -- Подробные служебные правила Telegram-обработчика, его очередь, история, systemd-запуск и особенности ответов описывать в `SHiNE-agent-bot-coder/AGENT.md`. +- Рабочая папка Codex для сервиса должна указывать на этот продуктовый репозиторий: `CODEX_WORKDIR=/home/ai/work/SHiNE/SHiNE-server-sha256/SHiNE-product`. +- Автоматически читаемые инструкции для Codex внутри сервиса держать в `../SHiNE-agent-bot-coder/AGENTS.md`. +- Подробные служебные правила Telegram-обработчика, его очередь, история, systemd-запуск и особенности ответов описывать в `../SHiNE-agent-bot-coder/AGENT.md`. - Если в сообщениях пользователя встречается «агент MD» или похожая формулировка про файл инструкций Codex, считать, что имеется в виду автоматически читаемый `AGENTS.md`. ## ESP32 UI homeserver diff --git a/CLAUDE.md b/CLAUDE.md index 0e5b4c5e..c75cd666 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -5,7 +5,7 @@ @shine-UI/AGENTS.md ## Справка по подпроектам -- При работе внутри `SHiNE-agent-bot-coder/` — читать `SHiNE-agent-bot-coder/AGENTS.md` и `SHiNE-agent-bot-coder/AGENT.md`. +- При работе с локальным агентом-кодером — читать внешние файлы `../SHiNE-agent-bot-coder/AGENTS.md` и `../SHiNE-agent-bot-coder/AGENT.md`. - При работе внутри `shine-solana/shine/` — читать `shine-solana/shine/AGENTS.md`. - При работе внутри `shine-UI/server-ui/` — читать `shine-UI/AGENTS.md`. - При работе внутри `SHiNE-server/` — читать `SHiNE-server/AGENTS.md`. diff --git a/Players/blackbyrd1/files/.gitkeep b/Players/blackbyrd1/files/.gitkeep deleted file mode 100644 index 4c0d52d1..00000000 --- a/Players/blackbyrd1/files/.gitkeep +++ /dev/null @@ -1 +0,0 @@ - diff --git a/Players/blackbyrd1/history/.gitkeep b/Players/blackbyrd1/history/.gitkeep deleted file mode 100644 index 4c0d52d1..00000000 --- a/Players/blackbyrd1/history/.gitkeep +++ /dev/null @@ -1 +0,0 @@ - diff --git a/Players/dimasol1/files/.gitkeep b/Players/dimasol1/files/.gitkeep deleted file mode 100644 index 4c0d52d1..00000000 --- a/Players/dimasol1/files/.gitkeep +++ /dev/null @@ -1 +0,0 @@ - diff --git a/Players/dimasol1/files/2026-05-30_agent_instructions_approval_task.md b/Players/dimasol1/files/2026-05-30_agent_instructions_approval_task.md deleted file mode 100644 index cfe05a4f..00000000 --- a/Players/dimasol1/files/2026-05-30_agent_instructions_approval_task.md +++ /dev/null @@ -1,71 +0,0 @@ -# Задание для Айдара: навести порядок в инструкциях агентов SHiNE - -## Кратко -Нужно согласовать и оформить единый порядок инструкций для Codex/Telegram-агентов в проекте SHiNE, чтобы агенты стабильно понимали структуру проекта, границы ответственности и правила работы с сервером, UI, Solana-модулем, Telegram-ботом и игроками. - -## Зачем это нужно -Сейчас проект состоит из нескольких связанных, но разных частей: - -- основной сервер `SHiNE-server/`; -- UI `shine-UI/`; -- Solana/Anchor-модуль `shine-solana/shine/`; -- Telegram-агент-кодер `SHiNE-agent-bot-coder/`; -- TURN-сервер; -- документация `docs/`; -- отдельные рабочие папки игроков `Players/`. - -Без явных инструкций агент может путать эти зоны: например, смешать деплой Solana с деплоем сервера, изменить код от имени игрока, не обновить документацию API/DM/блокчейна или неправильно трактовать файл инструкций. - -## Что предлагается сделать -1. Утвердить корневой `AGENTS.md` как главный набор правил проекта. -2. Проверить и при необходимости уточнить локальный `AGENTS.md` внутри `shine-solana/shine/`. -3. Оставить отдельные служебные инструкции Telegram-агента в `SHiNE-agent-bot-coder/AGENT.md`. -4. Оставить автоматически читаемые инструкции Telegram-агента в `SHiNE-agent-bot-coder/AGENTS.md`. -5. Явно закрепить режим игроков: - - игроки могут задавать вопросы, просить анализ, идеи и ТЗ; - - игроки не меняют код проекта напрямую; - - материалы игроков сохраняются только в `Players//`. -6. Зафиксировать правило: если пользователь говорит «агент MD» или похожую формулировку, считать, что речь про автоматически читаемый `AGENTS.md`. -7. Добавить простой процесс согласования изменений инструкций: - - Дима или другой участник готовит предложение; - - Айдар получает уведомление/заявку; - - Айдар отвечает: одобрить, отклонить или попросить доработать; - - только после одобрения агент вносит изменения в проектные инструкции. - -## Предлагаемая логика уведомления Айдару -Минимальный вариант без сложной разработки: - -1. Агент готовит текст заявки. -2. Текст отправляется Айдару в Telegram или в общий рабочий чат. -3. В заявке явно указаны варианты ответа: - - `одобрить`; - - `отклонить`; - - `доработать: ...`. -4. После ответа Айдара агент либо выполняет согласованные правки, либо фиксирует, что задача отклонена/нужна доработка. - -Более удобный вариант на будущее: - -- добавить в Telegram-бота команду или сценарий согласования задач, например: - - `/approve `; - - `/reject причина`; - - `/revise комментарий`. - -Но для начала достаточно простого текстового согласования через Telegram. - -## Что нужно от Айдара -Подтвердить, что такой порядок подходит: - -1. Корневой `AGENTS.md` остается главным правилом проекта. -2. Для Solana, Telegram-агента и игроков сохраняются отдельные локальные правила. -3. Игроки не меняют код напрямую, а готовят материалы и предложения. -4. Изменения инструкций выполняются только после явного одобрения Айдара. -5. Уведомления Айдару на первом этапе можно делать простым текстом в Telegram, без отдельной сложной системы заявок. - -## Ожидаемый результат -После одобрения: - -- агенты будут стабильнее понимать границы проекта; -- снизится риск случайных изменений не в той части системы; -- появится понятный порядок согласования задач от игроков; -- Айдар будет явно контролировать изменения в инструкциях и правилах работы агентов. - diff --git a/Players/dimasol1/history/.gitkeep b/Players/dimasol1/history/.gitkeep deleted file mode 100644 index 4c0d52d1..00000000 --- a/Players/dimasol1/history/.gitkeep +++ /dev/null @@ -1 +0,0 @@ - diff --git a/Players/malvviiina/files/.gitkeep b/Players/malvviiina/files/.gitkeep deleted file mode 100644 index 4c0d52d1..00000000 --- a/Players/malvviiina/files/.gitkeep +++ /dev/null @@ -1 +0,0 @@ - diff --git a/Players/malvviiina/history/.gitkeep b/Players/malvviiina/history/.gitkeep deleted file mode 100644 index 4c0d52d1..00000000 --- a/Players/malvviiina/history/.gitkeep +++ /dev/null @@ -1 +0,0 @@ - diff --git a/Players/malvviiina/shine-staging-screenshots/channels-list.png b/Players/malvviiina/shine-staging-screenshots/channels-list.png deleted file mode 100644 index 3f33dcf76f3aa0c33a11f5e7adba48480b1b63051efe4eb74b24df8e2554877f..0000000000000000000000000000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 31852 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 diff --git a/Players/malvviiina/shine-staging-screenshots/contact-search-view.png b/Players/malvviiina/shine-staging-screenshots/contact-search-view.png deleted file mode 100644 index afea30b0a3cff5a116fd0e30667991c19e146da22713a973753cc26fb88d19df..0000000000000000000000000000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 107433 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 LQ77Uk0Rlut1f{9;-dkuQz2-|tDWN2E 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 diff --git a/Players/malvviiina/shine-staging-screenshots/messages-list.png b/Players/malvviiina/shine-staging-screenshots/messages-list.png deleted file mode 100644 index 91499d93489d8b7f73f4149c9d95f09826bcb4b9d2650345ecd92a9a1234d57e..0000000000000000000000000000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 28201 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

M`i+k*13* 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 w{|h%pmw1l4gbuY3Uw11{j)Q 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 JsrYCT{6FP$f<*uT diff --git a/Players/malvviiina/shine-staging-screenshots/notifications-view.png b/Players/malvviiina/shine-staging-screenshots/notifications-view.png deleted file mode 100644 index 91499d93489d8b7f73f4149c9d95f09826bcb4b9d2650345ecd92a9a1234d57e..0000000000000000000000000000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 28201 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

M`i+k*13* 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 UY#V%Q0a_r==rfMx4%qm=0EB@33;+NC diff --git a/Players/malvviiina/shine-staging-screenshots/settings-view.png b/Players/malvviiina/shine-staging-screenshots/settings-view.png deleted file mode 100644 index 91499d93489d8b7f73f4149c9d95f09826bcb4b9d2650345ecd92a9a1234d57e..0000000000000000000000000000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 28201 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

M`i+k*13* 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 w{|h%pmw1{gRq{Sv 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 diff --git a/Players/malvviiina/shine-staging-screenshots/wallet-view.png b/Players/malvviiina/shine-staging-screenshots/wallet-view.png deleted file mode 100644 index 91499d93489d8b7f73f4149c9d95f09826bcb4b9d2650345ecd92a9a1234d57e..0000000000000000000000000000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 28201 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

M`i+k*13* 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 w{|h%pmw1/`. -- Игроки работают в режиме вопросов/анализа/подготовки материалов: в промпте явно задано правило не менять код проекта и писать материалы только в своей папке. -- Для неизвестных пользователей в личном чате сервис отвечает вежливым отказом. -- В Telegram-канале/группе `@shine_writing` сервис выполняет сообщения только от Айдара, а ответы отправляет в тот же чат. -- Если Telegram сообщает о миграции обычной группы в supergroup, сервис должен запомнить новый `chat_id` и отправлять ответы уже туда. -- На события подключения/отключения пользователей (join/leave) сервис не отвечает и ничего не отправляет. - -## Очередь и состояние -- Входящие задачи записываются в файловую очередь и обрабатываются строго по одной, чтобы не смешивать изменения в проекте. -- Сервис ведёт состояние активной задачи и текущего файла истории, а после рестарта продолжает незавершённую обработку с учётом сохранённого состояния. -- Истории диалогов хранятся в JSONL по каждому разрешённому username отдельно: `data/history//`. -- Архив истории после `/new`: `data/history//archive/`. -- После `/new` для этого же пользователя должен сбрасываться и контекст продолжения Codex-сессии; следующий запрос запускается как новая сессия, не через resume. -- Для просмотра истории игрока открывать файлы в его папке истории по username. -- Дедупликация входящих Telegram update нужна, чтобы одно сообщение не попало в обработку повторно. -- Если Codex молчит во время активной задачи 2 минуты подряд, сервис отправляет аварийный статус с общим временем работы задачи; при дальнейшем молчании повторяет статус каждые 2 минуты. -- После успешной обработки задачи из личного чата Айдара сервис должен отправить публичный итоговый отчёт в группу `@shine_writing`: первым сообщением исходный запрос, вторым сообщением-ответом итоговый ответ Codex. Промежуточные статусы в группу не дублировать. -- Для приватных voice/audio-запросов в публичном отчёте первым сообщением отправлять исходный Telegram voice/audio-файл с подписью, где указан распознанный текст. В пользовательском тексте отчёта не показывать Telegram `file_id`. -- Озвучивание финальных ответов настраивается персонально для каждого Telegram-пользователя командами `/voice_on`, `/voice_off`; для новых пользователей оно включено по умолчанию. -- Адаптация текста перед озвучкой настраивается персонально командами `/voice_rewrite_on`, `/voice_rewrite_off`. Если она включена, сервис перед TTS вызывает дешёвую текстовую модель OpenAI и делает голосовую версию без длинных хэшей, путей, команд и технического шума, сохраняя смысл и порядок исходного ответа. -- Режим личных ответов настраивается персонально командами `/single_message_on`, `/single_message_off`: либо одно редактируемое сообщение по этапам, либо отдельные сообщения как раньше. -- Команда `/settings` должна сразу показывать текущее состояние всех персональных настроек пользователя и список команд для их изменения. -- Если озвучивание включено, после полного текстового финального ответа сервис дополнительно отправляет voice-файл с синтезированной речью через OpenAI TTS даже для текстовых запросов. Voice отправляется в исходный чат, а также в известный личный чат пользователя и в общий чат `@shine_writing`, если они отличаются и доступны. Промежуточные статусы не озвучивать. -- Команда `/status` должна показывать состояние очереди и персональные настройки: voice-ответы, адаптацию текста перед озвучкой и режим одного сообщения в личке. - -## Правила голосовой версии ответа -- Текстовый финальный ответ должен оставаться полноценным: в нём можно указывать команды, пути, хэши коммитов, номера версий, результаты проверок и другие технические детали. -- Голосовую версию финального ответа нужно делать короче и проще для восприятия на слух. Основной механизм — персонально включаемая адаптация текста через дополнительный OpenAI-вызов перед TTS. -- В голосовой версии не зачитывать длинные хэши коммитов, токены, file_id, длинные команды, полные пути и другие строки, которые человек всё равно не сможет надёжно запомнить на слух. -- Для commit/push в голосовой версии достаточно сказать краткий итог: что коммит сделан, что именно изменено, проверки прошли без ошибок, push выполнен, рабочее дерево чистое. -- Если пользователю нужны точные команды, хэши или подробности, они должны оставаться в текстовом ответе. - -## Планы и отложенные фичи -- Планы проекта по отложенным фичам хранятся в `TODO/`. -- Внутри есть три горизонта: - - `near/` - ближайшие планы, обычно сегодня/завтра; - - `medium/` - среднесрочные планы, обычно недели или 1-2 месяца; - - `far/` - дальнее будущее без понятного срока. -- Если пользователь спрашивает, какие есть планы или что можно продолжить, нужно смотреть эти три папки и отвечать кратким списком по горизонтам. -- Файлы из `TODO/` не начинать реализовывать без явной команды пользователя. - -## Центр задач и предложений -- Сервис хранит простые задачи и предложения в `data/task_center/items.json`. -- Айдар может смотреть список через `/tasks` или естественные фразы вроде «покажи мои задачи», «покажи задачи Миланы». -- Айдар может ставить задачи игрокам фразой вида «поставь задачу Милане: ...». -- Игроки могут отправлять предложения Айдару фразой вида `предложение: ...`, `идея: ...` или `заявка: ...`. -- Статусы меняются фразами с ID: `одобрить TC-0001`, `отклонить TC-0001`, `доработать TC-0001`, `закрыть TC-0001`. -- После финального ответа в личном чате сервис добавляет короткое напоминание, если у пользователя есть активные задачи или предложения. - -## Локальный запуск и systemd -- Основной запуск сервиса выполняется Python-скриптом `py_bot_service.py` из папки `SHiNE-agent-bot-coder/`. -- Локальные секреты и параметры должны храниться в `.env`, этот файл не коммитится. -- Для проверки Codex без Telegram можно использовать self-test режим сервиса. -- Для постоянного локального запуска используется user-level systemd service `shine-agent-bot-coder`; скрипты установки лежат в `SHiNE-agent-bot-coder/scripts/systemd/`. -- Если меняется логика сервиса, после изменений нужно проверить запуск локально и при необходимости перезапустить user systemd service. -- Команда Telegram `/restart` (`/restart_service`) доступна только Айдару и выполняет отложенный рестарт после текущей задачи, до взятия следующей. Аварийный жёсткий рестарт доступен только Айдару командами `/restart_hard`, `/restart_now`, `/restart_force`. - -## Правила ответа -- Пиши содержательно и коротко. -- Не упоминай внутренние служебные детали, файловую систему и технические логи. -- Если запрос требует действий с кодом/проектом, выполняй их в рабочей директории. -- Если для ответа данных недостаточно, задай ровно один уточняющий вопрос. -- Если была ошибка предыдущего запуска, в промпте будет пометка retry — учти это и продолжи с учётом текущего состояния проекта. diff --git a/SHiNE-agent-bot-coder/AGENTS.md b/SHiNE-agent-bot-coder/AGENTS.md deleted file mode 100644 index b64d0f0e..00000000 --- a/SHiNE-agent-bot-coder/AGENTS.md +++ /dev/null @@ -1,25 +0,0 @@ -# AGENTS - -## Назначение -- Это автоматически читаемые инструкции Codex для папки `SHiNE-agent-bot-coder/`. -- `SHiNE-agent-bot-coder` — локальный Telegram-бот-сервис агента-кодера для работы с проектом SHiNE. -- Если пользователь говорит «агент MD», «агент с MD» или похожим образом про файл инструкций Codex, считать, что имеется в виду `AGENTS.md`. - -## Связанные инструкции -- Подробные служебные правила Telegram-обработчика лежат в `AGENT.md`. -- `AGENT.md` используется самим сервисом как файл инструкций, который передаётся в промпт обработчика входящих Telegram-сообщений. -- При изменении логики сервиса сначала читать `AGENT.md`, затем код `py_bot_service.py`. - -## Планы и задачи -- Отложенные задачи проекта лежат в `../TODO/`. -- Точка входа по планам: `../TODO/README.md`. -- Горизонты планов: - - `near/` - ближайшие планы; - - `medium/` - среднесрочные планы; - - `far/` - дальнее будущее. -- Если пользователь спрашивает, какие есть планы или что можно продолжить, кратко перечислять задачи по этим горизонтам. -- Не начинать реализацию задач из `TODO` без явной команды пользователя. - -## Проверка после изменений -- Если меняется логика Telegram-бота, проверить локальный запуск или self-test, когда это уместно. -- Если меняется только документация или инструкции, достаточно проверить, что ссылки на документы актуальны. diff --git a/SHiNE-agent-bot-coder/CLAUDE.md b/SHiNE-agent-bot-coder/CLAUDE.md deleted file mode 100644 index 4ed90ae6..00000000 --- a/SHiNE-agent-bot-coder/CLAUDE.md +++ /dev/null @@ -1,2 +0,0 @@ -@AGENTS.md -@AGENT.md diff --git a/SHiNE-agent-bot-coder/Players/PROMPTS_REVIEW.md b/SHiNE-agent-bot-coder/Players/PROMPTS_REVIEW.md deleted file mode 100644 index edeae1b9..00000000 --- a/SHiNE-agent-bot-coder/Players/PROMPTS_REVIEW.md +++ /dev/null @@ -1,26 +0,0 @@ -# Промпты для режима игроков (на согласование) - -## 1) Базовый служебный промпт (добавка к задаче игрока) - -```text -Режим игрока (обязательно): -- Пользователь: <Имя> (@). -- Рабочая папка игрока: /Players/ -- Код проекта не изменять. -- Можно отвечать на вопросы по проекту, предлагать идеи и готовить ТЗ. -- Если нужны правки кода, описывать предложение текстом и сохранять материалы только в папке игрока. -``` - -## 2) Приветственное сообщение игроку (один раз) - -```text -Привет, <Имя>. -Можно задавать вопросы по проекту, просить анализ, идеи и подготовку готового ТЗ. -Команда /new начинает новую сессию и архивирует текущую историю. -``` - -## 3) Отказ неизвестному пользователю - -```text -Извините, доступ к этому агенту пока не выдан. Обратитесь к Айдару. -``` diff --git a/SHiNE-agent-bot-coder/README.md b/SHiNE-agent-bot-coder/README.md deleted file mode 100644 index e1b815db..00000000 --- a/SHiNE-agent-bot-coder/README.md +++ /dev/null @@ -1,100 +0,0 @@ -# SHiNE-agent-bot-coder - -Локальный Telegram-бот-сервис для пользователя `ai`: -- принимает сообщения от `@AidarKC`; -- поддерживает whitelist игроков (`ALLOWED_TELEGRAM_PLAYERS`) с отдельными историями; -- ведёт историю диалога в `JSONL`; -- ставит задачи в файловую очередь; -- обрабатывает задачи строго последовательно; -- поддерживает текстовые и голосовые сообщения (voice/audio через OpenAI transcription); -- вызывает Codex CLI и отправляет ответ в Telegram; -- в личном чате умеет работать в двух персонально переключаемых режимах: через одно редактируемое статусное сообщение или через отдельные сообщения по этапам; -- умеет персонально для каждого пользователя озвучивать финальный ответ через OpenAI TTS; -- при рестарте восстанавливает незавершённые задачи; -- отправляет аварийный статус только если Codex молчит 2 минуты подряд во время активной задачи; -- принимает сообщения из канала/группы `@shine_writing`, выполняет команды только от `@AidarKC`; -- учитывает миграцию обычной Telegram-группы в supergroup и перенаправляет ответы на новый `chat_id`. - -Рабочая реализация сервиса — только `py_bot_service.py`. Старая Java-реализация удалена, потому что не заработала и больше не используется. - -## Структура -- `.env` — локальные секреты и параметры запуска (не коммитится); -- `data/py_queue.jsonl` — очередь Python-сервиса; -- `data/py_state.json` — текущее состояние Python-сервиса; -- `data/py_processed_updates.log` — дедуп входящих update; -- `data/history//*.jsonl` — активные истории по пользователям; -- `data/history//archive/*.jsonl` — архивы после `/new`. - -## Локальный запуск -1. Скопировать пример: - - `cp .env.example .env` -2. Заполнить секреты в `.env`. - - `TELEGRAM_BOT_TOKEN` — токен рабочего Telegram-бота. - - `ALLOWED_TELEGRAM_USERNAME` — пользователь, чьи сообщения выполняются как команды. - - `ALLOWED_TELEGRAM_PLAYERS` — whitelist игроков в формате `username:Имя,username2:Имя2`. - - `ALLOWED_TELEGRAM_CHANNEL_USERNAME` — канал, из которого принимаются `channel_post`; обычные group/supergroup-сообщения обрабатываются как `message`. - - `TELEGRAM_API_BASE_URL` — базовый URL Bot API; по умолчанию `https://api.telegram.org`. Для очень больших voice/audio можно поднять локальный `telegram-bot-api` и направить бота туда. - - `TELEGRAM_FILE_DOWNLOAD_TIMEOUT_SECONDS` — тайм-аут скачивания voice/audio из Telegram, по умолчанию 300 секунд. - - `OPENAI_TRANSCRIBE_TIMEOUT_SECONDS` — тайм-аут распознавания voice/audio в OpenAI, по умолчанию 900 секунд. - - `OPENAI_TRANSCRIBE_MAX_UPLOAD_BYTES` — безопасный лимит размера одного куска для OpenAI transcription, по умолчанию `24 MiB`. - - `OPENAI_TRANSCRIBE_MAX_CHUNK_SECONDS` — максимальная длина одного куска при длинном аудио, по умолчанию `900` секунд. - - `OPENAI_TRANSCRIBE_OVERLAP_SECONDS` — перекрытие соседних кусков для более ровной склейки текста, по умолчанию `2` секунды. - - `OPENAI_TRANSCRIBE_REENCODE_BITRATE_KBPS` — битрейт локального пережатия длинного аудио через `ffmpeg`, по умолчанию `24`. - - `OPENAI_TRANSCRIBE_FFMPEG_TIMEOUT_SECONDS` — тайм-аут локальной обработки длинного аудио через `ffmpeg`/`ffprobe`, по умолчанию `1800`. - - `FFMPEG_BIN` и `FFPROBE_BIN` — пути к локальным бинарям `ffmpeg`/`ffprobe`, если они не лежат в `PATH`. - - `OPENAI_TTS_MODEL` — модель синтеза речи, по умолчанию `gpt-4o-mini-tts`. - - `OPENAI_TTS_VOICE` — голос синтеза речи, по умолчанию `alloy`. - - `OPENAI_TTS_RESPONSE_FORMAT` — аудиоформат для Telegram voice, по умолчанию `opus`. - - `OPENAI_TTS_TIMEOUT_SECONDS` — тайм-аут генерации одного фрагмента речи, по умолчанию 180 секунд. - - `OPENAI_TTS_CHUNK_CHARS` — максимальный размер одного фрагмента озвучки, по умолчанию 3500 символов. -3. Запуск: - - `python3 SHiNE-agent-bot-coder/py_bot_service.py` - -## Быстрый self-test Codex (без Telegram) -```bash -python3 SHiNE-agent-bot-coder/py_bot_service.py --selftest-codex "Ответь одной строкой: Codex работает" -``` - -## Длинные voice/audio -- Если аудио короткое, бот отправляет его в OpenAI как раньше. -- Если аудио большое или длинное, бот локально пережимает его через `ffmpeg`, при необходимости режет на куски и распознаёт последовательно. -- Если Telegram заранее сообщает большой размер файла, бот больше не отказывается сразу: сначала явно пишет, что пробует скачать файл, затем отдельно сообщает, удалось ли скачивание, и только после успешной загрузки переходит к подготовке аудио и OpenAI. -- Для очень больших файлов упираемся не только в OpenAI, но и в лимит обычного облачного Telegram Bot API на скачивание файла ботом. Для таких случаев нужно использовать локальный `telegram-bot-api` сервер и указать его через `TELEGRAM_API_BASE_URL`. - -## Статусы в личке -- Для `private`-чата бот поддерживает персональную настройку режима ответа. -- По умолчанию он старается не засорять переписку промежуточными сообщениями: создаёт одно статусное сообщение и редактирует его по этапам. -- Если включить `/single_message_off`, бот возвращается к старому режиму и отправляет отдельные сообщения по этапам и финальный ответ отдельно. -- Если финальный текст в режиме одного сообщения не помещается целиком, бот оставляет первую часть в отредактированном статусном сообщении и отправляет максимум ещё одно дополнительное текстовое сообщение с хвостом ответа. -- Голосовой ответ, если он включён, всегда приходит отдельным новым сообщением. - -## Запуск как systemd-сервис -Файлы для установки: -- `scripts/systemd/shine-agent-bot-coder.service` -- `scripts/systemd/install-local-systemd.sh` - -Установка: -- `bash SHiNE-agent-bot-coder/scripts/systemd/install-local-systemd.sh` - -Проверка: -- `systemctl --user status shine-agent-bot-coder --no-pager` -- `journalctl --user -u shine-agent-bot-coder -f` - -Перезапуск после изменений: -- `systemctl --user restart shine-agent-bot-coder` - -## Telegram-команды -- `/status` — активная задача и размер очереди. -- `/settings` — текущие пользовательские настройки и команды для их изменения. -- `/queue` — список задач в очереди. -- `/stop` — остановить текущую задачу. -- `/cancel ` — удалить задачу по id/префиксу или очистить очередь. -- `/new` — архивировать текущую историю, сбросить продолжение Codex-сессии для этого пользователя и начать новый диалог. -- `/voice_on` — включить озвучивание финальных ответов для текущего пользователя. -- `/voice_off` — выключить озвучивание финальных ответов для текущего пользователя. -- `/voice_rewrite_on` — включить адаптацию текста перед озвучкой. -- `/voice_rewrite_off` — выключить адаптацию текста перед озвучкой. -- `/single_message_on` — вести ответ в личке через одно редактируемое сообщение. -- `/single_message_off` — слать отдельные сообщения по этапам и отдельный финальный ответ. -- `/restart` или `/restart_service` — отложенный рестарт после текущей задачи, до взятия следующей (только для Айдара). -- `/restart_hard` — жёсткий рестарт прямо сейчас (только для Айдара). diff --git a/SHiNE-agent-bot-coder/py_bot_service.py b/SHiNE-agent-bot-coder/py_bot_service.py deleted file mode 100644 index fa53d0de..00000000 --- a/SHiNE-agent-bot-coder/py_bot_service.py +++ /dev/null @@ -1,2976 +0,0 @@ -#!/usr/bin/env python3 -from __future__ import annotations - -import argparse -import datetime as dt -import fcntl -import json -import mimetypes -import os -import random -import re -import shutil -import string -import subprocess -import tempfile -import threading -import time -import traceback -import uuid -from pathlib import Path -from typing import Any, Callable -from urllib import error, request - -DEFAULT_ALLOWED_PLAYERS = ",".join([ - "malvviiina:Милана", - "zodiaktechnika32:Сергей", - "oidasyda:Иван", - "blackbyrd1:Ворон", - "dimasol1:Дима", -]) - -TASK_STATUS_LABELS = { - "new": "новая", - "approved": "одобрена", - "rejected": "отклонена", - "needs_work": "на доработку", - "done": "сделана", -} - - -def now_iso() -> str: - return dt.datetime.now(dt.timezone.utc).isoformat() - - -def normalize_username(value: str | None) -> str: - if not value: - return "" - value = value.strip() - if value.startswith("@"): - value = value[1:] - return value.lower() - - -def parse_allowed_players(raw: str) -> dict[str, str]: - players: dict[str, str] = {} - for item in (raw or "").split(","): - part = item.strip() - if not part: - continue - username_part, sep, name_part = part.partition(":") - username = normalize_username(username_part) - if not username: - continue - player_name = (name_part if sep else username_part).strip() or username - players[username] = player_name - return players - - -def compact_spaces(text: str) -> str: - return re.sub(r"\s+", " ", (text or "").strip()) - - -def split_long_text(text: str, chunk_size: int = 3500) -> list[str]: - text = (text or "").strip() - if not text: - return ["(пустой ответ)"] - return [text[i:i + chunk_size] for i in range(0, len(text), chunk_size)] - - -def split_final_private_text(text: str, first_chunk_size: int = 3900, second_chunk_size: int = 3900) -> list[str]: - text = (text or "").strip() - if not text: - return ["(пустой ответ)"] - if len(text) <= first_chunk_size: - return [text] - first = text[:first_chunk_size].rstrip() - rest = text[first_chunk_size:].lstrip() - if len(rest) <= second_chunk_size: - return [first, rest] - second = rest[:second_chunk_size].rstrip() - if len(second) > 40: - second = second[:-40].rstrip() - second = second.rstrip() + "\n...[ответ обрезан]" - return [first, second] - - -def split_text_for_tts(text: str, chunk_size: int) -> list[str]: - text = (text or "").strip() - if not text: - return [] - chunks: list[str] = [] - current = "" - paragraphs = re.split(r"\n\s*\n", text) - for paragraph in paragraphs: - paragraph = paragraph.strip() - if not paragraph: - continue - if len(paragraph) > chunk_size: - if current: - chunks.append(current) - current = "" - for i in range(0, len(paragraph), chunk_size): - part = paragraph[i:i + chunk_size].strip() - if part: - chunks.append(part) - continue - candidate = paragraph if not current else f"{current}\n\n{paragraph}" - if len(candidate) <= chunk_size: - current = candidate - else: - if current: - chunks.append(current) - current = paragraph - if current: - chunks.append(current) - return chunks - - -def read_env_file(path: Path) -> dict[str, str]: - result: dict[str, str] = {} - if not path.exists(): - return result - for raw_line in path.read_text(encoding="utf-8").splitlines(): - line = raw_line.strip() - if not line or line.startswith("#") or "=" not in line: - continue - key, value = line.split("=", 1) - key = key.strip() - value = value.strip().strip('"').strip("'") - result[key] = value - return result - - -class VoiceTranscriptionError(RuntimeError): - def __init__( - self, - user_message: str, - *, - stage: str, - retryable: bool = True, - detail: str = "", - ): - super().__init__(user_message) - self.user_message = user_message - self.stage = stage - self.retryable = retryable - self.detail = detail - - def log_text(self) -> str: - if self.detail and self.detail != self.user_message: - return f"{self.user_message} stage={self.stage} retryable={self.retryable} detail={self.detail}" - return f"{self.user_message} stage={self.stage} retryable={self.retryable}" - - -class VoiceReplyError(RuntimeError): - pass - - -class JsonLineStore: - @staticmethod - def load(path: Path) -> list[dict[str, Any]]: - if not path.exists(): - return [] - items: list[dict[str, Any]] = [] - for line in path.read_text(encoding="utf-8").splitlines(): - line = line.strip() - if not line: - continue - items.append(json.loads(line)) - return items - - @staticmethod - def save(path: Path, items: list[dict[str, Any]]) -> None: - path.parent.mkdir(parents=True, exist_ok=True) - tmp = path.with_suffix(path.suffix + ".tmp") - with tmp.open("w", encoding="utf-8") as f: - for item in items: - f.write(json.dumps(item, ensure_ascii=False) + "\n") - tmp.replace(path) - - @staticmethod - def append(path: Path, item: dict[str, Any]) -> None: - path.parent.mkdir(parents=True, exist_ok=True) - with path.open("a", encoding="utf-8") as f: - f.write(json.dumps(item, ensure_ascii=False) + "\n") - - -class TelegramApi: - def __init__(self, token: str, base_url: str = "https://api.telegram.org"): - self.token = token - self.api_root = (base_url or "https://api.telegram.org").rstrip("/") - self.base = f"{self.api_root}/bot{token}/" - self.file_base = f"{self.api_root}/file/bot{token}/" - - def call(self, method: str, payload: dict[str, Any] | None = None, timeout: int = 60) -> dict[str, Any]: - data = None - headers = {} - if payload is not None: - data = json.dumps(payload).encode("utf-8") - headers["Content-Type"] = "application/json" - req = request.Request(self.base + method, data=data, headers=headers, method="POST") - try: - with request.urlopen(req, timeout=timeout) as resp: - raw = resp.read().decode("utf-8") - except error.HTTPError as e: - body = e.read().decode("utf-8", errors="replace") - raise RuntimeError(f"Telegram HTTP {e.code}: {body}") from e - except Exception as e: - raise RuntimeError(f"Telegram request failed: {e}") from e - - result = json.loads(raw) - if not result.get("ok"): - raise RuntimeError(f"Telegram API error: {result}") - return result - - def call_multipart( - self, - method: str, - fields: dict[str, Any], - files: dict[str, tuple[str, bytes, str]], - timeout: int = 120, - ) -> dict[str, Any]: - boundary = "----shine-tg-boundary-" + "".join(random.choices("abcdef0123456789", k=16)) - body = bytearray() - for name, value in fields.items(): - if value is None: - continue - body.extend( - ( - f"--{boundary}\r\n" - f'Content-Disposition: form-data; name="{name}"\r\n\r\n' - f"{value}\r\n" - ).encode("utf-8") - ) - for name, (filename, data, mime) in files.items(): - body.extend( - ( - f"--{boundary}\r\n" - f'Content-Disposition: form-data; name="{name}"; filename="{filename}"\r\n' - f"Content-Type: {mime}\r\n\r\n" - ).encode("utf-8") - ) - body.extend(data) - body.extend(b"\r\n") - body.extend(f"--{boundary}--\r\n".encode("utf-8")) - - req = request.Request(self.base + method, data=bytes(body), method="POST") - req.add_header("Content-Type", f"multipart/form-data; boundary={boundary}") - try: - with request.urlopen(req, timeout=timeout) as resp: - raw = resp.read().decode("utf-8") - except error.HTTPError as e: - body_text = e.read().decode("utf-8", errors="replace") - raise RuntimeError(f"Telegram HTTP {e.code}: {body_text}") from e - except Exception as e: - raise RuntimeError(f"Telegram multipart request failed: {e}") from e - - result = json.loads(raw) - if not result.get("ok"): - raise RuntimeError(f"Telegram API error: {result}") - return result - - def get_updates(self, offset: int | None, timeout_sec: int) -> list[dict[str, Any]]: - payload: dict[str, Any] = {"timeout": timeout_sec, "allowed_updates": ["message", "channel_post"]} - if offset is not None: - payload["offset"] = offset - result = self.call("getUpdates", payload=payload, timeout=timeout_sec + 15) - return result.get("result", []) - - def send_message(self, chat_id: int | str, text: str, reply_to_message_id: int | None = None) -> dict[str, Any]: - payload: dict[str, Any] = {"chat_id": chat_id, "text": text} - if reply_to_message_id is not None: - payload["reply_to_message_id"] = reply_to_message_id - return self.call("sendMessage", payload=payload, timeout=30) - - def edit_message_text(self, chat_id: int | str, message_id: int, text: str) -> dict[str, Any]: - payload: dict[str, Any] = {"chat_id": chat_id, "message_id": message_id, "text": text} - return self.call("editMessageText", payload=payload, timeout=30) - - def send_voice( - self, - chat_id: int | str, - voice: str, - caption: str = "", - reply_to_message_id: int | None = None, - ) -> dict[str, Any]: - payload: dict[str, Any] = {"chat_id": chat_id, "voice": voice} - if caption: - payload["caption"] = caption - if reply_to_message_id is not None: - payload["reply_to_message_id"] = reply_to_message_id - return self.call("sendVoice", payload=payload, timeout=60) - - def send_audio( - self, - chat_id: int | str, - audio: str, - caption: str = "", - reply_to_message_id: int | None = None, - ) -> dict[str, Any]: - payload: dict[str, Any] = {"chat_id": chat_id, "audio": audio} - if caption: - payload["caption"] = caption - if reply_to_message_id is not None: - payload["reply_to_message_id"] = reply_to_message_id - return self.call("sendAudio", payload=payload, timeout=60) - - def send_voice_upload( - self, - chat_id: int | str, - voice_bytes: bytes, - filename: str, - caption: str = "", - reply_to_message_id: int | None = None, - ) -> dict[str, Any]: - fields: dict[str, Any] = {"chat_id": chat_id} - if caption: - fields["caption"] = caption - if reply_to_message_id is not None: - fields["reply_to_message_id"] = reply_to_message_id - return self.call_multipart( - "sendVoice", - fields=fields, - files={"voice": (filename, voice_bytes, "audio/ogg")}, - timeout=180, - ) - - def delete_webhook(self) -> None: - self.call("deleteWebhook", payload={"drop_pending_updates": False}, timeout=30) - - -class BotConfig: - def __init__(self, root_dir: Path): - env = dict(os.environ) - env.update(read_env_file(root_dir / ".env")) - - self.root_dir = root_dir - self.telegram_bot_token = self._required(env, "TELEGRAM_BOT_TOKEN") - self.allowed_username = normalize_username(env.get("ALLOWED_TELEGRAM_USERNAME", "AidarKC")) - self.allowed_players = parse_allowed_players(env.get("ALLOWED_TELEGRAM_PLAYERS", DEFAULT_ALLOWED_PLAYERS)) - self.allowed_channel_username = normalize_username(env.get("ALLOWED_TELEGRAM_CHANNEL_USERNAME", "shine_writing")) - self.bot_username = env.get("BOT_USERNAME", "aidar_su_bot") - self.telegram_api_base_url = env.get("TELEGRAM_API_BASE_URL", "https://api.telegram.org").strip() or "https://api.telegram.org" - self.openai_api_key = env.get("OPENAI_API_KEY", "").strip() - self.openai_transcribe_model = env.get("OPENAI_TRANSCRIBE_MODEL", "gpt-4o-mini-transcribe") - self.telegram_file_download_timeout_seconds = int(env.get("TELEGRAM_FILE_DOWNLOAD_TIMEOUT_SECONDS", "300")) - self.openai_transcribe_timeout_seconds = int(env.get("OPENAI_TRANSCRIBE_TIMEOUT_SECONDS", "900")) - self.openai_transcribe_max_upload_bytes = max(1_000_000, int(env.get("OPENAI_TRANSCRIBE_MAX_UPLOAD_BYTES", str(24 * 1024 * 1024)))) - self.openai_transcribe_max_chunk_seconds = max(60, int(env.get("OPENAI_TRANSCRIBE_MAX_CHUNK_SECONDS", "900"))) - self.openai_transcribe_overlap_seconds = max(0, int(env.get("OPENAI_TRANSCRIBE_OVERLAP_SECONDS", "2"))) - self.openai_transcribe_reencode_bitrate_kbps = max(12, int(env.get("OPENAI_TRANSCRIBE_REENCODE_BITRATE_KBPS", "24"))) - self.openai_transcribe_ffmpeg_timeout_seconds = max(30, int(env.get("OPENAI_TRANSCRIBE_FFMPEG_TIMEOUT_SECONDS", "1800"))) - self.ffmpeg_bin = env.get("FFMPEG_BIN", "ffmpeg").strip() or "ffmpeg" - self.ffprobe_bin = env.get("FFPROBE_BIN", "ffprobe").strip() or "ffprobe" - self.openai_tts_model = env.get("OPENAI_TTS_MODEL", "gpt-4o-mini-tts") - self.openai_tts_voice = env.get("OPENAI_TTS_VOICE", "alloy") - self.openai_tts_response_format = env.get("OPENAI_TTS_RESPONSE_FORMAT", "opus") - self.openai_tts_timeout_seconds = int(env.get("OPENAI_TTS_TIMEOUT_SECONDS", "180")) - self.openai_tts_chunk_chars = max(500, int(env.get("OPENAI_TTS_CHUNK_CHARS", "3500"))) - self.openai_voice_rewrite_model = env.get("OPENAI_VOICE_REWRITE_MODEL", "gpt-4.1-nano") - self.openai_voice_rewrite_timeout_seconds = int(env.get("OPENAI_VOICE_REWRITE_TIMEOUT_SECONDS", "90")) - self.openai_voice_rewrite_max_input_chars = max(1000, int(env.get("OPENAI_VOICE_REWRITE_MAX_INPUT_CHARS", "12000"))) - self.openai_voice_rewrite_max_output_tokens = max(200, int(env.get("OPENAI_VOICE_REWRITE_MAX_OUTPUT_TOKENS", "900"))) - self.codex_bin = Path(env.get( - "CODEX_BIN", - "/home/ai/.cache/JetBrains/IntelliJIdea2026.1/aia/codex/bin/codex-x86_64-unknown-linux-musl" - )) - self.codex_workdir = Path(env.get("CODEX_WORKDIR", "/home/ai/work/SHiNE/SHiNE-server-sha256")) - self.codex_timeout_seconds = int(env.get("CODEX_TIMEOUT_SECONDS", "900")) - self.max_retries = max(1, int(env.get("MAX_RETRIES", "3"))) - self.data_dir = (root_dir / env.get("DATA_DIR", "./data")).resolve() - self.agent_instructions_file = (root_dir / "AGENT.md").resolve() - - @staticmethod - def _required(env: dict[str, str], key: str) -> str: - value = env.get(key, "").strip() - if not value: - raise RuntimeError(f"Не задан обязательный параметр: {key}") - return value - - -class ShinePyBotService: - def __init__(self, config: BotConfig): - self.cfg = config - self.telegram = TelegramApi(config.telegram_bot_token, config.telegram_api_base_url) - - self.queue_file = config.data_dir / "py_queue.jsonl" - self.state_file = config.data_dir / "py_state.json" - self.processed_updates_file = config.data_dir / "py_processed_updates.log" - self.lock_file = config.data_dir / "py_app.lock" - self.history_dir = config.data_dir / "history" - self.history_archive_dir = self.history_dir / "archive" - self.task_center_dir = config.data_dir / "task_center" - self.task_center_file = self.task_center_dir / "items.json" - self.max_processed_updates = 5000 - - self.queue_lock = threading.RLock() - self.task_center_lock = threading.RLock() - self.stop_event = threading.Event() - self.worker = threading.Thread(target=self._worker_loop, name="shine-py-bot-worker", daemon=True) - - self.queue: list[dict[str, Any]] = [] - self.state: dict[str, Any] = {} - self.processed_updates: list[str] = [] - self.active_job_id: str | None = None - self.active_job_started_at: float | None = None - self.active_process: subprocess.Popen[str] | None = None - self.active_process_lock = threading.Lock() - self.stop_current_job = False - self.lock_fd = None - self.last_heartbeat_at: float = 0.0 - self.restart_requested = False - - def _is_owner(self, username: str) -> bool: - return normalize_username(username) == self.cfg.allowed_username - - def _is_allowed_player(self, username: str) -> bool: - return normalize_username(username) in self.cfg.allowed_players - - def _is_allowed_user(self, username: str) -> bool: - uname = normalize_username(username) - return uname == self.cfg.allowed_username or uname in self.cfg.allowed_players - - def _player_name(self, username: str) -> str: - uname = normalize_username(username) - return self.cfg.allowed_players.get(uname, uname) - - def _display_name(self, username: str) -> str: - uname = normalize_username(username) - if uname == self.cfg.allowed_username: - return "Айдар" - return self._player_name(uname) - - def _known_usernames(self) -> dict[str, str]: - users = {self.cfg.allowed_username: "Айдар"} - users.update(self.cfg.allowed_players) - return users - - def _find_user_by_text(self, text: str) -> str: - source = normalize_username(text) - if source in self._known_usernames(): - return source - source_lower = (text or "").strip().lower() - aliases = { - "айдар": self.cfg.allowed_username, - "айдару": self.cfg.allowed_username, - "айдара": self.cfg.allowed_username, - "милана": "malvviiina", - "милане": "malvviiina", - "милану": "malvviiina", - "миланы": "malvviiina", - "сергей": "zodiaktechnika32", - "сергею": "zodiaktechnika32", - "сергея": "zodiaktechnika32", - "иван": "oidasyda", - "ивану": "oidasyda", - "ивана": "oidasyda", - "ворон": "blackbyrd1", - "ворону": "blackbyrd1", - "ворона": "blackbyrd1", - "дима": "dimasol1", - "диме": "dimasol1", - "диму": "dimasol1", - "димы": "dimasol1", - } - for alias, username in aliases.items(): - if re.search(rf"(^|\W){re.escape(alias)}($|\W)", source_lower, flags=re.IGNORECASE): - return username - for username, name in self._known_usernames().items(): - if username and username in source_lower: - return username - if name and name.lower() in source_lower: - return username - return "" - - def run(self) -> None: - self._ensure_dirs() - self._acquire_single_instance_lock() - self._load_state() - self._load_queue() - self._load_processed_updates() - self._recover_active_jobs_after_restart() - self.telegram.delete_webhook() - self._init_offset_if_missing() - self.worker.start() - self._append_history_event("service_started", {"allowedUsername": self.cfg.allowed_username}) - print(f"[py-bot] Запущен. allowed user: @{self.cfg.allowed_username}", flush=True) - - try: - while not self.stop_event.is_set(): - try: - offset = self.state.get("offset") - updates = self.telegram.get_updates(offset=offset, timeout_sec=25) - except Exception as e: - print(f"[py-bot] Ошибка getUpdates: {e}", flush=True) - time.sleep(2) - continue - - for update in updates: - update_id = update.get("update_id") - if isinstance(update_id, int): - self.state["offset"] = update_id + 1 - self._persist_state() - self._handle_update(update) - finally: - self.shutdown() - - def shutdown(self) -> None: - if self.stop_event.is_set(): - pass - self.stop_event.set() - self._stop_active_codex_process() - if self.worker.is_alive(): - self.worker.join(timeout=10) - if self.lock_fd is not None: - try: - fcntl.flock(self.lock_fd, fcntl.LOCK_UN) - finally: - self.lock_fd.close() - self.lock_fd = None - self._append_history_event("service_stopped", {}) - - def _ensure_dirs(self) -> None: - self.cfg.data_dir.mkdir(parents=True, exist_ok=True) - self.history_dir.mkdir(parents=True, exist_ok=True) - self.history_archive_dir.mkdir(parents=True, exist_ok=True) - self.task_center_dir.mkdir(parents=True, exist_ok=True) - - def _acquire_single_instance_lock(self) -> None: - self.lock_file.parent.mkdir(parents=True, exist_ok=True) - self.lock_fd = self.lock_file.open("a+") - try: - fcntl.flock(self.lock_fd, fcntl.LOCK_EX | fcntl.LOCK_NB) - except BlockingIOError: - raise RuntimeError(f"Уже запущен другой инстанс (lock: {self.lock_file})") - - def _load_state(self) -> None: - if self.state_file.exists(): - self.state = json.loads(self.state_file.read_text(encoding="utf-8")) - else: - self.state = {} - sessions = self.state.get("user_sessions") - if not isinstance(sessions, dict): - sessions = {} - self.state["user_sessions"] = sessions - user_settings = self.state.get("user_settings") - if not isinstance(user_settings, dict): - user_settings = {} - self.state["user_settings"] = user_settings - if not self.state.get("current_history_file"): - history_file = self._create_new_history_file("initial", self.cfg.allowed_username) - self.state["current_history_file"] = str(history_file) - sessions[self.cfg.allowed_username] = {"current_history_file": str(history_file)} - elif self.cfg.allowed_username not in sessions: - sessions[self.cfg.allowed_username] = {"current_history_file": str(self.state["current_history_file"])} - if not isinstance(self.state.get("next_job_number"), int): - self.state["next_job_number"] = 1 - self.state["updated_at"] = now_iso() - self._persist_state() - - def _persist_state(self) -> None: - self.state["updated_at"] = now_iso() - tmp = self.state_file.with_suffix(".tmp") - tmp.write_text(json.dumps(self.state, ensure_ascii=False, indent=2), encoding="utf-8") - tmp.replace(self.state_file) - - def _load_queue(self) -> None: - self.queue = JsonLineStore.load(self.queue_file) - - def _persist_queue(self) -> None: - JsonLineStore.save(self.queue_file, self.queue) - - def _load_processed_updates(self) -> None: - if not self.processed_updates_file.exists(): - self.processed_updates = [] - return - lines = [x.strip() for x in self.processed_updates_file.read_text(encoding="utf-8").splitlines() if x.strip()] - if len(lines) > self.max_processed_updates: - lines = lines[-self.max_processed_updates:] - self.processed_updates_file.write_text("\n".join(lines) + "\n", encoding="utf-8") - self.processed_updates = lines - - def _mark_processed_update(self, update_key: str) -> bool: - if update_key in self.processed_updates: - return True - self.processed_updates.append(update_key) - if len(self.processed_updates) > self.max_processed_updates: - self.processed_updates = self.processed_updates[-self.max_processed_updates:] - self.processed_updates_file.write_text("\n".join(self.processed_updates) + "\n", encoding="utf-8") - else: - with self.processed_updates_file.open("a", encoding="utf-8") as f: - f.write(update_key + "\n") - return False - - def _recover_active_jobs_after_restart(self) -> None: - recovered_ids: list[str] = [] - for job in self.queue: - if job.get("status") == "active": - job["status"] = "pending" - job["retry_reason"] = "service_restart_recovery" - job["updated_at"] = now_iso() - recovered_ids.append(job.get("id", "")) - if recovered_ids: - self._persist_queue() - self._append_history_event("active_jobs_recovered", {"jobIds": recovered_ids}) - - def _init_offset_if_missing(self) -> None: - if self.state.get("offset") is not None: - return - try: - updates = self.telegram.get_updates(offset=None, timeout_sec=0) - if updates: - self.state["offset"] = int(updates[-1]["update_id"]) + 1 - else: - self.state["offset"] = 0 - self._persist_state() - except Exception as e: - print(f"[py-bot] Не удалось инициализировать offset: {e}", flush=True) - self.state["offset"] = 0 - self._persist_state() - - def _current_history_file(self) -> Path: - return self._current_history_file_for_user(self.cfg.allowed_username) - - def _history_dirs_for_user(self, username: str) -> tuple[Path, Path]: - uname = normalize_username(username) or "unknown" - history_dir = self.history_dir / uname - archive_dir = history_dir / "archive" - history_dir.mkdir(parents=True, exist_ok=True) - archive_dir.mkdir(parents=True, exist_ok=True) - return history_dir, archive_dir - - def _ensure_user_session(self, username: str) -> None: - uname = normalize_username(username) or self.cfg.allowed_username - sessions = self.state.setdefault("user_sessions", {}) - if not isinstance(sessions, dict): - sessions = {} - self.state["user_sessions"] = sessions - self._user_settings(uname) - session = sessions.get(uname) - if isinstance(session, dict) and session.get("current_history_file"): - return - history_file = self._create_new_history_file("initial", uname) - sessions[uname] = {"current_history_file": str(history_file)} - if uname == self.cfg.allowed_username: - self.state["current_history_file"] = str(history_file) - self._persist_state() - - def _user_session_state(self, username: str) -> dict[str, Any]: - uname = normalize_username(username) or self.cfg.allowed_username - self._ensure_user_session(uname) - sessions = self.state.get("user_sessions") or {} - session = sessions.get(uname) - if not isinstance(session, dict): - session = {} - sessions[uname] = session - return session - - def _current_history_file_for_user(self, username: str) -> Path: - session = self._user_session_state(username) - return Path(session["current_history_file"]) - - def _codex_thread_id_for_user(self, username: str) -> str: - thread_id = (self._user_session_state(username).get("codex_thread_id") or "").strip() - return thread_id - - def _set_codex_thread_id_for_user(self, username: str, thread_id: str) -> None: - session = self._user_session_state(username) - normalized = (thread_id or "").strip() - if normalized: - session["codex_thread_id"] = normalized - else: - session.pop("codex_thread_id", None) - self._persist_state() - - def _create_new_history_file(self, reason: str, username: str) -> Path: - ts = dt.datetime.now().strftime("%Y-%m-%d_%H%M%S") - rnd = "".join(random.choices(string.hexdigits.lower(), k=8)) - history_dir, _ = self._history_dirs_for_user(username) - path = history_dir / f"{ts}_{rnd}.jsonl" - JsonLineStore.append(path, { - "ts": now_iso(), - "type": "history_created", - "reason": reason, - "username": normalize_username(username), - }) - return path - - def _rotate_history(self, reason: str, username: str) -> Path: - uname = normalize_username(username) or self.cfg.allowed_username - current = self._current_history_file_for_user(uname) - _, archive_dir = self._history_dirs_for_user(uname) - if current.exists(): - archived = archive_dir / current.name - current.replace(archived) - else: - archived = archive_dir / "(empty)" - new_file = self._create_new_history_file(reason, uname) - sessions = self.state.setdefault("user_sessions", {}) - if not isinstance(sessions, dict): - sessions = {} - self.state["user_sessions"] = sessions - previous = sessions.get(uname) if isinstance(sessions.get(uname), dict) else {} - sessions[uname] = {"current_history_file": str(new_file)} - if reason != "command_new" and isinstance(previous, dict): - thread_id = (previous.get("codex_thread_id") or "").strip() - if thread_id: - sessions[uname]["codex_thread_id"] = thread_id - if uname == self.cfg.allowed_username: - self.state["current_history_file"] = str(new_file) - self._persist_state() - self._append_history_event("history_rotated", {"reason": reason, "username": uname, "archived": str(archived)}, username=uname) - return archived - - def _user_settings(self, username: str) -> dict[str, Any]: - uname = normalize_username(username) or self.cfg.allowed_username - settings = self.state.get("user_settings") - if not isinstance(settings, dict): - settings = {} - self.state["user_settings"] = settings - user_settings = settings.get(uname) - if not isinstance(user_settings, dict): - user_settings = {} - settings[uname] = user_settings - if not isinstance(user_settings.get("voice_replies_enabled"), bool): - user_settings["voice_replies_enabled"] = True - if not isinstance(user_settings.get("voice_rewrite_enabled"), bool): - user_settings["voice_rewrite_enabled"] = True - if not isinstance(user_settings.get("single_status_message_enabled"), bool): - user_settings["single_status_message_enabled"] = True - return user_settings - - def _voice_replies_enabled(self, username: str) -> bool: - return bool(self._user_settings(username).get("voice_replies_enabled")) - - def _set_voice_replies_enabled(self, username: str, enabled: bool) -> None: - self._user_settings(username)["voice_replies_enabled"] = enabled - self._persist_state() - - def _voice_rewrite_enabled(self, username: str) -> bool: - return bool(self._user_settings(username).get("voice_rewrite_enabled")) - - def _set_voice_rewrite_enabled(self, username: str, enabled: bool) -> None: - self._user_settings(username)["voice_rewrite_enabled"] = enabled - self._persist_state() - - def _single_status_message_enabled(self, username: str) -> bool: - return bool(self._user_settings(username).get("single_status_message_enabled")) - - def _set_single_status_message_enabled(self, username: str, enabled: bool) -> None: - self._user_settings(username)["single_status_message_enabled"] = enabled - self._persist_state() - - def _remember_private_chat(self, username: str, chat_id: int) -> None: - uname = normalize_username(username) - if not uname: - return - private_chats = self.state.get("private_chat_ids") - if not isinstance(private_chats, dict): - private_chats = {} - self.state["private_chat_ids"] = private_chats - if private_chats.get(uname) == chat_id: - return - private_chats[uname] = chat_id - self._persist_state() - - def _private_chat_id_for_user(self, username: str) -> int | None: - private_chats = self.state.get("private_chat_ids") - if not isinstance(private_chats, dict): - return None - chat_id = private_chats.get(normalize_username(username)) - return self._resolve_chat_id(chat_id) if isinstance(chat_id, int) else None - - def _append_history(self, history_path: Path, event_type: str, payload: dict[str, Any]) -> None: - row = {"ts": now_iso(), "type": event_type} - row.update(payload) - JsonLineStore.append(history_path, row) - - def _append_history_event(self, event_type: str, payload: dict[str, Any], username: str | None = None) -> None: - history_path = self._current_history_file_for_user(username or self.cfg.allowed_username) - self._append_history(history_path, "system_event", {"event": event_type, **payload}) - - def _load_task_items(self) -> list[dict[str, Any]]: - with self.task_center_lock: - if not self.task_center_file.exists(): - return [] - try: - data = json.loads(self.task_center_file.read_text(encoding="utf-8")) - except Exception: - return [] - return data if isinstance(data, list) else [] - - def _save_task_items(self, items: list[dict[str, Any]]) -> None: - with self.task_center_lock: - self.task_center_file.parent.mkdir(parents=True, exist_ok=True) - tmp = self.task_center_file.with_suffix(".tmp") - tmp.write_text(json.dumps(items, ensure_ascii=False, indent=2), encoding="utf-8") - tmp.replace(self.task_center_file) - - def _next_task_item_id(self, items: list[dict[str, Any]]) -> str: - max_num = 0 - for item in items: - raw = str(item.get("id") or "") - match = re.match(r"TC-(\d+)$", raw) - if match: - max_num = max(max_num, int(match.group(1))) - return f"TC-{max_num + 1:04d}" - - def _create_task_item( - self, - *, - kind: str, - title: str, - text: str, - source_username: str, - target_username: str, - source_message_id: int | None = None, - source_chat_id: int | None = None, - opinion: str = "", - ) -> dict[str, Any]: - items = self._load_task_items() - item = { - "id": self._next_task_item_id(items), - "kind": kind, - "status": "new", - "title": compact_spaces(title)[:160] or ("Предложение" if kind == "proposal" else "Задача"), - "text": (text or "").strip(), - "opinion": (opinion or "").strip(), - "source_username": normalize_username(source_username), - "source_name": self._display_name(source_username), - "target_username": normalize_username(target_username), - "target_name": self._display_name(target_username), - "source_chat_id": source_chat_id, - "source_message_id": source_message_id, - "created_at": now_iso(), - "updated_at": now_iso(), - } - items.append(item) - self._save_task_items(items) - self._append_history_event("task_center_item_created", { - "itemId": item["id"], - "kind": kind, - "sourceUsername": item["source_username"], - "targetUsername": item["target_username"], - "title": item["title"], - }, username=source_username) - return item - - def _task_items_for_user(self, username: str, *, include_done: bool = False) -> list[dict[str, Any]]: - uname = normalize_username(username) - items = self._load_task_items() - result = [ - item for item in items - if normalize_username(item.get("target_username")) == uname - and (include_done or item.get("status") != "done") - ] - return sorted(result, key=lambda x: str(x.get("created_at") or "")) - - def _task_center_counts_text(self, username: str) -> str: - counts: dict[str, int] = {} - for item in self._task_items_for_user(username): - status = str(item.get("status") or "new") - counts[status] = counts.get(status, 0) + 1 - active_total = sum(counts.values()) - if active_total <= 0: - return "" - parts = [] - for status in ("new", "approved", "needs_work", "rejected"): - count = counts.get(status, 0) - if count: - parts.append(f"{TASK_STATUS_LABELS.get(status, status)}: {count}") - return f"Напоминание по задачам: всего активных {active_total}; " + ", ".join(parts) + "." - - def _format_task_items(self, username: str, *, include_done: bool = False) -> str: - items = self._task_items_for_user(username, include_done=include_done) - if not items: - return f"Для {self._display_name(username)} активных задач и предложений нет." - lines = [f"Задачи и предложения для {self._display_name(username)}:"] - for item in items[:15]: - kind = "предложение" if item.get("kind") == "proposal" else "задача" - status = TASK_STATUS_LABELS.get(str(item.get("status") or "new"), str(item.get("status") or "new")) - source = item.get("source_name") or item.get("source_username") or "неизвестно" - title = item.get("title") or "(без названия)" - lines.append(f"{item.get('id')} [{status}] {kind} от {source}: {title}") - if len(items) > 15: - lines.append(f"...и ещё {len(items) - 15}") - return "\n".join(lines) - - def _update_task_item_status(self, item_id: str, status: str) -> dict[str, Any] | None: - item_id = (item_id or "").strip().upper() - items = self._load_task_items() - updated = None - for item in items: - if str(item.get("id") or "").upper() == item_id: - item["status"] = status - item["updated_at"] = now_iso() - updated = item - break - if updated is not None: - self._save_task_items(items) - return updated - - def _find_first_task_item(self, *, source_username: str = "", target_username: str = "", kind: str = "") -> dict[str, Any] | None: - source = normalize_username(source_username) - target = normalize_username(target_username) - for item in self._load_task_items(): - if item.get("status") == "done": - continue - if source and normalize_username(item.get("source_username")) != source: - continue - if target and normalize_username(item.get("target_username")) != target: - continue - if kind and item.get("kind") != kind: - continue - return item - return None - - def _notify_user_about_task_item(self, username: str, item: dict[str, Any]) -> None: - chat_id = self._private_chat_id_for_user(username) - if chat_id is None: - return - kind = "предложение" if item.get("kind") == "proposal" else "задача" - source = item.get("source_name") or item.get("source_username") or "кто-то" - title = item.get("title") or "(без названия)" - status = TASK_STATUS_LABELS.get(str(item.get("status") or "new"), str(item.get("status") or "new")) - if item.get("status") == "new": - text = f"У тебя новое {kind} от {source}: {title}\nID: {item.get('id')}" - else: - text = f"Обновление по {kind} {item.get('id')}: статус «{status}».\n{title}" - self._safe_send(chat_id, text) - - def _send_player_welcome_once(self, chat_id: int, message_id: int, username: str) -> None: - uname = normalize_username(username) - sent = self.state.get("player_welcome_sent") - if not isinstance(sent, dict): - sent = {} - self.state["player_welcome_sent"] = sent - if sent.get(uname): - return - player_name = self._player_name(uname) - text = ( - f"Привет, {player_name}.\n" - "Можно задавать вопросы по проекту, просить анализ, идеи и подготовку готового ТЗ.\n" - "Команда /new начинает новую Codex-сессию и архивирует текущую историю." - ) - reminder = self._task_center_counts_text(uname) - if reminder: - text = f"{text}\n\n{reminder}\nКоманда /tasks покажет список." - self._safe_send(chat_id, text, reply_to=message_id) - sent[uname] = now_iso() - self._persist_state() - - def _resolve_chat_id(self, chat_id: int) -> int: - migrations = self.state.get("chat_id_migrations") - if not isinstance(migrations, dict): - return chat_id - current = chat_id - visited: set[int] = set() - while current not in visited: - visited.add(current) - next_chat_id = migrations.get(str(current)) - if not isinstance(next_chat_id, int): - break - current = next_chat_id - return current - - def _remember_chat_migration(self, old_chat_id: int, new_chat_id: int, source: str) -> None: - if old_chat_id == new_chat_id: - return - migrations = self.state.get("chat_id_migrations") - if not isinstance(migrations, dict): - migrations = {} - self.state["chat_id_migrations"] = migrations - if migrations.get(str(old_chat_id)) == new_chat_id: - return - migrations[str(old_chat_id)] = new_chat_id - self._persist_state() - with self.queue_lock: - changed = False - for job in self.queue: - if job.get("chat_id") == old_chat_id: - job["chat_id"] = new_chat_id - job["updated_at"] = now_iso() - changed = True - if changed: - self._persist_queue() - self._append_history_event("chat_migrated_to_supergroup", { - "oldChatId": old_chat_id, - "newChatId": new_chat_id, - "source": source, - }) - - @staticmethod - def _extract_migrate_to_chat_id(error_text: str) -> int | None: - match = re.search(r'"migrate_to_chat_id"\s*:\s*(-?\d+)', error_text) - if match: - return int(match.group(1)) - match = re.search(r"'migrate_to_chat_id'\s*:\s*(-?\d+)", error_text) - if match: - return int(match.group(1)) - return None - - def _handle_update(self, update: dict[str, Any]) -> None: - message = update.get("message") - update_type = "message" - if not isinstance(message, dict): - message = update.get("channel_post") - update_type = "channel_post" - if not isinstance(message, dict): - return - chat = message.get("chat") or {} - chat_id = chat.get("id") - message_id = message.get("message_id") - chat_type = str(chat.get("type") or "") - chat_username = normalize_username(chat.get("username")) - chat_title = str(chat.get("title") or "") - sender = message.get("from") or {} - username = normalize_username(sender.get("username")) - author_signature = str(message.get("author_signature") or "").strip() - author_username = username or normalize_username(author_signature) - if not isinstance(chat_id, int) or not isinstance(message_id, int): - return - - migrate_to_chat_id = message.get("migrate_to_chat_id") - if isinstance(migrate_to_chat_id, int): - self._remember_chat_migration(chat_id, migrate_to_chat_id, "telegram_message") - return - - update_key = f"{chat_id}:{message_id}" - if self._mark_processed_update(update_key): - return - - is_channel_post = update_type == "channel_post" or chat_type == "channel" - is_group_message = update_type == "message" and chat_type in ("group", "supergroup") - is_allowed_channel = ( - not is_channel_post - or not self.cfg.allowed_channel_username - or chat_username == self.cfg.allowed_channel_username - ) - if is_channel_post and not is_allowed_channel: - return - if chat_username and chat_username == self.cfg.allowed_channel_username: - self._remember_public_report_chat(chat_id) - - # Игнорируем системные сообщения о входе/выходе и смене заголовка/фото. - if message.get("new_chat_members") or message.get("left_chat_member"): - return - if message.get("group_chat_created") or message.get("supergroup_chat_created") or message.get("channel_chat_created"): - return - - text = (message.get("text") or message.get("caption") or "").strip() - actor_username = normalize_username(author_username) - is_allowed = self._is_allowed_user(actor_username) - is_private = chat_type == "private" - if not is_allowed: - if is_private: - self._safe_send(chat_id, "Извините, доступ к этому агенту пока не выдан. Обратитесь к Айдару.", reply_to=message_id) - return - if self._is_allowed_player(actor_username) and not is_private: - return - - self._ensure_user_session(actor_username) - if is_private: - self._remember_private_chat(actor_username, chat_id) - history_path = self._current_history_file_for_user(actor_username) - if self._is_allowed_player(actor_username): - self._send_player_welcome_once(chat_id, message_id, actor_username) - - if not text: - if message.get("voice"): - self._enqueue_voice_job( - chat_id, - message_id, - actor_username, - message["voice"].get("file_id"), - duration_seconds=message["voice"].get("duration"), - telegram_file_size=message["voice"].get("file_size"), - media_type="voice", - update_type=update_type, - chat_username=chat_username, - chat_title=chat_title, - author_signature=author_signature, - chat_type=chat_type, - ) - return - if message.get("audio"): - self._enqueue_voice_job( - chat_id, - message_id, - actor_username, - message["audio"].get("file_id"), - duration_seconds=message["audio"].get("duration"), - telegram_file_size=message["audio"].get("file_size"), - media_type="audio", - update_type=update_type, - chat_username=chat_username, - chat_title=chat_title, - author_signature=author_signature, - chat_type=chat_type, - ) - return - self._safe_send(chat_id, "Поддерживаются текст, voice и audio.", reply_to=message_id) - return - - if text.startswith("/"): - self._handle_command(chat_id, message_id, actor_username, text) - return - - if self._handle_task_center_text(chat_id, message_id, actor_username, text): - return - - self._append_history(history_path, "incoming_text", { - "chatId": chat_id, - "messageId": message_id, - "updateType": update_type, - "chatType": chat_type, - "chatUsername": chat_username, - "chatTitle": chat_title, - "username": actor_username, - "authorSignature": author_signature, - "text": text, - }) - job = self._build_job_base(chat_id, message_id, actor_username, str(history_path)) - job["type"] = "text" - job["text"] = text - job["update_type"] = update_type - job["chat_type"] = chat_type - job["chat_username"] = chat_username - job["chat_title"] = chat_title - job["author_signature"] = author_signature - job["role"] = "owner" if self._is_owner(actor_username) else "player" - job["player_name"] = self._player_name(actor_username) if job["role"] == "player" else "" - with self.queue_lock: - self.queue.append(job) - self._persist_queue() - if chat_type == "private": - self._ensure_job_status_message( - job["id"], - chat_id, - message_id, - f"Задача #{job['num']} получена.\nСтатус: в очереди.", - ) - else: - self._safe_send(chat_id, f"Принял задачу #{job['num']}", reply_to=message_id) - - def _enqueue_voice_job( - self, - chat_id: int, - message_id: int, - username: str, - file_id: str | None, - *, - duration_seconds: int | None = None, - telegram_file_size: int | None = None, - media_type: str = "voice", - update_type: str = "message", - chat_username: str = "", - chat_title: str = "", - author_signature: str = "", - chat_type: str = "", - ) -> None: - if not file_id: - self._safe_send(chat_id, "Не удалось прочитать file_id голосового.", reply_to=message_id) - return - history_path = self._current_history_file_for_user(username) - self._append_history(history_path, "incoming_voice", { - "chatId": chat_id, - "messageId": message_id, - "updateType": update_type, - "chatType": chat_type, - "chatUsername": chat_username, - "chatTitle": chat_title, - "username": username, - "authorSignature": author_signature, - "fileId": file_id, - "mediaType": media_type, - "durationSeconds": duration_seconds, - "fileSize": telegram_file_size, - }) - job = self._build_job_base(chat_id, message_id, username, str(history_path)) - job["type"] = "voice" - job["telegram_file_id"] = file_id - job["telegram_media_type"] = media_type - job["telegram_duration_seconds"] = duration_seconds or 0 - job["telegram_file_size"] = telegram_file_size or 0 - job["update_type"] = update_type - job["chat_type"] = chat_type - job["chat_username"] = chat_username - job["chat_title"] = chat_title - job["author_signature"] = author_signature - job["role"] = "owner" if self._is_owner(username) else "player" - job["player_name"] = self._player_name(username) if job["role"] == "player" else "" - with self.queue_lock: - self.queue.append(job) - self._persist_queue() - if chat_type == "private": - self._ensure_job_status_message( - job["id"], - chat_id, - message_id, - f"Voice для задачи #{job['num']} получен.\nСтатус: в очереди.", - ) - else: - self._safe_send(chat_id, f"Принял voice в задачу #{job['num']}", reply_to=message_id) - - def _build_job_base(self, chat_id: int, message_id: int, username: str, history_file: str) -> dict[str, Any]: - with self.queue_lock: - num = int(self.state.get("next_job_number", 1)) - self.state["next_job_number"] = num + 1 - self._persist_state() - return { - "id": str(uuid.uuid4()), - "num": num, - "status": "pending", - "type": "text", - "chat_id": chat_id, - "message_id": message_id, - "username": username, - "update_type": "message", - "chat_type": "", - "chat_username": "", - "chat_title": "", - "author_signature": "", - "role": "owner", - "player_name": "", - "text": "", - "telegram_file_id": "", - "telegram_media_type": "", - "history_file": history_file, - "attempts": 0, - "retry_reason": "", - "last_error": "", - "created_at": now_iso(), - "updated_at": now_iso(), - "active_since": None, - "status_message_id": None, - "status_message_text": "", - } - - def _handle_task_center_text(self, chat_id: int, message_id: int, username: str, text: str) -> bool: - source_text = (text or "").strip() - lower = source_text.lower() - is_owner = self._is_owner(username) - - if re.search(r"\b(покажи|список|какие)\b.*\b(задач|задачи|предложени)", lower): - target = username - explicit_target = self._find_user_by_text(source_text) - if is_owner and explicit_target: - target = explicit_target - self._safe_send(chat_id, self._format_task_items(target), reply_to=message_id) - return True - - if is_owner: - assign_match = re.search( - r"(?:поставь|добавь|создай|запиши)\s+(?:задачу|задание)\s+(.+?)(?::|\s+-\s+|\s+—\s+)(.+)", - source_text, - flags=re.IGNORECASE | re.DOTALL, - ) - if assign_match: - target = self._find_user_by_text(assign_match.group(1)) - body = assign_match.group(2).strip() - if target and body: - item = self._create_task_item( - kind="task", - title=body, - text=body, - source_username=username, - target_username=target, - source_message_id=message_id, - source_chat_id=chat_id, - ) - self._notify_user_about_task_item(target, item) - self._safe_send( - chat_id, - f"Задача добавлена для {self._display_name(target)}: {item['id']} — {item['title']}", - reply_to=message_id, - ) - return True - - status_match = re.search(r"\b(одобрить|отклонить|доработать|закрыть|сделано|закрыта)\b(?:\s+(.+))?", lower, flags=re.IGNORECASE) - if status_match and ("задач" in lower or "предложени" in lower or re.search(r"tc-\d+", lower, flags=re.IGNORECASE)): - action = status_match.group(1) - tail = status_match.group(2) or "" - status = { - "одобрить": "approved", - "отклонить": "rejected", - "доработать": "needs_work", - "закрыть": "done", - "сделано": "done", - "закрыта": "done", - }.get(action, "new") - id_match = re.search(r"tc-\d+", source_text, flags=re.IGNORECASE) - item = None - if id_match: - item = self._update_task_item_status(id_match.group(0), status) - else: - source_user = self._find_user_by_text(tail) - item = self._find_first_task_item( - source_username=source_user, - target_username=username, - kind="proposal" if "предложени" in lower else "", - ) - if item: - item = self._update_task_item_status(str(item.get("id")), status) - if item: - label = TASK_STATUS_LABELS.get(status, status) - self._safe_send(chat_id, f"{item.get('id')} обновлена: {label}.", reply_to=message_id) - source_user = normalize_username(item.get("source_username")) - if source_user and source_user != username: - self._notify_user_about_task_item(source_user, item) - return True - - if not is_owner: - proposal_match = re.match(r"\s*(?:предложение|идея|заявка)\s*[::-]\s*(.+)", source_text, flags=re.IGNORECASE | re.DOTALL) - if proposal_match: - body = proposal_match.group(1).strip() - if body: - item = self._create_task_item( - kind="proposal", - title=body, - text=body, - opinion="Нужно решение Айдара: одобрить, отклонить или отправить на доработку.", - source_username=username, - target_username=self.cfg.allowed_username, - source_message_id=message_id, - source_chat_id=chat_id, - ) - self._notify_user_about_task_item(self.cfg.allowed_username, item) - self._safe_send( - chat_id, - f"Предложение отправлено Айдару как {item['id']}. Статус: новая.", - reply_to=message_id, - ) - return True - - return False - - def _handle_command(self, chat_id: int, message_id: int, username: str, text: str) -> None: - lower = text.lower() - command = lower.split(maxsplit=1)[0].split("@", 1)[0] - is_owner = self._is_owner(username) - if command in ("/start", "/help"): - self._safe_send(chat_id, self._help_text(is_owner=is_owner), reply_to=message_id) - return - if command == "/settings": - self._safe_send(chat_id, self._settings_text(username), reply_to=message_id) - return - if command == "/status": - self._safe_send(chat_id, self._status_text(username), reply_to=message_id) - return - if command == "/queue": - self._safe_send(chat_id, self._queue_text(), reply_to=message_id) - return - if command in ("/tasks", "/my_tasks"): - parts = text.split(maxsplit=1) - target = username - if is_owner and len(parts) > 1: - parsed = self._find_user_by_text(parts[1]) - if parsed: - target = parsed - self._safe_send(chat_id, self._format_task_items(target), reply_to=message_id) - return - if command == "/voice_on": - self._set_voice_replies_enabled(username, True) - self._append_history_event("voice_replies_enabled", {"username": normalize_username(username)}, username=username) - self._safe_send(chat_id, "Озвучивание финальных ответов включено для вашего пользователя.", reply_to=message_id) - return - if command == "/voice_off": - self._set_voice_replies_enabled(username, False) - self._append_history_event("voice_replies_disabled", {"username": normalize_username(username)}, username=username) - self._safe_send(chat_id, "Озвучивание финальных ответов выключено для вашего пользователя.", reply_to=message_id) - return - if command in ("/voice_status", "/voice_rewrite_status"): - self._safe_send(chat_id, self._status_text(username), reply_to=message_id) - return - if command == "/voice_rewrite_on": - self._set_voice_rewrite_enabled(username, True) - self._append_history_event("voice_rewrite_enabled", {"username": normalize_username(username)}, username=username) - self._safe_send(chat_id, "Адаптация текста перед озвучкой включена для вашего пользователя.", reply_to=message_id) - return - if command == "/voice_rewrite_off": - self._set_voice_rewrite_enabled(username, False) - self._append_history_event("voice_rewrite_disabled", {"username": normalize_username(username)}, username=username) - self._safe_send(chat_id, "Адаптация текста перед озвучкой выключена для вашего пользователя.", reply_to=message_id) - return - if command == "/single_message_on": - self._set_single_status_message_enabled(username, True) - self._append_history_event("single_status_message_enabled", {"username": normalize_username(username)}, username=username) - self._safe_send(chat_id, "Режим одного редактируемого сообщения в личке включён для вашего пользователя.", reply_to=message_id) - return - if command == "/single_message_off": - self._set_single_status_message_enabled(username, False) - self._append_history_event("single_status_message_disabled", {"username": normalize_username(username)}, username=username) - self._safe_send(chat_id, "Режим одного редактируемого сообщения в личке выключен. Бот будет отправлять отдельные сообщения по этапам.", reply_to=message_id) - return - if command == "/new": - archived = self._rotate_history("command_new", username) - self._safe_send(chat_id, f"История очищена. Новый диалог начат.\nАрхив: {archived.name}", reply_to=message_id) - return - if command in ("/restart_service", "/restart"): - if not is_owner: - self._safe_send(chat_id, "Команда недоступна.", reply_to=message_id) - return - self._append_history_event("restart_service_deferred_requested", { - "chatId": chat_id, - "messageId": message_id, - "username": username, - }, username=username) - self._safe_send( - chat_id, - "Отложенный рестарт принят. Если задача сейчас выполняется, сервис перезапустится после её завершения и до следующей задачи.", - reply_to=message_id, - ) - self._request_deferred_restart() - return - if command in ("/restart_hard", "/restart_now", "/restart_force"): - if not is_owner: - self._safe_send(chat_id, "Команда недоступна.", reply_to=message_id) - return - self._append_history_event("restart_service_hard_requested", { - "chatId": chat_id, - "messageId": message_id, - "username": username, - }, username=username) - self._safe_send( - chat_id, - "Выполняю жёсткий рестарт сервиса прямо сейчас. Активная задача, если есть, будет прервана и после старта вернётся в очередь.", - reply_to=message_id, - ) - self._schedule_self_restart("hard_restart_requested", force=True) - return - if command == "/stop": - stopped = self._cancel_active_job("stopped_by_user") - if stopped: - self._safe_send(chat_id, "Текущая задача остановлена и удалена из очереди.", reply_to=message_id) - else: - self._safe_send(chat_id, "Сейчас нет активной задачи.", reply_to=message_id) - return - if command == "/cancel": - parts = text.split(maxsplit=1) - if len(parts) < 2: - self._safe_send(chat_id, "Использование: /cancel ", reply_to=message_id) - return - arg = parts[1].strip() - if arg.lower() == "all": - with self.queue_lock: - self.stop_current_job = True - self._stop_active_codex_process() - count = len(self.queue) - self.queue = [] - self._persist_queue() - self._safe_send(chat_id, f"Удалено задач из очереди: {count}", reply_to=message_id) - return - cancelled = self._cancel_by_id_prefix(arg) - self._safe_send(chat_id, f"Задача удалена: {arg}" if cancelled else f"Задача не найдена: {arg}", reply_to=message_id) - return - - def _help_text(self, *, is_owner: bool) -> str: - lines = [ - "Доступные команды:", - "/status — активная задача и размер очереди", - "/settings — текущие настройки и команды для их изменения", - "/queue — список задач в очереди", - "/tasks — список ваших задач и предложений", - "/stop — остановить текущую задачу", - "/cancel — удалить задачу по id (префикс) или все", - "/new — архивировать историю и начать новую Codex-сессию", - "/help — эта справка", - ] - if is_owner: - lines.insert(-1, "/tasks <пользователь> — список задач игрока") - lines.insert(-1, "/restart — отложенный рестарт после текущей задачи") - lines.insert(-1, "/restart_hard — жёсткий рестарт прямо сейчас") - return "\n".join(lines) - - def _settings_text(self, username: str) -> str: - voice_status = "включено" if self._voice_replies_enabled(username) else "выключено" - rewrite_status = "включена" if self._voice_rewrite_enabled(username) else "выключена" - single_message_status = "включён" if self._single_status_message_enabled(username) else "выключен" - lines = [ - "Текущие настройки:", - f"Озвучивание финальных ответов: {voice_status}", - f"Адаптация текста перед озвучкой: {rewrite_status}", - f"Режим одного редактируемого сообщения в личке: {single_message_status}", - "", - "Команды настроек:", - "/voice_on — включить озвучивание", - "/voice_off — выключить озвучивание", - "/voice_rewrite_on — адаптировать текст перед озвучкой", - "/voice_rewrite_off — озвучивать обычный текст без адаптации", - "/single_message_on — один редактируемый ответ в личке", - "/single_message_off — отдельные сообщения по этапам и финалу", - ] - return "\n".join(lines) - - def _status_text(self, username: str) -> str: - with self.queue_lock: - active = next((j for j in self.queue if j.get("status") == "active"), None) - pending = sum(1 for j in self.queue if j.get("status") == "pending") - voice_status = "включено" if self._voice_replies_enabled(username) else "выключено" - rewrite_status = "включена" if self._voice_rewrite_enabled(username) else "выключена" - single_message_status = "включён" if self._single_status_message_enabled(username) else "выключен" - settings_text = ( - f"Голосовые ответы: {voice_status}\n" - f"Адаптация текста перед озвучкой: {rewrite_status}\n" - f"Режим одного сообщения в личке: {single_message_status}" - ) - restart_text = "\nОтложенный рестарт: ожидает завершения текущей задачи" if self.restart_requested else "" - if not active: - return f"Статус: активной задачи нет.\nВ очереди pending: {pending}\n{settings_text}{restart_text}" - elapsed = int(time.time() - (self.active_job_started_at or time.time())) - return ( - f"Статус: активная задача #{active.get('num', '?')}\n" - f"Тип: {active.get('type', 'text')}\n" - f"Попытка: {int(active.get('attempts', 0)) + 1}/{self.cfg.max_retries}\n" - f"Выполняется: {elapsed}с\n" - f"Pending: {pending}\n" - f"{settings_text}{restart_text}" - ) - - def _queue_text(self) -> str: - with self.queue_lock: - items = list(self.queue) - if not items: - return "Очередь пуста." - lines = [f"Очередь: {len(items)}"] - for i, job in enumerate(items[:10], start=1): - lines.append( - f"{i}) #{job.get('num', '?')} [{job.get('status')}] {job.get('type')} attempts={job.get('attempts', 0)}" - ) - if len(items) > 10: - lines.append(f"...и ещё {len(items) - 10} задач") - return "\n".join(lines) - - def _cancel_active_job(self, reason: str) -> bool: - with self.queue_lock: - active = next((j for j in self.queue if j.get("status") == "active"), None) - if not active: - return False - self.stop_current_job = True - self._stop_active_codex_process() - self.queue = [j for j in self.queue if j.get("id") != active.get("id")] - self._persist_queue() - self._append_history_event("job_stopped_by_user", {"jobId": active.get("id"), "reason": reason}) - return True - - def _cancel_by_id_prefix(self, prefix: str) -> bool: - prefix = prefix.strip().lower() - normalized_num = prefix.lstrip("#") - with self.queue_lock: - target = next( - ( - j for j in self.queue - if str(j.get("id", "")).lower().startswith(prefix) - or str(j.get("num", "")).lower() == normalized_num - ), - None - ) - if not target: - return False - if target.get("status") == "active": - self.stop_current_job = True - self._stop_active_codex_process() - self.queue = [j for j in self.queue if j.get("id") != target.get("id")] - self._persist_queue() - return True - - def _worker_loop(self) -> None: - while not self.stop_event.is_set(): - if self.restart_requested: - self._exit_for_restart("deferred_restart_before_next_job") - return - job = None - with self.queue_lock: - for item in self.queue: - if item.get("status") == "pending": - item["status"] = "active" - item["active_since"] = now_iso() - item["updated_at"] = now_iso() - self.active_job_id = item.get("id") - self.active_job_started_at = time.time() - job = dict(item) - self._persist_queue() - break - if not job: - time.sleep(0.5) - continue - - self.stop_current_job = False - self._process_job(job) - self.active_job_id = None - self.active_job_started_at = None - if self.restart_requested: - self._exit_for_restart("deferred_restart_after_job") - return - - def _process_job(self, job: dict[str, Any]) -> None: - job_id = job["id"] - job_num = job.get("num", "?") - chat_id = int(job["chat_id"]) - message_id = int(job["message_id"]) - history_path = Path(job["history_file"]) - private_single_message = ( - (job.get("chat_type") or "") == "private" - and self._single_status_message_enabled(job.get("username") or "") - ) - self._set_job_status_text(job, f"Задача #{job_num} в работе.\nСтатус: выполняется.") - try: - if job.get("type") == "voice": - self._set_job_status_text(job, f"Задача #{job_num} в работе.\nСтатус: распознаю voice.") - recognized = self._transcribe_voice_job( - job, - status_cb=lambda note: self._set_job_status_text( - job, - f"Задача #{job_num} в работе.\nСтатус: {note}", - ), - ) - job["text"] = recognized - self._append_history(history_path, "voice_transcription", {"jobId": job_id, "jobNum": job_num, "text": recognized}) - preview = recognized.strip() - if len(preview) > 800: - preview = preview[:800].rstrip() + " ...[обрезано]" - self._set_job_status_text( - job, - f"Задача #{job_num} в работе.\nСтатус: voice распознан, отправляю в Codex.\n\nТекст:\n{preview}", - ) - - prompt = self._build_prompt(job) - self._append_history(history_path, "codex_request", {"jobId": job_id, "prompt": prompt}) - self._set_job_status_text(job, f"Задача #{job_num} в работе.\nСтатус: выполняю через Codex.") - answer = self._run_codex(prompt, job) - if private_single_message: - parts = split_final_private_text(answer) - self._set_job_status_text(job, parts[0]) - if len(parts) > 1: - self._safe_send(chat_id, parts[1], reply_to=message_id) - else: - for chunk in split_long_text(answer): - self._safe_send(chat_id, chunk, reply_to=message_id) - self._append_history(history_path, "codex_response", {"jobId": job_id, "text": answer}) - self._send_private_job_public_report(job, answer) - self._send_task_center_reminder(job) - if self._voice_replies_enabled(job.get("username") or ""): - self._send_voice_reply_for_answer(job, answer, history_path, job_id) - self._mark_job_done(job_id) - except Exception as e: - if self.stop_current_job: - self._append_history(history_path, "job_stopped", {"jobId": job_id, "reason": str(e)}) - self._set_job_status_text(job, f"Задача #{job_num} остановлена.") - self._mark_job_removed(job_id) - self.stop_current_job = False - return - if isinstance(e, VoiceTranscriptionError): - self._append_history(history_path, "voice_transcription_failed", { - "jobId": job_id, - "jobNum": job_num, - "stage": e.stage, - "retryable": e.retryable, - "error": e.user_message, - "detail": e.detail, - }) - self._handle_job_failure(job, e) - - def _build_prompt(self, job: dict[str, Any]) -> str: - retry_block = "" - retry_reason = (job.get("retry_reason") or "").strip() - if retry_reason: - retry_block = f"\n\nПометка retry: {retry_reason}" - role = (job.get("role") or "owner").strip().lower() - player_block = "" - if role == "player": - player_name = (job.get("player_name") or "").strip() - player_dir = self.cfg.codex_workdir / "Players" / (job.get("username") or "") - player_block = ( - "\n\nРежим игрока (обязательно):\n" - f"- Пользователь: {player_name} (@{job.get('username')}).\n" - f"- Рабочая папка игрока: {player_dir}\n" - "- Код проекта не изменять.\n" - "- Можно отвечать на вопросы по проекту, предлагать идеи и готовить ТЗ.\n" - "- Если нужны правки кода, описывать предложение текстом и сохранять материалы только в папке игрока." - ) - return ( - "Пришло сообщение в Telegram.\n" - f"Тип: {job.get('type')}\n" - f"Источник Telegram: {job.get('update_type', 'message')}\n" - f"Тип чата: {job.get('chat_type') or ''}\n" - f"Канал/чат: @{job.get('chat_username') or ''} {job.get('chat_title') or ''}\n" - f"Username отправителя: @{job.get('username')}\n" - f"Подпись автора в Telegram: {job.get('author_signature') or ''}\n" - "Текст для обработки:\n" - f"{job.get('text')}\n\n" - f"История диалога (JSONL): {job.get('history_file')}\n" - f"Инструкции агента: {self.cfg.agent_instructions_file}\n" - f"Работай в рабочем проекте аккуратно и верни только текст ответа пользователю.{player_block}{retry_block}" - ) - - def _run_codex(self, prompt: str, job: dict[str, Any]) -> str: - username = job.get("username") or self.cfg.allowed_username - thread_id = self._codex_thread_id_for_user(username) - try: - return self._run_codex_once(prompt, job, thread_id=thread_id) - except RuntimeError as e: - if not thread_id or not self._is_missing_codex_session_error(str(e)): - raise - self._set_codex_thread_id_for_user(username, "") - self._append_history( - Path(job["history_file"]), - "system_event", - { - "event": "codex_thread_reset", - "reason": "missing_session", - "username": normalize_username(username), - "oldThreadId": thread_id, - }, - ) - return self._run_codex_once(prompt, job, thread_id="") - - def _run_codex_once(self, prompt: str, job: dict[str, Any], *, thread_id: str) -> str: - output_lines: list[str] = [] - job_id = str(job["id"]) - job_num = job.get("num", "?") - username = job.get("username") or self.cfg.allowed_username - with tempfile.NamedTemporaryFile(prefix="shine-codex-last-message-", suffix=".txt", delete=False) as tmp: - output_file = Path(tmp.name) - - cmd = [ - str(self.cfg.codex_bin), - "exec", - "--dangerously-bypass-approvals-and-sandbox", - "--json", - "-C", str(self.cfg.codex_workdir), - "-o", str(output_file), - ] - if thread_id: - cmd.extend(["resume", thread_id]) - cmd.append(prompt) - mode = f"resume {thread_id}" if thread_id else "new" - print(f"[py-bot] codex exec start job={job_id[:8]} mode={mode}", flush=True) - process = subprocess.Popen( - cmd, - stdin=subprocess.DEVNULL, - stdout=subprocess.PIPE, - stderr=subprocess.STDOUT, - text=True, - encoding="utf-8", - errors="replace", - bufsize=1, - ) - with self.active_process_lock: - self.active_process = process - - 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 - seen_thread_id = "" - - def on_line(line: str) -> None: - nonlocal last_user_note, last_user_note_at, last_job_message_at, seen_thread_id - output_lines.append(line) - current_thread_id = self._extract_codex_thread_id(line) - if current_thread_id: - seen_thread_id = current_thread_id - note = self._extract_codex_user_note(line) - now = time.time() - if note and note != last_user_note and now - last_user_note_at > 8: - self._set_job_status_text(job, f"Задача #{job_num} в работе.\nСтатус: {note}") - last_user_note = note - last_user_note_at = now - last_job_message_at = now - - reader_done = threading.Event() - - def reader() -> None: - if not process.stdout: - reader_done.set() - return - for line in process.stdout: - on_line(line.rstrip("\n")) - reader_done.set() - - t = threading.Thread(target=reader, name=f"codex-reader-{job_id[:8]}", daemon=True) - t.start() - - try: - 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._set_job_status_text( - job, - f"Задача #{job_num} в работе.\nСтатус: выполняется уже {elapsed}, от Codex давно нет новых сообщений.", - ) - last_job_message_at = now - self.last_heartbeat_at = now - time.sleep(1) - finally: - with self.active_process_lock: - self.active_process = None - - reader_done.wait(timeout=2) - - if return_code != 0: - tail = "\n".join(output_lines[-40:]) - raise RuntimeError(f"Codex exited with code {return_code}. Output tail:\n{tail}") - - if seen_thread_id and seen_thread_id != thread_id: - self._set_codex_thread_id_for_user(username, seen_thread_id) - - if output_file.exists(): - answer = output_file.read_text(encoding="utf-8").strip() - try: - output_file.unlink(missing_ok=True) - except Exception: - pass - if answer: - return answer - - fallback = self._extract_fallback_message(output_lines) - if not fallback: - raise RuntimeError("Codex returned empty response") - return fallback - - def _stop_active_codex_process(self) -> bool: - with self.active_process_lock: - process = self.active_process - if process is None: - return False - if process.poll() is not None: - return False - process.terminate() - try: - process.wait(timeout=2) - except subprocess.TimeoutExpired: - process.kill() - return True - - def _handle_job_failure(self, job: dict[str, Any], err: Exception) -> None: - job_id = job["id"] - job_num = job.get("num", "?") - error_text = str(err).strip() or err.__class__.__name__ - user_error_text = self._user_error_text(err) - retryable = not isinstance(err, VoiceTranscriptionError) or err.retryable - log_error_text = err.log_text() if isinstance(err, VoiceTranscriptionError) else error_text - print(f"[py-bot] Ошибка job={job_id[:8]}: {log_error_text}", flush=True) - print(traceback.format_exc(), flush=True) - - with self.queue_lock: - target = next((j for j in self.queue if j.get("id") == job_id), None) - if not target: - return - attempts = int(target.get("attempts", 0)) + 1 - target["attempts"] = attempts - target["last_error"] = error_text[:1000] - target["updated_at"] = now_iso() - if retryable and attempts < self.cfg.max_retries: - target["status"] = "pending" - target["retry_reason"] = error_text[:200] - self._persist_queue() - will_retry = True - else: - self.queue = [j for j in self.queue if j.get("id") != job_id] - self._persist_queue() - will_retry = False - - if will_retry: - self._set_job_status_text( - job, - f"{user_error_text}\nПовторю задачу #{job_num}: попытка {attempts + 1}/{self.cfg.max_retries}.", - ) - else: - self._set_job_status_text(job, f"{user_error_text}\nЗадача #{job_num} остановлена.") - - def _user_error_text(self, err: Exception) -> str: - if isinstance(err, VoiceTranscriptionError): - return f"Не удалось распознать голосовое: {err.user_message}" - error_text = str(err).strip() or err.__class__.__name__ - return f"Ошибка выполнения задачи: {error_text}" - - def _mark_job_done(self, job_id: str) -> None: - with self.queue_lock: - self.queue = [j for j in self.queue if j.get("id") != job_id] - self._persist_queue() - - def _mark_job_removed(self, job_id: str) -> None: - with self.queue_lock: - self.queue = [j for j in self.queue if j.get("id") != job_id] - self._persist_queue() - - def _send_task_center_reminder(self, job: dict[str, Any]) -> None: - if job.get("chat_type") != "private": - return - username = job.get("username") or "" - reminder = self._task_center_counts_text(username) - if not reminder: - return - self._safe_send(int(job["chat_id"]), reminder, reply_to=int(job["message_id"])) - - def _remember_public_report_chat(self, chat_id: int) -> None: - if self.state.get("public_report_chat_id") == chat_id: - return - self.state["public_report_chat_id"] = chat_id - self.state["updated_at"] = now_iso() - self._persist_state() - - def _public_report_chat_id(self) -> int | str | None: - chat_id = self.state.get("public_report_chat_id") - if isinstance(chat_id, int): - return self._resolve_chat_id(chat_id) - if self.cfg.allowed_channel_username: - return f"@{self.cfg.allowed_channel_username}" - return None - - def _send_private_job_public_report(self, job: dict[str, Any], answer: str) -> None: - if job.get("chat_type") != "private": - return - report_chat_id = self._public_report_chat_id() - if report_chat_id is None: - return - - job_num = job.get("num", "?") - source_text = (job.get("text") or "").strip() - if not source_text: - source_text = "(пустой текст запроса)" - role = (job.get("role") or "owner").strip().lower() - author_label = "Айдар" - if role == "player": - player_name = (job.get("player_name") or "").strip() or job.get("username") or "Игрок" - author_label = f"{player_name} (@{job.get('username')})" - if job.get("type") == "voice": - voice_file_id = (job.get("telegram_file_id") or "").strip() - media_type = (job.get("telegram_media_type") or "voice").strip() - request_caption = self._trim_telegram_caption( - f"{author_label} сделал {media_type}-запрос, задача #{job_num}.\n\n" - f"Распознанный текст:\n{source_text}" - ) - request_message_id = None - if voice_file_id: - request_message_id = self._safe_send_telegram_file( - report_chat_id, - voice_file_id, - media_type=media_type, - caption=request_caption, - ) - if request_message_id is None: - request_message_id = self._safe_send(report_chat_id, request_caption) - else: - request_report = ( - f"{author_label} сделал запрос, задача #{job_num}.\n\n" - f"{source_text}" - ) - request_message_id = self._safe_send(report_chat_id, request_report) - if request_message_id is None: - return - - answer_text = (answer or "").strip() or "(пустой ответ)" - answer_chunks = split_long_text(f"Ответ на задачу #{job_num}:\n\n{answer_text}") - for chunk in answer_chunks: - self._safe_send(report_chat_id, chunk, reply_to=request_message_id) - - @staticmethod - def _trim_telegram_caption(text: str, limit: int = 1000) -> str: - text = (text or "").strip() - if len(text) <= limit: - return text - return text[:limit].rstrip() + "\n...[обрезано]" - - def _safe_send_telegram_file( - self, - chat_id: int | str, - file_id: str, - *, - media_type: str = "voice", - caption: str = "", - reply_to: int | None = None, - ) -> int | None: - file_id = (file_id or "").strip() - if not file_id: - return None - caption = self._trim_telegram_caption(caption) - resolved_chat_id: int | str = self._resolve_chat_id(chat_id) if isinstance(chat_id, int) else chat_id - resolved_reply_to = reply_to if resolved_chat_id == chat_id or isinstance(chat_id, str) else None - - def send(target_chat_id: int | str, target_reply_to: int | None) -> dict[str, Any]: - if media_type == "audio": - return self.telegram.send_audio(target_chat_id, file_id, caption=caption, reply_to_message_id=target_reply_to) - return self.telegram.send_voice(target_chat_id, file_id, caption=caption, reply_to_message_id=target_reply_to) - - try: - sent = send(resolved_chat_id, resolved_reply_to) - result = sent.get("result") or {} - message_id = result.get("message_id") - return message_id if isinstance(message_id, int) else None - except Exception as e: - migrate_to_chat_id = self._extract_migrate_to_chat_id(str(e)) - if migrate_to_chat_id is not None: - if isinstance(resolved_chat_id, int): - self._remember_chat_migration(resolved_chat_id, migrate_to_chat_id, "send_file_error") - try: - sent = send(migrate_to_chat_id, None) - result = sent.get("result") or {} - message_id = result.get("message_id") - return message_id if isinstance(message_id, int) else None - except Exception as retry_error: - print(f"[py-bot] sendFile retry after migration error: {retry_error}", flush=True) - return None - print(f"[py-bot] sendFile error: {e}", flush=True) - return None - - def _safe_send_voice_upload( - self, - chat_id: int | str, - voice_bytes: bytes, - filename: str, - *, - caption: str = "", - reply_to: int | None = None, - ) -> int | None: - if not voice_bytes: - return None - caption = self._trim_telegram_caption(caption) - resolved_chat_id: int | str = self._resolve_chat_id(chat_id) if isinstance(chat_id, int) else chat_id - resolved_reply_to = reply_to if resolved_chat_id == chat_id or isinstance(chat_id, str) else None - - def send(target_chat_id: int | str, target_reply_to: int | None) -> dict[str, Any]: - return self.telegram.send_voice_upload( - target_chat_id, - voice_bytes, - filename, - caption=caption, - reply_to_message_id=target_reply_to, - ) - - try: - sent = send(resolved_chat_id, resolved_reply_to) - result = sent.get("result") or {} - message_id = result.get("message_id") - return message_id if isinstance(message_id, int) else None - except Exception as e: - migrate_to_chat_id = self._extract_migrate_to_chat_id(str(e)) - if migrate_to_chat_id is not None: - if isinstance(resolved_chat_id, int): - self._remember_chat_migration(resolved_chat_id, migrate_to_chat_id, "send_voice_upload_error") - try: - sent = send(migrate_to_chat_id, None) - result = sent.get("result") or {} - message_id = result.get("message_id") - return message_id if isinstance(message_id, int) else None - except Exception as retry_error: - print(f"[py-bot] sendVoiceUpload retry after migration error: {retry_error}", flush=True) - return None - print(f"[py-bot] sendVoiceUpload error: {e}", flush=True) - return None - - def _safe_send(self, chat_id: int | str, text: str, reply_to: int | None = None) -> int | None: - text = (text or "").strip() - if not text: - return None - if len(text) > 3900: - text = text[:3900] + "\n...[обрезано]" - resolved_chat_id: int | str = self._resolve_chat_id(chat_id) if isinstance(chat_id, int) else chat_id - resolved_reply_to = reply_to if resolved_chat_id == chat_id or isinstance(chat_id, str) else None - try: - sent = self.telegram.send_message(resolved_chat_id, text, reply_to_message_id=resolved_reply_to) - result = sent.get("result") or {} - message_id = result.get("message_id") - return message_id if isinstance(message_id, int) else None - except Exception as e: - migrate_to_chat_id = self._extract_migrate_to_chat_id(str(e)) - if migrate_to_chat_id is not None: - if isinstance(resolved_chat_id, int): - self._remember_chat_migration(resolved_chat_id, migrate_to_chat_id, "send_message_error") - try: - sent = self.telegram.send_message(migrate_to_chat_id, text, reply_to_message_id=None) - result = sent.get("result") or {} - message_id = result.get("message_id") - return message_id if isinstance(message_id, int) else None - except Exception as retry_error: - print(f"[py-bot] sendMessage retry after migration error: {retry_error}", flush=True) - return None - print(f"[py-bot] sendMessage error: {e}", flush=True) - return None - - def _safe_edit(self, chat_id: int | str, message_id: int | None, text: str) -> bool: - text = (text or "").strip() - if not text or not message_id: - return False - if len(text) > 3900: - text = text[:3900] + "\n...[обрезано]" - resolved_chat_id: int | str = self._resolve_chat_id(chat_id) if isinstance(chat_id, int) else chat_id - try: - self.telegram.edit_message_text(resolved_chat_id, message_id, text) - return True - except Exception as e: - error_text = str(e) - if "message is not modified" in error_text: - return True - migrate_to_chat_id = self._extract_migrate_to_chat_id(error_text) - if migrate_to_chat_id is not None: - if isinstance(resolved_chat_id, int): - self._remember_chat_migration(resolved_chat_id, migrate_to_chat_id, "edit_message_error") - try: - self.telegram.edit_message_text(migrate_to_chat_id, message_id, text) - return True - except Exception as retry_error: - print(f"[py-bot] editMessageText retry after migration error: {retry_error}", flush=True) - return False - print(f"[py-bot] editMessageText error: {e}", flush=True) - return False - - def _ensure_job_status_message(self, job_id: str, chat_id: int, reply_to_message_id: int, text: str) -> int | None: - text = (text or "").strip() - if not text: - return None - with self.queue_lock: - target = next((j for j in self.queue if j.get("id") == job_id), None) - if target: - existing_id = target.get("status_message_id") - existing_text = (target.get("status_message_text") or "").strip() - else: - existing_id = None - existing_text = "" - if existing_id and existing_text == text and self._safe_edit(chat_id, int(existing_id), text): - return int(existing_id) - if existing_id and self._safe_edit(chat_id, int(existing_id), text): - with self.queue_lock: - target = next((j for j in self.queue if j.get("id") == job_id), None) - if target: - target["status_message_text"] = text - target["updated_at"] = now_iso() - self._persist_queue() - return int(existing_id) - message_id = self._safe_send(chat_id, text, reply_to=reply_to_message_id) - if message_id is not None: - with self.queue_lock: - target = next((j for j in self.queue if j.get("id") == job_id), None) - if target: - target["status_message_id"] = message_id - target["status_message_text"] = text - target["updated_at"] = now_iso() - self._persist_queue() - return message_id - - def _set_job_status_text(self, job: dict[str, Any], text: str) -> None: - if (job.get("chat_type") or "") != "private": - self._safe_send(int(job["chat_id"]), text, reply_to=int(job["message_id"])) - return - if not self._single_status_message_enabled(job.get("username") or ""): - self._safe_send(int(job["chat_id"]), text, reply_to=int(job["message_id"])) - return - message_id = self._ensure_job_status_message( - job["id"], - int(job["chat_id"]), - int(job["message_id"]), - text, - ) - if message_id is not None: - job["status_message_id"] = message_id - job["status_message_text"] = text - - def _request_deferred_restart(self) -> None: - if self.restart_requested: - return - self.restart_requested = True - self._append_history_event("restart_service_deferred_scheduled", {}) - with self.queue_lock: - has_active = any(j.get("status") == "active" for j in self.queue) - if not has_active: - threading.Thread( - target=lambda: self._exit_for_restart("deferred_restart_no_active_job"), - name="shine-py-bot-deferred-restart", - daemon=True, - ).start() - - def _exit_for_restart(self, reason: str) -> None: - print(f"[py-bot] restart now: {reason}", flush=True) - self._append_history_event("restart_service_executing", {"reason": reason}) - time.sleep(0.5) - os._exit(0) - - def _schedule_self_restart(self, reason: str = "restart_requested", *, force: bool = False) -> None: - if self.restart_requested and not force: - return - self.restart_requested = True - - def restart() -> None: - time.sleep(1.5) - print(f"[py-bot] restart requested by Telegram command: {reason}", flush=True) - if force: - self._stop_active_codex_process() - os._exit(0) - - threading.Thread(target=restart, name="shine-py-bot-self-restart", daemon=True).start() - - def _voice_reply_targets(self, job: dict[str, Any]) -> list[tuple[int | str, int | None, str]]: - chat_id = int(job["chat_id"]) - message_id = int(job["message_id"]) - targets: list[tuple[int | str, int | None, str]] = [(chat_id, message_id, "source")] - username = job.get("username") or "" - - private_chat_id = self._private_chat_id_for_user(username) - if private_chat_id is not None and private_chat_id != self._resolve_chat_id(chat_id): - targets.append((private_chat_id, None, "private")) - - report_chat_id = self._public_report_chat_id() - if report_chat_id is not None: - resolved_report_chat_id = self._resolve_chat_id(report_chat_id) if isinstance(report_chat_id, int) else report_chat_id - resolved_current_chat_id: int | str = self._resolve_chat_id(chat_id) - if resolved_report_chat_id != resolved_current_chat_id: - targets.append((report_chat_id, None, "public")) - - deduped: list[tuple[int | str, int | None, str]] = [] - seen: set[str] = set() - for target_chat_id, target_reply_to, label in targets: - resolved: int | str = self._resolve_chat_id(target_chat_id) if isinstance(target_chat_id, int) else target_chat_id - key = str(resolved) - if key in seen: - continue - seen.add(key) - deduped.append((target_chat_id, target_reply_to, label)) - return deduped - - def _send_voice_reply_for_answer( - self, - job: dict[str, Any], - answer: str, - history_path: Path, - job_id: str, - ) -> None: - chat_id = int(job["chat_id"]) - message_id = int(job["message_id"]) - job_num = job.get("num", "?") - username = job.get("username") or "" - if not self.cfg.openai_api_key: - note = "не настроен ключ OpenAI для озвучивания." - self._append_history(history_path, "voice_reply_failed", {"jobId": job_id, "jobNum": job_num, "error": note}) - self._safe_send(chat_id, f"Озвучивание включено, но {note}", reply_to=message_id) - return - - voice_text = answer - rewrite_enabled = self._voice_rewrite_enabled(username) - if rewrite_enabled: - try: - voice_text = self._openai_rewrite_text_for_voice(answer) - self._append_history(history_path, "voice_rewrite_done", { - "jobId": job_id, - "jobNum": job_num, - "model": self.cfg.openai_voice_rewrite_model, - "sourceChars": len(answer or ""), - "resultChars": len(voice_text or ""), - }) - except VoiceReplyError as e: - self._append_history(history_path, "voice_rewrite_failed", { - "jobId": job_id, - "jobNum": job_num, - "model": self.cfg.openai_voice_rewrite_model, - "error": str(e), - }) - self._safe_send( - chat_id, - f"Не удалось адаптировать ответ #{job_num} для озвучки, озвучиваю обычный текст: {e}", - reply_to=message_id, - ) - voice_text = answer - - chunks = split_text_for_tts(voice_text, self.cfg.openai_tts_chunk_chars) - if not chunks: - return - - sent_count = 0 - total = len(chunks) - targets = self._voice_reply_targets(job) - print(f"[py-bot] tts start job={str(job_id)[:8]} chunks={total} targets={len(targets)} rewrite={rewrite_enabled}", flush=True) - for index, chunk in enumerate(chunks, start=1): - try: - audio = self._openai_tts(chunk) - except VoiceReplyError as e: - self._append_history(history_path, "voice_reply_failed", { - "jobId": job_id, - "jobNum": job_num, - "part": index, - "parts": total, - "error": str(e), - }) - self._safe_send(chat_id, f"Не удалось озвучить ответ #{job_num}: {e}", reply_to=message_id) - return - caption = f"Озвучка ответа #{job_num}" - if total > 1: - caption += f", часть {index}/{total}" - for target_chat_id, target_reply_to, target_label in targets: - message_sent = self._safe_send_voice_upload( - target_chat_id, - audio, - f"shine-answer-{job_num}-{index}.ogg", - caption=caption, - reply_to=target_reply_to, - ) - if message_sent is None: - self._append_history(history_path, "voice_reply_failed", { - "jobId": job_id, - "jobNum": job_num, - "part": index, - "parts": total, - "target": target_label, - "error": "Telegram не принял voice-файл озвучки.", - }) - if target_label == "source": - self._safe_send(chat_id, f"Озвучка ответа #{job_num} создана, но Telegram не принял voice-файл.", reply_to=message_id) - continue - sent_count += 1 - self._append_history(history_path, "voice_reply_sent", { - "jobId": job_id, - "jobNum": job_num, - "parts": total, - "messages": sent_count, - "targets": len(targets), - "rewriteEnabled": rewrite_enabled, - }) - print(f"[py-bot] tts done job={str(job_id)[:8]} sent={sent_count}", flush=True) - - def _openai_rewrite_text_for_voice(self, text: str) -> str: - source = (text or "").strip() - if not source: - return "" - if len(source) > self.cfg.openai_voice_rewrite_max_input_chars: - source = source[:self.cfg.openai_voice_rewrite_max_input_chars].rstrip() + "\n\n...[текстовый ответ был длиннее и обрезан для голосовой версии]" - payload = { - "model": self.cfg.openai_voice_rewrite_model, - "messages": [ - { - "role": "system", - "content": ( - "Ты готовишь русскую версию финального ответа технического агента для озвучивания. " - "Не пересказывай заново и не меняй смысл: сохрани порядок мыслей, итог, предупреждения, статусы и важные действия. " - "Мягко убери только то, что плохо воспринимается на слух: длинные пути, хэши, ID, команды, JSON, " - "длинные списки файлов, точные размеры и счётчики символов. Если деталь важна, замени её коротким описанием. " - "Не добавляй новых фактов. Пиши естественно, без markdown, близко к исходному тексту." - ), - }, - { - "role": "user", - "content": f"Переделай этот финальный текст в вариант для озвучки:\n\n{source}", - }, - ], - "temperature": 0.2, - "max_tokens": self.cfg.openai_voice_rewrite_max_output_tokens, - } - data = json.dumps(payload, ensure_ascii=False).encode("utf-8") - req = request.Request("https://api.openai.com/v1/chat/completions", method="POST", data=data) - req.add_header("Authorization", f"Bearer {self.cfg.openai_api_key}") - req.add_header("Content-Type", "application/json") - try: - with request.urlopen(req, timeout=self.cfg.openai_voice_rewrite_timeout_seconds) as resp: - raw = resp.read().decode("utf-8", errors="replace") - except TimeoutError as e: - raise VoiceReplyError( - f"OpenAI не успел адаптировать текст за {self.cfg.openai_voice_rewrite_timeout_seconds} секунд." - ) from e - except error.HTTPError as e: - detail = e.read().decode("utf-8", errors="replace") - if e.code == 401: - message = "OpenAI отклонил ключ API для адаптации текста." - elif e.code == 429: - message = "OpenAI временно ограничил адаптацию текста из-за лимита запросов." - elif e.code >= 500: - message = "OpenAI временно не смог адаптировать текст." - else: - message = f"OpenAI вернул ошибку HTTP {e.code} при адаптации текста." - if detail: - message = f"{message} Детали: {detail[:500]}" - raise VoiceReplyError(message) from e - except error.URLError as e: - raise VoiceReplyError(f"не удалось отправить текст в OpenAI для адаптации из-за сетевой ошибки: {e.reason}") from e - - try: - body = json.loads(raw) - content = (((body.get("choices") or [{}])[0].get("message") or {}).get("content") or "").strip() - except Exception as e: - raise VoiceReplyError("OpenAI вернул неразборчивый ответ при адаптации текста.") from e - if not content: - raise VoiceReplyError("OpenAI вернул пустой текст адаптации.") - return content - - def _openai_tts(self, text: str) -> bytes: - payload = { - "model": self.cfg.openai_tts_model, - "voice": self.cfg.openai_tts_voice, - "input": text, - "response_format": self.cfg.openai_tts_response_format, - } - data = json.dumps(payload, ensure_ascii=False).encode("utf-8") - req = request.Request("https://api.openai.com/v1/audio/speech", method="POST", data=data) - req.add_header("Authorization", f"Bearer {self.cfg.openai_api_key}") - req.add_header("Content-Type", "application/json") - try: - with request.urlopen(req, timeout=self.cfg.openai_tts_timeout_seconds) as resp: - audio = resp.read() - except TimeoutError as e: - raise VoiceReplyError(f"OpenAI не успел сгенерировать речь за {self.cfg.openai_tts_timeout_seconds} секунд.") from e - except error.HTTPError as e: - detail = e.read().decode("utf-8", errors="replace") - if e.code == 401: - message = "OpenAI отклонил ключ API для озвучивания." - elif e.code == 429: - message = "OpenAI временно ограничил озвучивание из-за лимита запросов." - elif e.code >= 500: - message = "OpenAI временно не смог сгенерировать речь." - else: - message = f"OpenAI вернул ошибку HTTP {e.code} при озвучивании." - if detail: - message = f"{message} Детали: {detail[:500]}" - raise VoiceReplyError(message) from e - except error.URLError as e: - raise VoiceReplyError(f"не удалось отправить текст в OpenAI TTS из-за сетевой ошибки: {e.reason}") from e - if not audio: - raise VoiceReplyError("OpenAI вернул пустой аудиофайл.") - return audio - - def _transcribe_voice_job( - self, - job: dict[str, Any], - *, - status_cb: Callable[[str], Any] | None = None, - ) -> str: - if not self.cfg.openai_api_key: - raise VoiceTranscriptionError( - "не настроен ключ OpenAI для распознавания.", - stage="config", - retryable=False, - ) - file_id = (job.get("telegram_file_id") or "").strip() - if not file_id: - raise VoiceTranscriptionError( - "Telegram не передал идентификатор файла.", - stage="telegram_file_id", - retryable=False, - ) - job_id = str(job.get("id") or "")[:8] - job_num = job.get("num", "?") - media_type = (job.get("telegram_media_type") or "voice").strip() - duration_seconds = int(job.get("telegram_duration_seconds") or 0) - telegram_file_size = int(job.get("telegram_file_size") or 0) - file_looks_big_for_cloud = self._telegram_cloud_download_is_likely_too_big(telegram_file_size) - if file_looks_big_for_cloud and status_cb is not None: - status_cb( - "файл большой, всё равно пробую скачать его из Telegram. " - f"Предварительный размер около {self._bytes_to_mb(telegram_file_size)} MB." - ) - started_at = time.time() - print(f"[py-bot] transcribe start job={job_id} num={job_num} media={media_type}", flush=True) - file_bytes, filename = self._download_telegram_file(file_id) - print( - f"[py-bot] transcribe downloaded job={job_id} filename={filename} size={len(file_bytes)} bytes", - flush=True, - ) - if file_looks_big_for_cloud and status_cb is not None: - status_cb( - "скачивание из Telegram прошло успешно. " - f"Фактический размер около {self._bytes_to_mb(len(file_bytes))} MB, дальше готовлю аудио и отправляю в OpenAI." - ) - prepared_parts = self._prepare_audio_parts_for_transcription( - file_bytes, - filename, - duration_seconds=duration_seconds, - job_id=job_id, - job_num=job_num, - ) - print( - f"[py-bot] transcribe prepared job={job_id} parts={len(prepared_parts)} duration={duration_seconds}s", - flush=True, - ) - parts_text: list[str] = [] - prompt_tail = "" - for index, (part_bytes, part_name) in enumerate(prepared_parts, start=1): - print( - f"[py-bot] transcribe part job={job_id} index={index}/{len(prepared_parts)} filename={part_name} size={len(part_bytes)} bytes", - flush=True, - ) - part_text = self._openai_transcribe(part_bytes, part_name, prompt=prompt_tail).strip() - if part_text: - parts_text.append(part_text) - prompt_tail = self._transcription_prompt_tail("\n".join(parts_text)) - text = "\n".join(parts_text).strip() - if not text: - raise VoiceTranscriptionError( - "сервис распознавания вернул пустой текст. Возможно, в записи нет слышимой речи или качество звука слишком низкое.", - stage="empty_text", - retryable=False, - ) - elapsed = self._format_duration(int(time.time() - started_at)) - print(f"[py-bot] transcribe done job={job_id} chars={len(text)} elapsed={elapsed}", flush=True) - return text - - def _download_telegram_file(self, file_id: str) -> tuple[bytes, str]: - try: - result = self.telegram.call("getFile", {"file_id": file_id}, timeout=120) - except TimeoutError as e: - raise VoiceTranscriptionError( - "Telegram долго не отдавал информацию о файле.", - stage="telegram_get_file_timeout", - detail=str(e), - ) from e - except Exception as e: - detail = str(e) - if "file is too big" in detail.lower(): - raise VoiceTranscriptionError( - "Файл большой: я попробовал скачать его через текущий Telegram Bot API, " - "но Telegram не дал это сделать. Для такого аудио нужен локальный `telegram-bot-api` " - "сервер или другой способ передать файл боту.", - stage="telegram_get_file_too_big", - retryable=False, - detail=detail, - ) from e - raise VoiceTranscriptionError( - "не удалось получить информацию о файле из Telegram.", - stage="telegram_get_file", - detail=detail, - ) from e - info = result.get("result") or {} - file_path = info.get("file_path") - if not file_path: - raise VoiceTranscriptionError( - "Telegram не вернул путь к файлу.", - stage="telegram_file_path", - retryable=True, - detail=json.dumps(info, ensure_ascii=False)[:1000], - ) - file_url = self.telegram.file_base + file_path.lstrip("/") - req = request.Request(file_url, method="GET") - try: - with request.urlopen(req, timeout=self.cfg.telegram_file_download_timeout_seconds) as resp: - data = resp.read() - except TimeoutError as e: - raise VoiceTranscriptionError( - f"Telegram не успел отдать аудиофайл за {self.cfg.telegram_file_download_timeout_seconds} секунд.", - stage="telegram_download_timeout", - detail=str(e), - ) from e - except error.HTTPError as e: - detail = e.read().decode("utf-8", errors="replace") - raise VoiceTranscriptionError( - f"Telegram вернул ошибку HTTP {e.code} при скачивании аудио.", - stage="telegram_download_http", - retryable=e.code >= 500 or e.code == 429, - detail=detail[:1000], - ) from e - except error.URLError as e: - raise VoiceTranscriptionError( - "не удалось скачать аудиофайл из Telegram из-за сетевой ошибки.", - stage="telegram_download_network", - detail=str(e.reason), - ) from e - if not data: - raise VoiceTranscriptionError( - "Telegram отдал пустой аудиофайл.", - stage="telegram_download_empty", - retryable=True, - ) - original_name = Path(file_path).name or "audio.ogg" - lower = original_name.lower() - # OpenAI transcription может не принимать расширение .oga, нормализуем в .ogg. - if lower.endswith(".oga"): - base = original_name[:-4] if len(original_name) > 4 else "audio" - normalized = f"{base}.ogg" - else: - normalized = original_name - return data, normalized - - def _prepare_audio_parts_for_transcription( - self, - file_bytes: bytes, - filename: str, - *, - duration_seconds: int, - job_id: str, - job_num: Any, - ) -> list[tuple[bytes, str]]: - needs_duration_chunking = duration_seconds > self.cfg.openai_transcribe_max_chunk_seconds - if len(file_bytes) <= self.cfg.openai_transcribe_max_upload_bytes and not needs_duration_chunking: - return [(file_bytes, filename)] - ffmpeg_path = shutil.which(self.cfg.ffmpeg_bin) - ffprobe_path = shutil.which(self.cfg.ffprobe_bin) - if not ffmpeg_path or not ffprobe_path: - raise VoiceTranscriptionError( - "для длинного аудио нужен локальный `ffmpeg`/`ffprobe`, но они не найдены в системе.", - stage="audio_prepare_tools_missing", - retryable=False, - ) - with tempfile.TemporaryDirectory(prefix="shine-audio-") as tmpdir: - tmp = Path(tmpdir) - input_suffix = Path(filename).suffix or ".ogg" - input_path = tmp / f"source{input_suffix}" - input_path.write_bytes(file_bytes) - prepared_path = tmp / "prepared.ogg" - self._ffmpeg_reencode_audio(input_path, prepared_path) - prepared_bytes = prepared_path.read_bytes() - prepared_duration = self._ffprobe_duration_seconds(prepared_path) - if ( - len(prepared_bytes) <= self.cfg.openai_transcribe_max_upload_bytes - and prepared_duration <= self.cfg.openai_transcribe_max_chunk_seconds - ): - return [(prepared_bytes, prepared_path.name)] - chunk_length = self._choose_transcription_chunk_seconds(prepared_duration, len(prepared_bytes)) - print( - f"[py-bot] audio chunking job={job_id} num={job_num} duration={prepared_duration:.1f}s total_bytes={len(prepared_bytes)} chunk_seconds={chunk_length}", - flush=True, - ) - chunks: list[tuple[bytes, str]] = [] - offset = 0 - index = 1 - total_duration = max(1, int(prepared_duration + 0.999)) - while offset < total_duration: - chunk_path = tmp / f"chunk_{index:03d}.ogg" - self._ffmpeg_extract_audio_chunk(prepared_path, chunk_path, offset, chunk_length) - chunk_bytes = chunk_path.read_bytes() - if not chunk_bytes: - break - if len(chunk_bytes) > self.cfg.openai_transcribe_max_upload_bytes: - raise VoiceTranscriptionError( - "локальная нарезка аудио дала слишком большой кусок для OpenAI; нужно уменьшить размер чанка.", - stage="audio_chunk_too_large", - retryable=False, - ) - chunks.append((chunk_bytes, chunk_path.name)) - step = max(1, chunk_length - self.cfg.openai_transcribe_overlap_seconds) - offset += step - index += 1 - if not chunks: - raise VoiceTranscriptionError( - "не удалось подготовить куски аудио для распознавания.", - stage="audio_chunk_empty", - retryable=False, - ) - return chunks - - def _ffmpeg_reencode_audio(self, input_path: Path, output_path: Path) -> None: - cmd = [ - self.cfg.ffmpeg_bin, - "-y", - "-i", - str(input_path), - "-vn", - "-ac", - "1", - "-ar", - "16000", - "-c:a", - "libopus", - "-b:a", - f"{self.cfg.openai_transcribe_reencode_bitrate_kbps}k", - str(output_path), - ] - self._run_subprocess_checked(cmd, "audio_reencode_ffmpeg") - - def _ffmpeg_extract_audio_chunk(self, input_path: Path, output_path: Path, offset_seconds: int, chunk_seconds: int) -> None: - cmd = [ - self.cfg.ffmpeg_bin, - "-y", - "-ss", - str(offset_seconds), - "-t", - str(chunk_seconds), - "-i", - str(input_path), - "-vn", - "-acodec", - "copy", - str(output_path), - ] - self._run_subprocess_checked(cmd, "audio_chunk_ffmpeg") - - def _ffprobe_duration_seconds(self, audio_path: Path) -> float: - cmd = [ - self.cfg.ffprobe_bin, - "-v", - "error", - "-show_entries", - "format=duration", - "-of", - "default=noprint_wrappers=1:nokey=1", - str(audio_path), - ] - try: - result = subprocess.run( - cmd, - check=True, - capture_output=True, - text=True, - timeout=self.cfg.openai_transcribe_ffmpeg_timeout_seconds, - ) - except subprocess.TimeoutExpired as e: - raise VoiceTranscriptionError( - f"`ffprobe` не успел определить длительность аудио за {self.cfg.openai_transcribe_ffmpeg_timeout_seconds} секунд.", - stage="audio_probe_timeout", - retryable=False, - ) from e - except subprocess.CalledProcessError as e: - detail = (e.stderr or e.stdout or "").strip() - raise VoiceTranscriptionError( - "не удалось определить длительность аудио через `ffprobe`.", - stage="audio_probe_failed", - retryable=False, - detail=detail[:1500], - ) from e - raw = (result.stdout or "").strip() - try: - return max(0.0, float(raw)) - except ValueError as e: - raise VoiceTranscriptionError( - "`ffprobe` вернул некорректную длительность аудио.", - stage="audio_probe_invalid", - retryable=False, - detail=raw[:300], - ) from e - - def _run_subprocess_checked(self, cmd: list[str], stage: str) -> None: - try: - subprocess.run( - cmd, - check=True, - capture_output=True, - text=True, - timeout=self.cfg.openai_transcribe_ffmpeg_timeout_seconds, - ) - except subprocess.TimeoutExpired as e: - raise VoiceTranscriptionError( - f"локальная обработка аудио не успела завершиться за {self.cfg.openai_transcribe_ffmpeg_timeout_seconds} секунд.", - stage=f"{stage}_timeout", - retryable=False, - ) from e - except subprocess.CalledProcessError as e: - detail = (e.stderr or e.stdout or "").strip() - raise VoiceTranscriptionError( - "локальная обработка аудио через `ffmpeg` завершилась с ошибкой.", - stage=f"{stage}_failed", - retryable=False, - detail=detail[:1500], - ) from e - - def _choose_transcription_chunk_seconds(self, duration_seconds: float, total_bytes: int) -> int: - max_chunk = self.cfg.openai_transcribe_max_chunk_seconds - safe_seconds = max(60, max_chunk - self.cfg.openai_transcribe_overlap_seconds) - if duration_seconds <= 0 or total_bytes <= 0: - return safe_seconds - bytes_per_second = total_bytes / max(duration_seconds, 1.0) - if bytes_per_second <= 0: - return safe_seconds - size_limited = int((self.cfg.openai_transcribe_max_upload_bytes * 0.9) / bytes_per_second) - return max(60, min(safe_seconds, size_limited if size_limited > 0 else safe_seconds)) - - @staticmethod - def _transcription_prompt_tail(text: str, limit: int = 1000) -> str: - source = compact_spaces(text) - if len(source) <= limit: - return source - return source[-limit:] - - def _telegram_cloud_download_is_likely_too_big(self, file_size: int) -> bool: - if file_size <= 0: - return False - using_cloud_api = self.cfg.telegram_api_base_url.rstrip("/") == "https://api.telegram.org" - return using_cloud_api and file_size > 20 * 1024 * 1024 - - @staticmethod - def _bytes_to_mb(value: int) -> str: - return f"{value / (1024 * 1024):.1f}" - - def _openai_transcribe(self, file_bytes: bytes, filename: str, prompt: str = "") -> str: - boundary = "----shine-boundary-" + "".join(random.choices("abcdef0123456789", k=16)) - mime = mimetypes.guess_type(filename)[0] or "application/octet-stream" - - def text_part(name: str, value: str) -> bytes: - return ( - f"--{boundary}\r\n" - f'Content-Disposition: form-data; name="{name}"\r\n\r\n' - f"{value}\r\n" - ).encode("utf-8") - - body = bytearray() - body.extend(text_part("model", self.cfg.openai_transcribe_model)) - body.extend(text_part("response_format", "text")) - prompt = compact_spaces(prompt) - if prompt: - body.extend(text_part("prompt", prompt[:1000])) - body.extend( - ( - f"--{boundary}\r\n" - f'Content-Disposition: form-data; name="file"; filename="{filename}"\r\n' - f"Content-Type: {mime}\r\n\r\n" - ).encode("utf-8") - ) - body.extend(file_bytes) - body.extend(b"\r\n") - body.extend(f"--{boundary}--\r\n".encode("utf-8")) - - req = request.Request("https://api.openai.com/v1/audio/transcriptions", method="POST", data=bytes(body)) - req.add_header("Authorization", f"Bearer {self.cfg.openai_api_key}") - req.add_header("Content-Type", f"multipart/form-data; boundary={boundary}") - try: - with request.urlopen(req, timeout=self.cfg.openai_transcribe_timeout_seconds) as resp: - return resp.read().decode("utf-8", errors="replace") - except TimeoutError as e: - raise VoiceTranscriptionError( - f"OpenAI не успел распознать аудио за {self.cfg.openai_transcribe_timeout_seconds} секунд.", - stage="openai_transcribe_timeout", - detail=str(e), - ) from e - except error.HTTPError as e: - detail = e.read().decode("utf-8", errors="replace") - if e.code == 400: - user_message = "OpenAI не принял аудиофайл для распознавания." - elif e.code == 401: - user_message = "OpenAI отклонил ключ API для распознавания." - elif e.code == 413: - user_message = "аудиофайл слишком большой для распознавания OpenAI." - elif e.code == 429: - user_message = "OpenAI временно ограничил распознавание из-за лимита запросов." - elif e.code >= 500: - user_message = "OpenAI временно не смог обработать распознавание." - else: - user_message = f"OpenAI вернул ошибку HTTP {e.code} при распознавании." - raise VoiceTranscriptionError( - user_message, - stage="openai_transcribe_http", - retryable=e.code == 429 or e.code >= 500, - detail=detail[:1500], - ) from e - except error.URLError as e: - raise VoiceTranscriptionError( - "не удалось отправить аудио в OpenAI из-за сетевой ошибки.", - stage="openai_transcribe_network", - detail=str(e.reason), - ) from e - - @staticmethod - def _extract_codex_user_note(line: str) -> str | None: - s = (line or "").strip() - if not s.startswith("{"): - return None - try: - obj = json.loads(s) - except Exception: - return None - if obj.get("type") != "item.completed": - return None - item = obj.get("item") or {} - if item.get("type") != "agent_message": - return None - text = (item.get("text") or "").strip() - if not text: - return None - if len(text) > 220: - return text[:220] + "..." - return text - - @staticmethod - def _extract_fallback_message(lines: list[str]) -> str: - for line in reversed(lines): - line = line.strip() - if not line: - continue - if line.startswith("{") and '"type":' in line: - continue - if line.startswith("mcp:") or line.startswith("OpenAI Codex"): - continue - return line - return "" - - @staticmethod - def _extract_codex_thread_id(line: str) -> str: - s = (line or "").strip() - if not s.startswith("{"): - return "" - try: - obj = json.loads(s) - except Exception: - return "" - if obj.get("type") != "thread.started": - return "" - thread_id = (obj.get("thread_id") or "").strip() - return thread_id - - @staticmethod - def _is_missing_codex_session_error(text: str) -> bool: - lowered = (text or "").lower() - markers = [ - "session not found", - "conversation not found", - "thread not found", - "no session found", - "invalid session", - "unknown session", - "no conversation found", - "unknown thread", - ] - return any(marker in lowered for marker in markers) - - @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 = [ - str(config.codex_bin), - "exec", - "--dangerously-bypass-approvals-and-sandbox", - "--json", - "-C", str(config.codex_workdir), - prompt, - ] - proc = subprocess.run( - cmd, - stdin=subprocess.DEVNULL, - capture_output=True, - text=True, - encoding="utf-8", - errors="replace", - ) - print(proc.stdout) - if proc.stderr: - print(proc.stderr) - return proc.returncode - - -def main() -> int: - parser = argparse.ArgumentParser(description="SHiNE Python Telegram bot wrapper for Codex CLI") - parser.add_argument("--selftest-codex", default="", help="Выполнить только codex exec с этим prompt и выйти") - args = parser.parse_args() - - root = Path(__file__).resolve().parent - cfg = BotConfig(root) - if args.selftest_codex: - return run_selftest(cfg, args.selftest_codex) - - service = ShinePyBotService(cfg) - try: - service.run() - except KeyboardInterrupt: - service.shutdown() - return 0 - except Exception as e: - print(f"[py-bot] FATAL: {e}", flush=True) - return 1 - return 0 - - -if __name__ == "__main__": - raise SystemExit(main()) diff --git a/SHiNE-agent-bot-coder/scripts/systemd/install-local-systemd.sh b/SHiNE-agent-bot-coder/scripts/systemd/install-local-systemd.sh deleted file mode 100755 index eb34b47b..00000000 --- a/SHiNE-agent-bot-coder/scripts/systemd/install-local-systemd.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -ROOT_DIR="/home/ai/work/SHiNE/SHiNE-server-sha256" -SERVICE_DIR="${ROOT_DIR}/SHiNE-agent-bot-coder" -UNIT_SRC="${SERVICE_DIR}/scripts/systemd/shine-agent-bot-coder.service" -UNIT_DST="${HOME}/.config/systemd/user/shine-agent-bot-coder.service" - -echo "[1/6] Проверка python3..." -command -v python3 >/dev/null 2>&1 || { echo "python3 не найден"; exit 1; } - -echo "[2/6] Подготовка папки логов..." -mkdir -p "${SERVICE_DIR}/logs" - -echo "[3/6] Копирование user systemd unit..." -mkdir -p "$(dirname "${UNIT_DST}")" -cp "${UNIT_SRC}" "${UNIT_DST}" - -echo "[4/6] daemon-reload..." -systemctl --user daemon-reload - -echo "[5/6] enable + start..." -systemctl --user enable --now shine-agent-bot-coder - -echo "[6/6] Статус:" -systemctl --user status shine-agent-bot-coder --no-pager - -echo "Готово. Логи: journalctl --user -u shine-agent-bot-coder -f" diff --git a/SHiNE-agent-bot-coder/scripts/systemd/shine-agent-bot-coder.service b/SHiNE-agent-bot-coder/scripts/systemd/shine-agent-bot-coder.service deleted file mode 100644 index 231e5557..00000000 --- a/SHiNE-agent-bot-coder/scripts/systemd/shine-agent-bot-coder.service +++ /dev/null @@ -1,19 +0,0 @@ -[Unit] -Description=SHiNE Agent Bot Coder (Telegram + Codex queue worker) -After=network-online.target -Wants=network-online.target - -[Service] -Type=simple -WorkingDirectory=/home/ai/work/SHiNE/SHiNE-server-sha256/SHiNE-agent-bot-coder -EnvironmentFile=/home/ai/work/SHiNE/SHiNE-server-sha256/SHiNE-agent-bot-coder/.env -ExecStart=/usr/bin/python3 /home/ai/work/SHiNE/SHiNE-server-sha256/SHiNE-agent-bot-coder/py_bot_service.py -Restart=always -RestartSec=5 -TimeoutStopSec=20 -SuccessExitStatus=143 0 -StandardOutput=append:/home/ai/work/SHiNE/SHiNE-server-sha256/SHiNE-agent-bot-coder/logs/service.log -StandardError=append:/home/ai/work/SHiNE/SHiNE-server-sha256/SHiNE-agent-bot-coder/logs/service.log - -[Install] -WantedBy=default.target diff --git a/VERSION.properties b/VERSION.properties index 88b1c020..c5543449 100644 --- a/VERSION.properties +++ b/VERSION.properties @@ -1,2 +1,2 @@ -client.version=1.2.332 -server.version=1.2.304 +client.version=1.2.333 +server.version=1.2.305 diff --git a/codex-agent-VPS/.env.example b/codex-agent-VPS/.env.example deleted file mode 100644 index 9b15d6d0..00000000 --- a/codex-agent-VPS/.env.example +++ /dev/null @@ -1,31 +0,0 @@ -TELEGRAM_BOT_TOKEN=replace_me -OPENAI_API_KEY= -ALLOWED_TELEGRAM_USERNAME=owner_username -ALLOWED_TELEGRAM_PLAYERS=user_one:User One,user_two:User Two -ALLOWED_TELEGRAM_CHANNEL_USERNAME= -BOT_USERNAME=your_bot_username -TELEGRAM_API_BASE_URL=https://api.telegram.org -OPENAI_TRANSCRIBE_MODEL=gpt-4o-mini-transcribe -TELEGRAM_FILE_DOWNLOAD_TIMEOUT_SECONDS=300 -OPENAI_TRANSCRIBE_TIMEOUT_SECONDS=900 -OPENAI_TRANSCRIBE_MAX_UPLOAD_BYTES=25165824 -OPENAI_TRANSCRIBE_MAX_CHUNK_SECONDS=900 -OPENAI_TRANSCRIBE_OVERLAP_SECONDS=2 -OPENAI_TRANSCRIBE_REENCODE_BITRATE_KBPS=24 -OPENAI_TRANSCRIBE_FFMPEG_TIMEOUT_SECONDS=1800 -FFMPEG_BIN=ffmpeg -FFPROBE_BIN=ffprobe -OPENAI_TTS_MODEL=gpt-4o-mini-tts -OPENAI_TTS_VOICE=alloy -OPENAI_TTS_RESPONSE_FORMAT=opus -OPENAI_TTS_TIMEOUT_SECONDS=180 -OPENAI_TTS_CHUNK_CHARS=3500 -OPENAI_VOICE_REWRITE_MODEL=gpt-4.1-nano -OPENAI_VOICE_REWRITE_TIMEOUT_SECONDS=90 -OPENAI_VOICE_REWRITE_MAX_INPUT_CHARS=12000 -OPENAI_VOICE_REWRITE_MAX_OUTPUT_TOKENS=900 -CODEX_BIN=/home/your_user/.local/bin/codex -CODEX_WORKDIR=/home/your_user -CODEX_TIMEOUT_SECONDS=900 -MAX_RETRIES=3 -DATA_DIR=./data diff --git a/codex-agent-VPS/.gitignore b/codex-agent-VPS/.gitignore deleted file mode 100644 index 2af457e8..00000000 --- a/codex-agent-VPS/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -.env -data/ -logs/ -run/ -__pycache__/ diff --git a/codex-agent-VPS/AGENTS.md b/codex-agent-VPS/AGENTS.md deleted file mode 100644 index 770e488a..00000000 --- a/codex-agent-VPS/AGENTS.md +++ /dev/null @@ -1,86 +0,0 @@ -# AGENTS - -## Назначение -- `codex-agent-VPS` — переносимая версия Telegram-бота для запуска `codex` CLI на VPS. -- Папку можно ставить в любое место на Linux-сервере, если там есть `python3`, `systemd`, `codex` и доступ в интернет. -- Конфигурация делается через `.env`. - -## Состав папки -- `README.md` — краткое описание структуры. -- `Agent-server-package/` — готовый набор файлов для копирования на VPS. -- `.env.example` — пример конфигурации. -- `AGENTS.md` — инструкция по установке и настройке. - -## Требования к VPS -- Linux-сервер с `systemd`. -- Установленные `python3`, `curl`, `ffmpeg`. -- Установленный `codex` CLI. -- Выполненный `codex login` под тем пользователем, от которого будет работать сервис. -- Telegram bot token. -- Telegram usernames разрешённых пользователей. - -## Установка через Codex -1. Скопировать содержимое `Agent-server-package/` на сервер в нужное место, например: - - `/home/your_user/codex-agent` -2. Установить `codex` CLI под рабочим пользователем. -3. Выполнить под этим же пользователем: - - `codex login` -4. Установить системные зависимости: - - `python3` - - `ffmpeg` -5. Взять `.env.example` из корня `codex-agent-VPS` и создать на сервере `.env`. -6. В `.env` заполнить: - - `TELEGRAM_BOT_TOKEN` - - `ALLOWED_TELEGRAM_USERNAME` - - `ALLOWED_TELEGRAM_PLAYERS` - - `BOT_USERNAME` - - `CODEX_BIN` - - `CODEX_WORKDIR` -7. Если нужны voice/audio и голосовые ответы, дополнительно задать: - - `OPENAI_API_KEY` -8. В `Agent-server-package/scripts/systemd/shine-agent-bot-coder.service` заменить: - - `your_user` - - `/home/your_user/codex-agent` - на реальные значения. -9. Скопировать unit в: - - `/etc/systemd/system/shine-agent-bot-coder.service` -10. Выполнить: - - `sudo systemctl daemon-reload` - - `sudo systemctl enable --now shine-agent-bot-coder` -11. Проверить: - - `sudo systemctl status shine-agent-bot-coder --no-pager` - - `sudo journalctl -u shine-agent-bot-coder -f` - -## Настройка доступа -- `ALLOWED_TELEGRAM_USERNAME` — основной разрешённый пользователь. -- `ALLOWED_TELEGRAM_PLAYERS` — дополнительные разрешённые пользователи: - - `username1:Имя 1,username2:Имя 2` -- Все пользователи из whitelist в этой версии считаются полноправными. -- Все входящие задачи попадают в одну общую очередь и выполняются строго последовательно. - -## Поведение агента -- Бот принимает текст, voice и audio. -- Для каждого пользователя ведётся отдельная история. -- Все задачи запускаются через `codex exec`. -- Рабочая директория задаётся через `CODEX_WORKDIR`. -- Вызов идёт без sandbox/approval ограничений: `--dangerously-bypass-approvals-and-sandbox`. - -## Что обычно меняют при переносе -- `.env` -- `Agent-server-package/scripts/systemd/shine-agent-bot-coder.service` -- при необходимости `Agent-server-package/AGENT.md` - -## Полезные команды -- Проверка установки Codex: - - `codex --version` - - `codex doctor` -- Self-test без Telegram: - - `python3 py_bot_service.py --selftest-codex "Ответь одной строкой: Codex работает"` -- Проверка сервиса: - - `sudo systemctl status shine-agent-bot-coder --no-pager` - - `sudo journalctl -u shine-agent-bot-coder -f` - -## Примечания -- Если `codex doctor` пишет, что credentials не найдены, нужно выполнить `codex login`. -- Если `OPENAI_API_KEY` пустой, текстовые задачи через `codex` будут работать, а voice/audio и TTS-функции — нет. -- Если у пользователя в Telegram нет username, whitelist по username его не пропустит. diff --git a/codex-agent-VPS/Agent-server-package/.env.example b/codex-agent-VPS/Agent-server-package/.env.example deleted file mode 100644 index 9b15d6d0..00000000 --- a/codex-agent-VPS/Agent-server-package/.env.example +++ /dev/null @@ -1,31 +0,0 @@ -TELEGRAM_BOT_TOKEN=replace_me -OPENAI_API_KEY= -ALLOWED_TELEGRAM_USERNAME=owner_username -ALLOWED_TELEGRAM_PLAYERS=user_one:User One,user_two:User Two -ALLOWED_TELEGRAM_CHANNEL_USERNAME= -BOT_USERNAME=your_bot_username -TELEGRAM_API_BASE_URL=https://api.telegram.org -OPENAI_TRANSCRIBE_MODEL=gpt-4o-mini-transcribe -TELEGRAM_FILE_DOWNLOAD_TIMEOUT_SECONDS=300 -OPENAI_TRANSCRIBE_TIMEOUT_SECONDS=900 -OPENAI_TRANSCRIBE_MAX_UPLOAD_BYTES=25165824 -OPENAI_TRANSCRIBE_MAX_CHUNK_SECONDS=900 -OPENAI_TRANSCRIBE_OVERLAP_SECONDS=2 -OPENAI_TRANSCRIBE_REENCODE_BITRATE_KBPS=24 -OPENAI_TRANSCRIBE_FFMPEG_TIMEOUT_SECONDS=1800 -FFMPEG_BIN=ffmpeg -FFPROBE_BIN=ffprobe -OPENAI_TTS_MODEL=gpt-4o-mini-tts -OPENAI_TTS_VOICE=alloy -OPENAI_TTS_RESPONSE_FORMAT=opus -OPENAI_TTS_TIMEOUT_SECONDS=180 -OPENAI_TTS_CHUNK_CHARS=3500 -OPENAI_VOICE_REWRITE_MODEL=gpt-4.1-nano -OPENAI_VOICE_REWRITE_TIMEOUT_SECONDS=90 -OPENAI_VOICE_REWRITE_MAX_INPUT_CHARS=12000 -OPENAI_VOICE_REWRITE_MAX_OUTPUT_TOKENS=900 -CODEX_BIN=/home/your_user/.local/bin/codex -CODEX_WORKDIR=/home/your_user -CODEX_TIMEOUT_SECONDS=900 -MAX_RETRIES=3 -DATA_DIR=./data diff --git a/codex-agent-VPS/Agent-server-package/AGENT.md b/codex-agent-VPS/Agent-server-package/AGENT.md deleted file mode 100644 index 8831ff17..00000000 --- a/codex-agent-VPS/Agent-server-package/AGENT.md +++ /dev/null @@ -1,51 +0,0 @@ -# AGENT.md для codex-agent-VPS - -Ты запущен как обработчик входящего Telegram-сообщения от пользователя. - -## Контекст -- `codex-agent-VPS` — Telegram-бот, который принимает сообщения, ведёт историю, ставит задачи в очередь и последовательно запускает `codex` CLI на VPS. -- Текстовые сообщения обрабатываются напрямую. -- Voice и audio сначала распознаются через OpenAI transcription, затем передаются как текстовая задача. -- История диалога хранится в JSONL-файле, путь передаётся в промпте. -- Ответ пойдёт пользователю в Telegram как обычное текстовое сообщение. -- Основная реализация сервиса — Python-скрипт `py_bot_service.py`. - -## Пользователи и доступ -- Разрешённые пользователи задаются через `ALLOWED_TELEGRAM_USERNAME` и `ALLOWED_TELEGRAM_PLAYERS`. -- Все разрешённые пользователи считаются полноправными. -- Для неизвестных пользователей в личном чате сервис отвечает вежливым отказом. -- Все входящие задачи попадают в одну общую очередь и выполняются строго по одной. - -## Очередь и состояние -- Сервис ведёт состояние активной задачи и текущего файла истории. -- После рестарта сервис продолжает незавершённую обработку с учётом сохранённого состояния. -- Истории диалогов хранятся отдельно по username: `data/history//`. -- Архив истории после `/new`: `data/history//archive/`. -- После `/new` для этого же пользователя должен сбрасываться и контекст продолжения Codex-сессии; следующий запрос запускается как новая сессия, не через resume. -- Дедупликация Telegram update обязательна, чтобы одно сообщение не обрабатывалось повторно. -- Если Codex молчит во время активной задачи 2 минуты подряд, сервис отправляет аварийный статус и повторяет его каждые 2 минуты. - -## Голосовые ответы -- Озвучивание финальных ответов настраивается персонально командами `/voice_on` и `/voice_off`. -- Для новых пользователей озвучивание включено по умолчанию. -- Адаптация текста перед озвучкой настраивается командами `/voice_rewrite_on` и `/voice_rewrite_off`. -- Если озвучивание включено, после текстового финального ответа сервис дополнительно отправляет voice-файл через OpenAI TTS. -- Промежуточные статусы озвучивать не нужно. - -## Команды -- `/status` — состояние очереди и персональных настроек. -- `/settings` — текущие пользовательские настройки. -- `/queue` — список задач в очереди. -- `/tasks` — список задач и предложений пользователя. -- `/new` — архивировать историю и начать новую Codex-сессию. -- `/stop` — остановить текущую задачу. -- `/cancel ` — удалить задачу по id или очистить очередь. -- `/restart` и `/restart_service` — отложенный рестарт после текущей задачи. -- `/restart_hard`, `/restart_now`, `/restart_force` — жёсткий рестарт прямо сейчас. - -## Правила ответа -- Пиши содержательно и коротко. -- Не упоминай внутренние служебные детали, файловую систему и технические логи, если это не нужно пользователю. -- Если запрос требует действий с кодом или файлами, выполняй их в рабочей директории `CODEX_WORKDIR`. -- Если данных недостаточно, задай ровно один уточняющий вопрос. -- Если в промпте есть пометка retry, учитывай текущее состояние и продолжай аккуратно, а не начинай заново без причины. diff --git a/codex-agent-VPS/Agent-server-package/py_bot_service.py b/codex-agent-VPS/Agent-server-package/py_bot_service.py deleted file mode 100644 index e96dee36..00000000 --- a/codex-agent-VPS/Agent-server-package/py_bot_service.py +++ /dev/null @@ -1,2960 +0,0 @@ -#!/usr/bin/env python3 -from __future__ import annotations - -import argparse -import datetime as dt -import fcntl -import json -import mimetypes -import os -import random -import re -import shutil -import string -import subprocess -import tempfile -import threading -import time -import traceback -import uuid -from pathlib import Path -from typing import Any, Callable -from urllib import error, request - -DEFAULT_ALLOWED_PLAYERS = ",".join([ - "user_one:User One", - "user_two:User Two", -]) - -TASK_STATUS_LABELS = { - "new": "новая", - "approved": "одобрена", - "rejected": "отклонена", - "needs_work": "на доработку", - "done": "сделана", -} - - -def now_iso() -> str: - return dt.datetime.now(dt.timezone.utc).isoformat() - - -def normalize_username(value: str | None) -> str: - if not value: - return "" - value = value.strip() - if value.startswith("@"): - value = value[1:] - return value.lower() - - -def parse_allowed_players(raw: str) -> dict[str, str]: - players: dict[str, str] = {} - for item in (raw or "").split(","): - part = item.strip() - if not part: - continue - username_part, sep, name_part = part.partition(":") - username = normalize_username(username_part) - if not username: - continue - player_name = (name_part if sep else username_part).strip() or username - players[username] = player_name - return players - - -def compact_spaces(text: str) -> str: - return re.sub(r"\s+", " ", (text or "").strip()) - - -def split_long_text(text: str, chunk_size: int = 3500) -> list[str]: - text = (text or "").strip() - if not text: - return ["(пустой ответ)"] - return [text[i:i + chunk_size] for i in range(0, len(text), chunk_size)] - - -def split_final_private_text(text: str, first_chunk_size: int = 3900, second_chunk_size: int = 3900) -> list[str]: - text = (text or "").strip() - if not text: - return ["(пустой ответ)"] - if len(text) <= first_chunk_size: - return [text] - first = text[:first_chunk_size].rstrip() - rest = text[first_chunk_size:].lstrip() - if len(rest) <= second_chunk_size: - return [first, rest] - second = rest[:second_chunk_size].rstrip() - if len(second) > 40: - second = second[:-40].rstrip() - second = second.rstrip() + "\n...[ответ обрезан]" - return [first, second] - - -def split_text_for_tts(text: str, chunk_size: int) -> list[str]: - text = (text or "").strip() - if not text: - return [] - chunks: list[str] = [] - current = "" - paragraphs = re.split(r"\n\s*\n", text) - for paragraph in paragraphs: - paragraph = paragraph.strip() - if not paragraph: - continue - if len(paragraph) > chunk_size: - if current: - chunks.append(current) - current = "" - for i in range(0, len(paragraph), chunk_size): - part = paragraph[i:i + chunk_size].strip() - if part: - chunks.append(part) - continue - candidate = paragraph if not current else f"{current}\n\n{paragraph}" - if len(candidate) <= chunk_size: - current = candidate - else: - if current: - chunks.append(current) - current = paragraph - if current: - chunks.append(current) - return chunks - - -def read_env_file(path: Path) -> dict[str, str]: - result: dict[str, str] = {} - if not path.exists(): - return result - for raw_line in path.read_text(encoding="utf-8").splitlines(): - line = raw_line.strip() - if not line or line.startswith("#") or "=" not in line: - continue - key, value = line.split("=", 1) - key = key.strip() - value = value.strip().strip('"').strip("'") - result[key] = value - return result - - -class VoiceTranscriptionError(RuntimeError): - def __init__( - self, - user_message: str, - *, - stage: str, - retryable: bool = True, - detail: str = "", - ): - super().__init__(user_message) - self.user_message = user_message - self.stage = stage - self.retryable = retryable - self.detail = detail - - def log_text(self) -> str: - if self.detail and self.detail != self.user_message: - return f"{self.user_message} stage={self.stage} retryable={self.retryable} detail={self.detail}" - return f"{self.user_message} stage={self.stage} retryable={self.retryable}" - - -class VoiceReplyError(RuntimeError): - pass - - -class JsonLineStore: - @staticmethod - def load(path: Path) -> list[dict[str, Any]]: - if not path.exists(): - return [] - items: list[dict[str, Any]] = [] - for line in path.read_text(encoding="utf-8").splitlines(): - line = line.strip() - if not line: - continue - items.append(json.loads(line)) - return items - - @staticmethod - def save(path: Path, items: list[dict[str, Any]]) -> None: - path.parent.mkdir(parents=True, exist_ok=True) - tmp = path.with_suffix(path.suffix + ".tmp") - with tmp.open("w", encoding="utf-8") as f: - for item in items: - f.write(json.dumps(item, ensure_ascii=False) + "\n") - tmp.replace(path) - - @staticmethod - def append(path: Path, item: dict[str, Any]) -> None: - path.parent.mkdir(parents=True, exist_ok=True) - with path.open("a", encoding="utf-8") as f: - f.write(json.dumps(item, ensure_ascii=False) + "\n") - - -class TelegramApi: - def __init__(self, token: str, base_url: str = "https://api.telegram.org"): - self.token = token - self.api_root = (base_url or "https://api.telegram.org").rstrip("/") - self.base = f"{self.api_root}/bot{token}/" - self.file_base = f"{self.api_root}/file/bot{token}/" - - def call(self, method: str, payload: dict[str, Any] | None = None, timeout: int = 60) -> dict[str, Any]: - data = None - headers = {} - if payload is not None: - data = json.dumps(payload).encode("utf-8") - headers["Content-Type"] = "application/json" - req = request.Request(self.base + method, data=data, headers=headers, method="POST") - try: - with request.urlopen(req, timeout=timeout) as resp: - raw = resp.read().decode("utf-8") - except error.HTTPError as e: - body = e.read().decode("utf-8", errors="replace") - raise RuntimeError(f"Telegram HTTP {e.code}: {body}") from e - except Exception as e: - raise RuntimeError(f"Telegram request failed: {e}") from e - - result = json.loads(raw) - if not result.get("ok"): - raise RuntimeError(f"Telegram API error: {result}") - return result - - def call_multipart( - self, - method: str, - fields: dict[str, Any], - files: dict[str, tuple[str, bytes, str]], - timeout: int = 120, - ) -> dict[str, Any]: - boundary = "----shine-tg-boundary-" + "".join(random.choices("abcdef0123456789", k=16)) - body = bytearray() - for name, value in fields.items(): - if value is None: - continue - body.extend( - ( - f"--{boundary}\r\n" - f'Content-Disposition: form-data; name="{name}"\r\n\r\n' - f"{value}\r\n" - ).encode("utf-8") - ) - for name, (filename, data, mime) in files.items(): - body.extend( - ( - f"--{boundary}\r\n" - f'Content-Disposition: form-data; name="{name}"; filename="{filename}"\r\n' - f"Content-Type: {mime}\r\n\r\n" - ).encode("utf-8") - ) - body.extend(data) - body.extend(b"\r\n") - body.extend(f"--{boundary}--\r\n".encode("utf-8")) - - req = request.Request(self.base + method, data=bytes(body), method="POST") - req.add_header("Content-Type", f"multipart/form-data; boundary={boundary}") - try: - with request.urlopen(req, timeout=timeout) as resp: - raw = resp.read().decode("utf-8") - except error.HTTPError as e: - body_text = e.read().decode("utf-8", errors="replace") - raise RuntimeError(f"Telegram HTTP {e.code}: {body_text}") from e - except Exception as e: - raise RuntimeError(f"Telegram multipart request failed: {e}") from e - - result = json.loads(raw) - if not result.get("ok"): - raise RuntimeError(f"Telegram API error: {result}") - return result - - def get_updates(self, offset: int | None, timeout_sec: int) -> list[dict[str, Any]]: - payload: dict[str, Any] = {"timeout": timeout_sec, "allowed_updates": ["message", "channel_post"]} - if offset is not None: - payload["offset"] = offset - result = self.call("getUpdates", payload=payload, timeout=timeout_sec + 15) - return result.get("result", []) - - def send_message(self, chat_id: int | str, text: str, reply_to_message_id: int | None = None) -> dict[str, Any]: - payload: dict[str, Any] = {"chat_id": chat_id, "text": text} - if reply_to_message_id is not None: - payload["reply_to_message_id"] = reply_to_message_id - return self.call("sendMessage", payload=payload, timeout=30) - - def edit_message_text(self, chat_id: int | str, message_id: int, text: str) -> dict[str, Any]: - payload: dict[str, Any] = {"chat_id": chat_id, "message_id": message_id, "text": text} - return self.call("editMessageText", payload=payload, timeout=30) - - def send_voice( - self, - chat_id: int | str, - voice: str, - caption: str = "", - reply_to_message_id: int | None = None, - ) -> dict[str, Any]: - payload: dict[str, Any] = {"chat_id": chat_id, "voice": voice} - if caption: - payload["caption"] = caption - if reply_to_message_id is not None: - payload["reply_to_message_id"] = reply_to_message_id - return self.call("sendVoice", payload=payload, timeout=60) - - def send_audio( - self, - chat_id: int | str, - audio: str, - caption: str = "", - reply_to_message_id: int | None = None, - ) -> dict[str, Any]: - payload: dict[str, Any] = {"chat_id": chat_id, "audio": audio} - if caption: - payload["caption"] = caption - if reply_to_message_id is not None: - payload["reply_to_message_id"] = reply_to_message_id - return self.call("sendAudio", payload=payload, timeout=60) - - def send_voice_upload( - self, - chat_id: int | str, - voice_bytes: bytes, - filename: str, - caption: str = "", - reply_to_message_id: int | None = None, - ) -> dict[str, Any]: - fields: dict[str, Any] = {"chat_id": chat_id} - if caption: - fields["caption"] = caption - if reply_to_message_id is not None: - fields["reply_to_message_id"] = reply_to_message_id - return self.call_multipart( - "sendVoice", - fields=fields, - files={"voice": (filename, voice_bytes, "audio/ogg")}, - timeout=180, - ) - - def delete_webhook(self) -> None: - self.call("deleteWebhook", payload={"drop_pending_updates": False}, timeout=30) - - -class BotConfig: - def __init__(self, root_dir: Path): - env = dict(os.environ) - env.update(read_env_file(root_dir / ".env")) - - self.root_dir = root_dir - self.telegram_bot_token = self._required(env, "TELEGRAM_BOT_TOKEN") - self.allowed_username = normalize_username(env.get("ALLOWED_TELEGRAM_USERNAME", "AidarKC")) - self.allowed_players = parse_allowed_players(env.get("ALLOWED_TELEGRAM_PLAYERS", DEFAULT_ALLOWED_PLAYERS)) - self.allowed_channel_username = normalize_username(env.get("ALLOWED_TELEGRAM_CHANNEL_USERNAME", "shine_writing")) - self.bot_username = env.get("BOT_USERNAME", "aidar_su_bot") - self.telegram_api_base_url = env.get("TELEGRAM_API_BASE_URL", "https://api.telegram.org").strip() or "https://api.telegram.org" - self.openai_api_key = env.get("OPENAI_API_KEY", "").strip() - self.openai_transcribe_model = env.get("OPENAI_TRANSCRIBE_MODEL", "gpt-4o-mini-transcribe") - self.telegram_file_download_timeout_seconds = int(env.get("TELEGRAM_FILE_DOWNLOAD_TIMEOUT_SECONDS", "300")) - self.openai_transcribe_timeout_seconds = int(env.get("OPENAI_TRANSCRIBE_TIMEOUT_SECONDS", "900")) - self.openai_transcribe_max_upload_bytes = max(1_000_000, int(env.get("OPENAI_TRANSCRIBE_MAX_UPLOAD_BYTES", str(24 * 1024 * 1024)))) - self.openai_transcribe_max_chunk_seconds = max(60, int(env.get("OPENAI_TRANSCRIBE_MAX_CHUNK_SECONDS", "900"))) - self.openai_transcribe_overlap_seconds = max(0, int(env.get("OPENAI_TRANSCRIBE_OVERLAP_SECONDS", "2"))) - self.openai_transcribe_reencode_bitrate_kbps = max(12, int(env.get("OPENAI_TRANSCRIBE_REENCODE_BITRATE_KBPS", "24"))) - self.openai_transcribe_ffmpeg_timeout_seconds = max(30, int(env.get("OPENAI_TRANSCRIBE_FFMPEG_TIMEOUT_SECONDS", "1800"))) - self.ffmpeg_bin = env.get("FFMPEG_BIN", "ffmpeg").strip() or "ffmpeg" - self.ffprobe_bin = env.get("FFPROBE_BIN", "ffprobe").strip() or "ffprobe" - self.openai_tts_model = env.get("OPENAI_TTS_MODEL", "gpt-4o-mini-tts") - self.openai_tts_voice = env.get("OPENAI_TTS_VOICE", "alloy") - self.openai_tts_response_format = env.get("OPENAI_TTS_RESPONSE_FORMAT", "opus") - self.openai_tts_timeout_seconds = int(env.get("OPENAI_TTS_TIMEOUT_SECONDS", "180")) - self.openai_tts_chunk_chars = max(500, int(env.get("OPENAI_TTS_CHUNK_CHARS", "3500"))) - self.openai_voice_rewrite_model = env.get("OPENAI_VOICE_REWRITE_MODEL", "gpt-4.1-nano") - self.openai_voice_rewrite_timeout_seconds = int(env.get("OPENAI_VOICE_REWRITE_TIMEOUT_SECONDS", "90")) - self.openai_voice_rewrite_max_input_chars = max(1000, int(env.get("OPENAI_VOICE_REWRITE_MAX_INPUT_CHARS", "12000"))) - self.openai_voice_rewrite_max_output_tokens = max(200, int(env.get("OPENAI_VOICE_REWRITE_MAX_OUTPUT_TOKENS", "900"))) - self.codex_bin = Path(env.get( - "CODEX_BIN", - str(Path.home() / ".local/bin/codex") - )) - self.codex_workdir = Path(env.get("CODEX_WORKDIR", str(Path.home()))) - self.codex_timeout_seconds = int(env.get("CODEX_TIMEOUT_SECONDS", "900")) - self.max_retries = max(1, int(env.get("MAX_RETRIES", "3"))) - self.data_dir = (root_dir / env.get("DATA_DIR", "./data")).resolve() - self.agent_instructions_file = (root_dir / "AGENT.md").resolve() - - @staticmethod - def _required(env: dict[str, str], key: str) -> str: - value = env.get(key, "").strip() - if not value: - raise RuntimeError(f"Не задан обязательный параметр: {key}") - return value - - -class ShinePyBotService: - def __init__(self, config: BotConfig): - self.cfg = config - self.telegram = TelegramApi(config.telegram_bot_token, config.telegram_api_base_url) - - self.queue_file = config.data_dir / "py_queue.jsonl" - self.state_file = config.data_dir / "py_state.json" - self.processed_updates_file = config.data_dir / "py_processed_updates.log" - self.lock_file = config.data_dir / "py_app.lock" - self.history_dir = config.data_dir / "history" - self.history_archive_dir = self.history_dir / "archive" - self.task_center_dir = config.data_dir / "task_center" - self.task_center_file = self.task_center_dir / "items.json" - self.max_processed_updates = 5000 - - self.queue_lock = threading.RLock() - self.task_center_lock = threading.RLock() - self.stop_event = threading.Event() - self.worker = threading.Thread(target=self._worker_loop, name="shine-py-bot-worker", daemon=True) - - self.queue: list[dict[str, Any]] = [] - self.state: dict[str, Any] = {} - self.processed_updates: list[str] = [] - self.active_job_id: str | None = None - self.active_job_started_at: float | None = None - self.active_process: subprocess.Popen[str] | None = None - self.active_process_lock = threading.Lock() - self.stop_current_job = False - self.lock_fd = None - self.last_heartbeat_at: float = 0.0 - self.restart_requested = False - - def _is_owner(self, username: str) -> bool: - return self._is_allowed_user(username) - - def _is_allowed_player(self, username: str) -> bool: - return False - - def _is_allowed_user(self, username: str) -> bool: - uname = normalize_username(username) - return uname == self.cfg.allowed_username or uname in self.cfg.allowed_players - - def _player_name(self, username: str) -> str: - uname = normalize_username(username) - return self.cfg.allowed_players.get(uname, uname) - - def _display_name(self, username: str) -> str: - uname = normalize_username(username) - if uname == self.cfg.allowed_username: - return "Айдар" - return self._player_name(uname) - - def _known_usernames(self) -> dict[str, str]: - users = {self.cfg.allowed_username: "Айдар"} - users.update(self.cfg.allowed_players) - return users - - def _find_user_by_text(self, text: str) -> str: - source = normalize_username(text) - if source in self._known_usernames(): - return source - source_lower = (text or "").strip().lower() - aliases = { - "айдар": self.cfg.allowed_username, - "айдару": self.cfg.allowed_username, - "айдара": self.cfg.allowed_username, - "милана": "malvviiina", - "милане": "malvviiina", - "милану": "malvviiina", - "миланы": "malvviiina", - "сергей": "zodiaktechnika32", - "сергею": "zodiaktechnika32", - "сергея": "zodiaktechnika32", - "иван": "oidasyda", - "ивану": "oidasyda", - "ивана": "oidasyda", - "ворон": "blackbyrd1", - "ворону": "blackbyrd1", - "ворона": "blackbyrd1", - "дима": "dimasol1", - "диме": "dimasol1", - "диму": "dimasol1", - "димы": "dimasol1", - } - for alias, username in aliases.items(): - if re.search(rf"(^|\W){re.escape(alias)}($|\W)", source_lower, flags=re.IGNORECASE): - return username - for username, name in self._known_usernames().items(): - if username and username in source_lower: - return username - if name and name.lower() in source_lower: - return username - return "" - - def run(self) -> None: - self._ensure_dirs() - self._acquire_single_instance_lock() - self._load_state() - self._load_queue() - self._load_processed_updates() - self._recover_active_jobs_after_restart() - self.telegram.delete_webhook() - self._init_offset_if_missing() - self.worker.start() - self._append_history_event("service_started", {"allowedUsername": self.cfg.allowed_username}) - print(f"[py-bot] Запущен. allowed user: @{self.cfg.allowed_username}", flush=True) - - try: - while not self.stop_event.is_set(): - try: - offset = self.state.get("offset") - updates = self.telegram.get_updates(offset=offset, timeout_sec=25) - except Exception as e: - print(f"[py-bot] Ошибка getUpdates: {e}", flush=True) - time.sleep(2) - continue - - for update in updates: - update_id = update.get("update_id") - if isinstance(update_id, int): - self.state["offset"] = update_id + 1 - self._persist_state() - self._handle_update(update) - finally: - self.shutdown() - - def shutdown(self) -> None: - if self.stop_event.is_set(): - pass - self.stop_event.set() - self._stop_active_codex_process() - if self.worker.is_alive(): - self.worker.join(timeout=10) - if self.lock_fd is not None: - try: - fcntl.flock(self.lock_fd, fcntl.LOCK_UN) - finally: - self.lock_fd.close() - self.lock_fd = None - self._append_history_event("service_stopped", {}) - - def _ensure_dirs(self) -> None: - self.cfg.data_dir.mkdir(parents=True, exist_ok=True) - self.history_dir.mkdir(parents=True, exist_ok=True) - self.history_archive_dir.mkdir(parents=True, exist_ok=True) - self.task_center_dir.mkdir(parents=True, exist_ok=True) - - def _acquire_single_instance_lock(self) -> None: - self.lock_file.parent.mkdir(parents=True, exist_ok=True) - self.lock_fd = self.lock_file.open("a+") - try: - fcntl.flock(self.lock_fd, fcntl.LOCK_EX | fcntl.LOCK_NB) - except BlockingIOError: - raise RuntimeError(f"Уже запущен другой инстанс (lock: {self.lock_file})") - - def _load_state(self) -> None: - if self.state_file.exists(): - self.state = json.loads(self.state_file.read_text(encoding="utf-8")) - else: - self.state = {} - sessions = self.state.get("user_sessions") - if not isinstance(sessions, dict): - sessions = {} - self.state["user_sessions"] = sessions - user_settings = self.state.get("user_settings") - if not isinstance(user_settings, dict): - user_settings = {} - self.state["user_settings"] = user_settings - if not self.state.get("current_history_file"): - history_file = self._create_new_history_file("initial", self.cfg.allowed_username) - self.state["current_history_file"] = str(history_file) - sessions[self.cfg.allowed_username] = {"current_history_file": str(history_file)} - elif self.cfg.allowed_username not in sessions: - sessions[self.cfg.allowed_username] = {"current_history_file": str(self.state["current_history_file"])} - if not isinstance(self.state.get("next_job_number"), int): - self.state["next_job_number"] = 1 - self.state["updated_at"] = now_iso() - self._persist_state() - - def _persist_state(self) -> None: - self.state["updated_at"] = now_iso() - tmp = self.state_file.with_suffix(".tmp") - tmp.write_text(json.dumps(self.state, ensure_ascii=False, indent=2), encoding="utf-8") - tmp.replace(self.state_file) - - def _load_queue(self) -> None: - self.queue = JsonLineStore.load(self.queue_file) - - def _persist_queue(self) -> None: - JsonLineStore.save(self.queue_file, self.queue) - - def _load_processed_updates(self) -> None: - if not self.processed_updates_file.exists(): - self.processed_updates = [] - return - lines = [x.strip() for x in self.processed_updates_file.read_text(encoding="utf-8").splitlines() if x.strip()] - if len(lines) > self.max_processed_updates: - lines = lines[-self.max_processed_updates:] - self.processed_updates_file.write_text("\n".join(lines) + "\n", encoding="utf-8") - self.processed_updates = lines - - def _mark_processed_update(self, update_key: str) -> bool: - if update_key in self.processed_updates: - return True - self.processed_updates.append(update_key) - if len(self.processed_updates) > self.max_processed_updates: - self.processed_updates = self.processed_updates[-self.max_processed_updates:] - self.processed_updates_file.write_text("\n".join(self.processed_updates) + "\n", encoding="utf-8") - else: - with self.processed_updates_file.open("a", encoding="utf-8") as f: - f.write(update_key + "\n") - return False - - def _recover_active_jobs_after_restart(self) -> None: - recovered_ids: list[str] = [] - for job in self.queue: - if job.get("status") == "active": - job["status"] = "pending" - job["retry_reason"] = "service_restart_recovery" - job["updated_at"] = now_iso() - recovered_ids.append(job.get("id", "")) - if recovered_ids: - self._persist_queue() - self._append_history_event("active_jobs_recovered", {"jobIds": recovered_ids}) - - def _init_offset_if_missing(self) -> None: - if self.state.get("offset") is not None: - return - try: - updates = self.telegram.get_updates(offset=None, timeout_sec=0) - if updates: - self.state["offset"] = int(updates[-1]["update_id"]) + 1 - else: - self.state["offset"] = 0 - self._persist_state() - except Exception as e: - print(f"[py-bot] Не удалось инициализировать offset: {e}", flush=True) - self.state["offset"] = 0 - self._persist_state() - - def _current_history_file(self) -> Path: - return self._current_history_file_for_user(self.cfg.allowed_username) - - def _history_dirs_for_user(self, username: str) -> tuple[Path, Path]: - uname = normalize_username(username) or "unknown" - history_dir = self.history_dir / uname - archive_dir = history_dir / "archive" - history_dir.mkdir(parents=True, exist_ok=True) - archive_dir.mkdir(parents=True, exist_ok=True) - return history_dir, archive_dir - - def _ensure_user_session(self, username: str) -> None: - uname = normalize_username(username) or self.cfg.allowed_username - sessions = self.state.setdefault("user_sessions", {}) - if not isinstance(sessions, dict): - sessions = {} - self.state["user_sessions"] = sessions - self._user_settings(uname) - session = sessions.get(uname) - if isinstance(session, dict) and session.get("current_history_file"): - return - history_file = self._create_new_history_file("initial", uname) - sessions[uname] = {"current_history_file": str(history_file)} - if uname == self.cfg.allowed_username: - self.state["current_history_file"] = str(history_file) - self._persist_state() - - def _user_session_state(self, username: str) -> dict[str, Any]: - uname = normalize_username(username) or self.cfg.allowed_username - self._ensure_user_session(uname) - sessions = self.state.get("user_sessions") or {} - session = sessions.get(uname) - if not isinstance(session, dict): - session = {} - sessions[uname] = session - return session - - def _current_history_file_for_user(self, username: str) -> Path: - session = self._user_session_state(username) - return Path(session["current_history_file"]) - - def _codex_thread_id_for_user(self, username: str) -> str: - thread_id = (self._user_session_state(username).get("codex_thread_id") or "").strip() - return thread_id - - def _set_codex_thread_id_for_user(self, username: str, thread_id: str) -> None: - session = self._user_session_state(username) - normalized = (thread_id or "").strip() - if normalized: - session["codex_thread_id"] = normalized - else: - session.pop("codex_thread_id", None) - self._persist_state() - - def _create_new_history_file(self, reason: str, username: str) -> Path: - ts = dt.datetime.now().strftime("%Y-%m-%d_%H%M%S") - rnd = "".join(random.choices(string.hexdigits.lower(), k=8)) - history_dir, _ = self._history_dirs_for_user(username) - path = history_dir / f"{ts}_{rnd}.jsonl" - JsonLineStore.append(path, { - "ts": now_iso(), - "type": "history_created", - "reason": reason, - "username": normalize_username(username), - }) - return path - - def _rotate_history(self, reason: str, username: str) -> Path: - uname = normalize_username(username) or self.cfg.allowed_username - current = self._current_history_file_for_user(uname) - _, archive_dir = self._history_dirs_for_user(uname) - if current.exists(): - archived = archive_dir / current.name - current.replace(archived) - else: - archived = archive_dir / "(empty)" - new_file = self._create_new_history_file(reason, uname) - sessions = self.state.setdefault("user_sessions", {}) - if not isinstance(sessions, dict): - sessions = {} - self.state["user_sessions"] = sessions - previous = sessions.get(uname) if isinstance(sessions.get(uname), dict) else {} - sessions[uname] = {"current_history_file": str(new_file)} - if reason != "command_new" and isinstance(previous, dict): - thread_id = (previous.get("codex_thread_id") or "").strip() - if thread_id: - sessions[uname]["codex_thread_id"] = thread_id - if uname == self.cfg.allowed_username: - self.state["current_history_file"] = str(new_file) - self._persist_state() - self._append_history_event("history_rotated", {"reason": reason, "username": uname, "archived": str(archived)}, username=uname) - return archived - - def _user_settings(self, username: str) -> dict[str, Any]: - uname = normalize_username(username) or self.cfg.allowed_username - settings = self.state.get("user_settings") - if not isinstance(settings, dict): - settings = {} - self.state["user_settings"] = settings - user_settings = settings.get(uname) - if not isinstance(user_settings, dict): - user_settings = {} - settings[uname] = user_settings - if not isinstance(user_settings.get("voice_replies_enabled"), bool): - user_settings["voice_replies_enabled"] = True - if not isinstance(user_settings.get("voice_rewrite_enabled"), bool): - user_settings["voice_rewrite_enabled"] = True - if not isinstance(user_settings.get("single_status_message_enabled"), bool): - user_settings["single_status_message_enabled"] = True - return user_settings - - def _voice_replies_enabled(self, username: str) -> bool: - return bool(self._user_settings(username).get("voice_replies_enabled")) - - def _set_voice_replies_enabled(self, username: str, enabled: bool) -> None: - self._user_settings(username)["voice_replies_enabled"] = enabled - self._persist_state() - - def _voice_rewrite_enabled(self, username: str) -> bool: - return bool(self._user_settings(username).get("voice_rewrite_enabled")) - - def _set_voice_rewrite_enabled(self, username: str, enabled: bool) -> None: - self._user_settings(username)["voice_rewrite_enabled"] = enabled - self._persist_state() - - def _single_status_message_enabled(self, username: str) -> bool: - return bool(self._user_settings(username).get("single_status_message_enabled")) - - def _set_single_status_message_enabled(self, username: str, enabled: bool) -> None: - self._user_settings(username)["single_status_message_enabled"] = enabled - self._persist_state() - - def _remember_private_chat(self, username: str, chat_id: int) -> None: - uname = normalize_username(username) - if not uname: - return - private_chats = self.state.get("private_chat_ids") - if not isinstance(private_chats, dict): - private_chats = {} - self.state["private_chat_ids"] = private_chats - if private_chats.get(uname) == chat_id: - return - private_chats[uname] = chat_id - self._persist_state() - - def _private_chat_id_for_user(self, username: str) -> int | None: - private_chats = self.state.get("private_chat_ids") - if not isinstance(private_chats, dict): - return None - chat_id = private_chats.get(normalize_username(username)) - return self._resolve_chat_id(chat_id) if isinstance(chat_id, int) else None - - def _append_history(self, history_path: Path, event_type: str, payload: dict[str, Any]) -> None: - row = {"ts": now_iso(), "type": event_type} - row.update(payload) - JsonLineStore.append(history_path, row) - - def _append_history_event(self, event_type: str, payload: dict[str, Any], username: str | None = None) -> None: - history_path = self._current_history_file_for_user(username or self.cfg.allowed_username) - self._append_history(history_path, "system_event", {"event": event_type, **payload}) - - def _load_task_items(self) -> list[dict[str, Any]]: - with self.task_center_lock: - if not self.task_center_file.exists(): - return [] - try: - data = json.loads(self.task_center_file.read_text(encoding="utf-8")) - except Exception: - return [] - return data if isinstance(data, list) else [] - - def _save_task_items(self, items: list[dict[str, Any]]) -> None: - with self.task_center_lock: - self.task_center_file.parent.mkdir(parents=True, exist_ok=True) - tmp = self.task_center_file.with_suffix(".tmp") - tmp.write_text(json.dumps(items, ensure_ascii=False, indent=2), encoding="utf-8") - tmp.replace(self.task_center_file) - - def _next_task_item_id(self, items: list[dict[str, Any]]) -> str: - max_num = 0 - for item in items: - raw = str(item.get("id") or "") - match = re.match(r"TC-(\d+)$", raw) - if match: - max_num = max(max_num, int(match.group(1))) - return f"TC-{max_num + 1:04d}" - - def _create_task_item( - self, - *, - kind: str, - title: str, - text: str, - source_username: str, - target_username: str, - source_message_id: int | None = None, - source_chat_id: int | None = None, - opinion: str = "", - ) -> dict[str, Any]: - items = self._load_task_items() - item = { - "id": self._next_task_item_id(items), - "kind": kind, - "status": "new", - "title": compact_spaces(title)[:160] or ("Предложение" if kind == "proposal" else "Задача"), - "text": (text or "").strip(), - "opinion": (opinion or "").strip(), - "source_username": normalize_username(source_username), - "source_name": self._display_name(source_username), - "target_username": normalize_username(target_username), - "target_name": self._display_name(target_username), - "source_chat_id": source_chat_id, - "source_message_id": source_message_id, - "created_at": now_iso(), - "updated_at": now_iso(), - } - items.append(item) - self._save_task_items(items) - self._append_history_event("task_center_item_created", { - "itemId": item["id"], - "kind": kind, - "sourceUsername": item["source_username"], - "targetUsername": item["target_username"], - "title": item["title"], - }, username=source_username) - return item - - def _task_items_for_user(self, username: str, *, include_done: bool = False) -> list[dict[str, Any]]: - uname = normalize_username(username) - items = self._load_task_items() - result = [ - item for item in items - if normalize_username(item.get("target_username")) == uname - and (include_done or item.get("status") != "done") - ] - return sorted(result, key=lambda x: str(x.get("created_at") or "")) - - def _task_center_counts_text(self, username: str) -> str: - counts: dict[str, int] = {} - for item in self._task_items_for_user(username): - status = str(item.get("status") or "new") - counts[status] = counts.get(status, 0) + 1 - active_total = sum(counts.values()) - if active_total <= 0: - return "" - parts = [] - for status in ("new", "approved", "needs_work", "rejected"): - count = counts.get(status, 0) - if count: - parts.append(f"{TASK_STATUS_LABELS.get(status, status)}: {count}") - return f"Напоминание по задачам: всего активных {active_total}; " + ", ".join(parts) + "." - - def _format_task_items(self, username: str, *, include_done: bool = False) -> str: - items = self._task_items_for_user(username, include_done=include_done) - if not items: - return f"Для {self._display_name(username)} активных задач и предложений нет." - lines = [f"Задачи и предложения для {self._display_name(username)}:"] - for item in items[:15]: - kind = "предложение" if item.get("kind") == "proposal" else "задача" - status = TASK_STATUS_LABELS.get(str(item.get("status") or "new"), str(item.get("status") or "new")) - source = item.get("source_name") or item.get("source_username") or "неизвестно" - title = item.get("title") or "(без названия)" - lines.append(f"{item.get('id')} [{status}] {kind} от {source}: {title}") - if len(items) > 15: - lines.append(f"...и ещё {len(items) - 15}") - return "\n".join(lines) - - def _update_task_item_status(self, item_id: str, status: str) -> dict[str, Any] | None: - item_id = (item_id or "").strip().upper() - items = self._load_task_items() - updated = None - for item in items: - if str(item.get("id") or "").upper() == item_id: - item["status"] = status - item["updated_at"] = now_iso() - updated = item - break - if updated is not None: - self._save_task_items(items) - return updated - - def _find_first_task_item(self, *, source_username: str = "", target_username: str = "", kind: str = "") -> dict[str, Any] | None: - source = normalize_username(source_username) - target = normalize_username(target_username) - for item in self._load_task_items(): - if item.get("status") == "done": - continue - if source and normalize_username(item.get("source_username")) != source: - continue - if target and normalize_username(item.get("target_username")) != target: - continue - if kind and item.get("kind") != kind: - continue - return item - return None - - def _notify_user_about_task_item(self, username: str, item: dict[str, Any]) -> None: - chat_id = self._private_chat_id_for_user(username) - if chat_id is None: - return - kind = "предложение" if item.get("kind") == "proposal" else "задача" - source = item.get("source_name") or item.get("source_username") or "кто-то" - title = item.get("title") or "(без названия)" - status = TASK_STATUS_LABELS.get(str(item.get("status") or "new"), str(item.get("status") or "new")) - if item.get("status") == "new": - text = f"У тебя новое {kind} от {source}: {title}\nID: {item.get('id')}" - else: - text = f"Обновление по {kind} {item.get('id')}: статус «{status}».\n{title}" - self._safe_send(chat_id, text) - - def _send_player_welcome_once(self, chat_id: int, message_id: int, username: str) -> None: - uname = normalize_username(username) - sent = self.state.get("player_welcome_sent") - if not isinstance(sent, dict): - sent = {} - self.state["player_welcome_sent"] = sent - if sent.get(uname): - return - player_name = self._player_name(uname) - text = ( - f"Привет, {player_name}.\n" - "Можно задавать вопросы по проекту, просить анализ, идеи и подготовку готового ТЗ.\n" - "Команда /new начинает новую Codex-сессию и архивирует текущую историю." - ) - reminder = self._task_center_counts_text(uname) - if reminder: - text = f"{text}\n\n{reminder}\nКоманда /tasks покажет список." - self._safe_send(chat_id, text, reply_to=message_id) - sent[uname] = now_iso() - self._persist_state() - - def _resolve_chat_id(self, chat_id: int) -> int: - migrations = self.state.get("chat_id_migrations") - if not isinstance(migrations, dict): - return chat_id - current = chat_id - visited: set[int] = set() - while current not in visited: - visited.add(current) - next_chat_id = migrations.get(str(current)) - if not isinstance(next_chat_id, int): - break - current = next_chat_id - return current - - def _remember_chat_migration(self, old_chat_id: int, new_chat_id: int, source: str) -> None: - if old_chat_id == new_chat_id: - return - migrations = self.state.get("chat_id_migrations") - if not isinstance(migrations, dict): - migrations = {} - self.state["chat_id_migrations"] = migrations - if migrations.get(str(old_chat_id)) == new_chat_id: - return - migrations[str(old_chat_id)] = new_chat_id - self._persist_state() - with self.queue_lock: - changed = False - for job in self.queue: - if job.get("chat_id") == old_chat_id: - job["chat_id"] = new_chat_id - job["updated_at"] = now_iso() - changed = True - if changed: - self._persist_queue() - self._append_history_event("chat_migrated_to_supergroup", { - "oldChatId": old_chat_id, - "newChatId": new_chat_id, - "source": source, - }) - - @staticmethod - def _extract_migrate_to_chat_id(error_text: str) -> int | None: - match = re.search(r'"migrate_to_chat_id"\s*:\s*(-?\d+)', error_text) - if match: - return int(match.group(1)) - match = re.search(r"'migrate_to_chat_id'\s*:\s*(-?\d+)", error_text) - if match: - return int(match.group(1)) - return None - - def _handle_update(self, update: dict[str, Any]) -> None: - message = update.get("message") - update_type = "message" - if not isinstance(message, dict): - message = update.get("channel_post") - update_type = "channel_post" - if not isinstance(message, dict): - return - chat = message.get("chat") or {} - chat_id = chat.get("id") - message_id = message.get("message_id") - chat_type = str(chat.get("type") or "") - chat_username = normalize_username(chat.get("username")) - chat_title = str(chat.get("title") or "") - sender = message.get("from") or {} - username = normalize_username(sender.get("username")) - author_signature = str(message.get("author_signature") or "").strip() - author_username = username or normalize_username(author_signature) - if not isinstance(chat_id, int) or not isinstance(message_id, int): - return - - migrate_to_chat_id = message.get("migrate_to_chat_id") - if isinstance(migrate_to_chat_id, int): - self._remember_chat_migration(chat_id, migrate_to_chat_id, "telegram_message") - return - - update_key = f"{chat_id}:{message_id}" - if self._mark_processed_update(update_key): - return - - is_channel_post = update_type == "channel_post" or chat_type == "channel" - is_group_message = update_type == "message" and chat_type in ("group", "supergroup") - is_allowed_channel = ( - not is_channel_post - or not self.cfg.allowed_channel_username - or chat_username == self.cfg.allowed_channel_username - ) - if is_channel_post and not is_allowed_channel: - return - if chat_username and chat_username == self.cfg.allowed_channel_username: - self._remember_public_report_chat(chat_id) - - # Игнорируем системные сообщения о входе/выходе и смене заголовка/фото. - if message.get("new_chat_members") or message.get("left_chat_member"): - return - if message.get("group_chat_created") or message.get("supergroup_chat_created") or message.get("channel_chat_created"): - return - - text = (message.get("text") or message.get("caption") or "").strip() - actor_username = normalize_username(author_username) - is_allowed = self._is_allowed_user(actor_username) - is_private = chat_type == "private" - if not is_allowed: - if is_private: - self._safe_send(chat_id, "Извините, доступ к этому агенту пока не выдан. Обратитесь к Айдару.", reply_to=message_id) - return - if self._is_allowed_player(actor_username) and not is_private: - return - - self._ensure_user_session(actor_username) - if is_private: - self._remember_private_chat(actor_username, chat_id) - history_path = self._current_history_file_for_user(actor_username) - if self._is_allowed_player(actor_username): - self._send_player_welcome_once(chat_id, message_id, actor_username) - - if not text: - if message.get("voice"): - self._enqueue_voice_job( - chat_id, - message_id, - actor_username, - message["voice"].get("file_id"), - duration_seconds=message["voice"].get("duration"), - telegram_file_size=message["voice"].get("file_size"), - media_type="voice", - update_type=update_type, - chat_username=chat_username, - chat_title=chat_title, - author_signature=author_signature, - chat_type=chat_type, - ) - return - if message.get("audio"): - self._enqueue_voice_job( - chat_id, - message_id, - actor_username, - message["audio"].get("file_id"), - duration_seconds=message["audio"].get("duration"), - telegram_file_size=message["audio"].get("file_size"), - media_type="audio", - update_type=update_type, - chat_username=chat_username, - chat_title=chat_title, - author_signature=author_signature, - chat_type=chat_type, - ) - return - self._safe_send(chat_id, "Поддерживаются текст, voice и audio.", reply_to=message_id) - return - - if text.startswith("/"): - self._handle_command(chat_id, message_id, actor_username, text) - return - - if self._handle_task_center_text(chat_id, message_id, actor_username, text): - return - - self._append_history(history_path, "incoming_text", { - "chatId": chat_id, - "messageId": message_id, - "updateType": update_type, - "chatType": chat_type, - "chatUsername": chat_username, - "chatTitle": chat_title, - "username": actor_username, - "authorSignature": author_signature, - "text": text, - }) - job = self._build_job_base(chat_id, message_id, actor_username, str(history_path)) - job["type"] = "text" - job["text"] = text - job["update_type"] = update_type - job["chat_type"] = chat_type - job["chat_username"] = chat_username - job["chat_title"] = chat_title - job["author_signature"] = author_signature - job["role"] = "owner" if self._is_owner(actor_username) else "player" - job["player_name"] = self._player_name(actor_username) if job["role"] == "player" else "" - with self.queue_lock: - self.queue.append(job) - self._persist_queue() - if chat_type == "private": - self._ensure_job_status_message( - job["id"], - chat_id, - message_id, - f"Задача #{job['num']} получена.\nСтатус: в очереди.", - ) - else: - self._safe_send(chat_id, f"Принял задачу #{job['num']}", reply_to=message_id) - - def _enqueue_voice_job( - self, - chat_id: int, - message_id: int, - username: str, - file_id: str | None, - *, - duration_seconds: int | None = None, - telegram_file_size: int | None = None, - media_type: str = "voice", - update_type: str = "message", - chat_username: str = "", - chat_title: str = "", - author_signature: str = "", - chat_type: str = "", - ) -> None: - if not file_id: - self._safe_send(chat_id, "Не удалось прочитать file_id голосового.", reply_to=message_id) - return - history_path = self._current_history_file_for_user(username) - self._append_history(history_path, "incoming_voice", { - "chatId": chat_id, - "messageId": message_id, - "updateType": update_type, - "chatType": chat_type, - "chatUsername": chat_username, - "chatTitle": chat_title, - "username": username, - "authorSignature": author_signature, - "fileId": file_id, - "mediaType": media_type, - "durationSeconds": duration_seconds, - "fileSize": telegram_file_size, - }) - job = self._build_job_base(chat_id, message_id, username, str(history_path)) - job["type"] = "voice" - job["telegram_file_id"] = file_id - job["telegram_media_type"] = media_type - job["telegram_duration_seconds"] = duration_seconds or 0 - job["telegram_file_size"] = telegram_file_size or 0 - job["update_type"] = update_type - job["chat_type"] = chat_type - job["chat_username"] = chat_username - job["chat_title"] = chat_title - job["author_signature"] = author_signature - job["role"] = "owner" if self._is_owner(username) else "player" - job["player_name"] = self._player_name(username) if job["role"] == "player" else "" - with self.queue_lock: - self.queue.append(job) - self._persist_queue() - if chat_type == "private": - self._ensure_job_status_message( - job["id"], - chat_id, - message_id, - f"Voice для задачи #{job['num']} получен.\nСтатус: в очереди.", - ) - else: - self._safe_send(chat_id, f"Принял voice в задачу #{job['num']}", reply_to=message_id) - - def _build_job_base(self, chat_id: int, message_id: int, username: str, history_file: str) -> dict[str, Any]: - with self.queue_lock: - num = int(self.state.get("next_job_number", 1)) - self.state["next_job_number"] = num + 1 - self._persist_state() - return { - "id": str(uuid.uuid4()), - "num": num, - "status": "pending", - "type": "text", - "chat_id": chat_id, - "message_id": message_id, - "username": username, - "update_type": "message", - "chat_type": "", - "chat_username": "", - "chat_title": "", - "author_signature": "", - "role": "owner", - "player_name": "", - "text": "", - "telegram_file_id": "", - "telegram_media_type": "", - "history_file": history_file, - "attempts": 0, - "retry_reason": "", - "last_error": "", - "created_at": now_iso(), - "updated_at": now_iso(), - "active_since": None, - "status_message_id": None, - "status_message_text": "", - } - - def _handle_task_center_text(self, chat_id: int, message_id: int, username: str, text: str) -> bool: - source_text = (text or "").strip() - lower = source_text.lower() - is_owner = self._is_owner(username) - - if re.search(r"\b(покажи|список|какие)\b.*\b(задач|задачи|предложени)", lower): - target = username - explicit_target = self._find_user_by_text(source_text) - if is_owner and explicit_target: - target = explicit_target - self._safe_send(chat_id, self._format_task_items(target), reply_to=message_id) - return True - - if is_owner: - assign_match = re.search( - r"(?:поставь|добавь|создай|запиши)\s+(?:задачу|задание)\s+(.+?)(?::|\s+-\s+|\s+—\s+)(.+)", - source_text, - flags=re.IGNORECASE | re.DOTALL, - ) - if assign_match: - target = self._find_user_by_text(assign_match.group(1)) - body = assign_match.group(2).strip() - if target and body: - item = self._create_task_item( - kind="task", - title=body, - text=body, - source_username=username, - target_username=target, - source_message_id=message_id, - source_chat_id=chat_id, - ) - self._notify_user_about_task_item(target, item) - self._safe_send( - chat_id, - f"Задача добавлена для {self._display_name(target)}: {item['id']} — {item['title']}", - reply_to=message_id, - ) - return True - - status_match = re.search(r"\b(одобрить|отклонить|доработать|закрыть|сделано|закрыта)\b(?:\s+(.+))?", lower, flags=re.IGNORECASE) - if status_match and ("задач" in lower or "предложени" in lower or re.search(r"tc-\d+", lower, flags=re.IGNORECASE)): - action = status_match.group(1) - tail = status_match.group(2) or "" - status = { - "одобрить": "approved", - "отклонить": "rejected", - "доработать": "needs_work", - "закрыть": "done", - "сделано": "done", - "закрыта": "done", - }.get(action, "new") - id_match = re.search(r"tc-\d+", source_text, flags=re.IGNORECASE) - item = None - if id_match: - item = self._update_task_item_status(id_match.group(0), status) - else: - source_user = self._find_user_by_text(tail) - item = self._find_first_task_item( - source_username=source_user, - target_username=username, - kind="proposal" if "предложени" in lower else "", - ) - if item: - item = self._update_task_item_status(str(item.get("id")), status) - if item: - label = TASK_STATUS_LABELS.get(status, status) - self._safe_send(chat_id, f"{item.get('id')} обновлена: {label}.", reply_to=message_id) - source_user = normalize_username(item.get("source_username")) - if source_user and source_user != username: - self._notify_user_about_task_item(source_user, item) - return True - - if not is_owner: - proposal_match = re.match(r"\s*(?:предложение|идея|заявка)\s*[::-]\s*(.+)", source_text, flags=re.IGNORECASE | re.DOTALL) - if proposal_match: - body = proposal_match.group(1).strip() - if body: - item = self._create_task_item( - kind="proposal", - title=body, - text=body, - opinion="Нужно решение Айдара: одобрить, отклонить или отправить на доработку.", - source_username=username, - target_username=self.cfg.allowed_username, - source_message_id=message_id, - source_chat_id=chat_id, - ) - self._notify_user_about_task_item(self.cfg.allowed_username, item) - self._safe_send( - chat_id, - f"Предложение отправлено Айдару как {item['id']}. Статус: новая.", - reply_to=message_id, - ) - return True - - return False - - def _handle_command(self, chat_id: int, message_id: int, username: str, text: str) -> None: - lower = text.lower() - command = lower.split(maxsplit=1)[0].split("@", 1)[0] - is_owner = self._is_owner(username) - if command in ("/start", "/help"): - self._safe_send(chat_id, self._help_text(is_owner=is_owner), reply_to=message_id) - return - if command == "/settings": - self._safe_send(chat_id, self._settings_text(username), reply_to=message_id) - return - if command == "/status": - self._safe_send(chat_id, self._status_text(username), reply_to=message_id) - return - if command == "/queue": - self._safe_send(chat_id, self._queue_text(), reply_to=message_id) - return - if command in ("/tasks", "/my_tasks"): - parts = text.split(maxsplit=1) - target = username - if is_owner and len(parts) > 1: - parsed = self._find_user_by_text(parts[1]) - if parsed: - target = parsed - self._safe_send(chat_id, self._format_task_items(target), reply_to=message_id) - return - if command == "/voice_on": - self._set_voice_replies_enabled(username, True) - self._append_history_event("voice_replies_enabled", {"username": normalize_username(username)}, username=username) - self._safe_send(chat_id, "Озвучивание финальных ответов включено для вашего пользователя.", reply_to=message_id) - return - if command == "/voice_off": - self._set_voice_replies_enabled(username, False) - self._append_history_event("voice_replies_disabled", {"username": normalize_username(username)}, username=username) - self._safe_send(chat_id, "Озвучивание финальных ответов выключено для вашего пользователя.", reply_to=message_id) - return - if command in ("/voice_status", "/voice_rewrite_status"): - self._safe_send(chat_id, self._status_text(username), reply_to=message_id) - return - if command == "/voice_rewrite_on": - self._set_voice_rewrite_enabled(username, True) - self._append_history_event("voice_rewrite_enabled", {"username": normalize_username(username)}, username=username) - self._safe_send(chat_id, "Адаптация текста перед озвучкой включена для вашего пользователя.", reply_to=message_id) - return - if command == "/voice_rewrite_off": - self._set_voice_rewrite_enabled(username, False) - self._append_history_event("voice_rewrite_disabled", {"username": normalize_username(username)}, username=username) - self._safe_send(chat_id, "Адаптация текста перед озвучкой выключена для вашего пользователя.", reply_to=message_id) - return - if command == "/single_message_on": - self._set_single_status_message_enabled(username, True) - self._append_history_event("single_status_message_enabled", {"username": normalize_username(username)}, username=username) - self._safe_send(chat_id, "Режим одного редактируемого сообщения в личке включён для вашего пользователя.", reply_to=message_id) - return - if command == "/single_message_off": - self._set_single_status_message_enabled(username, False) - self._append_history_event("single_status_message_disabled", {"username": normalize_username(username)}, username=username) - self._safe_send(chat_id, "Режим одного редактируемого сообщения в личке выключен. Бот будет отправлять отдельные сообщения по этапам.", reply_to=message_id) - return - if command == "/new": - archived = self._rotate_history("command_new", username) - self._safe_send(chat_id, f"История очищена. Новый диалог начат.\nАрхив: {archived.name}", reply_to=message_id) - return - if command in ("/restart_service", "/restart"): - if not is_owner: - self._safe_send(chat_id, "Команда недоступна.", reply_to=message_id) - return - self._append_history_event("restart_service_deferred_requested", { - "chatId": chat_id, - "messageId": message_id, - "username": username, - }, username=username) - self._safe_send( - chat_id, - "Отложенный рестарт принят. Если задача сейчас выполняется, сервис перезапустится после её завершения и до следующей задачи.", - reply_to=message_id, - ) - self._request_deferred_restart() - return - if command in ("/restart_hard", "/restart_now", "/restart_force"): - if not is_owner: - self._safe_send(chat_id, "Команда недоступна.", reply_to=message_id) - return - self._append_history_event("restart_service_hard_requested", { - "chatId": chat_id, - "messageId": message_id, - "username": username, - }, username=username) - self._safe_send( - chat_id, - "Выполняю жёсткий рестарт сервиса прямо сейчас. Активная задача, если есть, будет прервана и после старта вернётся в очередь.", - reply_to=message_id, - ) - self._schedule_self_restart("hard_restart_requested", force=True) - return - if command == "/stop": - stopped = self._cancel_active_job("stopped_by_user") - if stopped: - self._safe_send(chat_id, "Текущая задача остановлена и удалена из очереди.", reply_to=message_id) - else: - self._safe_send(chat_id, "Сейчас нет активной задачи.", reply_to=message_id) - return - if command == "/cancel": - parts = text.split(maxsplit=1) - if len(parts) < 2: - self._safe_send(chat_id, "Использование: /cancel ", reply_to=message_id) - return - arg = parts[1].strip() - if arg.lower() == "all": - with self.queue_lock: - self.stop_current_job = True - self._stop_active_codex_process() - count = len(self.queue) - self.queue = [] - self._persist_queue() - self._safe_send(chat_id, f"Удалено задач из очереди: {count}", reply_to=message_id) - return - cancelled = self._cancel_by_id_prefix(arg) - self._safe_send(chat_id, f"Задача удалена: {arg}" if cancelled else f"Задача не найдена: {arg}", reply_to=message_id) - return - - def _help_text(self, *, is_owner: bool) -> str: - lines = [ - "Доступные команды:", - "/status — активная задача и размер очереди", - "/settings — текущие настройки и команды для их изменения", - "/queue — список задач в очереди", - "/tasks — список ваших задач и предложений", - "/stop — остановить текущую задачу", - "/cancel — удалить задачу по id (префикс) или все", - "/new — архивировать историю и начать новую Codex-сессию", - "/help — эта справка", - ] - if is_owner: - lines.insert(-1, "/tasks <пользователь> — список задач пользователя") - lines.insert(-1, "/restart — отложенный рестарт после текущей задачи") - lines.insert(-1, "/restart_hard — жёсткий рестарт прямо сейчас") - return "\n".join(lines) - - def _settings_text(self, username: str) -> str: - voice_status = "включено" if self._voice_replies_enabled(username) else "выключено" - rewrite_status = "включена" if self._voice_rewrite_enabled(username) else "выключена" - single_message_status = "включён" if self._single_status_message_enabled(username) else "выключен" - lines = [ - "Текущие настройки:", - f"Озвучивание финальных ответов: {voice_status}", - f"Адаптация текста перед озвучкой: {rewrite_status}", - f"Режим одного редактируемого сообщения в личке: {single_message_status}", - "", - "Команды настроек:", - "/voice_on — включить озвучивание", - "/voice_off — выключить озвучивание", - "/voice_rewrite_on — адаптировать текст перед озвучкой", - "/voice_rewrite_off — озвучивать обычный текст без адаптации", - "/single_message_on — один редактируемый ответ в личке", - "/single_message_off — отдельные сообщения по этапам и финалу", - ] - return "\n".join(lines) - - def _status_text(self, username: str) -> str: - with self.queue_lock: - active = next((j for j in self.queue if j.get("status") == "active"), None) - pending = sum(1 for j in self.queue if j.get("status") == "pending") - voice_status = "включено" if self._voice_replies_enabled(username) else "выключено" - rewrite_status = "включена" if self._voice_rewrite_enabled(username) else "выключена" - single_message_status = "включён" if self._single_status_message_enabled(username) else "выключен" - settings_text = ( - f"Голосовые ответы: {voice_status}\n" - f"Адаптация текста перед озвучкой: {rewrite_status}\n" - f"Режим одного сообщения в личке: {single_message_status}" - ) - restart_text = "\nОтложенный рестарт: ожидает завершения текущей задачи" if self.restart_requested else "" - if not active: - return f"Статус: активной задачи нет.\nВ очереди pending: {pending}\n{settings_text}{restart_text}" - elapsed = int(time.time() - (self.active_job_started_at or time.time())) - return ( - f"Статус: активная задача #{active.get('num', '?')}\n" - f"Тип: {active.get('type', 'text')}\n" - f"Попытка: {int(active.get('attempts', 0)) + 1}/{self.cfg.max_retries}\n" - f"Выполняется: {elapsed}с\n" - f"Pending: {pending}\n" - f"{settings_text}{restart_text}" - ) - - def _queue_text(self) -> str: - with self.queue_lock: - items = list(self.queue) - if not items: - return "Очередь пуста." - lines = [f"Очередь: {len(items)}"] - for i, job in enumerate(items[:10], start=1): - lines.append( - f"{i}) #{job.get('num', '?')} [{job.get('status')}] {job.get('type')} attempts={job.get('attempts', 0)}" - ) - if len(items) > 10: - lines.append(f"...и ещё {len(items) - 10} задач") - return "\n".join(lines) - - def _cancel_active_job(self, reason: str) -> bool: - with self.queue_lock: - active = next((j for j in self.queue if j.get("status") == "active"), None) - if not active: - return False - self.stop_current_job = True - self._stop_active_codex_process() - self.queue = [j for j in self.queue if j.get("id") != active.get("id")] - self._persist_queue() - self._append_history_event("job_stopped_by_user", {"jobId": active.get("id"), "reason": reason}) - return True - - def _cancel_by_id_prefix(self, prefix: str) -> bool: - prefix = prefix.strip().lower() - normalized_num = prefix.lstrip("#") - with self.queue_lock: - target = next( - ( - j for j in self.queue - if str(j.get("id", "")).lower().startswith(prefix) - or str(j.get("num", "")).lower() == normalized_num - ), - None - ) - if not target: - return False - if target.get("status") == "active": - self.stop_current_job = True - self._stop_active_codex_process() - self.queue = [j for j in self.queue if j.get("id") != target.get("id")] - self._persist_queue() - return True - - def _worker_loop(self) -> None: - while not self.stop_event.is_set(): - if self.restart_requested: - self._exit_for_restart("deferred_restart_before_next_job") - return - job = None - with self.queue_lock: - for item in self.queue: - if item.get("status") == "pending": - item["status"] = "active" - item["active_since"] = now_iso() - item["updated_at"] = now_iso() - self.active_job_id = item.get("id") - self.active_job_started_at = time.time() - job = dict(item) - self._persist_queue() - break - if not job: - time.sleep(0.5) - continue - - self.stop_current_job = False - self._process_job(job) - self.active_job_id = None - self.active_job_started_at = None - if self.restart_requested: - self._exit_for_restart("deferred_restart_after_job") - return - - def _process_job(self, job: dict[str, Any]) -> None: - job_id = job["id"] - job_num = job.get("num", "?") - chat_id = int(job["chat_id"]) - message_id = int(job["message_id"]) - history_path = Path(job["history_file"]) - private_single_message = ( - (job.get("chat_type") or "") == "private" - and self._single_status_message_enabled(job.get("username") or "") - ) - self._set_job_status_text(job, f"Задача #{job_num} в работе.\nСтатус: выполняется.") - try: - if job.get("type") == "voice": - self._set_job_status_text(job, f"Задача #{job_num} в работе.\nСтатус: распознаю voice.") - recognized = self._transcribe_voice_job( - job, - status_cb=lambda note: self._set_job_status_text( - job, - f"Задача #{job_num} в работе.\nСтатус: {note}", - ), - ) - job["text"] = recognized - self._append_history(history_path, "voice_transcription", {"jobId": job_id, "jobNum": job_num, "text": recognized}) - preview = recognized.strip() - if len(preview) > 800: - preview = preview[:800].rstrip() + " ...[обрезано]" - self._set_job_status_text( - job, - f"Задача #{job_num} в работе.\nСтатус: voice распознан, отправляю в Codex.\n\nТекст:\n{preview}", - ) - - prompt = self._build_prompt(job) - self._append_history(history_path, "codex_request", {"jobId": job_id, "prompt": prompt}) - self._set_job_status_text(job, f"Задача #{job_num} в работе.\nСтатус: выполняю через Codex.") - answer = self._run_codex(prompt, job) - if private_single_message: - parts = split_final_private_text(answer) - self._set_job_status_text(job, parts[0]) - if len(parts) > 1: - self._safe_send(chat_id, parts[1], reply_to=message_id) - else: - for chunk in split_long_text(answer): - self._safe_send(chat_id, chunk, reply_to=message_id) - self._append_history(history_path, "codex_response", {"jobId": job_id, "text": answer}) - self._send_private_job_public_report(job, answer) - self._send_task_center_reminder(job) - if self._voice_replies_enabled(job.get("username") or ""): - self._send_voice_reply_for_answer(job, answer, history_path, job_id) - self._mark_job_done(job_id) - except Exception as e: - if self.stop_current_job: - self._append_history(history_path, "job_stopped", {"jobId": job_id, "reason": str(e)}) - self._set_job_status_text(job, f"Задача #{job_num} остановлена.") - self._mark_job_removed(job_id) - self.stop_current_job = False - return - if isinstance(e, VoiceTranscriptionError): - self._append_history(history_path, "voice_transcription_failed", { - "jobId": job_id, - "jobNum": job_num, - "stage": e.stage, - "retryable": e.retryable, - "error": e.user_message, - "detail": e.detail, - }) - self._handle_job_failure(job, e) - - def _build_prompt(self, job: dict[str, Any]) -> str: - retry_block = "" - retry_reason = (job.get("retry_reason") or "").strip() - if retry_reason: - retry_block = f"\n\nПометка retry: {retry_reason}" - return ( - "Пришло сообщение в Telegram.\n" - f"Тип: {job.get('type')}\n" - f"Источник Telegram: {job.get('update_type', 'message')}\n" - f"Тип чата: {job.get('chat_type') or ''}\n" - f"Канал/чат: @{job.get('chat_username') or ''} {job.get('chat_title') or ''}\n" - f"Username отправителя: @{job.get('username')}\n" - f"Подпись автора в Telegram: {job.get('author_signature') or ''}\n" - "Текст для обработки:\n" - f"{job.get('text')}\n\n" - f"История диалога (JSONL): {job.get('history_file')}\n" - f"Инструкции агента: {self.cfg.agent_instructions_file}\n" - f"Работай в рабочем проекте аккуратно и верни только текст ответа пользователю.{retry_block}" - ) - - def _run_codex(self, prompt: str, job: dict[str, Any]) -> str: - username = job.get("username") or self.cfg.allowed_username - thread_id = self._codex_thread_id_for_user(username) - try: - return self._run_codex_once(prompt, job, thread_id=thread_id) - except RuntimeError as e: - if not thread_id or not self._is_missing_codex_session_error(str(e)): - raise - self._set_codex_thread_id_for_user(username, "") - self._append_history( - Path(job["history_file"]), - "system_event", - { - "event": "codex_thread_reset", - "reason": "missing_session", - "username": normalize_username(username), - "oldThreadId": thread_id, - }, - ) - return self._run_codex_once(prompt, job, thread_id="") - - def _run_codex_once(self, prompt: str, job: dict[str, Any], *, thread_id: str) -> str: - output_lines: list[str] = [] - job_id = str(job["id"]) - job_num = job.get("num", "?") - username = job.get("username") or self.cfg.allowed_username - with tempfile.NamedTemporaryFile(prefix="shine-codex-last-message-", suffix=".txt", delete=False) as tmp: - output_file = Path(tmp.name) - - cmd = [ - str(self.cfg.codex_bin), - "exec", - "--dangerously-bypass-approvals-and-sandbox", - "--json", - "-C", str(self.cfg.codex_workdir), - "-o", str(output_file), - ] - if thread_id: - cmd.extend(["resume", thread_id]) - cmd.append(prompt) - mode = f"resume {thread_id}" if thread_id else "new" - print(f"[py-bot] codex exec start job={job_id[:8]} mode={mode}", flush=True) - process = subprocess.Popen( - cmd, - stdin=subprocess.DEVNULL, - stdout=subprocess.PIPE, - stderr=subprocess.STDOUT, - text=True, - encoding="utf-8", - errors="replace", - bufsize=1, - ) - with self.active_process_lock: - self.active_process = process - - 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 - seen_thread_id = "" - - def on_line(line: str) -> None: - nonlocal last_user_note, last_user_note_at, last_job_message_at, seen_thread_id - output_lines.append(line) - current_thread_id = self._extract_codex_thread_id(line) - if current_thread_id: - seen_thread_id = current_thread_id - note = self._extract_codex_user_note(line) - now = time.time() - if note and note != last_user_note and now - last_user_note_at > 8: - self._set_job_status_text(job, f"Задача #{job_num} в работе.\nСтатус: {note}") - last_user_note = note - last_user_note_at = now - last_job_message_at = now - - reader_done = threading.Event() - - def reader() -> None: - if not process.stdout: - reader_done.set() - return - for line in process.stdout: - on_line(line.rstrip("\n")) - reader_done.set() - - t = threading.Thread(target=reader, name=f"codex-reader-{job_id[:8]}", daemon=True) - t.start() - - try: - 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._set_job_status_text( - job, - f"Задача #{job_num} в работе.\nСтатус: выполняется уже {elapsed}, от Codex давно нет новых сообщений.", - ) - last_job_message_at = now - self.last_heartbeat_at = now - time.sleep(1) - finally: - with self.active_process_lock: - self.active_process = None - - reader_done.wait(timeout=2) - - if return_code != 0: - tail = "\n".join(output_lines[-40:]) - raise RuntimeError(f"Codex exited with code {return_code}. Output tail:\n{tail}") - - if seen_thread_id and seen_thread_id != thread_id: - self._set_codex_thread_id_for_user(username, seen_thread_id) - - if output_file.exists(): - answer = output_file.read_text(encoding="utf-8").strip() - try: - output_file.unlink(missing_ok=True) - except Exception: - pass - if answer: - return answer - - fallback = self._extract_fallback_message(output_lines) - if not fallback: - raise RuntimeError("Codex returned empty response") - return fallback - - def _stop_active_codex_process(self) -> bool: - with self.active_process_lock: - process = self.active_process - if process is None: - return False - if process.poll() is not None: - return False - process.terminate() - try: - process.wait(timeout=2) - except subprocess.TimeoutExpired: - process.kill() - return True - - def _handle_job_failure(self, job: dict[str, Any], err: Exception) -> None: - job_id = job["id"] - job_num = job.get("num", "?") - error_text = str(err).strip() or err.__class__.__name__ - user_error_text = self._user_error_text(err) - retryable = not isinstance(err, VoiceTranscriptionError) or err.retryable - log_error_text = err.log_text() if isinstance(err, VoiceTranscriptionError) else error_text - print(f"[py-bot] Ошибка job={job_id[:8]}: {log_error_text}", flush=True) - print(traceback.format_exc(), flush=True) - - with self.queue_lock: - target = next((j for j in self.queue if j.get("id") == job_id), None) - if not target: - return - attempts = int(target.get("attempts", 0)) + 1 - target["attempts"] = attempts - target["last_error"] = error_text[:1000] - target["updated_at"] = now_iso() - if retryable and attempts < self.cfg.max_retries: - target["status"] = "pending" - target["retry_reason"] = error_text[:200] - self._persist_queue() - will_retry = True - else: - self.queue = [j for j in self.queue if j.get("id") != job_id] - self._persist_queue() - will_retry = False - - if will_retry: - self._set_job_status_text( - job, - f"{user_error_text}\nПовторю задачу #{job_num}: попытка {attempts + 1}/{self.cfg.max_retries}.", - ) - else: - self._set_job_status_text(job, f"{user_error_text}\nЗадача #{job_num} остановлена.") - - def _user_error_text(self, err: Exception) -> str: - if isinstance(err, VoiceTranscriptionError): - return f"Не удалось распознать голосовое: {err.user_message}" - error_text = str(err).strip() or err.__class__.__name__ - return f"Ошибка выполнения задачи: {error_text}" - - def _mark_job_done(self, job_id: str) -> None: - with self.queue_lock: - self.queue = [j for j in self.queue if j.get("id") != job_id] - self._persist_queue() - - def _mark_job_removed(self, job_id: str) -> None: - with self.queue_lock: - self.queue = [j for j in self.queue if j.get("id") != job_id] - self._persist_queue() - - def _send_task_center_reminder(self, job: dict[str, Any]) -> None: - if job.get("chat_type") != "private": - return - username = job.get("username") or "" - reminder = self._task_center_counts_text(username) - if not reminder: - return - self._safe_send(int(job["chat_id"]), reminder, reply_to=int(job["message_id"])) - - def _remember_public_report_chat(self, chat_id: int) -> None: - if self.state.get("public_report_chat_id") == chat_id: - return - self.state["public_report_chat_id"] = chat_id - self.state["updated_at"] = now_iso() - self._persist_state() - - def _public_report_chat_id(self) -> int | str | None: - chat_id = self.state.get("public_report_chat_id") - if isinstance(chat_id, int): - return self._resolve_chat_id(chat_id) - if self.cfg.allowed_channel_username: - return f"@{self.cfg.allowed_channel_username}" - return None - - def _send_private_job_public_report(self, job: dict[str, Any], answer: str) -> None: - if job.get("chat_type") != "private": - return - report_chat_id = self._public_report_chat_id() - if report_chat_id is None: - return - - job_num = job.get("num", "?") - source_text = (job.get("text") or "").strip() - if not source_text: - source_text = "(пустой текст запроса)" - role = (job.get("role") or "owner").strip().lower() - author_label = "Айдар" - if role == "player": - player_name = (job.get("player_name") or "").strip() or job.get("username") or "Игрок" - author_label = f"{player_name} (@{job.get('username')})" - if job.get("type") == "voice": - voice_file_id = (job.get("telegram_file_id") or "").strip() - media_type = (job.get("telegram_media_type") or "voice").strip() - request_caption = self._trim_telegram_caption( - f"{author_label} сделал {media_type}-запрос, задача #{job_num}.\n\n" - f"Распознанный текст:\n{source_text}" - ) - request_message_id = None - if voice_file_id: - request_message_id = self._safe_send_telegram_file( - report_chat_id, - voice_file_id, - media_type=media_type, - caption=request_caption, - ) - if request_message_id is None: - request_message_id = self._safe_send(report_chat_id, request_caption) - else: - request_report = ( - f"{author_label} сделал запрос, задача #{job_num}.\n\n" - f"{source_text}" - ) - request_message_id = self._safe_send(report_chat_id, request_report) - if request_message_id is None: - return - - answer_text = (answer or "").strip() or "(пустой ответ)" - answer_chunks = split_long_text(f"Ответ на задачу #{job_num}:\n\n{answer_text}") - for chunk in answer_chunks: - self._safe_send(report_chat_id, chunk, reply_to=request_message_id) - - @staticmethod - def _trim_telegram_caption(text: str, limit: int = 1000) -> str: - text = (text or "").strip() - if len(text) <= limit: - return text - return text[:limit].rstrip() + "\n...[обрезано]" - - def _safe_send_telegram_file( - self, - chat_id: int | str, - file_id: str, - *, - media_type: str = "voice", - caption: str = "", - reply_to: int | None = None, - ) -> int | None: - file_id = (file_id or "").strip() - if not file_id: - return None - caption = self._trim_telegram_caption(caption) - resolved_chat_id: int | str = self._resolve_chat_id(chat_id) if isinstance(chat_id, int) else chat_id - resolved_reply_to = reply_to if resolved_chat_id == chat_id or isinstance(chat_id, str) else None - - def send(target_chat_id: int | str, target_reply_to: int | None) -> dict[str, Any]: - if media_type == "audio": - return self.telegram.send_audio(target_chat_id, file_id, caption=caption, reply_to_message_id=target_reply_to) - return self.telegram.send_voice(target_chat_id, file_id, caption=caption, reply_to_message_id=target_reply_to) - - try: - sent = send(resolved_chat_id, resolved_reply_to) - result = sent.get("result") or {} - message_id = result.get("message_id") - return message_id if isinstance(message_id, int) else None - except Exception as e: - migrate_to_chat_id = self._extract_migrate_to_chat_id(str(e)) - if migrate_to_chat_id is not None: - if isinstance(resolved_chat_id, int): - self._remember_chat_migration(resolved_chat_id, migrate_to_chat_id, "send_file_error") - try: - sent = send(migrate_to_chat_id, None) - result = sent.get("result") or {} - message_id = result.get("message_id") - return message_id if isinstance(message_id, int) else None - except Exception as retry_error: - print(f"[py-bot] sendFile retry after migration error: {retry_error}", flush=True) - return None - print(f"[py-bot] sendFile error: {e}", flush=True) - return None - - def _safe_send_voice_upload( - self, - chat_id: int | str, - voice_bytes: bytes, - filename: str, - *, - caption: str = "", - reply_to: int | None = None, - ) -> int | None: - if not voice_bytes: - return None - caption = self._trim_telegram_caption(caption) - resolved_chat_id: int | str = self._resolve_chat_id(chat_id) if isinstance(chat_id, int) else chat_id - resolved_reply_to = reply_to if resolved_chat_id == chat_id or isinstance(chat_id, str) else None - - def send(target_chat_id: int | str, target_reply_to: int | None) -> dict[str, Any]: - return self.telegram.send_voice_upload( - target_chat_id, - voice_bytes, - filename, - caption=caption, - reply_to_message_id=target_reply_to, - ) - - try: - sent = send(resolved_chat_id, resolved_reply_to) - result = sent.get("result") or {} - message_id = result.get("message_id") - return message_id if isinstance(message_id, int) else None - except Exception as e: - migrate_to_chat_id = self._extract_migrate_to_chat_id(str(e)) - if migrate_to_chat_id is not None: - if isinstance(resolved_chat_id, int): - self._remember_chat_migration(resolved_chat_id, migrate_to_chat_id, "send_voice_upload_error") - try: - sent = send(migrate_to_chat_id, None) - result = sent.get("result") or {} - message_id = result.get("message_id") - return message_id if isinstance(message_id, int) else None - except Exception as retry_error: - print(f"[py-bot] sendVoiceUpload retry after migration error: {retry_error}", flush=True) - return None - print(f"[py-bot] sendVoiceUpload error: {e}", flush=True) - return None - - def _safe_send(self, chat_id: int | str, text: str, reply_to: int | None = None) -> int | None: - text = (text or "").strip() - if not text: - return None - if len(text) > 3900: - text = text[:3900] + "\n...[обрезано]" - resolved_chat_id: int | str = self._resolve_chat_id(chat_id) if isinstance(chat_id, int) else chat_id - resolved_reply_to = reply_to if resolved_chat_id == chat_id or isinstance(chat_id, str) else None - try: - sent = self.telegram.send_message(resolved_chat_id, text, reply_to_message_id=resolved_reply_to) - result = sent.get("result") or {} - message_id = result.get("message_id") - return message_id if isinstance(message_id, int) else None - except Exception as e: - migrate_to_chat_id = self._extract_migrate_to_chat_id(str(e)) - if migrate_to_chat_id is not None: - if isinstance(resolved_chat_id, int): - self._remember_chat_migration(resolved_chat_id, migrate_to_chat_id, "send_message_error") - try: - sent = self.telegram.send_message(migrate_to_chat_id, text, reply_to_message_id=None) - result = sent.get("result") or {} - message_id = result.get("message_id") - return message_id if isinstance(message_id, int) else None - except Exception as retry_error: - print(f"[py-bot] sendMessage retry after migration error: {retry_error}", flush=True) - return None - print(f"[py-bot] sendMessage error: {e}", flush=True) - return None - - def _safe_edit(self, chat_id: int | str, message_id: int | None, text: str) -> bool: - text = (text or "").strip() - if not text or not message_id: - return False - if len(text) > 3900: - text = text[:3900] + "\n...[обрезано]" - resolved_chat_id: int | str = self._resolve_chat_id(chat_id) if isinstance(chat_id, int) else chat_id - try: - self.telegram.edit_message_text(resolved_chat_id, message_id, text) - return True - except Exception as e: - error_text = str(e) - if "message is not modified" in error_text: - return True - migrate_to_chat_id = self._extract_migrate_to_chat_id(error_text) - if migrate_to_chat_id is not None: - if isinstance(resolved_chat_id, int): - self._remember_chat_migration(resolved_chat_id, migrate_to_chat_id, "edit_message_error") - try: - self.telegram.edit_message_text(migrate_to_chat_id, message_id, text) - return True - except Exception as retry_error: - print(f"[py-bot] editMessageText retry after migration error: {retry_error}", flush=True) - return False - print(f"[py-bot] editMessageText error: {e}", flush=True) - return False - - def _ensure_job_status_message(self, job_id: str, chat_id: int, reply_to_message_id: int, text: str) -> int | None: - text = (text or "").strip() - if not text: - return None - with self.queue_lock: - target = next((j for j in self.queue if j.get("id") == job_id), None) - if target: - existing_id = target.get("status_message_id") - existing_text = (target.get("status_message_text") or "").strip() - else: - existing_id = None - existing_text = "" - if existing_id and existing_text == text and self._safe_edit(chat_id, int(existing_id), text): - return int(existing_id) - if existing_id and self._safe_edit(chat_id, int(existing_id), text): - with self.queue_lock: - target = next((j for j in self.queue if j.get("id") == job_id), None) - if target: - target["status_message_text"] = text - target["updated_at"] = now_iso() - self._persist_queue() - return int(existing_id) - message_id = self._safe_send(chat_id, text, reply_to=reply_to_message_id) - if message_id is not None: - with self.queue_lock: - target = next((j for j in self.queue if j.get("id") == job_id), None) - if target: - target["status_message_id"] = message_id - target["status_message_text"] = text - target["updated_at"] = now_iso() - self._persist_queue() - return message_id - - def _set_job_status_text(self, job: dict[str, Any], text: str) -> None: - if (job.get("chat_type") or "") != "private": - self._safe_send(int(job["chat_id"]), text, reply_to=int(job["message_id"])) - return - if not self._single_status_message_enabled(job.get("username") or ""): - self._safe_send(int(job["chat_id"]), text, reply_to=int(job["message_id"])) - return - message_id = self._ensure_job_status_message( - job["id"], - int(job["chat_id"]), - int(job["message_id"]), - text, - ) - if message_id is not None: - job["status_message_id"] = message_id - job["status_message_text"] = text - - def _request_deferred_restart(self) -> None: - if self.restart_requested: - return - self.restart_requested = True - self._append_history_event("restart_service_deferred_scheduled", {}) - with self.queue_lock: - has_active = any(j.get("status") == "active" for j in self.queue) - if not has_active: - threading.Thread( - target=lambda: self._exit_for_restart("deferred_restart_no_active_job"), - name="shine-py-bot-deferred-restart", - daemon=True, - ).start() - - def _exit_for_restart(self, reason: str) -> None: - print(f"[py-bot] restart now: {reason}", flush=True) - self._append_history_event("restart_service_executing", {"reason": reason}) - time.sleep(0.5) - os._exit(0) - - def _schedule_self_restart(self, reason: str = "restart_requested", *, force: bool = False) -> None: - if self.restart_requested and not force: - return - self.restart_requested = True - - def restart() -> None: - time.sleep(1.5) - print(f"[py-bot] restart requested by Telegram command: {reason}", flush=True) - if force: - self._stop_active_codex_process() - os._exit(0) - - threading.Thread(target=restart, name="shine-py-bot-self-restart", daemon=True).start() - - def _voice_reply_targets(self, job: dict[str, Any]) -> list[tuple[int | str, int | None, str]]: - chat_id = int(job["chat_id"]) - message_id = int(job["message_id"]) - targets: list[tuple[int | str, int | None, str]] = [(chat_id, message_id, "source")] - username = job.get("username") or "" - - private_chat_id = self._private_chat_id_for_user(username) - if private_chat_id is not None and private_chat_id != self._resolve_chat_id(chat_id): - targets.append((private_chat_id, None, "private")) - - report_chat_id = self._public_report_chat_id() - if report_chat_id is not None: - resolved_report_chat_id = self._resolve_chat_id(report_chat_id) if isinstance(report_chat_id, int) else report_chat_id - resolved_current_chat_id: int | str = self._resolve_chat_id(chat_id) - if resolved_report_chat_id != resolved_current_chat_id: - targets.append((report_chat_id, None, "public")) - - deduped: list[tuple[int | str, int | None, str]] = [] - seen: set[str] = set() - for target_chat_id, target_reply_to, label in targets: - resolved: int | str = self._resolve_chat_id(target_chat_id) if isinstance(target_chat_id, int) else target_chat_id - key = str(resolved) - if key in seen: - continue - seen.add(key) - deduped.append((target_chat_id, target_reply_to, label)) - return deduped - - def _send_voice_reply_for_answer( - self, - job: dict[str, Any], - answer: str, - history_path: Path, - job_id: str, - ) -> None: - chat_id = int(job["chat_id"]) - message_id = int(job["message_id"]) - job_num = job.get("num", "?") - username = job.get("username") or "" - if not self.cfg.openai_api_key: - note = "не настроен ключ OpenAI для озвучивания." - self._append_history(history_path, "voice_reply_failed", {"jobId": job_id, "jobNum": job_num, "error": note}) - self._safe_send(chat_id, f"Озвучивание включено, но {note}", reply_to=message_id) - return - - voice_text = answer - rewrite_enabled = self._voice_rewrite_enabled(username) - if rewrite_enabled: - try: - voice_text = self._openai_rewrite_text_for_voice(answer) - self._append_history(history_path, "voice_rewrite_done", { - "jobId": job_id, - "jobNum": job_num, - "model": self.cfg.openai_voice_rewrite_model, - "sourceChars": len(answer or ""), - "resultChars": len(voice_text or ""), - }) - except VoiceReplyError as e: - self._append_history(history_path, "voice_rewrite_failed", { - "jobId": job_id, - "jobNum": job_num, - "model": self.cfg.openai_voice_rewrite_model, - "error": str(e), - }) - self._safe_send( - chat_id, - f"Не удалось адаптировать ответ #{job_num} для озвучки, озвучиваю обычный текст: {e}", - reply_to=message_id, - ) - voice_text = answer - - chunks = split_text_for_tts(voice_text, self.cfg.openai_tts_chunk_chars) - if not chunks: - return - - sent_count = 0 - total = len(chunks) - targets = self._voice_reply_targets(job) - print(f"[py-bot] tts start job={str(job_id)[:8]} chunks={total} targets={len(targets)} rewrite={rewrite_enabled}", flush=True) - for index, chunk in enumerate(chunks, start=1): - try: - audio = self._openai_tts(chunk) - except VoiceReplyError as e: - self._append_history(history_path, "voice_reply_failed", { - "jobId": job_id, - "jobNum": job_num, - "part": index, - "parts": total, - "error": str(e), - }) - self._safe_send(chat_id, f"Не удалось озвучить ответ #{job_num}: {e}", reply_to=message_id) - return - caption = f"Озвучка ответа #{job_num}" - if total > 1: - caption += f", часть {index}/{total}" - for target_chat_id, target_reply_to, target_label in targets: - message_sent = self._safe_send_voice_upload( - target_chat_id, - audio, - f"shine-answer-{job_num}-{index}.ogg", - caption=caption, - reply_to=target_reply_to, - ) - if message_sent is None: - self._append_history(history_path, "voice_reply_failed", { - "jobId": job_id, - "jobNum": job_num, - "part": index, - "parts": total, - "target": target_label, - "error": "Telegram не принял voice-файл озвучки.", - }) - if target_label == "source": - self._safe_send(chat_id, f"Озвучка ответа #{job_num} создана, но Telegram не принял voice-файл.", reply_to=message_id) - continue - sent_count += 1 - self._append_history(history_path, "voice_reply_sent", { - "jobId": job_id, - "jobNum": job_num, - "parts": total, - "messages": sent_count, - "targets": len(targets), - "rewriteEnabled": rewrite_enabled, - }) - print(f"[py-bot] tts done job={str(job_id)[:8]} sent={sent_count}", flush=True) - - def _openai_rewrite_text_for_voice(self, text: str) -> str: - source = (text or "").strip() - if not source: - return "" - if len(source) > self.cfg.openai_voice_rewrite_max_input_chars: - source = source[:self.cfg.openai_voice_rewrite_max_input_chars].rstrip() + "\n\n...[текстовый ответ был длиннее и обрезан для голосовой версии]" - payload = { - "model": self.cfg.openai_voice_rewrite_model, - "messages": [ - { - "role": "system", - "content": ( - "Ты готовишь русскую версию финального ответа технического агента для озвучивания. " - "Не пересказывай заново и не меняй смысл: сохрани порядок мыслей, итог, предупреждения, статусы и важные действия. " - "Мягко убери только то, что плохо воспринимается на слух: длинные пути, хэши, ID, команды, JSON, " - "длинные списки файлов, точные размеры и счётчики символов. Если деталь важна, замени её коротким описанием. " - "Не добавляй новых фактов. Пиши естественно, без markdown, близко к исходному тексту." - ), - }, - { - "role": "user", - "content": f"Переделай этот финальный текст в вариант для озвучки:\n\n{source}", - }, - ], - "temperature": 0.2, - "max_tokens": self.cfg.openai_voice_rewrite_max_output_tokens, - } - data = json.dumps(payload, ensure_ascii=False).encode("utf-8") - req = request.Request("https://api.openai.com/v1/chat/completions", method="POST", data=data) - req.add_header("Authorization", f"Bearer {self.cfg.openai_api_key}") - req.add_header("Content-Type", "application/json") - try: - with request.urlopen(req, timeout=self.cfg.openai_voice_rewrite_timeout_seconds) as resp: - raw = resp.read().decode("utf-8", errors="replace") - except TimeoutError as e: - raise VoiceReplyError( - f"OpenAI не успел адаптировать текст за {self.cfg.openai_voice_rewrite_timeout_seconds} секунд." - ) from e - except error.HTTPError as e: - detail = e.read().decode("utf-8", errors="replace") - if e.code == 401: - message = "OpenAI отклонил ключ API для адаптации текста." - elif e.code == 429: - message = "OpenAI временно ограничил адаптацию текста из-за лимита запросов." - elif e.code >= 500: - message = "OpenAI временно не смог адаптировать текст." - else: - message = f"OpenAI вернул ошибку HTTP {e.code} при адаптации текста." - if detail: - message = f"{message} Детали: {detail[:500]}" - raise VoiceReplyError(message) from e - except error.URLError as e: - raise VoiceReplyError(f"не удалось отправить текст в OpenAI для адаптации из-за сетевой ошибки: {e.reason}") from e - - try: - body = json.loads(raw) - content = (((body.get("choices") or [{}])[0].get("message") or {}).get("content") or "").strip() - except Exception as e: - raise VoiceReplyError("OpenAI вернул неразборчивый ответ при адаптации текста.") from e - if not content: - raise VoiceReplyError("OpenAI вернул пустой текст адаптации.") - return content - - def _openai_tts(self, text: str) -> bytes: - payload = { - "model": self.cfg.openai_tts_model, - "voice": self.cfg.openai_tts_voice, - "input": text, - "response_format": self.cfg.openai_tts_response_format, - } - data = json.dumps(payload, ensure_ascii=False).encode("utf-8") - req = request.Request("https://api.openai.com/v1/audio/speech", method="POST", data=data) - req.add_header("Authorization", f"Bearer {self.cfg.openai_api_key}") - req.add_header("Content-Type", "application/json") - try: - with request.urlopen(req, timeout=self.cfg.openai_tts_timeout_seconds) as resp: - audio = resp.read() - except TimeoutError as e: - raise VoiceReplyError(f"OpenAI не успел сгенерировать речь за {self.cfg.openai_tts_timeout_seconds} секунд.") from e - except error.HTTPError as e: - detail = e.read().decode("utf-8", errors="replace") - if e.code == 401: - message = "OpenAI отклонил ключ API для озвучивания." - elif e.code == 429: - message = "OpenAI временно ограничил озвучивание из-за лимита запросов." - elif e.code >= 500: - message = "OpenAI временно не смог сгенерировать речь." - else: - message = f"OpenAI вернул ошибку HTTP {e.code} при озвучивании." - if detail: - message = f"{message} Детали: {detail[:500]}" - raise VoiceReplyError(message) from e - except error.URLError as e: - raise VoiceReplyError(f"не удалось отправить текст в OpenAI TTS из-за сетевой ошибки: {e.reason}") from e - if not audio: - raise VoiceReplyError("OpenAI вернул пустой аудиофайл.") - return audio - - def _transcribe_voice_job( - self, - job: dict[str, Any], - *, - status_cb: Callable[[str], Any] | None = None, - ) -> str: - if not self.cfg.openai_api_key: - raise VoiceTranscriptionError( - "не настроен ключ OpenAI для распознавания.", - stage="config", - retryable=False, - ) - file_id = (job.get("telegram_file_id") or "").strip() - if not file_id: - raise VoiceTranscriptionError( - "Telegram не передал идентификатор файла.", - stage="telegram_file_id", - retryable=False, - ) - job_id = str(job.get("id") or "")[:8] - job_num = job.get("num", "?") - media_type = (job.get("telegram_media_type") or "voice").strip() - duration_seconds = int(job.get("telegram_duration_seconds") or 0) - telegram_file_size = int(job.get("telegram_file_size") or 0) - file_looks_big_for_cloud = self._telegram_cloud_download_is_likely_too_big(telegram_file_size) - if file_looks_big_for_cloud and status_cb is not None: - status_cb( - "файл большой, всё равно пробую скачать его из Telegram. " - f"Предварительный размер около {self._bytes_to_mb(telegram_file_size)} MB." - ) - started_at = time.time() - print(f"[py-bot] transcribe start job={job_id} num={job_num} media={media_type}", flush=True) - file_bytes, filename = self._download_telegram_file(file_id) - print( - f"[py-bot] transcribe downloaded job={job_id} filename={filename} size={len(file_bytes)} bytes", - flush=True, - ) - if file_looks_big_for_cloud and status_cb is not None: - status_cb( - "скачивание из Telegram прошло успешно. " - f"Фактический размер около {self._bytes_to_mb(len(file_bytes))} MB, дальше готовлю аудио и отправляю в OpenAI." - ) - prepared_parts = self._prepare_audio_parts_for_transcription( - file_bytes, - filename, - duration_seconds=duration_seconds, - job_id=job_id, - job_num=job_num, - ) - print( - f"[py-bot] transcribe prepared job={job_id} parts={len(prepared_parts)} duration={duration_seconds}s", - flush=True, - ) - parts_text: list[str] = [] - prompt_tail = "" - for index, (part_bytes, part_name) in enumerate(prepared_parts, start=1): - print( - f"[py-bot] transcribe part job={job_id} index={index}/{len(prepared_parts)} filename={part_name} size={len(part_bytes)} bytes", - flush=True, - ) - part_text = self._openai_transcribe(part_bytes, part_name, prompt=prompt_tail).strip() - if part_text: - parts_text.append(part_text) - prompt_tail = self._transcription_prompt_tail("\n".join(parts_text)) - text = "\n".join(parts_text).strip() - if not text: - raise VoiceTranscriptionError( - "сервис распознавания вернул пустой текст. Возможно, в записи нет слышимой речи или качество звука слишком низкое.", - stage="empty_text", - retryable=False, - ) - elapsed = self._format_duration(int(time.time() - started_at)) - print(f"[py-bot] transcribe done job={job_id} chars={len(text)} elapsed={elapsed}", flush=True) - return text - - def _download_telegram_file(self, file_id: str) -> tuple[bytes, str]: - try: - result = self.telegram.call("getFile", {"file_id": file_id}, timeout=120) - except TimeoutError as e: - raise VoiceTranscriptionError( - "Telegram долго не отдавал информацию о файле.", - stage="telegram_get_file_timeout", - detail=str(e), - ) from e - except Exception as e: - detail = str(e) - if "file is too big" in detail.lower(): - raise VoiceTranscriptionError( - "Файл большой: я попробовал скачать его через текущий Telegram Bot API, " - "но Telegram не дал это сделать. Для такого аудио нужен локальный `telegram-bot-api` " - "сервер или другой способ передать файл боту.", - stage="telegram_get_file_too_big", - retryable=False, - detail=detail, - ) from e - raise VoiceTranscriptionError( - "не удалось получить информацию о файле из Telegram.", - stage="telegram_get_file", - detail=detail, - ) from e - info = result.get("result") or {} - file_path = info.get("file_path") - if not file_path: - raise VoiceTranscriptionError( - "Telegram не вернул путь к файлу.", - stage="telegram_file_path", - retryable=True, - detail=json.dumps(info, ensure_ascii=False)[:1000], - ) - file_url = self.telegram.file_base + file_path.lstrip("/") - req = request.Request(file_url, method="GET") - try: - with request.urlopen(req, timeout=self.cfg.telegram_file_download_timeout_seconds) as resp: - data = resp.read() - except TimeoutError as e: - raise VoiceTranscriptionError( - f"Telegram не успел отдать аудиофайл за {self.cfg.telegram_file_download_timeout_seconds} секунд.", - stage="telegram_download_timeout", - detail=str(e), - ) from e - except error.HTTPError as e: - detail = e.read().decode("utf-8", errors="replace") - raise VoiceTranscriptionError( - f"Telegram вернул ошибку HTTP {e.code} при скачивании аудио.", - stage="telegram_download_http", - retryable=e.code >= 500 or e.code == 429, - detail=detail[:1000], - ) from e - except error.URLError as e: - raise VoiceTranscriptionError( - "не удалось скачать аудиофайл из Telegram из-за сетевой ошибки.", - stage="telegram_download_network", - detail=str(e.reason), - ) from e - if not data: - raise VoiceTranscriptionError( - "Telegram отдал пустой аудиофайл.", - stage="telegram_download_empty", - retryable=True, - ) - original_name = Path(file_path).name or "audio.ogg" - lower = original_name.lower() - # OpenAI transcription может не принимать расширение .oga, нормализуем в .ogg. - if lower.endswith(".oga"): - base = original_name[:-4] if len(original_name) > 4 else "audio" - normalized = f"{base}.ogg" - else: - normalized = original_name - return data, normalized - - def _prepare_audio_parts_for_transcription( - self, - file_bytes: bytes, - filename: str, - *, - duration_seconds: int, - job_id: str, - job_num: Any, - ) -> list[tuple[bytes, str]]: - needs_duration_chunking = duration_seconds > self.cfg.openai_transcribe_max_chunk_seconds - if len(file_bytes) <= self.cfg.openai_transcribe_max_upload_bytes and not needs_duration_chunking: - return [(file_bytes, filename)] - ffmpeg_path = shutil.which(self.cfg.ffmpeg_bin) - ffprobe_path = shutil.which(self.cfg.ffprobe_bin) - if not ffmpeg_path or not ffprobe_path: - raise VoiceTranscriptionError( - "для длинного аудио нужен локальный `ffmpeg`/`ffprobe`, но они не найдены в системе.", - stage="audio_prepare_tools_missing", - retryable=False, - ) - with tempfile.TemporaryDirectory(prefix="shine-audio-") as tmpdir: - tmp = Path(tmpdir) - input_suffix = Path(filename).suffix or ".ogg" - input_path = tmp / f"source{input_suffix}" - input_path.write_bytes(file_bytes) - prepared_path = tmp / "prepared.ogg" - self._ffmpeg_reencode_audio(input_path, prepared_path) - prepared_bytes = prepared_path.read_bytes() - prepared_duration = self._ffprobe_duration_seconds(prepared_path) - if ( - len(prepared_bytes) <= self.cfg.openai_transcribe_max_upload_bytes - and prepared_duration <= self.cfg.openai_transcribe_max_chunk_seconds - ): - return [(prepared_bytes, prepared_path.name)] - chunk_length = self._choose_transcription_chunk_seconds(prepared_duration, len(prepared_bytes)) - print( - f"[py-bot] audio chunking job={job_id} num={job_num} duration={prepared_duration:.1f}s total_bytes={len(prepared_bytes)} chunk_seconds={chunk_length}", - flush=True, - ) - chunks: list[tuple[bytes, str]] = [] - offset = 0 - index = 1 - total_duration = max(1, int(prepared_duration + 0.999)) - while offset < total_duration: - chunk_path = tmp / f"chunk_{index:03d}.ogg" - self._ffmpeg_extract_audio_chunk(prepared_path, chunk_path, offset, chunk_length) - chunk_bytes = chunk_path.read_bytes() - if not chunk_bytes: - break - if len(chunk_bytes) > self.cfg.openai_transcribe_max_upload_bytes: - raise VoiceTranscriptionError( - "локальная нарезка аудио дала слишком большой кусок для OpenAI; нужно уменьшить размер чанка.", - stage="audio_chunk_too_large", - retryable=False, - ) - chunks.append((chunk_bytes, chunk_path.name)) - step = max(1, chunk_length - self.cfg.openai_transcribe_overlap_seconds) - offset += step - index += 1 - if not chunks: - raise VoiceTranscriptionError( - "не удалось подготовить куски аудио для распознавания.", - stage="audio_chunk_empty", - retryable=False, - ) - return chunks - - def _ffmpeg_reencode_audio(self, input_path: Path, output_path: Path) -> None: - cmd = [ - self.cfg.ffmpeg_bin, - "-y", - "-i", - str(input_path), - "-vn", - "-ac", - "1", - "-ar", - "16000", - "-c:a", - "libopus", - "-b:a", - f"{self.cfg.openai_transcribe_reencode_bitrate_kbps}k", - str(output_path), - ] - self._run_subprocess_checked(cmd, "audio_reencode_ffmpeg") - - def _ffmpeg_extract_audio_chunk(self, input_path: Path, output_path: Path, offset_seconds: int, chunk_seconds: int) -> None: - cmd = [ - self.cfg.ffmpeg_bin, - "-y", - "-ss", - str(offset_seconds), - "-t", - str(chunk_seconds), - "-i", - str(input_path), - "-vn", - "-acodec", - "copy", - str(output_path), - ] - self._run_subprocess_checked(cmd, "audio_chunk_ffmpeg") - - def _ffprobe_duration_seconds(self, audio_path: Path) -> float: - cmd = [ - self.cfg.ffprobe_bin, - "-v", - "error", - "-show_entries", - "format=duration", - "-of", - "default=noprint_wrappers=1:nokey=1", - str(audio_path), - ] - try: - result = subprocess.run( - cmd, - check=True, - capture_output=True, - text=True, - timeout=self.cfg.openai_transcribe_ffmpeg_timeout_seconds, - ) - except subprocess.TimeoutExpired as e: - raise VoiceTranscriptionError( - f"`ffprobe` не успел определить длительность аудио за {self.cfg.openai_transcribe_ffmpeg_timeout_seconds} секунд.", - stage="audio_probe_timeout", - retryable=False, - ) from e - except subprocess.CalledProcessError as e: - detail = (e.stderr or e.stdout or "").strip() - raise VoiceTranscriptionError( - "не удалось определить длительность аудио через `ffprobe`.", - stage="audio_probe_failed", - retryable=False, - detail=detail[:1500], - ) from e - raw = (result.stdout or "").strip() - try: - return max(0.0, float(raw)) - except ValueError as e: - raise VoiceTranscriptionError( - "`ffprobe` вернул некорректную длительность аудио.", - stage="audio_probe_invalid", - retryable=False, - detail=raw[:300], - ) from e - - def _run_subprocess_checked(self, cmd: list[str], stage: str) -> None: - try: - subprocess.run( - cmd, - check=True, - capture_output=True, - text=True, - timeout=self.cfg.openai_transcribe_ffmpeg_timeout_seconds, - ) - except subprocess.TimeoutExpired as e: - raise VoiceTranscriptionError( - f"локальная обработка аудио не успела завершиться за {self.cfg.openai_transcribe_ffmpeg_timeout_seconds} секунд.", - stage=f"{stage}_timeout", - retryable=False, - ) from e - except subprocess.CalledProcessError as e: - detail = (e.stderr or e.stdout or "").strip() - raise VoiceTranscriptionError( - "локальная обработка аудио через `ffmpeg` завершилась с ошибкой.", - stage=f"{stage}_failed", - retryable=False, - detail=detail[:1500], - ) from e - - def _choose_transcription_chunk_seconds(self, duration_seconds: float, total_bytes: int) -> int: - max_chunk = self.cfg.openai_transcribe_max_chunk_seconds - safe_seconds = max(60, max_chunk - self.cfg.openai_transcribe_overlap_seconds) - if duration_seconds <= 0 or total_bytes <= 0: - return safe_seconds - bytes_per_second = total_bytes / max(duration_seconds, 1.0) - if bytes_per_second <= 0: - return safe_seconds - size_limited = int((self.cfg.openai_transcribe_max_upload_bytes * 0.9) / bytes_per_second) - return max(60, min(safe_seconds, size_limited if size_limited > 0 else safe_seconds)) - - @staticmethod - def _transcription_prompt_tail(text: str, limit: int = 1000) -> str: - source = compact_spaces(text) - if len(source) <= limit: - return source - return source[-limit:] - - def _telegram_cloud_download_is_likely_too_big(self, file_size: int) -> bool: - if file_size <= 0: - return False - using_cloud_api = self.cfg.telegram_api_base_url.rstrip("/") == "https://api.telegram.org" - return using_cloud_api and file_size > 20 * 1024 * 1024 - - @staticmethod - def _bytes_to_mb(value: int) -> str: - return f"{value / (1024 * 1024):.1f}" - - def _openai_transcribe(self, file_bytes: bytes, filename: str, prompt: str = "") -> str: - boundary = "----shine-boundary-" + "".join(random.choices("abcdef0123456789", k=16)) - mime = mimetypes.guess_type(filename)[0] or "application/octet-stream" - - def text_part(name: str, value: str) -> bytes: - return ( - f"--{boundary}\r\n" - f'Content-Disposition: form-data; name="{name}"\r\n\r\n' - f"{value}\r\n" - ).encode("utf-8") - - body = bytearray() - body.extend(text_part("model", self.cfg.openai_transcribe_model)) - body.extend(text_part("response_format", "text")) - prompt = compact_spaces(prompt) - if prompt: - body.extend(text_part("prompt", prompt[:1000])) - body.extend( - ( - f"--{boundary}\r\n" - f'Content-Disposition: form-data; name="file"; filename="{filename}"\r\n' - f"Content-Type: {mime}\r\n\r\n" - ).encode("utf-8") - ) - body.extend(file_bytes) - body.extend(b"\r\n") - body.extend(f"--{boundary}--\r\n".encode("utf-8")) - - req = request.Request("https://api.openai.com/v1/audio/transcriptions", method="POST", data=bytes(body)) - req.add_header("Authorization", f"Bearer {self.cfg.openai_api_key}") - req.add_header("Content-Type", f"multipart/form-data; boundary={boundary}") - try: - with request.urlopen(req, timeout=self.cfg.openai_transcribe_timeout_seconds) as resp: - return resp.read().decode("utf-8", errors="replace") - except TimeoutError as e: - raise VoiceTranscriptionError( - f"OpenAI не успел распознать аудио за {self.cfg.openai_transcribe_timeout_seconds} секунд.", - stage="openai_transcribe_timeout", - detail=str(e), - ) from e - except error.HTTPError as e: - detail = e.read().decode("utf-8", errors="replace") - if e.code == 400: - user_message = "OpenAI не принял аудиофайл для распознавания." - elif e.code == 401: - user_message = "OpenAI отклонил ключ API для распознавания." - elif e.code == 413: - user_message = "аудиофайл слишком большой для распознавания OpenAI." - elif e.code == 429: - user_message = "OpenAI временно ограничил распознавание из-за лимита запросов." - elif e.code >= 500: - user_message = "OpenAI временно не смог обработать распознавание." - else: - user_message = f"OpenAI вернул ошибку HTTP {e.code} при распознавании." - raise VoiceTranscriptionError( - user_message, - stage="openai_transcribe_http", - retryable=e.code == 429 or e.code >= 500, - detail=detail[:1500], - ) from e - except error.URLError as e: - raise VoiceTranscriptionError( - "не удалось отправить аудио в OpenAI из-за сетевой ошибки.", - stage="openai_transcribe_network", - detail=str(e.reason), - ) from e - - @staticmethod - def _extract_codex_user_note(line: str) -> str | None: - s = (line or "").strip() - if not s.startswith("{"): - return None - try: - obj = json.loads(s) - except Exception: - return None - if obj.get("type") != "item.completed": - return None - item = obj.get("item") or {} - if item.get("type") != "agent_message": - return None - text = (item.get("text") or "").strip() - if not text: - return None - if len(text) > 220: - return text[:220] + "..." - return text - - @staticmethod - def _extract_fallback_message(lines: list[str]) -> str: - for line in reversed(lines): - line = line.strip() - if not line: - continue - if line.startswith("{") and '"type":' in line: - continue - if line.startswith("mcp:") or line.startswith("OpenAI Codex"): - continue - return line - return "" - - @staticmethod - def _extract_codex_thread_id(line: str) -> str: - s = (line or "").strip() - if not s.startswith("{"): - return "" - try: - obj = json.loads(s) - except Exception: - return "" - if obj.get("type") != "thread.started": - return "" - thread_id = (obj.get("thread_id") or "").strip() - return thread_id - - @staticmethod - def _is_missing_codex_session_error(text: str) -> bool: - lowered = (text or "").lower() - markers = [ - "session not found", - "conversation not found", - "thread not found", - "no session found", - "invalid session", - "unknown session", - "no conversation found", - "unknown thread", - ] - return any(marker in lowered for marker in markers) - - @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 = [ - str(config.codex_bin), - "exec", - "--dangerously-bypass-approvals-and-sandbox", - "--json", - "-C", str(config.codex_workdir), - prompt, - ] - proc = subprocess.run( - cmd, - stdin=subprocess.DEVNULL, - capture_output=True, - text=True, - encoding="utf-8", - errors="replace", - ) - print(proc.stdout) - if proc.stderr: - print(proc.stderr) - return proc.returncode - - -def main() -> int: - parser = argparse.ArgumentParser(description="SHiNE Python Telegram bot wrapper for Codex CLI") - parser.add_argument("--selftest-codex", default="", help="Выполнить только codex exec с этим prompt и выйти") - args = parser.parse_args() - - root = Path(__file__).resolve().parent - cfg = BotConfig(root) - if args.selftest_codex: - return run_selftest(cfg, args.selftest_codex) - - service = ShinePyBotService(cfg) - try: - service.run() - except KeyboardInterrupt: - service.shutdown() - return 0 - except Exception as e: - print(f"[py-bot] FATAL: {e}", flush=True) - return 1 - return 0 - - -if __name__ == "__main__": - raise SystemExit(main()) diff --git a/codex-agent-VPS/Agent-server-package/scripts/systemd/shine-agent-bot-coder.service b/codex-agent-VPS/Agent-server-package/scripts/systemd/shine-agent-bot-coder.service deleted file mode 100644 index f166ef87..00000000 --- a/codex-agent-VPS/Agent-server-package/scripts/systemd/shine-agent-bot-coder.service +++ /dev/null @@ -1,23 +0,0 @@ -[Unit] -Description=SHiNE Agent Bot Coder (Telegram + Codex queue worker) -After=network-online.target -Wants=network-online.target - -[Service] -Type=simple -User=your_user -Group=your_user -WorkingDirectory=/home/your_user/codex-agent -Environment=HOME=/home/your_user -Environment=PATH=/home/your_user/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin -EnvironmentFile=/home/your_user/codex-agent/.env -ExecStart=/usr/bin/python3 /home/your_user/codex-agent/py_bot_service.py -Restart=always -RestartSec=5 -TimeoutStopSec=20 -SuccessExitStatus=143 0 -StandardOutput=append:/home/your_user/codex-agent/logs/service.log -StandardError=append:/home/your_user/codex-agent/logs/service.log - -[Install] -WantedBy=multi-user.target diff --git a/codex-agent-VPS/README.md b/codex-agent-VPS/README.md deleted file mode 100644 index 9ce3b9a2..00000000 --- a/codex-agent-VPS/README.md +++ /dev/null @@ -1,32 +0,0 @@ -# codex-agent-VPS - -Переносимый комплект Telegram-бота для запуска `codex` CLI на VPS. - -## Структура -- `README.md` — краткое описание структуры. -- `AGENTS.md` — инструкции по установке и настройке через Codex. -- `.env.example` — верхнеуровневый пример конфига. -- `Agent-server-package/` — готовый комплект файлов для копирования на другой сервер. - -## Что копировать на сервер -На VPS обычно копируется содержимое папки: - -- `Agent-server-package/` - -Внутри неё лежат: -- `py_bot_service.py` -- `AGENT.md` -- `scripts/systemd/shine-agent-bot-coder.service` - -## Что настраивать -- взять `.env.example` из корня `codex-agent-VPS/` -- создать на сервере `.env` -- вписать Telegram bot token -- вписать разрешённые usernames -- указать путь к `codex` -- указать рабочую директорию `CODEX_WORKDIR` - -## Где инструкция -Полная инструкция по установке и настройке лежит в: - -- `AGENTS.md` diff --git a/deploy/AGENT_BOT_CODER_LOCAL_SYSTEMD.md b/deploy/AGENT_BOT_CODER_LOCAL_SYSTEMD.md index d458841c..8a4c0fc1 100644 --- a/deploy/AGENT_BOT_CODER_LOCAL_SYSTEMD.md +++ b/deploy/AGENT_BOT_CODER_LOCAL_SYSTEMD.md @@ -2,9 +2,9 @@ ## Где находится сервис -- Папка сервиса: `SHiNE-agent-bot-coder/` -- Systemd unit: `SHiNE-agent-bot-coder/scripts/systemd/shine-agent-bot-coder.service` -- Скрипт установки: `SHiNE-agent-bot-coder/scripts/systemd/install-local-systemd.sh` +- Папка сервиса находится рядом с репозиторием продукта: `../SHiNE-agent-bot-coder/` +- Systemd unit: `../SHiNE-agent-bot-coder/scripts/systemd/shine-agent-bot-coder.service` +- Скрипт установки: `../SHiNE-agent-bot-coder/scripts/systemd/install-local-systemd.sh` ## Предусловия @@ -18,7 +18,13 @@ Из корня репозитория: ```bash -bash SHiNE-agent-bot-coder/scripts/systemd/install-local-systemd.sh +bash ../SHiNE-agent-bot-coder/scripts/systemd/install-local-systemd.sh +``` + +В `.env` агента `CODEX_WORKDIR` должен указывать на этот репозиторий продукта: + +```env +CODEX_WORKDIR=/home/ai/work/SHiNE/SHiNE-server-sha256/SHiNE-product ``` Скрипт: