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.
60 lines
2.8 KiB
Python
60 lines
2.8 KiB
Python
"""Background sync loop: watches bot_drafts for updates from Web Wizard or external API.
|
|
|
|
If a draft was updated in the Wizard:
|
|
- If status == 'active': re-renders review text & keyboard in Bale so chat reflects edits.
|
|
- If status == 'committed': edits Bale message to show it was committed and removes buttons.
|
|
- If status == 'cancelled': edits Bale message to show it was cancelled and removes buttons.
|
|
"""
|
|
import asyncio
|
|
import logging
|
|
from app import drafts as draft_store
|
|
from app.handlers import quote
|
|
|
|
logger = logging.getLogger("bot.sync")
|
|
|
|
|
|
async def sync_drafts_loop(ctx) -> None:
|
|
while True:
|
|
try:
|
|
pending = await draft_store.get_pending_bale_updates()
|
|
for draft in pending:
|
|
try:
|
|
if not draft.review_message_id:
|
|
await draft_store.set_bale_updated_at(draft.id)
|
|
continue
|
|
|
|
if draft.status == "committed":
|
|
payload = draft.payload or {}
|
|
quote_id = payload.get("committed_quote_id") or ""
|
|
msg = "✅ این پیشنهاد با موفقیت در سیستم ثبت نهایی شد."
|
|
if quote_id:
|
|
msg += f"\nشناسه پیشنهاد: {quote_id}"
|
|
await ctx.bale.edit_message_text(draft.chat_id, draft.review_message_id, msg, reply_markup=None)
|
|
await draft_store.set_bale_updated_at(draft.id)
|
|
logger.info("Synced committed draft %s to Bale message %s", draft.id, draft.review_message_id)
|
|
|
|
elif draft.status == "cancelled":
|
|
msg = "❌ این پیشنویس لغو شد."
|
|
await ctx.bale.edit_message_text(draft.chat_id, draft.review_message_id, msg, reply_markup=None)
|
|
await draft_store.set_bale_updated_at(draft.id)
|
|
logger.info("Synced cancelled draft %s to Bale message %s", draft.id, draft.review_message_id)
|
|
|
|
elif draft.status == "active" and draft.kind == draft_store.KIND_QUOTE:
|
|
await quote.render(ctx, draft.chat_id, draft, fresh=False)
|
|
await draft_store.set_bale_updated_at(draft.id)
|
|
logger.info("Synced active draft %s edits to Bale message %s", draft.id, draft.review_message_id)
|
|
|
|
else:
|
|
await draft_store.set_bale_updated_at(draft.id)
|
|
|
|
except Exception as exc:
|
|
logger.warning("Failed to sync draft %s to Bale: %s", draft.id, exc)
|
|
await draft_store.set_bale_updated_at(draft.id)
|
|
|
|
except asyncio.CancelledError:
|
|
break
|
|
except Exception:
|
|
logger.exception("Error in sync_drafts_loop")
|
|
|
|
await asyncio.sleep(1.5)
|