AWS Builder Center
Building Stacks: Integrate your AI Agent into a Website

Building Stacks: Integrate your AI Agent into a Website

Hackathon Challenge #7: Use your AI agent to create a fully functional chatbot in your AWS Amplify Webpage.

AWS Solutions Archtiect
Welcome to Day 7 of Challenge #2 ! Today, you'll combine the power of your AI agent from Day 6 with the polished website from Challenge 5 of Week 1 to create a complete real-time chat experience. You'll integrate your existing WebSocket API with your website to build a production-ready chat application.

What You Will Accomplish Today

✅ Integrate your existing WebSocket API from Challenge 6 with your website
✅ Add a responsive chat interface to your existing website
✅ Deploy the complete solution using Amplify
✅ Test real-time bidirectional messaging
✅ Create a seamless user experience combining static site + AI chat

What You Will Need

  • Your website from Challenge 5  of Week 1  (deployed on Amplify) 🌐
    • Alternative: If you haven't completed Challenge 5, you can use and existing website you have or this sample React app  as your base website
  • Your AI agent and WebSocket API from Challenge 6 (Lambda + API Gateway) 🤖
  • About 45 minutes ⏰

Step 1: Understanding the Integration Architecture 🏗️

Today we're combining two powerful components you've already built to create a complete user experience.

Your Existing Components

From Challenge 5 of Week 1, you have made:
  • A static website deployed on Amplify
  • Professional styling and responsive design
  • An automated deployment pipeline via GitHub
From Challenge 6, you have:
  • A Lambda function with Strands AI agent
  • A API Gateway WebSocket API for real-time communication
  • A complete chat backend that processes messages

How They Will Work Together

  1. User visits your website - Loads your existing Amplify-hosted site
  2. Chat interface initializes - Connects to your existing WebSocket API
  3. User sends message - Goes through your existing Lambda function
  4. AI processes and responds - Using your existing Strands agent
  5. Response displays instantly - Real-time update in the website chat

Step 2: Preparing Your Website Repository 📁

Let's add the chat interface to your existing website from Challenge 5 of Week 1.

Option A: Using Your Existing Website

If you completed Challenge 5 of Week 1:
Clone your repository locally:
1
2
git clone https://github.com/YOUR-USERNAME/rift-rewind-project.git
cd rift-rewind-project

Option B: Using Sample Application

If you haven't completed Challenge 5, set up a base website:
Follow the Amplify React Quickstart:
  • Visit: https://docs.amplify.aws/react/start/quickstart/ 
  • Complete the "Prerequisites" and "Build your frontend" sections
  • Deploy to Amplify using the GitHub integration
  • Gather the WebSocket API from your previous challenge
  • Return here once you have a live website

Step 3: Adding Chat Interface to Your Website 💬

Now let's integrate a beautiful chat interface into your existing website that connects to your Challenge 6 WebSocket API.

Create Chat HTML Structure

Add this chat interface to your existing index.html (or create a new chat component if using React):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
<!-- Add this CSS to your existing styles.css or in a <style> tag -->
<style>
.chat-container {
position: fixed;
bottom: 20px;
right: 20px;
width: 350px;
height: 500px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border-radius: 15px;
box-shadow: 0 10px 30px rgba(0,0,0,0.3);
display: flex;
flex-direction: column;
z-index: 1000;
transition: transform 0.3s ease;
}

.chat-container.minimized {
height: 60px;
transform: translateY(440px);
}

.chat-header {
background: rgba(255,255,255,0.1);
padding: 15px;
border-radius: 15px 15px 0 0;
color: white;
font-weight: bold;
cursor: pointer;
display: flex;
justify-content: space-between;
align-items: center;
}

.chat-messages {
flex: 1;
padding: 15px;
overflow-y: auto;
background: rgba(255,255,255,0.95);
margin: 0 10px;
border-radius: 10px;
max-height: 350px;
}

.message {
margin-bottom: 10px;
padding: 8px 12px;
border-radius: 15px;
max-width: 80%;
word-wrap: break-word;
}

.user-message {
background: #007bff;
color: white;
margin-left: auto;
text-align: right;
}

.assistant-message {
background: #f1f1f1;
color: #333;
margin-right: auto;
}

.chat-input-container {
padding: 15px;
display: flex;
gap: 10px;
}

.chat-input {
flex: 1;
padding: 10px;
border: none;
border-radius: 20px;
outline: none;
background: rgba(255,255,255,0.9);
}

.chat-send-btn {
background: #28a745;
color: white;
border: none;
border-radius: 50%;
width: 40px;
height: 40px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
transition: background 0.3s ease;
}

.chat-send-btn:hover {
background: #218838;
}

.typing-indicator {
padding: 8px 12px;
background: #f1f1f1;
border-radius: 15px;
margin-bottom: 10px;
max-width: 80%;
font-style: italic;
color: #666;
}

.connection-status {
font-size: 12px;
opacity: 0.8;
}
</style>

<!-- Add this chat container to your HTML body -->
<div class="chat-container" id="chatContainer">
<div class="chat-header" onclick="toggleChat()">
<span>🎮 League Expert Chat</span>
<span class="connection-status" id="connectionStatus">Connecting...</span>
</div>

<div class="chat-messages" id="chatMessages">
<div class="message assistant-message">
👋 Hi! I'm your League of Legends expert. Ask me about stats, champions, items, builds, or any game mechanics!
</div>
</div>

<div class="chat-input-container">
<input
type="text"
class="chat-input"
id="chatInput"
placeholder="Ask about League of Legends..."
onkeypress="handleKeyPress(event)"
>

<button class="chat-send-btn" onclick="sendMessage()">
➤
</button>
</div>
</div>

Add WebSocket JavaScript Integration

Add this JavaScript to connect to your existing Challenge 6 WebSocket API.
You can find the value for WEBSOCKET_URL in your AWS Console:
  • API Gateway Console → Your WebSocket API → Settings → WebSocket URL
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
// Your WebSocket API configuration from Challenge 6
const WEBSOCKET_URL = 'wss://API-ID.execute-api.PLACEHOLDER-REGION.amazonaws.com/production/';

let socket = null;
let isConnected = false;
let isMinimized = false;
let messageQueue = [];

// WebSocket Connection Management
function connectToWebSocket() {
try {
updateConnectionStatus('Connecting...');

// Create WebSocket connection to your existing API Gateway
socket = new WebSocket(WEBSOCKET_URL);

socket.onopen = () => {
console.log('Connected to WebSocket API');
updateConnectionStatus('Connected');
isConnected = true;

// Process any queued messages
while (messageQueue.length > 0) {
const queuedMessage = messageQueue.shift();
socket.send(JSON.stringify(queuedMessage));
}
};

socket.onmessage = (event) => {
try {
const response = JSON.parse(event.data);
console.log('Received:', response);

// Handle different message types from your Challenge 6 API
if (response.type === 'chunk' && response.content) {
displayMessage(response.content, 'assistant');
hideTypingIndicator();
} else if (response.type === 'end') {
// Response complete
hideTypingIndicator();
} else if (response.type === 'error') {
hideTypingIndicator();
displayMessage('Sorry, I encountered an error processing your message.', 'assistant');
}
} catch (error) {
console.error('Error parsing message:', error);
hideTypingIndicator();
}
};

socket.onclose = (evt) => {
console.log('WebSocket closed:', evt.reason);
isConnected = false;
updateConnectionStatus('Disconnected');

// Attempt to reconnect after 3 seconds
setTimeout(connectToWebSocket, 3000);
};

socket.onerror = (error) => {
console.error('WebSocket error:', error);
updateConnectionStatus('Error');
isConnected = false;
};

} catch (error) {
console.error('Connection error:', error);
updateConnectionStatus('Failed');
}
}

// Chat Interface Functions
function sendMessage() {
const input = document.getElementById('chatInput');
const message = input.value.trim();

if (!message) return;

// Display user message immediately
displayMessage(message, 'user');
showTypingIndicator();

// Clear input
input.value = '';

// Prepare message in the format your Challenge 6 Lambda expects
const messageData = {
messages: [
{ role: "user", content: message }
]
};

// Send message through WebSocket
if (isConnected && socket.readyState === WebSocket.OPEN) {
socket.send(JSON.stringify(messageData));
} else {
// Queue message if not connected
messageQueue.push(messageData);
updateConnectionStatus('Reconnecting...');
connectToWebSocket();
}
}

function displayMessage(content, role) {
const messagesContainer = document.getElementById('chatMessages');
const messageDiv = document.createElement('div');

messageDiv.className = `message ${role}-message`;
messageDiv.textContent = content;

messagesContainer.appendChild(messageDiv);
messagesContainer.scrollTop = messagesContainer.scrollHeight;
}

function showTypingIndicator() {
const messagesContainer = document.getElementById('chatMessages');
const typingDiv = document.createElement('div');

typingDiv.className = 'typing-indicator';
typingDiv.id = 'typingIndicator';
typingDiv.textContent = '🤔 Thinking...';

messagesContainer.appendChild(typingDiv);
messagesContainer.scrollTop = messagesContainer.scrollHeight;
}

function hideTypingIndicator() {
const typingIndicator = document.getElementById('typingIndicator');
if (typingIndicator) {
typingIndicator.remove();
}
}

function updateConnectionStatus(status) {
const statusElement = document.getElementById('connectionStatus');
statusElement.textContent = status;

// Add visual indicators
statusElement.style.color = status === 'Connected' ? '#90EE90' :
status === 'Connecting...' ? '#FFD700' : '#FF6B6B';
}

function toggleChat() {
const chatContainer = document.getElementById('chatContainer');
isMinimized = !isMinimized;

if (isMinimized) {
chatContainer.classList.add('minimized');
} else {
chatContainer.classList.remove('minimized');
}
}

function handleKeyPress(event) {
if (event.key === 'Enter') {
sendMessage();
}
}

// Initialize connection when page loads
document.addEventListener('DOMContentLoaded', () => {
connectToWebSocket();
});

Step 4: Deploy Your Enhanced Website 🚀

Now let's deploy your website with the integrated chat functionality using your existing Amplify setup.

Update Your GitHub Repository

Add your changes:
1
2
3
git add .
git commit -m "Add real-time AI chat integration with existing WebSocket API"
git push origin main
Watch Amplify deploy - Your changes will automatically deploy within 2-3 minutes thanks to the pipeline you set up in Challenge 5 of Week 1

Verify Your Integration

Check your existing Lambda function - Make sure it's still running from Challenge 6:
  • Go to Lambda Console
  • Find your chat-agent-handler function
  • Verify it has the correct permissions and layer
Check your WebSocket API - Ensure it's properly configured:
  • Go to API Gateway Console
  • Find your WebSocket API from Challenge 6
  • Verify it's deployed to the production stage

Step 5: Test Your Complete Application 🧪

Let's verify that your website and chat integration work seamlessly together.

Test the Complete Flow

Open your Amplify URL - Visit your deployed website from Challenge 5 of Week 1
Test website functionality:
  1. ✅ Your original website loads correctly
  2. ✅ All existing features work as expected
  3. ✅ Chat window appears in bottom-right corner
Test chat integration:
  1. ✅ Connection status shows "Connected"
  2. ✅ Send a message
  3. ✅ See typing indicator appear
  4. ✅ Receive AI response with accurate game data from your Challenge 6 agent
  5. ✅ Test follow-up questions for conversation flow
  6. ✅ Minimize/maximize chat window

Monitor Your Existing Infrastructure

Lambda Function (from Challenge 6):
  • Check CloudWatch logs for function invocations
  • Verify messages are being processed correctly
  • Monitor for any errors or timeouts
API Gateway WebSocket:
  • Check connection metrics
  • Verify messages are flowing through properly
Amplify Hosting:
  • Confirm website loads quickly
  • Check that chat interface displays correctly across devices

Step 6: Enhancing Your Integrated Experience 🎨

Now that your basic integration works, let's add some polish to make it feel like a seamless experience.

Add Loading States

Enhance the user experience with better loading indicators:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// Add this to your existing JavaScript
function showConnectingState() {
const messagesContainer = document.getElementById('chatMessages');
const connectingDiv = document.createElement('div');

connectingDiv.className = 'typing-indicator';
connectingDiv.id = 'connectingIndicator';
connectingDiv.textContent = '🔌 Connecting to League Expert...';

messagesContainer.appendChild(connectingDiv);
}

function hideConnectingState() {
const connectingIndicator = document.getElementById('connectingIndicator');
if (connectingIndicator) {
connectingIndicator.remove();
}
}

OPTIONAL: Add Chat Persistence

Store chat history in your browser's local storage so conversations persist across page reloads:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// Add to your existing JavaScript
function saveChatHistory() {
const messages = Array.from(document.querySelectorAll('.message')).map(msg => ({
content: msg.textContent,
role: msg.classList.contains('user-message') ? 'user' : 'assistant'
}));
localStorage.setItem('chatHistory', JSON.stringify(messages));
}

function loadChatHistory() {
const history = localStorage.getItem('chatHistory');
if (history) {
const messages = JSON.parse(history);
const messagesContainer = document.getElementById('chatMessages');

// Clear default message
messagesContainer.innerHTML = '';

messages.forEach(msg => {
displayMessage(msg.content, msg.role);
});
}
}

// Call loadChatHistory() in your DOMContentLoaded event

OPTIONAL: Add Mobile Responsiveness

Make your chat work great on mobile devices:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
/* Add to your existing CSS */
@media (max-width: 768px) {
.chat-container {
width: calc(100vw - 20px);
height: 400px;
bottom: 10px;
right: 10px;
left: 10px;
}

.chat-container.minimized {
transform: translateY(340px);
}
}

Troubleshooting Common Issues 🔍

WebSocket Connection Fails

Problem: Connection status shows "Failed" or "Error"
Solutions:
  • ✅ Verify your WebSocket URL from Challenge 6 is correct
  • ✅ Check that your API Gateway is deployed to production stage
  • ✅ Ensure Lambda function from Challenge 6 is still active
  • ✅ Check browser console for detailed error messages

Messages Not Appearing

Problem: User sends message but no AI response appears
Solutions:
  • ✅ Check Lambda function logs in CloudWatch
  • ✅ Verify your Challenge 6 Lambda function is working independently
  • ✅ Test your WebSocket API directly using a WebSocket client
  • ✅ Check that message format matches what your Lambda expects

Chat Interface Issues

Problem: Chat window doesn't display properly
Solutions:
  • ✅ Check browser developer tools for CSS conflicts with your existing website
  • ✅ Verify all CSS classes are properly defined
  • ✅ Test in different browsers for compatibility
  • ✅ Ensure JavaScript is loading without errors

Amplify Deployment Issues

Problem: Changes don't appear on your live website
Solutions:
  • ✅ Check Amplify console for build status and errors
  • ✅ Verify your GitHub repository has the latest changes
  • ✅ Clear browser cache and try again
  • ✅ Check Amplify build logs for any deployment issues

Conclusion 🎉

Congratulations! You've successfully integrated your AI chat system with your website to create a complete user experience. You now have:
✅ Seamless integration between your static website and AI chat backend
✅ Real-time communication using your existing WebSocket infrastructure
✅ Professional user interface that complements your website design
✅ Scalable architecture leveraging your Challenge 6 backend
✅ Automated deployment through your existing Amplify pipeline
GG on creating your complete integrated application! 🎮🚀
Any opinions in this article are those of the individual author and may not reflect the opinions of AWS.
Enjoyed reading this content? Let the author know!

Your likes, comments, shares, and saves help creators reach more builders.

Loading recommendations

Loading article