Build AI assistants with intelligent product recommendation capabilities using AdMesh
Backend (Python + FastAPI)
# ai_assistant.py
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from typing import List, Optional
import openai
import requests
import re
app = FastAPI()
# Initialize clients
openai.api_key = "your-openai-api-key"
ADMESH_API_KEY = "your-admesh-api-key"
class ChatMessage(BaseModel):
role: str
content: str
class ChatRequest(BaseModel):
messages: List[ChatMessage]
include_recommendations: bool = True
class RecommendationResponse(BaseModel):
title: str
reason: str
intent_match_score: float
admesh_link: str
ad_id: str
async def get_admesh_recommendations(query: str) -> List[RecommendationResponse]:
"""Get recommendations from AdMesh API"""
try:
response = requests.post(
'https://api.useadmesh.com/agent/recommendations',
headers={'Authorization': f'Bearer {ADMESH_API_KEY}'},
json={
'query': query,
'agent_id': 'your_agent_id'
}
)
data = response.json()
recommendations = data['recommendations']
return [
RecommendationResponse(
title=rec['title'],
reason=rec['reason'],
intent_match_score=rec.get('intent_match_score', 0.0),
admesh_link=rec['admesh_link'],
ad_id=rec['ad_id']
)
for rec in recommendations
]
except Exception as e:
print(f"Error getting recommendations: {e}")
return []
def should_include_recommendations(user_message: str) -> bool:
"""Determine if recommendations should be included"""
recommendation_triggers = [
r'\b(recommend|suggest|best|top|compare|which|what.*should)\b',
r'\b(looking for|need|want|searching|find)\b',
r'\b(tool|software|service|product|solution)\b',
r'\b(help.*choose|advice|opinion)\b'
]
return any(re.search(pattern, user_message.lower()) for pattern in recommendation_triggers)
@app.post("/chat")
async def chat_with_assistant(request: ChatRequest):
"""Main chat endpoint with recommendation integration"""
try:
# Get the latest user message
user_message = request.messages[-1].content
# Generate AI response
ai_response = await openai.ChatCompletion.acreate(
model="gpt-3.5-turbo",
messages=[{"role": msg.role, "content": msg.content} for msg in request.messages],
max_tokens=500
)
assistant_message = ai_response.choices[0].message.content
# Check if we should include recommendations
recommendations = []
if (request.include_recommendations and
should_include_recommendations(user_message)):
recommendations = await get_admesh_recommendations(user_message)
return {
"message": assistant_message,
"recommendations": recommendations,
"has_recommendations": len(recommendations) > 0
}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8000)
Frontend (React)
// AIAssistant.tsx
import React, { useState } from 'react';
import { AdMeshLayout } from 'admesh-ui-sdk';
interface Message {
role: 'user' | 'assistant';
content: string;
recommendations?: Recommendation[];
}
interface Recommendation {
title: string;
reason: string;
intent_match_score: number;
admesh_link: string;
ad_id: string;
}
const AIAssistant: React.FC = () => {
const [messages, setMessages] = useState<Message[]>([]);
const [input, setInput] = useState('');
const [loading, setLoading] = useState(false);
const sendMessage = async () => {
if (!input.trim()) return;
const userMessage: Message = { role: 'user', content: input };
setMessages(prev => [...prev, userMessage]);
setInput('');
setLoading(true);
try {
const response = await fetch('/api/chat', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
messages: [...messages, userMessage],
include_recommendations: true
})
});
const data = await response.json();
const assistantMessage: Message = {
role: 'assistant',
content: data.message,
recommendations: data.recommendations || []
};
setMessages(prev => [...prev, assistantMessage]);
} catch (error) {
console.error('Error sending message:', error);
} finally {
setLoading(false);
}
};
return (
<div className="ai-assistant">
<div className="chat-container">
{messages.map((message, index) => (
<div key={index} className={`message ${message.role}`}>
<div className="message-content">
{message.content}
</div>
{message.recommendations && message.recommendations.length > 0 && (
<div className="recommendations-section">
<h4>Recommended for you:</h4>
<AdMeshLayout
recommendations={message.recommendations}
layout="citation"
onRecommendationClick={(adId, admeshLink) => {
window.open(admeshLink, '_blank');
}}
/>
</div>
)}
</div>
))}
{loading && (
<div className="message assistant">
<div className="typing-indicator">Assistant is typing...</div>
</div>
)}
</div>
<div className="input-container">
<input
type="text"
value={input}
onChange={(e) => setInput(e.target.value)}
onKeyPress={(e) => e.key === 'Enter' && sendMessage()}
placeholder="Ask me anything..."
disabled={loading}
/>
<button onClick={sendMessage} disabled={loading || !input.trim()}>
Send
</button>
</div>
</div>
);
};
export default AIAssistant;
Styling (CSS)
/* AIAssistant.css */
.ai-assistant {
max-width: 800px;
margin: 0 auto;
height: 600px;
display: flex;
flex-direction: column;
border: 1px solid #e1e5e9;
border-radius: 8px;
overflow: hidden;
}
.chat-container {
flex: 1;
overflow-y: auto;
padding: 20px;
background: #f8f9fa;
}
.message {
margin-bottom: 20px;
padding: 12px 16px;
border-radius: 8px;
max-width: 80%;
}
.message.user {
background: #007bff;
color: white;
margin-left: auto;
text-align: right;
}
.message.assistant {
background: white;
border: 1px solid #e1e5e9;
margin-right: auto;
}
.recommendations-section {
margin-top: 16px;
padding-top: 16px;
border-top: 1px solid #e1e5e9;
}
.recommendations-section h4 {
margin: 0 0 12px 0;
color: #495057;
font-size: 14px;
font-weight: 600;
}
.input-container {
display: flex;
padding: 16px;
background: white;
border-top: 1px solid #e1e5e9;
}
.input-container input {
flex: 1;
padding: 12px;
border: 1px solid #e1e5e9;
border-radius: 6px;
margin-right: 12px;
font-size: 14px;
}
.input-container button {
padding: 12px 24px;
background: #007bff;
color: white;
border: none;
border-radius: 6px;
cursor: pointer;
font-size: 14px;
font-weight: 500;
}
.input-container button:disabled {
background: #6c757d;
cursor: not-allowed;
}
.typing-indicator {
color: #6c757d;
font-style: italic;
}
/* Mobile responsive */
@media (max-width: 768px) {
.ai-assistant {
height: 100vh;
border-radius: 0;
}
.message {
max-width: 90%;
}
}
Intent Detection
def analyze_user_intent(message: str) -> dict:
"""Advanced intent analysis for better recommendations"""
# Product categories
categories = {
'crm': ['crm', 'customer relationship', 'sales management'],
'project_management': ['project management', 'task tracking', 'team collaboration'],
'analytics': ['analytics', 'data analysis', 'reporting', 'dashboard'],
'marketing': ['marketing', 'email marketing', 'social media', 'advertising'],
'ecommerce': ['ecommerce', 'online store', 'shopping cart', 'payment']
}
# Purchase intent signals
purchase_signals = {
'high': ['buy', 'purchase', 'pricing', 'cost', 'price', 'subscribe'],
'medium': ['compare', 'vs', 'versus', 'difference', 'which is better'],
'low': ['learn', 'understand', 'what is', 'how does', 'explain']
}
detected_categories = []
for category, keywords in categories.items():
if any(keyword in message.lower() for keyword in keywords):
detected_categories.append(category)
purchase_intent = 'low'
for intent_level, signals in purchase_signals.items():
if any(signal in message.lower() for signal in signals):
purchase_intent = intent_level
break
return {
'categories': detected_categories,
'purchase_intent': purchase_intent,
'should_recommend': len(detected_categories) > 0 or purchase_intent in ['high', 'medium']
}
Analytics Integration
import asyncio
from datetime import datetime
class RecommendationAnalytics:
def __init__(self):
self.events = []
async def track_recommendation_shown(self, ad_id: str, user_id: str, query: str):
"""Track when a recommendation is displayed"""
event = {
'event_type': 'recommendation_shown',
'ad_id': ad_id,
'user_id': user_id,
'query': query,
'timestamp': datetime.utcnow().isoformat()
}
self.events.append(event)
# Send to analytics service
await self.send_to_analytics(event)
async def track_recommendation_clicked(self, ad_id: str, user_id: str):
"""Track when a recommendation is clicked"""
event = {
'event_type': 'recommendation_clicked',
'ad_id': ad_id,
'user_id': user_id,
'timestamp': datetime.utcnow().isoformat()
}
self.events.append(event)
# Send to analytics service
await self.send_to_analytics(event)
async def send_to_analytics(self, event: dict):
"""Send event to analytics service"""
try:
# Example: Send to Google Analytics, Mixpanel, etc.
print(f"Analytics event: {event}")
except Exception as e:
print(f"Analytics error: {e}")
# Usage in chat endpoint
analytics = RecommendationAnalytics()
@app.post("/chat")
async def chat_with_assistant(request: ChatRequest):
# ... existing code ...
# Track recommendations shown
for rec in recommendations:
await analytics.track_recommendation_shown(
ad_id=rec.ad_id,
user_id=request.user_id, # Add user_id to request model
query=user_message
)
return response
Conversation Context
class ConversationContext:
def __init__(self):
self.conversations = {}
def update_context(self, user_id: str, message: str, recommendations: List[dict]):
"""Update conversation context for better recommendations"""
if user_id not in self.conversations:
self.conversations[user_id] = {
'messages': [],
'mentioned_products': set(),
'categories_discussed': set(),
'last_recommendations': []
}
context = self.conversations[user_id]
context['messages'].append(message)
context['last_recommendations'] = recommendations
# Extract mentioned products and categories
for rec in recommendations:
context['mentioned_products'].add(rec['title'])
context['categories_discussed'].update(rec.get('categories', []))
def get_context_for_recommendations(self, user_id: str) -> dict:
"""Get context to improve recommendation relevance"""
if user_id not in self.conversations:
return {}
context = self.conversations[user_id]
return {
'previous_products': list(context['mentioned_products']),
'discussed_categories': list(context['categories_discussed']),
'conversation_length': len(context['messages'])
}
# Usage
context_manager = ConversationContext()
async def get_contextual_recommendations(query: str, user_id: str) -> List[dict]:
"""Get recommendations with conversation context"""
context = context_manager.get_context_for_recommendations(user_id)
# Include context in AdMesh request
request_data = {
'query': query,
'format': 'auto',
'previous_products': context.get('previous_products', []),
'session_id': user_id
}
response = requests.post(
'https://api.useadmesh.com/recommend',
headers={'Authorization': f'Bearer {ADMESH_API_KEY}'},
json=request_data
)
recommendations = response.json()['response']['recommendations']
# Update context
context_manager.update_context(user_id, query, recommendations)
return recommendations
FROM python:3.9-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
EXPOSE 8000
CMD ["uvicorn", "ai_assistant:app", "--host", "0.0.0.0", "--port", "8000"]