Aimpress-site/chatbot-api/rocketchat.py
Vadym Samoilenko 8e73d77abc Fix chatbot: lead persistence, CRM creation, RC delivery, mobile UI
- Store lead info in Redis session meta so bot remembers name across messages
- Create Twenty CRM lead immediately from form data (bypass tool-call flow)
- Store room→session reverse mapping in Redis for RC webhook delivery
- Update system prompt: don't re-ask for form-provided info
- Fix "Most Popular" badge clipped on mobile (overflow: visible)
- Fix contact form inputs overflowing on small screens (box-sizing)
- Reduce chat tooltip size on mobile to avoid overlapping content

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 20:18:29 +00:00

117 lines
4.4 KiB
Python

import httpx
import logging
from config import settings
from security import get_redis
logger = logging.getLogger("rocketchat")
HEADERS: dict[str, str] = {}
# Cache: session_id -> room_id
_room_cache: dict[str, str] = {}
def _get_headers() -> dict[str, str]:
if not HEADERS:
HEADERS.update({
"X-Auth-Token": settings.rocketchat_auth_token,
"X-User-Id": settings.rocketchat_user_id,
"Content-Type": "application/json",
})
return HEADERS
async def get_or_create_room(session_id: str, visitor_name: str = "Website Visitor") -> str | None:
"""Get or create a Rocket.Chat livechat room for a session."""
if not settings.rocketchat_auth_token:
return None
# Return cached room
if session_id in _room_cache:
return _room_cache[session_id]
try:
async with httpx.AsyncClient() as http:
# Register visitor
resp = await http.post(
f"{settings.rocketchat_url}/api/v1/livechat/visitor",
headers=_get_headers(),
json={
"visitor": {
"token": session_id,
"name": visitor_name,
}
},
timeout=10,
)
resp.raise_for_status()
# Get or create room
resp = await http.get(
f"{settings.rocketchat_url}/api/v1/livechat/room",
headers=_get_headers(),
params={"token": session_id},
timeout=10,
)
resp.raise_for_status()
room_id = resp.json().get("room", {}).get("_id")
if room_id:
_room_cache[session_id] = room_id
# Store reverse mapping for webhook delivery
r = await get_redis()
await r.set(f"chat:room_session:{room_id}", session_id, ex=86400)
return room_id
except Exception as e:
logger.error(f"RC get_or_create_room error: {e}")
return None
async def send_message(room_id: str, session_id: str, text: str, sender: str = "bot") -> None:
"""Send a message to a Rocket.Chat livechat room."""
if not room_id or not settings.rocketchat_auth_token:
return
try:
async with httpx.AsyncClient() as http:
if sender == "visitor":
# Visitor sends via livechat visitor API
resp = await http.post(
f"{settings.rocketchat_url}/api/v1/livechat/message",
headers={"Content-Type": "application/json"},
json={
"token": session_id,
"rid": room_id,
"msg": text,
},
timeout=10,
)
if resp.status_code != 200:
logger.error(f"RC visitor msg error: {resp.status_code} {resp.text}")
else:
# Bot/agent sends via authenticated API
resp = await http.post(
f"{settings.rocketchat_url}/api/v1/chat.sendMessage",
headers=_get_headers(),
json={
"message": {
"rid": room_id,
"msg": f"🤖 {text}",
}
},
timeout=10,
)
if resp.status_code != 200:
logger.error(f"RC bot msg error: {resp.status_code} {resp.text}")
# Fallback: try livechat/message as agent
resp2 = await http.post(
f"{settings.rocketchat_url}/api/v1/livechat/message",
headers=_get_headers(),
json={
"token": session_id,
"rid": room_id,
"msg": f"🤖 {text}",
},
timeout=10,
)
if resp2.status_code != 200:
logger.error(f"RC bot msg fallback error: {resp2.status_code} {resp2.text}")
except Exception as e:
logger.error(f"RC send_message exception: {e}")