refactor(bot)!: rename 'ai procurement' -> 'bot/' so the compose build context is committed
The bot service in docker-compose.yml builds from ./bot, but the agent code lived in 'ai procurement/' and ./bot was only a Windows junction on reza.g's machine (and was gitignored) — exactly as the team reported: 'bot/ was never committed — prod-v7's bot is un-buildable from the repo.' - junction removed; 'ai procurement/' renamed to 'bot/' via git mv (all 41 files keep their history as pure renames) - 'bot/' dropped from .gitignore (voice/ stays ignored — runtime voice notes; bot/.env stays ignored by bot/.gitignore) - compose needs no change: context: ./bot and ./bot/app now resolve to committed files - bot/INTEGRATION-REPORT.md added: full story (problem, root cause, git state, security note on the committed BALE_BOT_TOKEN / AI_API_KEY compose defaults, and usage instructions for the team) Verified: 41 renames staged with zero secret/cache files; voice/ and bot/.env still ignored.
This commit is contained in:
@@ -0,0 +1,60 @@
|
||||
"""Bot entrypoint: ensure tables → sweeper task → Bale long-poll loop.
|
||||
|
||||
Mirrors the api's pattern of a plain asyncio background loop (no Celery/Redis).
|
||||
"""
|
||||
import asyncio
|
||||
import logging
|
||||
|
||||
from app.bale.client import BaleClient, poll_loop
|
||||
from app.config import settings
|
||||
from app.db_init import ensure_schema
|
||||
from app.drafts import expire_stale
|
||||
from app.handlers import handle_update
|
||||
from app.runtime import BotContext
|
||||
from app.api.client import ErpClient
|
||||
from app.sync import sync_drafts_loop
|
||||
|
||||
logging.basicConfig(
|
||||
level=getattr(logging, settings.LOG_LEVEL.upper(), logging.INFO),
|
||||
format="%(asctime)s %(levelname)s %(name)s — %(message)s",
|
||||
)
|
||||
logger = logging.getLogger("bot.main")
|
||||
|
||||
|
||||
async def sweeper_loop() -> None:
|
||||
"""Expire stale drafts + sweep dead pending flows every 10 minutes."""
|
||||
while True:
|
||||
try:
|
||||
expired = await expire_stale(settings.DRAFT_TTL_HOURS)
|
||||
if expired:
|
||||
logger.info("expired %s stale drafts", expired)
|
||||
except Exception:
|
||||
logger.exception("sweeper failed")
|
||||
await asyncio.sleep(600)
|
||||
|
||||
|
||||
async def main() -> None:
|
||||
if not settings.BOT_TOKEN:
|
||||
raise SystemExit("PROCUREMENT_BOT_BOT_TOKEN is not set — get one from Bale's BotFather")
|
||||
logger.info("starting bale procurement bot (api=%s, ai=%s)",
|
||||
settings.API_BASE_URL, "configured" if settings.AI_BASE_URL else "NOT configured")
|
||||
await ensure_schema()
|
||||
|
||||
bale = BaleClient(settings.BALE_API_BASE, settings.BOT_TOKEN)
|
||||
api = ErpClient(settings.API_BASE_URL, settings.API_TIMEOUT_SECONDS, settings.SERVICE_TOKEN)
|
||||
ctx = BotContext(bale, api)
|
||||
|
||||
sweeper = asyncio.create_task(sweeper_loop())
|
||||
sync_task = asyncio.create_task(sync_drafts_loop(ctx))
|
||||
try:
|
||||
await poll_loop(bale, lambda update: handle_update(ctx, update))
|
||||
finally:
|
||||
sweeper.cancel()
|
||||
sync_task.cancel()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
try:
|
||||
asyncio.run(main())
|
||||
except KeyboardInterrupt:
|
||||
pass
|
||||
Reference in New Issue
Block a user