148 lines
5.1 KiB
Python
148 lines
5.1 KiB
Python
import asyncio
|
|
import logging
|
|
|
|
from aiogram import Bot, Dispatcher, F
|
|
from tortoise import Tortoise
|
|
from aiogram.client.session.aiohttp import AiohttpSession
|
|
|
|
from app import config
|
|
from app.handlers import callbacks, commands, prompt
|
|
from app.handlers.reviews import send_queue_worker, sheet_queue_worker
|
|
from app.models import Settings
|
|
from app.services.ozon import OzonClient
|
|
from app.services.wb import WildberriesClient
|
|
|
|
# Configure logging
|
|
logging.basicConfig(
|
|
level=logging.INFO,
|
|
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
|
|
)
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
async def ozon_worker():
|
|
ozon_client = OzonClient()
|
|
|
|
while True:
|
|
try:
|
|
logger.info("Checking for new Ozon reviews...")
|
|
ozon_result = await ozon_client.process_new_reviews()
|
|
logger.info(
|
|
f"Processed {ozon_result['processed']} Ozon reviews, {ozon_result['new']} new"
|
|
)
|
|
except Exception as e:
|
|
logger.error(f"Error during Ozon review check: {e.__class__.__name__}: {e}")
|
|
|
|
logger.info(f"Next check in {config.OZON_CHECK_INTERVAL} seconds")
|
|
await asyncio.sleep(config.OZON_CHECK_INTERVAL)
|
|
|
|
|
|
async def wb_worker():
|
|
wb_client = WildberriesClient()
|
|
|
|
while True:
|
|
try:
|
|
logger.info("Checking for new Wildberries reviews...")
|
|
wb_result = await wb_client.process_new_reviews()
|
|
logger.info(
|
|
f"Processed {wb_result['processed']} Wildberries reviews, {wb_result['new']} new"
|
|
)
|
|
except Exception as e:
|
|
logger.error(
|
|
f"Error during Wildberries review check: {e.__class__.__name__}: {e}"
|
|
)
|
|
|
|
logger.info(f"Next check in {config.WB_CHECK_INTERVAL} seconds")
|
|
await asyncio.sleep(config.WB_CHECK_INTERVAL)
|
|
|
|
|
|
async def main():
|
|
"""Set up and run the bot."""
|
|
session = (
|
|
AiohttpSession(proxy=(config.TG_PROXY,))
|
|
if config.TG_PROXY
|
|
else AiohttpSession()
|
|
)
|
|
bot = Bot(token=config.BOT_TOKEN, session=session)
|
|
dp = Dispatcher()
|
|
|
|
dp.include_router(commands.router)
|
|
dp.include_router(callbacks.router)
|
|
dp.include_router(prompt.prompt_router)
|
|
allowed_threads = [
|
|
config.BAD_REVIEWS_THREAD_ID,
|
|
config.GOOD_REVIEWS_THREAD_ID,
|
|
]
|
|
if config.EMPTY_LOW_RATING_THREAD_ID:
|
|
allowed_threads.append(config.EMPTY_LOW_RATING_THREAD_ID)
|
|
if config.EMPTY_HIGH_RATING_THREAD_ID:
|
|
allowed_threads.append(config.EMPTY_HIGH_RATING_THREAD_ID)
|
|
dp.message.filter(
|
|
(F.chat.id == config.TG_CHAT_ID)
|
|
& F.message_thread_id.in_(allowed_threads)
|
|
)
|
|
|
|
await Tortoise.init(
|
|
db_url=config.TORTOISE_ORM["connections"]["default"],
|
|
modules={"models": ["app.models"]},
|
|
)
|
|
await Tortoise.generate_schemas()
|
|
|
|
# Миграция: добавить колонку автоответа без текста, если её ещё нет
|
|
try:
|
|
conn = Tortoise.get_connection("default")
|
|
await conn.execute_query(
|
|
"ALTER TABLE settings ADD COLUMN auto_response_empty_enabled INTEGER DEFAULT 0"
|
|
)
|
|
except Exception as e:
|
|
if "duplicate column" not in str(e).lower():
|
|
logger.warning(f"Migration auto_response_empty_enabled: {e}")
|
|
|
|
# Миграция: шаблоны ответа на отзывы без текста (1–3 и 4–5 звёзд)
|
|
for col in ("template_empty_low_rating", "template_empty_high_rating"):
|
|
try:
|
|
conn = Tortoise.get_connection("default")
|
|
await conn.execute_query(
|
|
f"ALTER TABLE settings ADD COLUMN {col} TEXT"
|
|
)
|
|
except Exception as e:
|
|
if "duplicate column" not in str(e).lower():
|
|
logger.warning(f"Migration {col}: {e}")
|
|
|
|
# Миграция: WB bables (теги отзыва) в таблицу review
|
|
try:
|
|
conn = Tortoise.get_connection("default")
|
|
await conn.execute_query(
|
|
"ALTER TABLE review ADD COLUMN bables TEXT"
|
|
)
|
|
except Exception as e:
|
|
if "duplicate column" not in str(e).lower():
|
|
logger.warning(f"Migration review.bables: {e}")
|
|
|
|
# Создаём настройки для хороших и плохих отзывов при первом запуске.
|
|
# Существующие настройки (включая автоответы) не трогаем, чтобы они
|
|
# переживали перезапуск и редеплой.
|
|
for is_good in [True, False]:
|
|
await Settings.get_or_create(
|
|
is_good=is_good,
|
|
defaults={
|
|
"analysis_enabled": not is_good,
|
|
},
|
|
)
|
|
|
|
workers = asyncio.ensure_future(
|
|
asyncio.gather(
|
|
ozon_worker(),
|
|
wb_worker(),
|
|
send_queue_worker(),
|
|
sheet_queue_worker(),
|
|
)
|
|
) # future must be saved to prevent GC
|
|
print(f"Workers future: {workers}")
|
|
|
|
await dp.start_polling(bot)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
asyncio.run(main())
|