[ZILANT] переход на тг-релей, смена базы.
ci/woodpecker/push/woodpecker Pipeline was successful

This commit is contained in:
2026-08-02 13:37:01 +03:00
parent 7c4efdbc8e
commit df45f6c83c
9 changed files with 125 additions and 37 deletions
+31 -20
View File
@@ -3,18 +3,28 @@ SECRET_KEY=24af5f41dba9d8cc0dbc1841660da0b14d7df86ab5e0ed973cdd3bc2dbac23f6
LOG_FILE = /opt/testbot-git/logs/testzilantposter.log
# LOG_FILE = /opt/volk/logs/volkposter.log
# WORKMODE = "ZILANT"
WORKMODE = "VOLK"
WORKMODE = "ZILANT"
# WORKMODE = "VOLK"
# Telegram API через internal_relay (retransbot) — обязательно
# Локально: http://127.0.0.1:8081
# Через nginx: https://rbin.aabpro.ru
RELAY_URL = "https://rbin.aabpro.ru"
# Webhook Responder-bot
# WEBHOOK_URL = "https://bot.aabpro.ru/volk_bot"
# WEBHOOK_URL — адрес, по которому internal_relay доставляет апдейты боту
# (должен быть доступен с машины internal_relay). Не публичный URL для Telegram:
# Telegram ходит на external_relay; setWebhook перехватывается relay.
# WEBHOOK_URL = "http://127.0.0.1:5010/volk_bot"
# WEBHOOK_PORT = 5010
# WEBHOOK_SECRET = "cc0dbc1841660da0b14d7df86ab5e0ed973c"
# Webhook Responder-bot
# Пример: бот и relay на одной машине — http://127.0.0.1:5005/testbot
# Или URL через nginx, если internal_relay достучится до него
WEBHOOK_URL = "https://bot.aabpro.ru/testbot"
WEBHOOK_PORT = 5005
WEBHOOK_SECRET = "cc0dbc1841660da0b14d7df86ab5e0ed973c"
@@ -40,16 +50,18 @@ DEFPW=Z1l@ntAdm1n23
# VK access
# Zilant group
# VK_GROUP_ID = -3342146
VK_GROUP_ID = -3342146
# VOLK group
VK_GROUP_ID = -58475527
# VK_GROUP_ID = -58475527
VK_ACCESS_TOKEN = 'e3732a7ee3732a7ee3732a7ea7e044a75fee373e3732a7e8bf4e48a52d012e946b952a8'
VK_API_VERSION = '5.131'
# MySQL database
# MDBASE = 'testposts'
# MDBASE = 'tempzilant' # debug Zilant database
MDBASE = 'volk_test' # debug VOLK database
# Zilant 2026 database
MDBASE = 'zilant_2026'
# MDBASE = 'volk_test' # debug VOLK database
# MDBASE = 'volkdata' # VOLK production database
MDB_HOST = 'localhost'
MDB_USER = 'testuser'
@@ -61,16 +73,14 @@ MDB_PW = 'T38tU83r69'
# Debug bot @posto_1638_bot
# BOT_TOKEN = "8301828103:AAHDuBkw7EUkmMvv5TPpVJaLeeBLu-EB21U"
# @info_1638_bot
# POSTER_BOT_TOKEN = "8215624618:AAF6VtqRtFr4twFRTiTjedSDE6txkbIy6rc"
POSTER_BOT_TOKEN = "8215624618:AAF6VtqRtFr4twFRTiTjedSDE6txkbIy6rc"
# VOLK production bot @VOLK_informer_bot
POSTER_BOT_TOKEN = "8279661544:AAEsJee6icCUn_AbWxhDpk2CLxQhzaartuI"
# POSTER_BOT_TOKEN = "8279661544:AAEsJee6icCUn_AbWxhDpk2CLxQhzaartuI"
# VOLK backup production bot @VOLK_informer2_bot
# POSTER_BOT_TOKEN = "8001674071:AAFyGW4xibAFnuApEaSJvshqEyYHmD7RRts"
# VOLK responder bot
# RESPONDER_BOT_TOKEN = "8072579275:AAFiyKN1EPPnP5ZVZNTDGEriYJf1xADbfsY"
# RESPONDER_BOT_NAME = "VOLK_responder_bot"
# @posto_1638_bot
RESPONDER_BOT_TOKEN = "8301828103:AAHDuBkw7EUkmMvv5TPpVJaLeeBLu-EB21U"
RESPONDER_BOT_NAME = "posto_1638_bot"
@@ -100,9 +110,9 @@ VK_NO_REPOST_TAG = "#окоЗиланта"
# !! DB datetime is UTC !!
#
# Set 1 hour when Zilant is near
EVENT_POST_DELAY = 60
# EVENT_POST_DELAY = 60
# keep 1 day when far from Zilant
# EVENT_POST_DELAY = 1440
EVENT_POST_DELAY = 1440
# Poster channel
# Debug channel
@@ -120,16 +130,16 @@ MAX_TEXT_LENGTH = 4000
#
# add event number and trailing /
#
# PZK_PREFIX = "https://reg.konvent.ru/zk2025/draft/plan/api/add/"
# EVT_PREFIX = "https://reg.konvent.ru/zk2025/events/actions/api/"
# DESC_PREFIX = "https://reg.konvent.ru/zk2025/events/actions/"
PZK_PREFIX = "https://reg.konvent.ru/zk2026/draft/plan/api/add/"
EVT_PREFIX = "https://reg.konvent.ru/zk2026/events/actions/api/"
DESC_PREFIX = "https://reg.konvent.ru/zk2026/events/actions/"
# VOLK mode API links
# add category ID (volk24_larp for ex.)
VOLK_API_VERSION = "1.0"
VOLK_CATEGORY_LIST = "https://base.volk-nn.ru/api/categories?event=volk26&form=volk26_event"
VOLK_CATEGORY_DESC_PREFIX = "https://base.volk-nn.ru/api/category?event=volk26&form=volk26_event&category="
VOLK_EVENT_LIST_PREFIX = "https://base.volk-nn.ru/api/applications?event=volk26&form=volk26_event&apps_on_page=200&page=0&category="
# VOLK_API_VERSION = "1.0"
# VOLK_CATEGORY_LIST = "https://base.volk-nn.ru/api/categories?event=volk26&form=volk26_event"
# VOLK_CATEGORY_DESC_PREFIX = "https://base.volk-nn.ru/api/category?event=volk26&form=volk26_event&category="
# VOLK_EVENT_LIST_PREFIX = "https://base.volk-nn.ru/api/applications?event=volk26&form=volk26_event&apps_on_page=200&page=0&category="
# Event status
IS_EVENT = true
@@ -143,7 +153,8 @@ LOG_DEBUG_DATA = false
# OpenRouter
OR_KEY = "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"
OR_MODEL_NAME = "qwen/qwen3-vl-235b-a22b-instruct"
# OR_MODEL_NAME = "qwen/qwen3-vl-235b-a22b-instruct"
OR_MODEL_NAME = "anthropic/claude-sonnet-5"
# OR_MODEL_NAME = "deepseek/deepseek-chat-v3.1"
# OR_MODEL_NAME = "deepseek/deepseek-r1-0528:free"
# OR_MODEL_NAME = "qwen/qwen3-coder:free"
+2 -1
View File
@@ -20,8 +20,9 @@ API endpoint `/send_message` находится в Telegram боте, поэто
### Конфигурация портов
Порты и URL настраиваются в файле `.env`:
- `RELAY_URL` - базовый URL **internal_relay** (все исходящие вызовы Bot API идут только через него)
- `WEBHOOK_PORT` - порт для Telegram бота (по умолчанию 5005)
- `WEBHOOK_URL` - полный URL бота (например, https://bot.aabpro.ru/testbot)
- `WEBHOOK_URL` - URL доставки апдейтов от internal_relay к боту (доступен с машины relay; не URL, который видит Telegram напрямую)
- `WEBCTRL_PORT` - порт для веб-интерфейса (по умолчанию 5006)
Веб-интерфейс автоматически читает URL и порт бота из переменных окружения и использует их для отправки запросов.
+5 -4
View File
@@ -8,6 +8,7 @@ import httpx
from datetime import datetime, timezone, timedelta
from dotenv import load_dotenv
from formatter import get_event_text
from telegram_relay import bot_api_method_url
# Загрузка переменных окружения
load_dotenv()
@@ -188,8 +189,8 @@ async def tg_post_event(httpx_client, event_data):
logger.info(f"Текст для публикации: {initial_text[:200]}..." if len(initial_text) > 200 else f"Текст для публикации: {initial_text}")
# Публикация первоначального сообщения без ссылок
send_photo_url = f"https://api.telegram.org/bot{BOT_TOKEN}/sendPhoto"
send_message_url = f"https://api.telegram.org/bot{BOT_TOKEN}/sendMessage"
send_photo_url = bot_api_method_url(BOT_TOKEN, "sendPhoto")
send_message_url = bot_api_method_url(BOT_TOKEN, "sendMessage")
if has_image:
try:
@@ -373,8 +374,8 @@ async def tg_post_event(httpx_client, event_data):
# Редактируем сообщение, добавляя ссылки
logger.info(f"Попытка редактирования сообщения для события {event_data['number']}: message_id={message_id}, final_text_length={len(final_text)}")
edit_caption_url = f"https://api.telegram.org/bot{BOT_TOKEN}/editMessageCaption"
edit_text_url = f"https://api.telegram.org/bot{BOT_TOKEN}/editMessageText"
edit_caption_url = bot_api_method_url(BOT_TOKEN, "editMessageCaption")
edit_text_url = bot_api_method_url(BOT_TOKEN, "editMessageText")
if has_image:
try:
+49
View File
@@ -0,0 +1,49 @@
"""
Конфигурация доступа к Telegram Bot API через internal_relay (retransbot).
Все исходящие вызовы Bot API должны идти на RELAY_URL, а не на api.telegram.org.
"""
import os
from typing import Tuple
from dotenv import load_dotenv
def get_relay_url() -> str:
"""Базовый URL internal_relay без завершающего слэша."""
load_dotenv()
relay = (os.getenv("RELAY_URL") or "").rstrip("/")
if not relay:
raise RuntimeError(
"Требуется переменная окружения RELAY_URL "
"(базовый URL internal_relay, например http://127.0.0.1:8081)"
)
return relay
def configure_telebot_api() -> str:
"""
Настраивает pyTelegramBotAPI (telebot.apihelper) на работу через relay.
Вызывать до создания TeleBot.
"""
from telebot import apihelper
relay = get_relay_url()
apihelper.API_URL = f"{relay}/bot{{0}}/{{1}}"
apihelper.FILE_URL = f"{relay}/file/bot{{0}}/{{1}}"
return relay
def get_ptb_base_urls() -> Tuple[str, str]:
"""
base_url и base_file_url для python-telegram-bot.Bot.
Формат как в Bot API: .../bot и .../file/bot (библиотека сама дописывает token/method).
"""
relay = get_relay_url()
return f"{relay}/bot", f"{relay}/file/bot"
def bot_api_method_url(token: str, method: str) -> str:
"""Полный URL метода Bot API через relay (для сырых httpx/requests вызовов)."""
return f"{get_relay_url()}/bot{token}/{method}"
+10 -2
View File
@@ -6,6 +6,7 @@ from dotenv import load_dotenv
from telegram import Bot
from telegram.error import TelegramError, TimedOut
from telegram.request import HTTPXRequest
from telegram_relay import get_ptb_base_urls, get_relay_url
# Загрузка переменных окружения
load_dotenv()
@@ -74,8 +75,15 @@ async def make_test_post_async():
media_write_timeout=120.0 # Таймаут для медиа (на будущее)
)
# Создание экземпляра бота с кастомным Request
bot = Bot(token=POSTER_BOT_TOKEN, request=request)
# Создание экземпляра бота через internal_relay
base_url, base_file_url = get_ptb_base_urls()
bot = Bot(
token=POSTER_BOT_TOKEN,
request=request,
base_url=base_url,
base_file_url=base_file_url,
)
logger.info(f"Telegram Bot API через ретранслятор: {get_relay_url()}")
# Определяем путь к изображению в том же каталоге, что и скрипт
script_dir = os.path.dirname(os.path.abspath(__file__))
+8 -1
View File
@@ -14,6 +14,7 @@ import requests
from io import BytesIO
from flask import Flask, request
from formatter import get_post_text, get_event_text
from telegram_relay import configure_telebot_api, get_relay_url
# Создаем Flask app на верхнем уровне для экспорта
app = Flask(__name__)
@@ -28,6 +29,7 @@ WEBHOOK_URL = os.getenv('WEBHOOK_URL')
WEBHOOK_PORT = int(os.getenv('WEBHOOK_PORT', '8443'))
WEBHOOK_SECRET = os.getenv('WEBHOOK_SECRET')
LOG_FILE = os.getenv('LOG_FILE', 'bot.log')
RELAY_URL = os.getenv('RELAY_URL')
# Настройка логирования
logger = logging.getLogger('TG_bot')
@@ -149,6 +151,7 @@ required_vars = {
"RESPONDER_BOT_TOKEN": RESPONDER_BOT_TOKEN,
"CHANNEL_ID": CHANNEL_ID,
"WEBHOOK_URL": WEBHOOK_URL,
"RELAY_URL": RELAY_URL,
"MDB_HOST": MDB_HOST,
"MDB_USER": MDB_USER,
"MDB_PW": MDB_PW,
@@ -165,6 +168,10 @@ apihelper.READ_TIMEOUT = 120 # Таймаут на чтение ответа (
apihelper.CONNECT_TIMEOUT = 30 # Таймаут на подключение
apihelper.RETRY_ON_TIMEOUT = True # Автоматические повторные попытки при таймауте
# Весь Bot API — только через internal_relay
relay = configure_telebot_api()
logger.info(f"Telegram Bot API через ретранслятор: {relay}")
# Создаем экземпляр бота
bot = telebot.TeleBot(RESPONDER_BOT_TOKEN)
@@ -1438,7 +1445,7 @@ def setup_webhook():
secret_token=WEBHOOK_SECRET,
max_connections=40
)
logger.info(f"Вебхук установлен: {WEBHOOK_URL}")
logger.info(f"Вебхук установлен через ретранслятор {get_relay_url()}: локальная доставка {WEBHOOK_URL}")
logger.info(f"Секретный токен: {'установлен' if WEBHOOK_SECRET else 'не установлен'}")
logger.info(f"Прослушивание порта: {WEBHOOK_PORT}")
logger.info(f"Путь вебхука: {WEBHOOK_PATH}")
+10 -2
View File
@@ -16,6 +16,7 @@ from formatter import get_event_text
from telegram import Bot
from telegram.error import TelegramError, TimedOut
from telegram.request import HTTPXRequest
from telegram_relay import get_ptb_base_urls, get_relay_url
# Настройка anyio для правильной работы в отдельном потоке
# Устанавливаем правильный backend для anyio (используем asyncio)
@@ -182,8 +183,15 @@ async def publish_to_tg(vk_post_id):
media_write_timeout=120.0 # Таймаут для медиа
)
# Создание экземпляра бота с кастомным Request
bot = Bot(token=BOT_TOKEN, request=request)
# Bot API только через internal_relay
base_url, base_file_url = get_ptb_base_urls()
bot = Bot(
token=BOT_TOKEN,
request=request,
base_url=base_url,
base_file_url=base_file_url,
)
logger.info(f"Telegram Bot API через ретранслятор: {get_relay_url()}")
# Создаем httpx клиент только для скачивания изображений
timeout_config = httpx.Timeout(
+3 -2
View File
@@ -8,6 +8,7 @@ import httpx
from datetime import datetime, timezone
from dotenv import load_dotenv
from formatter import get_event_text
from telegram_relay import bot_api_method_url
# Загрузка переменных окружения
load_dotenv()
@@ -113,8 +114,8 @@ async def tg_post_category(httpx_client, category_data):
logger.info(f"Текст для публикации: {initial_text[:200]}..." if len(initial_text) > 200 else f"Текст для публикации: {initial_text}")
# Публикация сообщения
send_photo_url = f"https://api.telegram.org/bot{BOT_TOKEN}/sendPhoto"
send_message_url = f"https://api.telegram.org/bot{BOT_TOKEN}/sendMessage"
send_photo_url = bot_api_method_url(BOT_TOKEN, "sendPhoto")
send_message_url = bot_api_method_url(BOT_TOKEN, "sendMessage")
if has_image:
try:
+7 -5
View File
@@ -7,6 +7,7 @@ import sys
import json
from datetime import datetime
from dotenv import load_dotenv
from telegram_relay import bot_api_method_url, get_relay_url
# Загрузка переменных окружения
load_dotenv()
@@ -68,6 +69,7 @@ async def test_telegram_publish():
logger.info(f" MAX_TEXT_LENGTH: {MAX_TEXT_LENGTH}")
logger.info(f" PUBLISH_SILENTLY: {PUBLISH_SILENTLY}")
logger.info(f" USE_SUBSCRIPTION_BOT: {USE_SUBSCRIPTION_BOT}")
logger.info(f" RELAY_URL: {get_relay_url()}")
# Проверка обязательных параметров
if not POSTER_BOT_TOKEN:
@@ -147,7 +149,7 @@ async def test_telegram_publish():
logger.info("=" * 80)
logger.info("ПОПЫТКА ПОЛУЧЕНИЯ ИНФОРМАЦИИ О БОТЕ")
logger.info("=" * 80)
get_me_url = f"https://api.telegram.org/bot{POSTER_BOT_TOKEN}/getMe"
get_me_url = bot_api_method_url(POSTER_BOT_TOKEN, "getMe")
logger.info(f"URL запроса: {get_me_url}")
logger.info(f"Метод: GET")
@@ -209,7 +211,7 @@ async def test_telegram_publish():
logger.info("=" * 80)
logger.info("ПОПЫТКА ОТПРАВКИ ТЕСТОВОГО СООБЩЕНИЯ")
logger.info("=" * 80)
send_message_url = f"https://api.telegram.org/bot{POSTER_BOT_TOKEN}/sendMessage"
send_message_url = bot_api_method_url(POSTER_BOT_TOKEN, "sendMessage")
logger.info(f"URL запроса: {send_message_url}")
logger.info(f"Метод: POST")
logger.info(f"Параметры запроса:")
@@ -258,7 +260,7 @@ async def test_telegram_publish():
logger.info("=" * 80)
logger.info("ПОПЫТКА РЕДАКТИРОВАНИЯ СООБЩЕНИЯ")
logger.info("=" * 80)
edit_message_url = f"https://api.telegram.org/bot{POSTER_BOT_TOKEN}/editMessageText"
edit_message_url = bot_api_method_url(POSTER_BOT_TOKEN, "editMessageText")
logger.info(f"URL запроса: {edit_message_url}")
logger.info(f"Метод: POST")
logger.info(f"Параметры запроса:")
@@ -336,7 +338,7 @@ async def test_telegram_publish():
logger.info("=" * 80)
logger.info("ПОПЫТКА ОТПРАВКИ ТЕСТОВОГО СООБЩЕНИЯ С КАРТИНКОЙ")
logger.info("=" * 80)
send_photo_url = f"https://api.telegram.org/bot{POSTER_BOT_TOKEN}/sendPhoto"
send_photo_url = bot_api_method_url(POSTER_BOT_TOKEN, "sendPhoto")
image_url = "https://base.volk-nn.ru/uploads/events/volk26/volk26_event/20251210_175059_0.jpg"
# Формируем текст для сообщения с картинкой
@@ -391,7 +393,7 @@ async def test_telegram_publish():
logger.info("=" * 80)
logger.info("ПОПЫТКА РЕДАКТИРОВАНИЯ СООБЩЕНИЯ С КАРТИНКОЙ")
logger.info("=" * 80)
edit_photo_caption_url = f"https://api.telegram.org/bot{POSTER_BOT_TOKEN}/editMessageCaption"
edit_photo_caption_url = bot_api_method_url(POSTER_BOT_TOKEN, "editMessageCaption")
logger.info(f"URL запроса: {edit_photo_caption_url}")
logger.info(f"Метод: POST")
logger.info(f"Параметры запроса:")