mirror of
https://github.com/mudler/LocalAI.git
synced 2025-12-30 22:20:20 -06:00
* wip * Simplify stop Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * Improve UI Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * Show installed backends at the index Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * Imporve UI Signed-off-by: Ettore Di Giacinto <mudler@localai.io> --------- Signed-off-by: Ettore Di Giacinto <mudler@localai.io>
387 lines
21 KiB
HTML
387 lines
21 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
{{template "views/partials/head" .}}
|
|
|
|
<body class="bg-gradient-to-br from-gray-900 via-gray-950 to-black text-gray-200">
|
|
<div class="flex flex-col min-h-screen">
|
|
|
|
{{template "views/partials/navbar" .}}
|
|
{{ $numModelsPerPage := 21 }}
|
|
<div class="container mx-auto px-4 py-8 flex-grow">
|
|
|
|
<!-- Hero Header -->
|
|
<div class="relative bg-gradient-to-r from-indigo-900/40 via-purple-900/30 to-pink-900/40 rounded-3xl shadow-2xl p-8 mb-12 overflow-hidden">
|
|
<!-- Background Pattern -->
|
|
<div class="absolute inset-0 opacity-10">
|
|
<div class="absolute inset-0 bg-gradient-to-r from-indigo-500/20 to-purple-500/20"></div>
|
|
<div class="absolute top-0 left-0 w-full h-full" style="background-image: radial-gradient(circle at 1px 1px, rgba(255,255,255,0.15) 1px, transparent 0); background-size: 20px 20px;"></div>
|
|
</div>
|
|
|
|
<div class="relative max-w-5xl mx-auto text-center">
|
|
<h1 class="text-4xl md:text-5xl font-bold text-white mb-4">
|
|
<span class="bg-clip-text text-transparent bg-gradient-to-r from-indigo-400 via-purple-400 to-pink-400">
|
|
Model Gallery
|
|
</span>
|
|
</h1>
|
|
<p class="text-lg md:text-xl text-gray-300 mb-6 font-light">
|
|
Discover and install AI models from our curated collection
|
|
</p>
|
|
<div class="flex flex-wrap justify-center items-center gap-6 text-sm md:text-base">
|
|
<div class="flex items-center bg-white/10 rounded-full px-4 py-2">
|
|
<div class="w-2 h-2 bg-indigo-400 rounded-full mr-2 animate-pulse"></div>
|
|
<span class="font-semibold text-indigo-300">{{.AvailableModels}}</span>
|
|
<span class="text-gray-300 ml-1">models available</span>
|
|
</div>
|
|
<div class="flex items-center bg-white/10 rounded-full px-4 py-2">
|
|
<div class="w-2 h-2 bg-purple-400 rounded-full mr-2 animate-pulse"></div>
|
|
<span class="font-semibold text-purple-300">{{ len .Repositories }}</span>
|
|
<span class="text-gray-300 ml-1">repositories</span>
|
|
</div>
|
|
<a href="https://localai.io/models/" target="_blank"
|
|
class="flex items-center bg-blue-600/80 hover:bg-blue-600 text-white px-4 py-2 rounded-full transition-all duration-300 hover:scale-105">
|
|
<i class="fas fa-info-circle mr-2"></i>
|
|
<span>Documentation</span>
|
|
<i class="fas fa-external-link-alt ml-2 text-xs"></i>
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{{template "views/partials/inprogress" .}}
|
|
|
|
<!-- Search and Filter Section -->
|
|
<div class="relative bg-gradient-to-br from-gray-800/80 to-gray-900/80 rounded-2xl p-8 mb-8 shadow-xl border border-gray-700/50 backdrop-blur-sm">
|
|
<div class="absolute inset-0 rounded-2xl bg-gradient-to-br from-blue-500/5 to-purple-500/5"></div>
|
|
|
|
<div class="relative">
|
|
<!-- Search Input -->
|
|
<div class="mb-8">
|
|
<h3 class="text-xl font-semibold text-white mb-4 flex items-center">
|
|
<i class="fas fa-search mr-3 text-blue-400"></i>
|
|
Find Your Perfect Model
|
|
</h3>
|
|
<div class="relative">
|
|
<div class="absolute inset-y-0 start-0 flex items-center ps-4 pointer-events-none">
|
|
<i class="fas fa-search text-gray-400"></i>
|
|
</div>
|
|
<input class="w-full pl-12 pr-16 py-4 text-base font-normal text-gray-300 bg-gray-900/90 border border-gray-700/70 rounded-xl transition-all duration-300 focus:text-gray-200 focus:bg-gray-900 focus:border-blue-500 focus:ring-2 focus:ring-blue-500/50 focus:outline-none"
|
|
type="search"
|
|
name="search"
|
|
placeholder="Search models by name, tag, or description..."
|
|
hx-post="browse/search/models"
|
|
hx-trigger="input changed delay:500ms, search"
|
|
hx-target="#search-results"
|
|
oninput="hidePagination()"
|
|
onchange="hidePagination()"
|
|
onsearch="hidePagination()"
|
|
hx-indicator=".htmx-indicator">
|
|
<span class="htmx-indicator absolute right-4 top-4">
|
|
<svg class="animate-spin h-6 w-6 text-blue-500" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
|
|
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
|
|
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
|
|
</svg>
|
|
</span>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Filter by Type -->
|
|
<div class="mb-8">
|
|
<h3 class="text-lg font-semibold text-white mb-4 flex items-center">
|
|
<i class="fas fa-filter mr-3 text-purple-400"></i>
|
|
Filter by Model Type
|
|
</h3>
|
|
<div class="grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-4 xl:grid-cols-8 gap-3">
|
|
<button hx-post="browse/search/models"
|
|
class="group flex items-center justify-center rounded-xl px-4 py-3 text-sm font-semibold bg-gradient-to-r from-indigo-600/80 to-indigo-700/80 hover:from-indigo-600 hover:to-indigo-700 text-indigo-100 border border-indigo-500/30 hover:border-indigo-400/50 transition-all duration-300 transform hover:scale-105 hover:shadow-lg hover:shadow-indigo-500/25"
|
|
hx-target="#search-results"
|
|
hx-vals='{"search": "tts"}'
|
|
onclick="hidePagination()"
|
|
hx-indicator=".htmx-indicator">
|
|
<i class="fas fa-microphone mr-2 group-hover:animate-pulse"></i>
|
|
<span>TTS</span>
|
|
</button>
|
|
<button hx-post="browse/search/models"
|
|
class="group flex items-center justify-center rounded-xl px-4 py-3 text-sm font-semibold bg-gradient-to-r from-purple-600/80 to-purple-700/80 hover:from-purple-600 hover:to-purple-700 text-purple-100 border border-purple-500/30 hover:border-purple-400/50 transition-all duration-300 transform hover:scale-105 hover:shadow-lg hover:shadow-purple-500/25"
|
|
hx-target="#search-results"
|
|
hx-vals='{"search": "stablediffusion"}'
|
|
onclick="hidePagination()"
|
|
hx-indicator=".htmx-indicator">
|
|
<i class="fas fa-image mr-2 group-hover:animate-pulse"></i>
|
|
<span>Image</span>
|
|
</button>
|
|
<button hx-post="browse/search/models"
|
|
class="group flex items-center justify-center rounded-xl px-4 py-3 text-sm font-semibold bg-gradient-to-r from-blue-600/80 to-blue-700/80 hover:from-blue-600 hover:to-blue-700 text-blue-100 border border-blue-500/30 hover:border-blue-400/50 transition-all duration-300 transform hover:scale-105 hover:shadow-lg hover:shadow-blue-500/25"
|
|
hx-target="#search-results"
|
|
hx-vals='{"search": "llm"}'
|
|
onclick="hidePagination()"
|
|
hx-indicator=".htmx-indicator">
|
|
<i class="fas fa-comment-alt mr-2 group-hover:animate-bounce"></i>
|
|
<span>LLM</span>
|
|
</button>
|
|
<button hx-post="browse/search/models"
|
|
class="group flex items-center justify-center rounded-xl px-4 py-3 text-sm font-semibold bg-gradient-to-r from-green-600/80 to-green-700/80 hover:from-green-600 hover:to-green-700 text-green-100 border border-green-500/30 hover:border-green-400/50 transition-all duration-300 transform hover:scale-105 hover:shadow-lg hover:shadow-green-500/25"
|
|
hx-target="#search-results"
|
|
hx-vals='{"search": "multimodal"}'
|
|
onclick="hidePagination()"
|
|
hx-indicator=".htmx-indicator">
|
|
<i class="fas fa-object-group mr-2 group-hover:animate-pulse"></i>
|
|
<span>Multimodal</span>
|
|
</button>
|
|
<button hx-post="browse/search/models"
|
|
class="group flex items-center justify-center rounded-xl px-4 py-3 text-sm font-semibold bg-gradient-to-r from-cyan-600/80 to-cyan-700/80 hover:from-cyan-600 hover:to-cyan-700 text-cyan-100 border border-cyan-500/30 hover:border-cyan-400/50 transition-all duration-300 transform hover:scale-105 hover:shadow-lg hover:shadow-cyan-500/25"
|
|
hx-target="#search-results"
|
|
hx-vals='{"search": "embedding"}'
|
|
onclick="hidePagination()"
|
|
hx-indicator=".htmx-indicator">
|
|
<i class="fas fa-vector-square mr-2 group-hover:animate-pulse"></i>
|
|
<span>Embedding</span>
|
|
</button>
|
|
<button hx-post="browse/search/models"
|
|
class="group flex items-center justify-center rounded-xl px-4 py-3 text-sm font-semibold bg-gradient-to-r from-amber-600/80 to-amber-700/80 hover:from-amber-600 hover:to-amber-700 text-amber-100 border border-amber-500/30 hover:border-amber-400/50 transition-all duration-300 transform hover:scale-105 hover:shadow-lg hover:shadow-amber-500/25"
|
|
hx-target="#search-results"
|
|
hx-vals='{"search": "rerank"}'
|
|
onclick="hidePagination()"
|
|
hx-indicator=".htmx-indicator">
|
|
<i class="fas fa-sort-amount-up mr-2 group-hover:animate-pulse"></i>
|
|
<span>Rerank</span>
|
|
</button>
|
|
<button hx-post="browse/search/models"
|
|
class="group flex items-center justify-center rounded-xl px-4 py-3 text-sm font-semibold bg-gradient-to-r from-teal-600/80 to-teal-700/80 hover:from-teal-600 hover:to-teal-700 text-teal-100 border border-teal-500/30 hover:border-teal-400/50 transition-all duration-300 transform hover:scale-105 hover:shadow-lg hover:shadow-teal-500/25"
|
|
hx-target="#search-results"
|
|
hx-vals='{"search": "whisper"}'
|
|
onclick="hidePagination()"
|
|
hx-indicator=".htmx-indicator">
|
|
<i class="fas fa-headphones mr-2 group-hover:animate-pulse"></i>
|
|
<span>Whisper</span>
|
|
</button>
|
|
<button hx-post="browse/search/models"
|
|
class="group flex items-center justify-center rounded-xl px-4 py-3 text-sm font-semibold bg-gradient-to-r from-red-600/80 to-red-700/80 hover:from-red-600 hover:to-red-700 text-red-100 border border-red-500/30 hover:border-red-400/50 transition-all duration-300 transform hover:scale-105 hover:shadow-lg hover:shadow-red-500/25"
|
|
hx-target="#search-results"
|
|
hx-vals='{"search": "object-detection"}'
|
|
onclick="hidePagination()"
|
|
hx-indicator=".htmx-indicator">
|
|
<i class="fas fa-eye mr-2 group-hover:animate-pulse"></i>
|
|
<span>Vision</span>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Filter by Tags -->
|
|
<div>
|
|
<h3 class="text-lg font-semibold text-white mb-4 flex items-center">
|
|
<i class="fas fa-tags mr-3 text-pink-400"></i>
|
|
Browse by Tags
|
|
</h3>
|
|
<div class="max-h-32 overflow-y-auto scrollbar-thin scrollbar-thumb-gray-600/50 scrollbar-track-gray-800/50 pr-2">
|
|
<div class="flex flex-wrap gap-2">
|
|
{{ range .AllTags }}
|
|
<button hx-post="browse/search/models"
|
|
class="group inline-flex items-center text-xs px-3 py-2 rounded-full bg-gray-700/60 hover:bg-gray-600/80 text-gray-300 hover:text-white border border-gray-600/50 hover:border-gray-500/70 transition-all duration-200 ease-in-out transform hover:scale-105"
|
|
hx-target="#search-results"
|
|
hx-vals='{"search": "{{.}}"}'
|
|
onclick="hidePagination()"
|
|
hx-indicator=".htmx-indicator">
|
|
<i class="fas fa-tag text-xs mr-2 group-hover:animate-pulse"></i>
|
|
<span>{{.}}</span>
|
|
</button>
|
|
{{ end }}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Results Section -->
|
|
<div id="search-results" class="transition-all duration-300">
|
|
{{.Models}}
|
|
</div>
|
|
|
|
<!-- Pagination -->
|
|
{{ if gt .AvailableModels $numModelsPerPage }}
|
|
<div id="paginate" class="flex justify-center mt-12">
|
|
<div class="flex items-center gap-4 bg-gray-800/60 rounded-2xl p-4 backdrop-blur-sm border border-gray-700/50">
|
|
<button onclick="window.location.href='browse?page={{.PrevPage}}'"
|
|
class="group flex items-center justify-center h-12 w-12 bg-gray-700/80 hover:bg-indigo-600 text-gray-300 hover:text-white rounded-xl shadow-lg transition-all duration-300 ease-in-out transform hover:scale-110 {{if not .PrevPage}}opacity-50 cursor-not-allowed{{end}}"
|
|
{{if not .PrevPage}}disabled{{end}}>
|
|
<i class="fas fa-chevron-left group-hover:animate-pulse"></i>
|
|
</button>
|
|
<div class="text-gray-300 text-sm font-medium px-4">
|
|
<span class="text-gray-400">Page</span>
|
|
<span class="text-white font-bold text-lg mx-2">{{add .PrevPage 1}}</span>
|
|
<span class="text-gray-400">of many</span>
|
|
</div>
|
|
<button onclick="window.location.href='browse?page={{.NextPage}}'"
|
|
class="group flex items-center justify-center h-12 w-12 bg-gray-700/80 hover:bg-indigo-600 text-gray-300 hover:text-white rounded-xl shadow-lg transition-all duration-300 ease-in-out transform hover:scale-110 {{if not .NextPage}}opacity-50 cursor-not-allowed{{end}}"
|
|
{{if not .NextPage}}disabled{{end}}>
|
|
<i class="fas fa-chevron-right group-hover:animate-pulse"></i>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
{{ end }}
|
|
|
|
</div>
|
|
{{template "views/partials/footer" .}}
|
|
</div>
|
|
|
|
<style>
|
|
/* Enhanced scrollbar styling */
|
|
.scrollbar-thin::-webkit-scrollbar {
|
|
width: 6px;
|
|
}
|
|
|
|
.scrollbar-thin::-webkit-scrollbar-track {
|
|
background: rgba(31, 41, 55, 0.5);
|
|
border-radius: 6px;
|
|
}
|
|
|
|
.scrollbar-thin::-webkit-scrollbar-thumb {
|
|
background: rgba(107, 114, 128, 0.5);
|
|
border-radius: 6px;
|
|
}
|
|
|
|
.scrollbar-thin::-webkit-scrollbar-thumb:hover {
|
|
background: rgba(107, 114, 128, 0.8);
|
|
}
|
|
|
|
/* Add some custom CSS for gallery model cards to match our theme */
|
|
#search-results .dark\:bg-gray-800 {
|
|
background: linear-gradient(135deg, rgba(31, 41, 55, 0.9) 0%, rgba(17, 24, 39, 0.9) 100%) !important;
|
|
border: 1px solid rgba(75, 85, 99, 0.5) !important;
|
|
border-radius: 1rem !important;
|
|
transition: all 0.5s ease !important;
|
|
backdrop-filter: blur(8px) !important;
|
|
}
|
|
|
|
#search-results .dark\:bg-gray-800:hover {
|
|
transform: translateY(-8px) !important;
|
|
box-shadow: 0 25px 50px -12px rgba(59, 130, 246, 0.1) !important;
|
|
border-color: rgba(59, 130, 246, 0.3) !important;
|
|
}
|
|
|
|
/* Style the install buttons */
|
|
#search-results .bg-blue-600 {
|
|
background: linear-gradient(135deg, #3b82f6 0%, #2563eb 100%) !important;
|
|
border-radius: 0.75rem !important;
|
|
padding: 0.75rem 1.5rem !important;
|
|
font-weight: 600 !important;
|
|
transition: all 0.3s ease !important;
|
|
box-shadow: 0 4px 15px rgba(59, 130, 246, 0.25) !important;
|
|
}
|
|
|
|
#search-results .bg-blue-600:hover {
|
|
background: linear-gradient(135deg, #2563eb 0%, #1d4ed8 100%) !important;
|
|
transform: scale(1.05) !important;
|
|
box-shadow: 0 8px 25px rgba(59, 130, 246, 0.4) !important;
|
|
}
|
|
|
|
/* Style the model images */
|
|
#search-results img.rounded-t-lg {
|
|
border-radius: 1rem !important;
|
|
transition: transform 0.3s ease !important;
|
|
}
|
|
|
|
#search-results .dark\:bg-gray-800:hover img.rounded-t-lg {
|
|
transform: scale(1.05) !important;
|
|
}
|
|
|
|
/* Style the progress bars */
|
|
#search-results .progress {
|
|
background: linear-gradient(135deg, rgba(59, 130, 246, 0.2) 0%, rgba(99, 102, 241, 0.2) 100%) !important;
|
|
border-radius: 0.5rem !important;
|
|
border: 1px solid rgba(59, 130, 246, 0.3) !important;
|
|
}
|
|
|
|
/* Style action buttons */
|
|
#search-results button[class*="primary"] {
|
|
background: linear-gradient(135deg, #6366f1 0%, #4f46e5 100%) !important;
|
|
border-radius: 0.5rem !important;
|
|
transition: all 0.2s ease !important;
|
|
}
|
|
|
|
#search-results button[class*="primary"]:hover {
|
|
transform: scale(1.05) !important;
|
|
box-shadow: 0 4px 15px rgba(99, 102, 241, 0.3) !important;
|
|
}
|
|
|
|
/* Style the reinstall buttons specifically */
|
|
#search-results .bg-primary {
|
|
background: linear-gradient(135deg, #059669 0%, #047857 100%) !important;
|
|
border-radius: 0.75rem !important;
|
|
padding: 0.75rem 1.5rem !important;
|
|
font-weight: 600 !important;
|
|
transition: all 0.3s ease !important;
|
|
box-shadow: 0 4px 15px rgba(5, 150, 105, 0.25) !important;
|
|
}
|
|
|
|
#search-results .bg-primary:hover {
|
|
background: linear-gradient(135deg, #047857 0%, #065f46 100%) !important;
|
|
transform: scale(1.05) !important;
|
|
box-shadow: 0 8px 25px rgba(5, 150, 105, 0.4) !important;
|
|
}
|
|
|
|
/* Style the delete buttons */
|
|
#search-results .bg-red-800 {
|
|
background: linear-gradient(135deg, #dc2626 0%, #b91c1c 100%) !important;
|
|
border-radius: 0.75rem !important;
|
|
padding: 0.75rem 1.5rem !important;
|
|
font-weight: 600 !important;
|
|
transition: all 0.3s ease !important;
|
|
box-shadow: 0 4px 15px rgba(220, 38, 38, 0.25) !important;
|
|
}
|
|
|
|
#search-results .bg-red-800:hover {
|
|
background: linear-gradient(135deg, #b91c1c 0%, #991b1b 100%) !important;
|
|
transform: scale(1.05) !important;
|
|
box-shadow: 0 8px 25px rgba(220, 38, 38, 0.4) !important;
|
|
}
|
|
|
|
/* Style the info buttons */
|
|
#search-results .bg-gray-700 {
|
|
background: linear-gradient(135deg, #374151 0%, #1f2937 100%) !important;
|
|
border-radius: 0.75rem !important;
|
|
padding: 0.75rem 1.5rem !important;
|
|
font-weight: 600 !important;
|
|
transition: all 0.3s ease !important;
|
|
box-shadow: 0 4px 15px rgba(55, 65, 81, 0.25) !important;
|
|
}
|
|
|
|
#search-results .bg-gray-700:hover {
|
|
background: linear-gradient(135deg, #1f2937 0%, #111827 100%) !important;
|
|
transform: scale(1.05) !important;
|
|
box-shadow: 0 8px 25px rgba(55, 65, 81, 0.4) !important;
|
|
}
|
|
</style>
|
|
|
|
<script>
|
|
function hidePagination() {
|
|
const paginateDiv = document.getElementById('paginate');
|
|
if (paginateDiv) {
|
|
paginateDiv.style.display = 'none';
|
|
}
|
|
}
|
|
|
|
// Listen for the htmx:afterSwap event to handle cases when the search results are updated
|
|
document.body.addEventListener('htmx:afterSwap', function(event) {
|
|
if (event.detail.target.id === 'search-results') {
|
|
hidePagination();
|
|
}
|
|
});
|
|
|
|
// Add loading state animation
|
|
document.body.addEventListener('htmx:beforeRequest', function(event) {
|
|
const searchInput = document.querySelector('input[name="search"]');
|
|
if (searchInput && event.detail.elt === searchInput) {
|
|
searchInput.classList.add('animate-pulse');
|
|
}
|
|
});
|
|
|
|
document.body.addEventListener('htmx:afterRequest', function(event) {
|
|
const searchInput = document.querySelector('input[name="search"]');
|
|
if (searchInput) {
|
|
searchInput.classList.remove('animate-pulse');
|
|
}
|
|
});
|
|
</script>
|
|
|
|
</body>
|
|
</html> |