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>
This commit is contained in:
Vadym Samoilenko 2026-03-08 20:18:29 +00:00
parent e78d6dc1c6
commit 8e73d77abc
6 changed files with 59 additions and 13 deletions

View file

@ -8,7 +8,8 @@ RULES:
- Respond in the same language the visitor uses. Default language: British English
- Keep responses under 3 sentences unless more detail is genuinely needed
- After 3-4 exchanges of genuine interest suggest booking a free consultation
- Naturally collect visitor's name, email, company — don't ask all at once, weave into conversation
- If the visitor's name, email, or company was already provided via the form (shown in system context as "[System: The visitor has introduced themselves...]"), you already have it — DO NOT ask for it again. Use that info directly.
- For visitors without form data, naturally collect name, email, company don't ask all at once, weave into conversation
- When you have collected name + email + company + their need, use the capture_lead tool
- After capturing a lead, if the visitor reveals additional useful info (job title, phone, city, budget, timeline, specific requirements), use the update_lead tool to enrich their profile
- Be warm, professional, and concise. No waffle

View file

@ -15,6 +15,7 @@ from security import (
)
from llm import get_ai_response
from rocketchat import get_or_create_room, send_message
from twenty_crm import create_lead_in_crm
app = FastAPI(title="AImpress Chatbot API", docs_url=None, redoc_url=None)
@ -80,22 +81,43 @@ async def chat(req: ChatRequest):
# Store user message and get conversation history
messages = await store_messages(req.session_id, "user", message)
# If lead info provided, prepend context for LLM
if req.lead and req.lead.name:
lead_context = f"[System: The visitor has introduced themselves. Name: {req.lead.name}"
if req.lead.email:
lead_context += f", Email: {req.lead.email}"
if req.lead.company:
lead_context += f", Company: {req.lead.company}"
lead_context += ". Use this info naturally — greet them by name. Don't re-ask for info you already have.]"
messages = [{"role": "user", "content": lead_context}, {"role": "assistant", "content": "Understood."}] + messages
# Load session meta (twenty_person_id, etc.)
# Load session meta (twenty_person_id, lead info, etc.)
r = await get_redis()
meta_raw = await r.get(f"chat:meta:{req.session_id}")
session_meta = json.loads(meta_raw) if meta_raw else {}
session_meta["page_context"] = req.page_context
# If lead info provided (first message), save to session meta + create CRM lead
if req.lead and req.lead.name and "lead" not in session_meta:
lead_info = {"name": req.lead.name}
if req.lead.email:
lead_info["email"] = req.lead.email
if req.lead.company:
lead_info["company"] = req.lead.company
session_meta["lead"] = lead_info
# Create lead in Twenty CRM immediately from form data
person_id = await create_lead_in_crm(
name=req.lead.name,
email=req.lead.email or "",
company=req.lead.company or "",
need=message,
page_context=req.page_context or "/",
)
if person_id:
session_meta["twenty_person_id"] = person_id
# Always prepend lead context from session meta (persists across messages)
stored_lead = session_meta.get("lead")
if stored_lead:
lead_context = f"[System: The visitor has introduced themselves. Name: {stored_lead['name']}"
if stored_lead.get("email"):
lead_context += f", Email: {stored_lead['email']}"
if stored_lead.get("company"):
lead_context += f", Company: {stored_lead['company']}"
lead_context += ". Use this info naturally — greet them by name. Don't re-ask for info you already have.]"
messages = [{"role": "user", "content": lead_context}, {"role": "assistant", "content": "Understood."}] + messages
# Get AI response
try:
reply, lead_data = await get_ai_response(messages, session_meta)

View file

@ -1,6 +1,7 @@
import httpx
import logging
from config import settings
from security import get_redis
logger = logging.getLogger("rocketchat")
@ -55,6 +56,9 @@ async def get_or_create_room(session_id: str, visitor_name: str = "Website Visit
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}")

View file

@ -122,4 +122,14 @@
bottom: 16px;
right: 16px;
}
.chat-bubble__greeting {
max-width: 170px;
padding: 8px 10px;
}
.chat-bubble__greeting p {
font-size: 12px;
line-height: 1.3;
}
}

View file

@ -52,6 +52,8 @@
}
.form-group input {
box-sizing: border-box;
width: 100%;
background: rgba(255, 255, 255, 0.04);
border: 1px solid rgba(255, 255, 255, 0.08);
border-radius: 12px;
@ -151,4 +153,9 @@
grid-template-columns: 1fr;
gap: 1rem;
}
.form-group input {
padding: 0.75rem 0.9rem;
font-size: 0.9rem;
}
}

View file

@ -123,7 +123,7 @@
display: flex;
flex-direction: column;
position: relative;
overflow: hidden;
overflow: visible;
transition: border-color 0.3s, box-shadow 0.4s, transform 0.35s;
}
@ -138,6 +138,8 @@
opacity: 0;
transition: opacity 0.4s;
pointer-events: none;
border-radius: 20px;
overflow: hidden;
}
.retainer-card:hover {