|
|
<!DOCTYPE html> |
|
|
<html lang="en"> |
|
|
<head> |
|
|
<meta charset="UTF-8"> |
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|
|
<title>Amazon Multimodal Assistant - Redesigned</title> |
|
|
<script src="https://cdn.tailwindcss.com"></script> |
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/animejs/3.2.1/anime.min.js"></script> |
|
|
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet"> |
|
|
<style> |
|
|
:root { |
|
|
--amazon-orange: #FF9900; |
|
|
--amazon-orange-dark: #E68A00; |
|
|
--amazon-blue: #146EB4; |
|
|
--amazon-header: #131921; |
|
|
--amazon-subnav: #232F3E; |
|
|
--page-bg: #FAFAFA; |
|
|
--panel-bg: #FFFFFF; |
|
|
--panel-muted: #F9FAFB; |
|
|
--border-subtle: #E5E7EB; |
|
|
--text-main: #2D3748; |
|
|
--text-muted: #4B5563; |
|
|
--success: #10B981; |
|
|
--warning: #F59E0B; |
|
|
} |
|
|
|
|
|
* { font-family: 'Inter', sans-serif; } |
|
|
body { background-color: var(--page-bg); color: var(--text-main); } |
|
|
|
|
|
.glass-effect { |
|
|
background: rgba(255, 255, 255, 0.25); |
|
|
backdrop-filter: blur(10px); |
|
|
border: 1px solid rgba(255, 255, 255, 0.18); |
|
|
} |
|
|
|
|
|
.hover-lift { transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); } |
|
|
.hover-lift:hover { |
|
|
transform: translateY(-2px); |
|
|
box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04); |
|
|
} |
|
|
|
|
|
.search-input:focus { |
|
|
box-shadow: 0 0 0 3px rgba(255, 153, 0, 0.1); |
|
|
border-color: var(--amazon-orange); |
|
|
} |
|
|
|
|
|
|
|
|
.product-card { transition: all 0.2s ease; } |
|
|
.product-card:hover { |
|
|
transform: scale(1.02); |
|
|
box-shadow: 0 8px 25px -5px rgba(0, 0, 0, 0.1); |
|
|
} |
|
|
|
|
|
.similarity-bar { |
|
|
background: linear-gradient(90deg, var(--amazon-orange) 0%, var(--amazon-orange-dark) 100%); |
|
|
height: 4px; |
|
|
border-radius: 2px; |
|
|
transition: width 0.8s ease; |
|
|
} |
|
|
|
|
|
.loading-skeleton { |
|
|
background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%); |
|
|
background-size: 200% 100%; |
|
|
animation: loading 1.5s infinite; |
|
|
} |
|
|
|
|
|
@keyframes loading { |
|
|
0% { background-position: 200% 0; } |
|
|
100% { background-position: -200% 0; } |
|
|
} |
|
|
|
|
|
.fade-in { animation: fadeIn 0.5s ease-in; } |
|
|
@keyframes fadeIn { |
|
|
from { opacity: 0; transform: translateY(20px); } |
|
|
to { opacity: 1; transform: translateY(0); } |
|
|
} |
|
|
|
|
|
.status-indicator { animation: pulse 2s infinite; } |
|
|
@keyframes pulse { |
|
|
0%, 100% { opacity: 1; } |
|
|
50% { opacity: 0.7; } |
|
|
} |
|
|
|
|
|
.micro-interaction { transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1); } |
|
|
.micro-interaction:active { transform: scale(0.98); } |
|
|
|
|
|
.answer-card { |
|
|
background: linear-gradient(135deg, rgba(255, 255, 255, 0.9) 0%, rgba(249, 250, 251, 0.9) 100%); |
|
|
border: 1px solid rgba(229, 231, 235, 0.5); |
|
|
} |
|
|
|
|
|
.evidence-highlight { |
|
|
background: linear-gradient(135deg, rgba(255, 153, 0, 0.1) 0%, rgba(255, 153, 0, 0.05) 100%); |
|
|
border: 1px solid rgba(255, 153, 0, 0.2); |
|
|
} |
|
|
|
|
|
.header-bg { background: linear-gradient(135deg, var(--amazon-header) 0%, var(--amazon-subnav) 100%); } |
|
|
|
|
|
.search-button { |
|
|
background: linear-gradient(135deg, var(--amazon-orange) 0%, var(--amazon-orange-dark) 100%); |
|
|
transition: all 0.3s ease; |
|
|
} |
|
|
.search-button:hover { |
|
|
background: linear-gradient(135deg, var(--amazon-orange-dark) 0%, var(--amazon-orange) 100%); |
|
|
transform: translateY(-1px); |
|
|
box-shadow: 0 4px 12px rgba(255, 153, 0, 0.3); |
|
|
} |
|
|
|
|
|
.upload-area { border: 2px dashed #D1D5DB; transition: all 0.3s ease; } |
|
|
.upload-area:hover { |
|
|
border-color: var(--amazon-orange); |
|
|
background-color: rgba(255, 153, 0, 0.05); |
|
|
} |
|
|
.upload-area.dragover { |
|
|
border-color: var(--amazon-orange); |
|
|
background-color: rgba(255, 153, 0, 0.1); |
|
|
} |
|
|
|
|
|
@media (max-width: 1024px) { |
|
|
.three-column-layout { grid-template-columns: 1fr; gap: 1rem; } |
|
|
.sidebar-panel { order: -1; } |
|
|
} |
|
|
</style> |
|
|
</head> |
|
|
<body class="min-h-screen flex flex-col"> |
|
|
<header class="header-bg text-white shadow-lg"> |
|
|
<div class="container mx-auto px-6 py-4"> |
|
|
<div class="flex items-center justify-between"> |
|
|
<div class="flex items-center space-x-4"> |
|
|
<img src="amazon-logo.png" onerror="this.style.display='none'" alt="Amazon" class="h-8 w-auto"> |
|
|
<div> |
|
|
<h1 class="text-2xl font-bold">Multimodal Assistant</h1> |
|
|
<p class="text-sm text-gray-300">AI-powered product search with CLIP + GPT-4</p> |
|
|
</div> |
|
|
</div> |
|
|
<div class="flex items-center space-x-4"> |
|
|
<div class="flex items-center space-x-2 glass-effect px-3 py-2 rounded-full"> |
|
|
<div class="w-2 h-2 bg-green-400 rounded-full status-indicator"></div> |
|
|
<span class="text-xs">Index Ready</span> |
|
|
</div> |
|
|
<div class="flex items-center space-x-2 glass-effect px-3 py-2 rounded-full"> |
|
|
<span class="text-xs">9,509 Products</span> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</header> |
|
|
|
|
|
<main class="container mx-auto px-6 py-8 flex-grow"> |
|
|
<div class="three-column-layout grid grid-cols-12 gap-6"> |
|
|
|
|
|
<div class="col-span-12 lg:col-span-4"> |
|
|
<div class="bg-white rounded-xl shadow-sm border border-gray-200 p-6 hover-lift"> |
|
|
<h2 class="text-xl font-semibold mb-4 text-gray-800">Search Query</h2> |
|
|
|
|
|
<div class="mb-6"> |
|
|
<label for="search-text" class="block text-sm font-medium text-gray-700 mb-2"> |
|
|
Describe what you're looking for |
|
|
</label> |
|
|
<textarea |
|
|
id="search-text" |
|
|
placeholder="e.g., 'Wireless earbuds with noise cancellation under $150' or 'What is this product and how is it used?'" |
|
|
class="search-input w-full p-4 border border-gray-300 rounded-lg resize-none focus:outline-none transition-all duration-200" |
|
|
rows="3" |
|
|
></textarea> |
|
|
</div> |
|
|
|
|
|
<div class="mb-6"> |
|
|
<label class="block text-sm font-medium text-gray-700 mb-2"> |
|
|
Upload product image (optional) |
|
|
</label> |
|
|
<div id="upload-area" class="upload-area rounded-lg p-8 text-center cursor-pointer"> |
|
|
<div id="upload-content"> |
|
|
<svg class="mx-auto h-12 w-12 text-gray-400 mb-4" stroke="currentColor" fill="none" viewBox="0 0 48 48"> |
|
|
<path d="M28 8H12a4 4 0 00-4 4v20m32-12v8m0 0v8a4 4 0 01-4 4H12a4 4 0 01-4-4v-4m32-4l-3.172-3.172a4 4 0 00-5.656 0L28 28M8 32l9.172-9.172a4 4 0 015.656 0L28 28m0 0l4 4m4-24h8m-4-4v8m-12 4h.02" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /> |
|
|
</svg> |
|
|
<p class="text-sm text-gray-600 mb-2"> |
|
|
<span class="font-medium text-orange-600">Click to upload</span> or drag and drop |
|
|
</p> |
|
|
<p class="text-xs text-gray-500">PNG, JPG up to 10MB</p> |
|
|
</div> |
|
|
<div id="image-preview" class="hidden relative"> |
|
|
<img id="preview-img" class="mx-auto max-h-32 rounded-lg shadow-sm" alt="Preview"> |
|
|
<button id="remove-image" class="mt-2 text-sm text-red-600 hover:text-red-800">Remove image</button> |
|
|
</div> |
|
|
</div> |
|
|
<input type="file" id="image-input" accept="image/*" class="hidden"> |
|
|
</div> |
|
|
|
|
|
<div class="mb-6"> |
|
|
<label class="block text-sm font-medium text-gray-700 mb-3">Search Mode</label> |
|
|
<div class="space-y-2"> |
|
|
<label class="flex items-center cursor-pointer"> |
|
|
<input type="radio" name="search-mode" value="text_only" class="text-orange-600 focus:ring-orange-500"> |
|
|
<span class="ml-2 text-sm text-gray-700">Text Only</span> |
|
|
</label> |
|
|
<label class="flex items-center cursor-pointer"> |
|
|
<input type="radio" name="search-mode" value="image_only" class="text-orange-600 focus:ring-orange-500"> |
|
|
<span class="ml-2 text-sm text-gray-700">Image Only</span> |
|
|
</label> |
|
|
<label class="flex items-center cursor-pointer"> |
|
|
<input type="radio" name="search-mode" value="multimodal" checked class="text-orange-600 focus:ring-orange-500"> |
|
|
<span class="ml-2 text-sm text-gray-700">Multimodal (Text + Image)</span> |
|
|
</label> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<button id="search-button" class="search-button w-full text-white font-semibold py-3 px-6 rounded-lg micro-interaction"> |
|
|
<span class="flex items-center justify-center"> |
|
|
<svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24"> |
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"></path> |
|
|
</svg> |
|
|
<span id="btn-text">Search Products</span> |
|
|
<div id="loading-state" class="hidden ml-2 w-4 h-4 border-2 border-white border-t-transparent rounded-full animate-spin"></div> |
|
|
</span> |
|
|
</button> |
|
|
|
|
|
<div class="mt-6 pt-6 border-t border-gray-100"> |
|
|
<div class="flex items-center justify-between mb-4"> |
|
|
<h3 class="text-sm font-semibold text-gray-800">History</h3> |
|
|
<button id="clear-history" class="text-xs text-red-600 hover:text-red-800">Clear</button> |
|
|
</div> |
|
|
<div id="history-container" class="space-y-2 max-h-48 overflow-y-auto pr-1"> |
|
|
<div class="text-xs text-gray-400 text-center py-2">No history yet</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<div class="col-span-12 lg:col-span-5"> |
|
|
<div id="query-card" class="bg-white rounded-xl shadow-sm border border-gray-200 p-6 mb-6 hover-lift hidden fade-in"> |
|
|
<div class="flex items-center justify-between mb-4"> |
|
|
<h3 class="text-lg font-semibold text-gray-800">Current Query</h3> |
|
|
<span id="retrieval-method" class="px-3 py-1 bg-orange-100 text-orange-800 text-xs font-medium rounded-full"> |
|
|
Multimodal Fusion |
|
|
</span> |
|
|
</div> |
|
|
<div id="query-content" class="text-gray-700 text-sm leading-relaxed font-medium"> |
|
|
</div> |
|
|
<div id="query-image" class="mt-4 hidden"> |
|
|
<img class="rounded-lg shadow-sm max-h-32 object-contain border border-gray-100" alt="Query image"> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<div id="answer-card" class="answer-card rounded-xl p-6 mb-6 hover-lift hidden fade-in"> |
|
|
<div class="flex items-center mb-4"> |
|
|
<div class="w-8 h-8 bg-gradient-to-br from-orange-400 to-orange-600 rounded-full flex items-center justify-center mr-3 shadow-md"> |
|
|
<svg class="w-4 h-4 text-white" fill="currentColor" viewBox="0 0 20 20"> |
|
|
<path d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"></path> |
|
|
</svg> |
|
|
</div> |
|
|
<h3 class="text-lg font-semibold text-gray-800">AI Assistant Answer</h3> |
|
|
</div> |
|
|
<div id="answer-content" class="text-gray-700 leading-relaxed text-sm whitespace-pre-wrap"> |
|
|
</div> |
|
|
<div class="mt-4 text-xs text-gray-500 flex items-center"> |
|
|
<span class="inline-block w-2 h-2 bg-green-500 rounded-full mr-2"></span> |
|
|
Generated using CLIP retrieval + GPT-4 reasoning |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<div id="evidence-card" class="evidence-highlight rounded-xl p-6 mb-6 hover-lift hidden fade-in"> |
|
|
<h4 class="text-md font-semibold text-gray-800 mb-3">π Grounding Evidence</h4> |
|
|
<div class="flex items-start space-x-4"> |
|
|
<div class="flex-shrink-0 bg-white p-1 rounded-lg border border-gray-200"> |
|
|
<img id="evidence-image" class="w-20 h-20 object-contain rounded-md" src="https://via.placeholder.com/150?text=Wait..." onerror="this.src='https://via.placeholder.com/150?text=No+Img'" alt="Evidence product"> |
|
|
</div> |
|
|
<div class="flex-1"> |
|
|
<h5 id="evidence-name" class="font-semibold text-gray-800 mb-1 text-sm line-clamp-2">Product Name</h5> |
|
|
<p id="evidence-category" class="text-xs text-gray-600 mb-2">Category</p> |
|
|
<div class="flex items-center space-x-2"> |
|
|
<span class="text-xs bg-orange-100 text-orange-800 px-2 py-1 rounded font-medium">Top Match</span> |
|
|
<span id="evidence-similarity" class="text-xs text-green-700 font-bold">95.2% match</span> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
<p class="text-xs text-gray-500 mt-4 italic"> |
|
|
The assistant's answer is primarily based on this product and similar items from the retrieved set. |
|
|
</p> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<div class="col-span-12 lg:col-span-3"> |
|
|
<div class="bg-white rounded-xl shadow-sm border border-gray-200 p-6 hover-lift h-full flex flex-col"> |
|
|
<div class="flex items-center justify-between mb-4 border-b border-gray-100 pb-3"> |
|
|
<h3 class="text-lg font-semibold text-gray-800">Retrieved Products</h3> |
|
|
<span id="results-count" class="text-xs font-medium bg-gray-100 text-gray-600 px-2 py-1 rounded-full">0 items</span> |
|
|
</div> |
|
|
|
|
|
<div id="results-container" class="space-y-3 flex-1 overflow-y-auto custom-scrollbar" style="max-height: 70vh;"> |
|
|
<div class="text-sm text-gray-400 text-center py-10"> |
|
|
Results from ChromaDB will appear here. |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</main> |
|
|
|
|
|
<footer class="bg-white border-t border-gray-200 mt-auto"> |
|
|
<div class="container mx-auto px-6 py-8"> |
|
|
<div class="grid grid-cols-1 md:grid-cols-3 gap-8 text-sm"> |
|
|
<div> |
|
|
<h4 class="font-semibold text-gray-800 mb-2">System Information</h4> |
|
|
<div class="space-y-1 text-gray-500"> |
|
|
<p>Products indexed: 9,509</p> |
|
|
<p>Index status: <span class="text-green-600 font-medium">Ready</span></p> |
|
|
</div> |
|
|
</div> |
|
|
<div> |
|
|
<h4 class="font-semibold text-gray-800 mb-2">How it Works</h4> |
|
|
<div class="space-y-1 text-gray-500"> |
|
|
<p>1. CLIP encodes your query</p> |
|
|
<p>2. ChromaDB retrieves similar products</p> |
|
|
</div> |
|
|
</div> |
|
|
<div> |
|
|
<h4 class="font-semibold text-gray-800 mb-2">Tips</h4> |
|
|
<div class="space-y-1 text-gray-500"> |
|
|
<p>β’ Combine text + image for best results</p> |
|
|
<p>β’ Be specific in your descriptions</p> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
<div class="border-t border-gray-100 mt-8 pt-6 text-center text-xs text-gray-400"> |
|
|
© 2025 Amazon Multimodal RAG Demo. Powered by FastAPI + ChromaDB. |
|
|
</div> |
|
|
</div> |
|
|
</footer> |
|
|
|
|
|
<script src="main.js"></script> |
|
|
</body> |
|
|
</html> |