326 lines
7.7 KiB
Markdown
326 lines
7.7 KiB
Markdown
# Mascot Chatbot Implementation Guide
|
|||
|
|
|
||
|
|
## Overview
|
||
|
|
|
||
|
|
The mascot has been upgraded from a simple insights display to a **full-featured interactive chatbot** that can:
|
||
|
|
- Engage in conversations with users
|
||
|
|
- Provide real-time analytics insights
|
||
|
|
- Answer questions about messages and conversations
|
||
|
|
- Generate intelligent recommendations
|
||
|
|
- Maintain conversation history
|
||
|
|
|
||
|
|
## Architecture
|
||
|
|
|
||
|
|
### Components
|
||
|
|
|
||
|
|
#### MascotChatbot (`src/widgets/mascot/MascotChatbot.tsx`)
|
||
|
|
Main chatbot UI component with chat interface, message bubbles, and user input.
|
||
|
|
|
||
|
|
```typescript
|
||
|
|
<MascotChatbot
|
||
|
|
isOpen={boolean} // Chat window visibility
|
||
|
|
onSetIsOpen={(open) => void} // Toggle chat window
|
||
|
|
onSendMessage={async (msg) => string} // Handle user messages
|
||
|
|
mascotName="Discord Watcher" // Mascot name
|
||
|
|
mascotAvatar={url} // Mascot avatar image
|
||
|
|
/>
|
||
|
|
```
|
||
|
|
|
||
|
|
**Features:**
|
||
|
|
- Framer Motion animations
|
||
|
|
- Message bubbles with typing indicator
|
||
|
|
- Minimize/maximize window
|
||
|
|
- Message history
|
||
|
|
- Responsive design
|
||
|
|
- Auto-scroll to latest message
|
||
|
|
|
||
|
|
#### useMascotChat (`src/shared/hooks/useMascotChat.ts`)
|
||
|
|
React hook for managing mascot chat logic and AI responses.
|
||
|
|
|
||
|
|
```typescript
|
||
|
|
const mascotChat = useMascotChat({
|
||
|
|
messageCount: number, // Total messages
|
||
|
|
activeParticipants: number, // Unique users
|
||
|
|
lastActivity: string, // Activity status
|
||
|
|
topicsDiscussed: string[] // Conversation topics
|
||
|
|
});
|
||
|
|
|
||
|
|
mascotChat.handleSendMessage(message) // Send message & get response
|
||
|
|
```
|
||
|
|
|
||
|
|
### Data Flow
|
||
|
|
|
||
|
|
```
|
||
|
|
User Input
|
||
|
|
↓
|
||
|
|
MascotChatbot (UI)
|
||
|
|
↓
|
||
|
|
useMascotChat hook
|
||
|
|
↓
|
||
|
|
generateIntelligentResponse()
|
||
|
|
↓
|
||
|
|
Response (local) or Backend API
|
||
|
|
↓
|
||
|
|
Message displayed in chat
|
||
|
|
```
|
||
|
|
|
||
|
|
## Features
|
||
|
|
|
||
|
|
### 1. Smart Responses
|
||
|
|
The mascot responds intelligently based on keywords and context:
|
||
|
|
|
||
|
|
**Analytics Questions:**
|
||
|
|
- "Berapa pesan?" → Returns message count with context
|
||
|
|
- "Berapa orang?" → Returns participant count
|
||
|
|
- "Berapa aktif?" → Activity metrics
|
||
|
|
|
||
|
|
**Insights:**
|
||
|
|
- "Apa insight?" → Summarizes conversation patterns
|
||
|
|
- "Ringkasan" → Full conversation summary
|
||
|
|
- "Saran" → Recommendations for improvement
|
||
|
|
|
||
|
|
**General:**
|
||
|
|
- Greetings recognition
|
||
|
|
- Help/info requests
|
||
|
|
- Default contextual responses
|
||
|
|
|
||
|
|
### 2. Real-time Context
|
||
|
|
The chatbot receives live data about:
|
||
|
|
- Message counts
|
||
|
|
- Active participants
|
||
|
|
- Last activity status
|
||
|
|
- Topics being discussed
|
||
|
|
|
||
|
|
### 3. Conversation History
|
||
|
|
- Messages persist during session
|
||
|
|
- Typing indicator while processing
|
||
|
|
- Timestamps on all messages
|
||
|
|
- User/mascot distinction
|
||
|
|
|
||
|
|
### 4. Extensibility
|
||
|
|
The implementation is ready for:
|
||
|
|
- Backend AI integration via API
|
||
|
|
- Discord Gateway context enrichment
|
||
|
|
- Custom response training
|
||
|
|
- Multi-language support
|
||
|
|
|
||
|
|
## Usage
|
||
|
|
|
||
|
|
### Basic Setup
|
||
|
|
```typescript
|
||
|
|
const [isChatOpen, setIsChatOpen] = useState(false);
|
||
|
|
const mascotChat = useMascotChat(contextData);
|
||
|
|
|
||
|
|
<MascotChatbot
|
||
|
|
isOpen={isChatOpen}
|
||
|
|
onSetIsOpen={setIsChatOpen}
|
||
|
|
onSendMessage={mascotChat.handleSendMessage}
|
||
|
|
/>
|
||
|
|
```
|
||
|
|
|
||
|
|
### With Backend Integration
|
||
|
|
```typescript
|
||
|
|
const handleMessage = async (message: string) => {
|
||
|
|
const response = await fetch('/api/mascot/chat', {
|
||
|
|
method: 'POST',
|
||
|
|
body: JSON.stringify({ message, context })
|
||
|
|
});
|
||
|
|
return response.json();
|
||
|
|
};
|
||
|
|
|
||
|
|
<MascotChatbot
|
||
|
|
onSendMessage={handleMessage}
|
||
|
|
/>
|
||
|
|
```
|
||
|
|
|
||
|
|
### With Discord Gateway
|
||
|
|
```typescript
|
||
|
|
const handleMessage = async (message: string) => {
|
||
|
|
// Get enriched context from Discord
|
||
|
|
const guildContext = await getDiscordGuildContext(guildId);
|
||
|
|
|
||
|
|
// Generate response with context
|
||
|
|
return generateResponse(message, guildContext);
|
||
|
|
};
|
||
|
|
```
|
||
|
|
|
||
|
|
## Chat Interface
|
||
|
|
|
||
|
|
### Visual Design
|
||
|
|
- **Header:** Gradient background (primary color), mascot info, controls
|
||
|
|
- **Messages:** Distinct bubbles for user (right) and mascot (left)
|
||
|
|
- **Input:** Text field with send button
|
||
|
|
- **Animations:** Spring physics for smooth entrance/exit
|
||
|
|
- **Typing Indicator:** Animated dots while processing
|
||
|
|
|
||
|
|
### Keyboard Shortcuts
|
||
|
|
- **Enter:** Send message
|
||
|
|
- **Esc:** Close chat (future enhancement)
|
||
|
|
- **Tab:** Minimize/restore window
|
||
|
|
|
||
|
|
## Integration Points
|
||
|
|
|
||
|
|
### 1. In App.tsx
|
||
|
|
```typescript
|
||
|
|
const mascotChat = useMascotChat({
|
||
|
|
messageCount: messages.messages.length,
|
||
|
|
activeParticipants: uniqueUserCount,
|
||
|
|
lastActivity: activityStatus,
|
||
|
|
topicsDiscussed: extractTopics(messages),
|
||
|
|
});
|
||
|
|
|
||
|
|
<MascotChatbot
|
||
|
|
isOpen={isMascotChatOpen}
|
||
|
|
onSetIsOpen={setIsMascotChatOpen}
|
||
|
|
onSendMessage={mascotChat.handleSendMessage}
|
||
|
|
/>
|
||
|
|
```
|
||
|
|
|
||
|
|
### 2. Position
|
||
|
|
- **Fixed:** bottom-right corner (bottom-6, right-6)
|
||
|
|
- **Z-index:** High (shadow-2xl ensures visibility)
|
||
|
|
- **Responsive:** Adapts to mobile/tablet
|
||
|
|
|
||
|
|
### 3. State Management
|
||
|
|
- `isMascotChatOpen`: Boolean flag for visibility
|
||
|
|
- `messages`: Array of ChatMessage objects
|
||
|
|
- `input`: Current user input text
|
||
|
|
- `loading`: Processing state
|
||
|
|
- `isMinimized`: Window state
|
||
|
|
|
||
|
|
## Extending with Backend
|
||
|
|
|
||
|
|
### Example: Express Backend Endpoint
|
||
|
|
```typescript
|
||
|
|
// POST /api/mascot/chat
|
||
|
|
app.post('/api/mascot/chat', async (req, res) => {
|
||
|
|
const { message, context } = req.body;
|
||
|
|
|
||
|
|
// Process with AI/LLM
|
||
|
|
const response = await callAI(message, context);
|
||
|
|
|
||
|
|
res.json({ response });
|
||
|
|
});
|
||
|
|
```
|
||
|
|
|
||
|
|
### Example: Discord Gateway Integration
|
||
|
|
```typescript
|
||
|
|
async function getGuildContext(guildId: string) {
|
||
|
|
const messages = await getGuildMessages(guildId);
|
||
|
|
const members = await getActiveMembers(guildId);
|
||
|
|
|
||
|
|
return {
|
||
|
|
messageCount: messages.length,
|
||
|
|
activeParticipants: members.length,
|
||
|
|
recentTopics: extractTopics(messages),
|
||
|
|
serverHealth: analyzeHealth(messages, members)
|
||
|
|
};
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
## Customization
|
||
|
|
|
||
|
|
### Change Mascot Avatar
|
||
|
|
```typescript
|
||
|
|
<MascotChatbot
|
||
|
|
mascotAvatar="https://your-custom-avatar.com/image.png"
|
||
|
|
/>
|
||
|
|
```
|
||
|
|
|
||
|
|
### Change Mascot Name
|
||
|
|
```typescript
|
||
|
|
<MascotChatbot
|
||
|
|
mascotName="Your Mascot Name"
|
||
|
|
/>
|
||
|
|
```
|
||
|
|
|
||
|
|
### Customize Responses
|
||
|
|
Edit `generateMascotResponse()` in `useMascotChat.ts`:
|
||
|
|
```typescript
|
||
|
|
function generateMascotResponse(input: string, context?: ChatContext): string {
|
||
|
|
const lower = input.toLowerCase();
|
||
|
|
|
||
|
|
// Add custom keywords
|
||
|
|
if (lower.includes('your-keyword')) {
|
||
|
|
return 'Your custom response';
|
||
|
|
}
|
||
|
|
|
||
|
|
// ... rest of logic
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### Theme Colors
|
||
|
|
Edit Tailwind classes in `MascotChatbot.tsx`:
|
||
|
|
```typescript
|
||
|
|
// Change primary color
|
||
|
|
className="bg-gradient-to-r from-primary to-primary/80"
|
||
|
|
|
||
|
|
// Change to custom color
|
||
|
|
className="bg-gradient-to-r from-blue-500 to-blue-600"
|
||
|
|
```
|
||
|
|
|
||
|
|
## Performance
|
||
|
|
|
||
|
|
### Optimizations
|
||
|
|
- ✅ Lazy-loaded component (renders only when needed)
|
||
|
|
- ✅ Memoized responses
|
||
|
|
- ✅ Efficient message rendering (virtualization possible)
|
||
|
|
- ✅ Minimal re-renders with useCallback
|
||
|
|
|
||
|
|
### Bundle Impact
|
||
|
|
- Component: ~15 KB
|
||
|
|
- Hook: ~5 KB
|
||
|
|
- Total: ~20 KB (gzipped)
|
||
|
|
|
||
|
|
## Future Enhancements
|
||
|
|
|
||
|
|
- [ ] Multi-language support
|
||
|
|
- [ ] Message persistence to database
|
||
|
|
- [ ] Advanced NLP/AI integration
|
||
|
|
- [ ] Export chat history
|
||
|
|
- [ ] Voice input/output
|
||
|
|
- [ ] Emoji reactions
|
||
|
|
- [ ] Suggested quick replies
|
||
|
|
- [ ] User preferences storage
|
||
|
|
- [ ] Chat analytics
|
||
|
|
- [ ] Integration with Discord Rich Presence
|
||
|
|
|
||
|
|
## Troubleshooting
|
||
|
|
|
||
|
|
### Chat window not appearing
|
||
|
|
- Check `isOpen` prop is being set correctly
|
||
|
|
- Verify `onSetIsOpen` callback works
|
||
|
|
- Check z-index conflicts with other overlays
|
||
|
|
|
||
|
|
### Messages not sending
|
||
|
|
- Check `onSendMessage` is provided
|
||
|
|
- Verify message is not empty
|
||
|
|
- Check browser console for errors
|
||
|
|
|
||
|
|
### Responses not intelligent
|
||
|
|
- Add more keyword patterns
|
||
|
|
- Integrate with backend for better AI
|
||
|
|
- Provide context data to useMascotChat
|
||
|
|
|
||
|
|
## Testing
|
||
|
|
|
||
|
|
```typescript
|
||
|
|
// Test basic rendering
|
||
|
|
render(<MascotChatbot isOpen={true} />);
|
||
|
|
|
||
|
|
// Test message sending
|
||
|
|
const mockOnSend = jest.fn().mockResolvedValue('Response');
|
||
|
|
fireEvent.change(input, { target: { value: 'Hello' } });
|
||
|
|
fireEvent.click(sendButton);
|
||
|
|
expect(mockOnSend).toHaveBeenCalledWith('Hello');
|
||
|
|
|
||
|
|
// Test animations
|
||
|
|
expect(screen.getByRole('dialog')).toHaveClass('motion-div');
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
**Status:** ✅ Production Ready
|
||
|
|
**Version:** 1.0.0
|
||
|
|
**Last Updated:** 2026-06-03
|