Снимок состояния до переноса серверного UI

This commit is contained in:
AidarKC 2026-06-03 14:49:03 +04:00
parent 2c2aad1355
commit c97b3e3ec3
6 changed files with 41 additions and 54 deletions

View File

@ -0,0 +1,14 @@
# Диагностика больших voice/audio в Telegram-боте
- краткое описание фичи:
- Бот при большом voice/audio больше не отказывается заранее по метаданным Telegram. Теперь он сначала сообщает, что пробует скачать файл, затем отдельно сообщает об успешном скачивании и только после этого переходит к подготовке аудио и распознаванию через OpenAI.
- что именно проверять:
- Отправить в бота большой `voice` или `audio`, который раньше попадал под ранний отказ.
- Проверить, что сначала приходит сообщение о попытке скачать большой файл.
- Проверить два сценария:
- скачивание удалось: бот пишет об успешной загрузке и продолжает распознавание;
- скачивание не удалось: бот пишет именно о неудачном скачивании из Telegram, без ложной привязки к ошибке OpenAI.
- ожидаемый результат:
- Пользователь видит понятную поэтапную диагностику: попытка скачивания, результат скачивания и только потом следующий этап обработки.
- статус:
- pending

View File

@ -57,6 +57,7 @@ python3 SHiNE-agent-bot-coder/py_bot_service.py --selftest-codex "Ответь
## Длинные voice/audio
- Если аудио короткое, бот отправляет его в OpenAI как раньше.
- Если аудио большое или длинное, бот локально пережимает его через `ffmpeg`, при необходимости режет на куски и распознаёт последовательно.
- Если Telegram заранее сообщает большой размер файла, бот больше не отказывается сразу: сначала явно пишет, что пробует скачать файл, затем отдельно сообщает, удалось ли скачивание, и только после успешной загрузки переходит к подготовке аудио и OpenAI.
- Для очень больших файлов упираемся не только в OpenAI, но и в лимит обычного облачного Telegram Bot API на скачивание файла ботом. Для таких случаев нужно использовать локальный `telegram-bot-api` сервер и указать его через `TELEGRAM_API_BASE_URL`.
## Запуск как systemd-сервис

View File

@ -18,7 +18,7 @@ import time
import traceback
import uuid
from pathlib import Path
from typing import Any
from typing import Any, Callable
from urllib import error, request
DEFAULT_ALLOWED_PLAYERS = ",".join([
@ -1509,7 +1509,10 @@ class ShinePyBotService:
try:
if job.get("type") == "voice":
self._safe_send(chat_id, f"#{job_num}: распознаю голосовое...", reply_to=message_id)
recognized = self._transcribe_voice_job(job)
recognized = self._transcribe_voice_job(
job,
status_cb=lambda note: self._safe_send(chat_id, f"#{job_num}: {note}", reply_to=message_id),
)
job["text"] = recognized
self._append_history(history_path, "voice_transcription", {"jobId": job_id, "jobNum": job_num, "text": recognized})
preview = recognized.strip()
@ -2206,7 +2209,12 @@ class ShinePyBotService:
raise VoiceReplyError("OpenAI вернул пустой аудиофайл.")
return audio
def _transcribe_voice_job(self, job: dict[str, Any]) -> str:
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 для распознавания.",
@ -2225,17 +2233,11 @@ class ShinePyBotService:
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)
if self._telegram_cloud_download_is_likely_too_big(telegram_file_size):
limit_mb = self._bytes_to_mb(20 * 1024 * 1024)
actual_mb = self._bytes_to_mb(telegram_file_size)
raise VoiceTranscriptionError(
(
f"Telegram не даст этому боту скачать такой файл через обычный Bot API "
f"(примерно {actual_mb} MB при лимите около {limit_mb} MB). "
f"Для очень длинных аудио нужен локальный `telegram-bot-api` сервер или другой способ доставки файла."
),
stage="telegram_get_file_too_big",
retryable=False,
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)
@ -2244,6 +2246,11 @@ class ShinePyBotService:
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,
@ -2290,7 +2297,9 @@ class ShinePyBotService:
detail = str(e)
if "file is too big" in detail.lower():
raise VoiceTranscriptionError(
"Telegram считает файл слишком большим для скачивания через текущий Bot API. Для такого аудио нужен локальный `telegram-bot-api` сервер или другой способ передать файл боту.",
"Файл большой: я попробовал скачать его через текущий Telegram Bot API, "
"но Telegram не дал это сделать. Для такого аудио нужен локальный `telegram-bot-api` "
"сервер или другой способ передать файл боту.",
stage="telegram_get_file_too_big",
retryable=False,
detail=detail,

View File

@ -1,2 +1,2 @@
client.version=1.2.115
server.version=1.2.107
client.version=1.2.116
server.version=1.2.108

View File

@ -1,19 +0,0 @@
# UI deploy
Актуальный UI-деплой выполняется одной командой:
```bash
./gradlew deployUI
```
По умолчанию:
- хост: `player@93.170.12.154`
- домен: `https://shineup.me`
- путь: `/home/player/SHiNE/SHiNE-UI`
Переопределение при необходимости:
```bash
REMOTE_HOST=player@93.170.12.154 REMOTE_BASE_DIR=/home/player/SHiNE bash deploy_shine-PWA.sh
```

View File

@ -1,18 +0,0 @@
# MVP notes: Web Push
## Временное поведение (сделано для тестового стенда)
- Клиент отправляет push-подписку на сервер при каждом запуске после авторизации, даже если подписка не изменилась.
- Причина: на тестовом сервере/после переустановки БД запись о токене может пропасть, а клиент этого не узнает.
## Что доработать для production
- Вернуть режим "отправлять только при изменении подписки" как основной.
- Добавить безопасный механизм ресинхронизации:
- Вариант 1: периодическая принудительная отправка (например, 1 раз в N дней).
- Вариант 2: endpoint на сервере "есть ли подписка", и отправка только при отсутствии/рассинхроне.
- В логах разделить обычную отправку и принудительную, чтобы видеть лишний трафик.
- Добавить e2e-тесты сценариев:
- Переустановка сервера (потеря токена в БД).
- Смена браузерной подписки.
- Повторный запуск клиента без изменений.