Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
*.terraform.lock.hcl
.terraform.lock.hcl
*src/.env
app-logs.zip
LogFiles
deploy.log

# .tfstate files
*.tfstate
Expand Down
4 changes: 2 additions & 2 deletions TROUBLESHOOTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -347,7 +347,7 @@ terraform apply

<!-- START BADGE -->
<div align="center">
<img src="https://img.shields.io/badge/Total%20views-1410-limegreen" alt="Total views">
<p>Refresh Date: 2025-11-24</p>
<img src="https://img.shields.io/badge/Total%20views-1543-limegreen" alt="Total views">
<p>Refresh Date: 2025-11-25</p>
</div>
<!-- END BADGE -->
4 changes: 2 additions & 2 deletions src/DATA_PIPELINE.md
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,7 @@ az search index show-statistics \

<!-- START BADGE -->
<div align="center">
<img src="https://img.shields.io/badge/Total%20views-1410-limegreen" alt="Total views">
<p>Refresh Date: 2025-11-24</p>
<img src="https://img.shields.io/badge/Total%20views-1543-limegreen" alt="Total views">
<p>Refresh Date: 2025-11-25</p>
</div>
<!-- END BADGE -->
16 changes: 16 additions & 0 deletions src/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
FROM python:3.11-slim

WORKDIR /app

# Copy requirements first for better caching
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# Copy application code
COPY . .

# Expose port
EXPOSE 8000

# Run the application
CMD ["uvicorn", "chat_app:app", "--host", "0.0.0.0", "--port", "8000"]
1 change: 1 addition & 0 deletions src/app/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Zava AI Shopping Assistant Application
2 changes: 2 additions & 0 deletions src/app/static/.gitkeep
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Placeholder file to preserve the static directory in git
# Add static assets like CSS, JavaScript, or images here as needed
306 changes: 306 additions & 0 deletions src/app/templates/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,306 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Zava AI Shopping Assistant</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}

body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
}

.chat-container {
width: 90%;
max-width: 800px;
height: 90vh;
background: white;
border-radius: 20px;
box-shadow: 0 20px 60px rgba(0,0,0,0.3);
display: flex;
flex-direction: column;
overflow: hidden;
}

.chat-header {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
padding: 20px;
text-align: center;
}

.chat-header h1 {
font-size: 24px;
margin-bottom: 5px;
}

.chat-header p {
font-size: 14px;
opacity: 0.9;
}

.chat-messages {
flex: 1;
overflow-y: auto;
padding: 20px;
background: #f7f7f7;
}

.message {
margin-bottom: 15px;
display: flex;
animation: fadeIn 0.3s ease-in;
}

@keyframes fadeIn {
from { opacity: 0; transform: translateY(10px); }
to { opacity: 1; transform: translateY(0); }
}

.message.user {
justify-content: flex-end;
}

.message-content {
max-width: 70%;
padding: 12px 16px;
border-radius: 18px;
word-wrap: break-word;
}

.message.user .message-content {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
}

.message.assistant .message-content {
background: white;
color: #333;
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
}

.message.system .message-content {
background: #fff3cd;
color: #856404;
max-width: 100%;
text-align: center;
}

.chat-input-container {
padding: 20px;
background: white;
border-top: 1px solid #e0e0e0;
display: flex;
gap: 10px;
}

#messageInput {
flex: 1;
padding: 12px 16px;
border: 2px solid #e0e0e0;
border-radius: 25px;
font-size: 14px;
outline: none;
transition: border-color 0.3s;
}

#messageInput:focus {
border-color: #667eea;
}

#sendButton {
padding: 12px 30px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
border: none;
border-radius: 25px;
font-size: 14px;
font-weight: 600;
cursor: pointer;
transition: transform 0.2s;
}

#sendButton:hover {
transform: scale(1.05);
}

#sendButton:active {
transform: scale(0.95);
}

#sendButton:disabled {
opacity: 0.5;
cursor: not-allowed;
}

.typing-indicator {
display: none;
padding: 12px 16px;
background: white;
border-radius: 18px;
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
width: fit-content;
}

.typing-indicator.active {
display: block;
}

.typing-indicator span {
height: 8px;
width: 8px;
background: #667eea;
border-radius: 50%;
display: inline-block;
margin: 0 2px;
animation: typing 1.4s infinite;
}

.typing-indicator span:nth-child(2) {
animation-delay: 0.2s;
}

.typing-indicator span:nth-child(3) {
animation-delay: 0.4s;
}

@keyframes typing {
0%, 60%, 100% { transform: translateY(0); }
30% { transform: translateY(-10px); }
}
</style>
</head>
<body>
<div class="chat-container">
<div class="chat-header">
<h1>🏠 Zava AI Shopping Assistant</h1>
<p>Your DIY Project Helper</p>
</div>

<div class="chat-messages" id="chatMessages">
<div class="message system">
<div class="message-content">
Welcome to Zava! I'm here to help you with your DIY projects. Ask me about our products, get recommendations, or find store locations.
</div>
</div>
</div>

<div class="chat-input-container">
<input type="text" id="messageInput" placeholder="Ask about paints, tools, or DIY tips..." />
<button id="sendButton">Send</button>
</div>
</div>

<script>
const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
const ws = new WebSocket(`${protocol}//${window.location.host}/ws`);
const messagesContainer = document.getElementById('chatMessages');
const messageInput = document.getElementById('messageInput');
const sendButton = document.getElementById('sendButton');

let typingIndicator = null;

ws.onopen = () => {
console.log('WebSocket connected');
addSystemMessage('Connected to Zava Assistant');
};

ws.onclose = () => {
console.log('WebSocket disconnected');
addSystemMessage('Disconnected from server');
};

ws.onerror = (error) => {
console.error('WebSocket error:', error);
addSystemMessage('Connection error occurred');
};

ws.onmessage = (event) => {
const data = JSON.parse(event.data);
removeTypingIndicator();

if (data.answer) {
addMessage(data.answer, 'assistant');
}

if (data.error) {
addSystemMessage(`Error: ${data.error}`);
}
};

function addMessage(text, type) {
const messageDiv = document.createElement('div');
messageDiv.className = `message ${type}`;

const contentDiv = document.createElement('div');
contentDiv.className = 'message-content';
contentDiv.textContent = text;

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

function addSystemMessage(text) {
const messageDiv = document.createElement('div');
messageDiv.className = 'message system';

const contentDiv = document.createElement('div');
contentDiv.className = 'message-content';
contentDiv.textContent = text;

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

function showTypingIndicator() {
typingIndicator = document.createElement('div');
typingIndicator.className = 'message assistant';

const indicator = document.createElement('div');
indicator.className = 'typing-indicator active';
indicator.innerHTML = '<span></span><span></span><span></span>';

typingIndicator.appendChild(indicator);
messagesContainer.appendChild(typingIndicator);
messagesContainer.scrollTop = messagesContainer.scrollHeight;
}

function removeTypingIndicator() {
if (typingIndicator) {
typingIndicator.remove();
typingIndicator = null;
}
}

function sendMessage() {
const message = messageInput.value.trim();
if (!message || ws.readyState !== WebSocket.OPEN) return;

addMessage(message, 'user');
ws.send(message);
messageInput.value = '';
showTypingIndicator();
}

sendButton.addEventListener('click', sendMessage);

messageInput.addEventListener('keypress', (e) => {
if (e.key === 'Enter') {
sendMessage();
}
});
</script>
</body>
</html>
1 change: 1 addition & 0 deletions src/app/tools/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Agent tools module
Loading